From 207c66809fe125de3b8f5805d80e50f56222b63a Mon Sep 17 00:00:00 2001 From: Max Lee Date: Thu, 9 Feb 2017 22:19:26 +0100 Subject: [PATCH 001/399] Add separate logging entry for ender crystal explosions and default all posible explosions to true (#669) --- src/main/java/de/diddiz/LogBlock/Logging.java | 4 ++-- .../de/diddiz/LogBlock/listeners/ExplosionLogging.java | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index 77765181..e042265b 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -2,13 +2,13 @@ public enum Logging { BLOCKPLACE(true), BLOCKBREAK(true), SIGNTEXT, TNTEXPLOSION(true), CREEPEREXPLOSION(true), - GHASTFIREBALLEXPLOSION(true), ENDERDRAGON(true), MISCEXPLOSION, FIRE(true), LEAVESDECAY, + GHASTFIREBALLEXPLOSION(true), ENDERDRAGON(true), MISCEXPLOSION(true), FIRE(true), LEAVESDECAY, LAVAFLOW, WATERFLOW, CHESTACCESS, KILL, CHAT, SNOWFORM, SNOWFADE, DOORINTERACT, SWITCHINTERACT, CAKEEAT, ENDERMEN, NOTEBLOCKINTERACT, DIODEINTERACT, COMPARATORINTERACT, PRESUREPLATEINTERACT, TRIPWIREINTERACT, CREATURECROPTRAMPLE, CROPTRAMPLE, NATURALSTRUCTUREGROW, GRASSGROWTH, MYCELIUMSPREAD, VINEGROWTH, MUSHROOMSPREAD, WITHER(true), WITHER_SKULL(true), BONEMEALSTRUCTUREGROW, - WORLDEDIT, TNTMINECARTEXPLOSION(true), LOCKEDCHESTDECAY; + WORLDEDIT, TNTMINECARTEXPLOSION(true), LOCKEDCHESTDECAY, ENDERCRYSTALEXPLOSION(true); public static final int length = Logging.values().length; private final boolean defaultEnabled; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index 070b7174..eb1a1fc7 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -85,6 +85,13 @@ public void onEntityExplode(EntityExplodeEvent event) { return; } actor = Actor.actorFromEntity(source); + + } else if (source instanceof EnderCrystal){ + if (!wcfg.isLogging(Logging.ENDERCRYSTALEXPLOSION)) { + return; + } + actor = Actor.actorFromEntity(source); + } else { if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { return; From 80de6eb38335528c20062c5e76e13ad4bf5e4b74 Mon Sep 17 00:00:00 2001 From: Niklas Date: Sat, 10 Jun 2017 00:27:28 +0200 Subject: [PATCH 002/399] Update for 1.12 (#694) --- pom.xml | 4 ++-- src/main/java/de/diddiz/util/BukkitUtils.java | 1 + src/main/java/de/diddiz/util/MaterialName.java | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index fe6a40c0..8747c3b5 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.11-SNAPSHOT + 1.12-SNAPSHOT jar LogBlock @@ -42,7 +42,7 @@ org.bukkit bukkit - 1.11-R0.1-SNAPSHOT + 1.12-R0.1-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 02f4b730..4fedab3e 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -95,6 +95,7 @@ public class BukkitUtils { relativeTopFallables.add(Material.GRAVEL); relativeTopFallables.add(Material.DRAGON_EGG); relativeTopFallables.add(Material.ANVIL); + relativeTopFallables.add(Material.CONCRETE_POWDER); // Blocks that break falling entities fallingEntityKillers = new HashSet(32); diff --git a/src/main/java/de/diddiz/util/MaterialName.java b/src/main/java/de/diddiz/util/MaterialName.java index 9c763bdb..b85ce912 100644 --- a/src/main/java/de/diddiz/util/MaterialName.java +++ b/src/main/java/de/diddiz/util/MaterialName.java @@ -178,10 +178,12 @@ public class MaterialName { for (byte i = 0; i < 16; i++) { cfg.set("351." + i, toReadable(Material.INK_SACK.getNewData(i))); cfg.set("35." + i, COLORS[i] + " wool"); - cfg.set("159." + i, COLORS[i] + " stained clay"); + cfg.set("159." + i, COLORS[i] + " stained terracotta"); cfg.set("95." + i, COLORS[i] + " stained glass"); cfg.set("160." + i, COLORS[i] + " stained glass pane"); cfg.set("171." + i, COLORS[i] + " carpet"); + cfg.set("251." + i, COLORS[i] + " concrete"); + cfg.set("252." + i, COLORS[i] + " concrete powder"); } for (byte i = 0; i < 6; i++) { cfg.set("125." + i, toReadable(Material.WOOD_DOUBLE_STEP.getNewData(i))); @@ -194,7 +196,7 @@ public class MaterialName { getLogger().log(Level.WARNING, "Unable to save material.yml: ", ex); } } - if (cfg.getString("263.1") == null) { + if (cfg.getString("252.1") == null) { getLogger().info("[Logblock-names] Logblock's default materials.yml file has been updated with more names"); getLogger().info("[Logblock-names] Consider deleting your current materials.yml file to allow it to be recreated"); } From ba8c1281e3609b0ad8dde2d5ad176b94f0ce902d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Preu=C3=9F?= Date: Fri, 30 Jun 2017 01:01:30 +0200 Subject: [PATCH 003/399] Change `materials.yml` location to relative (#697) --- src/main/java/de/diddiz/util/MaterialName.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/util/MaterialName.java b/src/main/java/de/diddiz/util/MaterialName.java index b85ce912..9d6fe22d 100644 --- a/src/main/java/de/diddiz/util/MaterialName.java +++ b/src/main/java/de/diddiz/util/MaterialName.java @@ -1,5 +1,6 @@ package de.diddiz.util; +import de.diddiz.LogBlock.LogBlock; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; @@ -27,7 +28,7 @@ public class MaterialName { materialNames.put(mat.getId(), mat.toString().replace('_', ' ').toLowerCase()); } // Load config - final File file = new File("plugins/LogBlock/materials.yml"); + final File file = new File(LogBlock.getInstance().getDataFolder(), "materials.yml"); final YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file); if (cfg.getKeys(false).isEmpty()) { // Generate defaults From defcfeeb076a462c979451981a3e8fee5461526a Mon Sep 17 00:00:00 2001 From: md_5 Date: Sat, 8 Jul 2017 18:04:21 +1000 Subject: [PATCH 004/399] #698: Misc explosion logging --- .../LogBlock/listeners/ExplosionLogging.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index eb1a1fc7..e53b5568 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -11,6 +11,7 @@ import org.bukkit.entity.minecart.ExplosiveMinecart; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockExplodeEvent; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.projectiles.ProjectileSource; @@ -109,4 +110,27 @@ public void onEntityExplode(EntityExplodeEvent event) { } } } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockExplode(BlockExplodeEvent event) { + for (final Block block : event.blockList()) { + final WorldConfig wcfg = getWorldConfig(block.getLocation().getWorld()); + + if (wcfg != null) { + if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { + return; + } + Actor actor = new Actor("Explosion"); + + final int type = block.getTypeId(); + if (wcfg.isLogging(Logging.SIGNTEXT) & (type == 63 || type == 68)) { + consumer.queueSignBreak(actor, (Sign) block.getState()); + } else if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(Material.getMaterial(type)))) { + consumer.queueContainerBreak(actor, block.getState()); + } else { + consumer.queueBlockBreak(actor, block.getState()); + } + } + } + } } From 72851ca52f44b1e0cb1c683e77ddcd0c5a299640 Mon Sep 17 00:00:00 2001 From: md_5 Date: Fri, 11 Aug 2017 18:31:55 +1000 Subject: [PATCH 005/399] #700: Change chat columns to 256 --- src/main/java/de/diddiz/LogBlock/Updater.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index f0767aee..24c49ade 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -386,6 +386,22 @@ boolean update() { config.set("version", "1.10.0"); } + if (configVersion.compareTo(new ComparableVersion("1.12.0")) < 0) { + getLogger().info("Updating tables to 1.12.0 ..."); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + st.execute("ALTER TABLE `lb-chat` ALTER COLUMN `message` VARCHAR(256) NOT NULL"); + st.close(); + conn.close(); + } catch (final SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.12.0"); + } + logblock.saveConfig(); return true; } @@ -423,7 +439,7 @@ void checkTables() throws SQLException { state.execute("INSERT IGNORE INTO `lb-players` (UUID,playername) VALUES ('log_dummy_record','dummy_record')"); } if (isLogging(Logging.CHAT)) { - createTable(dbm, state, "lb-chat", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, message VARCHAR(255) NOT NULL, PRIMARY KEY (id), KEY playerid (playerid), FULLTEXT message (message)) ENGINE=MyISAM DEFAULT CHARSET " + charset); + createTable(dbm, 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)) ENGINE=MyISAM DEFAULT CHARSET " + charset); } for (final WorldConfig wcfg : getLoggedWorlds()) { createTable(dbm, state, wcfg.table, "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced TINYINT UNSIGNED NOT NULL, type TINYINT UNSIGNED NOT NULL, data TINYINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))"); From a51651c30675fdb0fe312f1516bc50890a601812 Mon Sep 17 00:00:00 2001 From: md_5 Date: Sun, 13 Aug 2017 19:41:34 +1000 Subject: [PATCH 006/399] repo.md-5.net -> https --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8747c3b5..c2f80e3d 100644 --- a/pom.xml +++ b/pom.xml @@ -30,11 +30,11 @@ md_5-releases - http://repo.md-5.net/content/repositories/releases/ + https://repo.md-5.net/content/repositories/releases/ md_5-snapshots - http://repo.md-5.net/content/repositories/snapshots/ + https://repo.md-5.net/content/repositories/snapshots/ From 40c1cc1c22505199cebb1cc4deff801033141295 Mon Sep 17 00:00:00 2001 From: md_5 Date: Wed, 16 Aug 2017 20:52:28 +1000 Subject: [PATCH 007/399] #702: MySQL error in upgrader --- src/main/java/de/diddiz/LogBlock/Updater.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 24c49ade..d7dffdf2 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -388,16 +388,18 @@ boolean update() { if (configVersion.compareTo(new ComparableVersion("1.12.0")) < 0) { getLogger().info("Updating tables to 1.12.0 ..."); - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - st.execute("ALTER TABLE `lb-chat` ALTER COLUMN `message` VARCHAR(256) NOT NULL"); - st.close(); - conn.close(); - } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; + if (isLogging(Logging.CHAT)) { + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + st.execute("ALTER TABLE `lb-chat` MODIFY COLUMN `message` VARCHAR(256) NOT NULL"); + st.close(); + conn.close(); + } catch (final SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } } config.set("version", "1.12.0"); } From 0ed8728d0149460bb0377fc5971dddeb7fbe2ae4 Mon Sep 17 00:00:00 2001 From: md_5 Date: Fri, 18 Aug 2017 17:57:09 +1000 Subject: [PATCH 008/399] #703: Chest rollback issues on 1.12.1 --- src/main/java/de/diddiz/LogBlock/WorldEditor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 1c54adc3..7ddc83d1 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -182,7 +182,7 @@ PerformResult perform() throws WorldEditorException { } catch (final Exception ex) { throw new WorldEditorException(ex.getMessage(), block.getLocation()); } - if (!state.update()) { + if (false /*!state.update()*/) { // Raw inventory doesn't need update, really should be using snapshot inventory however. Do this for backwards compat with < 1.12.1 throw new WorldEditorException("Failed to update inventory of " + materialName(block.getTypeId()), block.getLocation()); } if (leftover > 0 && ca.itemAmount < 0) { From 1ce92e1d3fdb46cc8af97f6326f9b9e8231716a3 Mon Sep 17 00:00:00 2001 From: Yannick Schinko Date: Tue, 12 Dec 2017 00:01:32 +0100 Subject: [PATCH 009/399] Updated HikariCP to latest version (#707) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c2f80e3d..faf72091 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ com.zaxxer HikariCP - 2.4.1 + 2.7.4 compile From ce30d33824ef63032ec58a3239342abbbae06f71 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 21 Jul 2018 02:41:52 +0200 Subject: [PATCH 010/399] Update to 1.13 / Logging/Rollbacks work but largely untested Still missing: Import data from 1.12 and older --- pom.xml | 10 +- src/main/java/de/diddiz/LogBlock/Actor.java | 2 +- .../java/de/diddiz/LogBlock/BlockChange.java | 112 +-- .../java/de/diddiz/LogBlock/ChestAccess.java | 12 +- .../de/diddiz/LogBlock/CommandsHandler.java | 48 +- .../java/de/diddiz/LogBlock/Consumer.java | 707 ++++++++---------- src/main/java/de/diddiz/LogBlock/Kill.java | 13 +- .../java/de/diddiz/LogBlock/LogBlock.java | 10 +- .../de/diddiz/LogBlock/MaterialConverter.java | 129 ++++ .../java/de/diddiz/LogBlock/QueryParams.java | 131 +--- .../diddiz/LogBlock/SummedBlockChanges.java | 7 +- src/main/java/de/diddiz/LogBlock/Tool.java | 5 +- src/main/java/de/diddiz/LogBlock/Updater.java | 9 +- .../java/de/diddiz/LogBlock/WorldEditor.java | 121 +-- .../de/diddiz/LogBlock/config/Config.java | 40 +- .../events/BlockChangePreLogEvent.java | 41 +- .../LogBlock/listeners/BanListener.java | 2 +- .../LogBlock/listeners/BlockBreakLogging.java | 7 +- .../LogBlock/listeners/BlockPlaceLogging.java | 14 +- .../listeners/BlockSpreadLogging.java | 2 +- .../listeners/ChestAccessLogging.java | 7 +- .../listeners/CreatureInteractLogging.java | 22 +- .../LogBlock/listeners/EndermenLogging.java | 2 +- .../LogBlock/listeners/ExplosionLogging.java | 12 +- .../LogBlock/listeners/FluidFlowLogging.java | 77 +- .../LogBlock/listeners/InteractLogging.java | 79 +- .../listeners/LockedChestDecayLogging.java | 26 - .../LogBlock/listeners/SignChangeLogging.java | 2 +- .../LogBlock/listeners/SnowFadeLogging.java | 6 +- .../LogBlock/listeners/SnowFormLogging.java | 6 +- .../LogBlock/listeners/ToolListener.java | 9 +- .../LogBlock/listeners/WitherLogging.java | 2 +- src/main/java/de/diddiz/util/Block.java | 34 - src/main/java/de/diddiz/util/BukkitUtils.java | 308 ++++---- .../de/diddiz/util/ComparableVersion.java | 2 + src/main/java/de/diddiz/util/LoggingUtil.java | 105 +-- .../java/de/diddiz/util/MaterialName.java | 280 ------- .../de/diddiz/util/MySQLConnectionPool.java | 2 +- src/main/java/de/diddiz/util/Utils.java | 59 ++ .../worldedit/WorldEditLoggingHook.java | 58 +- src/main/resources/plugin.yml | 1 + 41 files changed, 1142 insertions(+), 1379 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/MaterialConverter.java delete mode 100644 src/main/java/de/diddiz/LogBlock/listeners/LockedChestDecayLogging.java delete mode 100644 src/main/java/de/diddiz/util/Block.java delete mode 100644 src/main/java/de/diddiz/util/MaterialName.java diff --git a/pom.xml b/pom.xml index faf72091..93108f97 100644 --- a/pom.xml +++ b/pom.xml @@ -40,9 +40,9 @@ - org.bukkit - bukkit - 1.12-R0.1-SNAPSHOT + org.spigotmc + spigot-api + 1.13-pre7-R0.1-SNAPSHOT provided @@ -136,8 +136,8 @@ maven-compiler-plugin 3.2 - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index b739739f..95d0f96b 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -74,7 +74,7 @@ public static Actor actorFromEntity(Entity entity) { } public static Actor actorFromEntity(EntityType entity) { - return new Actor(entity.getName()); + return new Actor(entity.name()); } public static Actor actorFromProjectileSource(ProjectileSource psource) { diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index a5803df4..caa282e3 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -2,33 +2,40 @@ import de.diddiz.LogBlock.config.Config; import de.diddiz.util.BukkitUtils; +import de.diddiz.util.Utils; + import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Openable; +import org.bukkit.block.data.Powerable; +import org.bukkit.block.data.type.Switch; +import org.bukkit.inventory.ItemStack; import java.sql.ResultSet; import java.sql.SQLException; import static de.diddiz.util.LoggingUtil.checkText; -import static de.diddiz.util.MaterialName.materialName; public class BlockChange implements LookupCacheElement { public final long id, date; public final Location loc; public final Actor actor; public final String playerName; - public final int replaced, type; - public final byte data; + // public final BlockData replaced, type; + public final int replacedMaterial, replacedData, typeMaterial, typeData; public final String signtext; public final ChestAccess ca; - public BlockChange(long date, Location loc, Actor actor, int replaced, int type, byte data, String signtext, ChestAccess ca) { + public BlockChange(long date, Location loc, Actor actor, int replaced, int replacedData, int type, int typeData, String signtext, ChestAccess ca) { id = 0; this.date = date; this.loc = loc; this.actor = actor; - this.replaced = replaced; - this.type = type; - this.data = data; + this.replacedMaterial = replaced; + this.replacedData = replacedData; + this.typeMaterial = type; + this.typeData = typeData; this.signtext = checkText(signtext); this.ca = ca; this.playerName = actor == null ? null : actor.getName(); @@ -40,15 +47,25 @@ public BlockChange(ResultSet rs, QueryParams p) throws SQLException { loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null; actor = p.needPlayer ? new Actor(rs) : null; playerName = p.needPlayer ? rs.getString("playername") : null; - replaced = p.needType ? rs.getInt("replaced") : 0; - type = p.needType ? rs.getInt("type") : 0; - data = p.needData ? rs.getByte("data") : (byte) 0; + replacedMaterial = p.needType ? rs.getInt("replaced") : 0; + replacedData = p.needType ? rs.getInt("replacedData") : -1; + typeMaterial = p.needType ? rs.getInt("type") : 0; + typeData = p.needType ? rs.getInt("typeData") : -1; signtext = p.needSignText ? rs.getString("signtext") : null; - ca = p.needChestAccess && rs.getShort("itemtype") != 0 && rs.getShort("itemamount") != 0 ? new ChestAccess(rs.getShort("itemtype"), rs.getShort("itemamount"), rs.getShort("itemdata")) : null; + ChestAccess catemp = null; + if (p.needChestAccess) { + ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); + if (stack != null) { + catemp = new ChestAccess(stack, rs.getBoolean("itemremove")); + } + } + ca = catemp; } @Override public String toString() { + BlockData type = MaterialConverter.getBlockData(typeMaterial, typeData); + BlockData replaced = MaterialConverter.getBlockData(replacedMaterial, replacedData); final StringBuilder msg = new StringBuilder(); if (date > 0) { msg.append(Config.formatter.format(date)).append(" "); @@ -57,58 +74,47 @@ public String toString() { msg.append(actor.getName()).append(" "); } if (signtext != null) { - final String action = type == 0 ? "destroyed " : "created "; + final String action = type.getMaterial() == Material.AIR ? "destroyed " : "created "; if (!signtext.contains("\0")) { msg.append(action).append(signtext); } else { - msg.append(action).append(materialName(type != 0 ? type : replaced)).append(" [").append(signtext.replace("\0", "] [")).append("]"); + msg.append(action).append((type.getMaterial() != Material.AIR ? type : replaced).getMaterial().name()).append(" [").append(signtext.replace("\0", "] [")).append("]"); } - } else if (type == replaced) { - if (type == 0) { + } else if (type.equals(replaced)) { + if (type.getMaterial() == Material.AIR) { msg.append("did an unspecified action"); } else if (ca != null) { - if (ca.itemType == 0 || ca.itemAmount == 0) { - msg.append("looked inside ").append(materialName(type)); - } else if (ca.itemAmount < 0) { - msg.append("took ").append(-ca.itemAmount).append("x ").append(materialName(ca.itemType, ca.itemData)).append(" from ").append(materialName(type)); + if (ca.itemStack == null) { + msg.append("looked inside ").append(type.getMaterial().name()); + } else if (ca.remove) { + msg.append("took ").append(ca.itemStack.getAmount()).append("x ").append(ca.itemStack.getType().name()).append(" from ").append(type.getMaterial().name()); } else { - msg.append("put ").append(ca.itemAmount).append("x ").append(materialName(ca.itemType, ca.itemData)).append(" into ").append(materialName(type)); + msg.append("put ").append(ca.itemStack.getAmount()).append("x ").append(ca.itemStack.getType().name()).append(" into ").append(type.getMaterial().name()); } - } else if (BukkitUtils.getContainerBlocks().contains(Material.getMaterial(type))) { - msg.append("opened ").append(materialName(type)); - } else if (type == 64 || type == 71) - // This is a problem that will have to be addressed in LB 2, - // there is no way to tell from the top half of the block if - // the door is opened or closed. - { - msg.append("moved ").append(materialName(type)); - } - // Trapdoor - else if (type == 96) { - msg.append((data < 8 || data > 11) ? "opened" : "closed").append(" ").append(materialName(type)); - } - // Fence gate - else if (type == 107) { - msg.append(data > 3 ? "opened" : "closed").append(" ").append(materialName(type)); - } else if (type == 69) { - msg.append("switched ").append(materialName(type)); - } else if (type == 77 || type == 143) { - msg.append("pressed ").append(materialName(type)); - } else if (type == 92) { - msg.append("ate a piece of ").append(materialName(type)); - } else if (type == 25 || type == 93 || type == 94 || type == 149 || type == 150) { - msg.append("changed ").append(materialName(type)); - } else if (type == 70 || type == 72 || type == 147 || type == 148) { - msg.append("stepped on ").append(materialName(type)); - } else if (type == 132) { - msg.append("ran into ").append(materialName(type)); + } else if (BukkitUtils.getContainerBlocks().contains(type.getMaterial())) { + msg.append("opened ").append(type.getMaterial().name()); + } else if (type instanceof Openable) { + // Door, Trapdoor, Fence gate + msg.append(((Openable)type).isOpen() ? "opened" : "closed").append(" ").append(type.getMaterial().name()); + } else if (type.getMaterial() == Material.LEVER) { + msg.append("switched ").append(type.getMaterial().name()); + } else if (type instanceof Switch) { + msg.append("pressed ").append(type.getMaterial().name()); + } else if (type.getMaterial() == Material.CAKE) { + msg.append("ate a piece of ").append(type.getMaterial().name()); + } else if (type.getMaterial() == Material.NOTE_BLOCK || type.getMaterial() == Material.REPEATER || type.getMaterial() == Material.COMPARATOR || type.getMaterial() == Material.DAYLIGHT_DETECTOR) { + msg.append("changed ").append(type.getMaterial().name()); + } else if (type instanceof Powerable) { + msg.append("stepped on ").append(type.getMaterial().name()); + } else if (type.getMaterial() == Material.TRIPWIRE) { + msg.append("ran into ").append(type.getMaterial().name()); } - } else if (type == 0) { - msg.append("destroyed ").append(materialName(replaced, data)); - } else if (replaced == 0) { - msg.append("created ").append(materialName(type, data)); + } else if (type.getMaterial() == Material.AIR) { + msg.append("destroyed ").append(replaced.getMaterial().name()); + } else if (replaced.getMaterial() == Material.AIR) { + msg.append("created ").append(type.getMaterial().name()); } else { - msg.append("replaced ").append(materialName(replaced, (byte) 0)).append(" with ").append(materialName(type, data)); + msg.append("replaced ").append(replaced.getMaterial().name()).append(" with ").append(type.getMaterial().name()); } if (loc != null) { msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ()); diff --git a/src/main/java/de/diddiz/LogBlock/ChestAccess.java b/src/main/java/de/diddiz/LogBlock/ChestAccess.java index 10260e5b..f4926627 100644 --- a/src/main/java/de/diddiz/LogBlock/ChestAccess.java +++ b/src/main/java/de/diddiz/LogBlock/ChestAccess.java @@ -1,11 +1,13 @@ package de.diddiz.LogBlock; +import org.bukkit.inventory.ItemStack; + public class ChestAccess { - final short itemType, itemAmount, itemData; + final ItemStack itemStack; + final boolean remove; - public ChestAccess(short itemType, short itemAmount, short itemData) { - this.itemType = itemType; - this.itemAmount = itemAmount; - this.itemData = itemData >= 0 ? itemData : 0; + public ChestAccess(ItemStack itemStack, boolean remove) { + this.itemStack = itemStack; + this.remove = remove; } } diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 78bbf2ac..4fca25d4 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -6,9 +6,11 @@ import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.LogBlockQuestioner.LogBlockQuestioner; -import de.diddiz.util.Block; +import de.diddiz.util.Utils; + import org.bukkit.ChatColor; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -17,7 +19,6 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.scheduler.BukkitScheduler; -import java.io.Closeable; import java.io.File; import java.io.FileWriter; import java.sql.Connection; @@ -398,7 +399,7 @@ private boolean checkRestrictions(CommandSender sender, QueryParams params) { return true; } - public abstract class AbstractCommand implements Runnable, Closeable { + public abstract class AbstractCommand implements Runnable { protected CommandSender sender; protected QueryParams params; protected Connection conn = null; @@ -409,15 +410,12 @@ protected AbstractCommand(CommandSender sender, QueryParams params, boolean asyn this.sender = sender; this.params = params; if (async) { - if (scheduler.scheduleAsyncDelayedTask(logblock, this) == -1) { - throw new Exception("Failed to schedule the command"); - } + scheduler.runTaskAsynchronously(logblock, this); } else { run(); } } - @Override public final void close() { try { if (conn != null) { @@ -458,7 +456,7 @@ public void run() { params.needType = true; params.needData = true; params.needPlayer = true; - if (params.types.isEmpty() || Block.inList(params.types, 63) || Block.inList(params.types, 68)) { + if (params.types.isEmpty() || params.types.contains(Material.SIGN) || params.types.contains(Material.WALL_SIGN)) { params.needSignText = true; } if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) { @@ -523,7 +521,7 @@ public void run() { params.needType = true; params.needData = true; params.needPlayer = true; - if (params.types.isEmpty() || Block.inList(params.types, 63) || Block.inList(params.types, 68)) { + if (params.types.isEmpty() || params.types.contains(Material.SIGN) || params.types.contains(Material.WALL_SIGN)) { params.needSignText = true; } if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) { @@ -671,7 +669,12 @@ public void run() { final WorldEditor editor = new WorldEditor(logblock, params.world); while (rs.next()) { - editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("type"), rs.getByte("data"), rs.getString("signtext"), rs.getShort("itemtype"), rs.getShort("itemamount"), rs.getShort("itemdata")); + ChestAccess chestaccess = null; + ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); + if (stack != null) { + chestaccess = new ChestAccess(stack, rs.getBoolean("itemremove")); + } + editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getInt("type"), rs.getByte("typeData"), rs.getString("signtext"), chestaccess); } final int changes = editor.getSize(); if (changes > 10000) { @@ -741,7 +744,12 @@ public void run() { } final WorldEditor editor = new WorldEditor(logblock, params.world); while (rs.next()) { - editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("replaced"), rs.getByte("data"), rs.getString("signtext"), rs.getShort("itemtype"), (short) -rs.getShort("itemamount"), rs.getShort("itemdata")); + ChestAccess chestaccess = null; + ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); + if (stack != null) { + chestaccess = new ChestAccess(stack, !rs.getBoolean("itemremove")); + } + editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getInt("replaced"), rs.getByte("replacedData"), rs.getString("signtext"), chestaccess); } final int changes = editor.getSize(); if (!params.silent) { @@ -793,7 +801,7 @@ public void run() { int deleted; final String table = params.getTable(); final String join = params.players.size() > 0 ? "INNER JOIN `lb-players` USING (playerid) " : ""; - rs = state.executeQuery("SELECT count(*) FROM `" + table + "` " + join + params.getWhere()); + rs = state.executeQuery("SELECT count(*) FROM `" + table + "-blocks` " + join + params.getWhere()); rs.next(); if ((deleted = rs.getInt(1)) > 0) { if (!params.silent && askClearLogs && sender instanceof Player && questioner != null) { @@ -806,32 +814,32 @@ public void run() { } if (dumpDeletedLog) { try { - state.execute("SELECT * FROM `" + table + "` " + join + params.getWhere() + "INTO OUTFILE '" + new File(dumpFolder, time + " " + table + " " + params.getTitle().replace(":", ".") + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); + state.execute("SELECT * FROM `" + table + "-blocks` " + join + params.getWhere() + "INTO OUTFILE '" + new File(dumpFolder, time + " " + table + " " + params.getTitle().replace(":", ".") + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); } catch (final SQLException ex) { sender.sendMessage(ChatColor.RED + "Error while dumping log. Make sure your MySQL user has access to the LogBlock folder, or disable clearlog.dumpDeletedLog"); getLogger().log(Level.SEVERE, "[ClearLog] Exception while dumping log: ", ex); return; } } - state.execute("DELETE `" + table + "` FROM `" + table + "` " + join + params.getWhere()); + state.execute("DELETE `" + table + "` FROM `" + table + "-blocks` " + join + params.getWhere()); sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + ". Deleted " + deleted + " entries."); } - rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-sign` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL"); + rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-sign` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL"); rs.next(); if ((deleted = rs.getInt(1)) > 0) { if (dumpDeletedLog) { - state.execute("SELECT id, signtext FROM `" + table + "-sign` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-sign " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); + state.execute("SELECT id, signtext FROM `" + table + "-sign` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-sign " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); } - state.execute("DELETE `" + table + "-sign` FROM `" + table + "-sign` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL;"); + state.execute("DELETE `" + table + "-sign` FROM `" + table + "-sign` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL;"); sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-sign. Deleted " + deleted + " entries."); } - rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-chest` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL"); + rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-chestdata` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL"); rs.next(); if ((deleted = rs.getInt(1)) > 0) { if (dumpDeletedLog) { - state.execute("SELECT id, itemtype, itemamount, itemdata FROM `" + table + "-chest` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-chest " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); + state.execute("SELECT id, item, itemremove FROM `" + table + "-chest` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-chest " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); } - state.execute("DELETE `" + table + "-chest` FROM `" + table + "-chest` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL;"); + state.execute("DELETE `" + table + "-chest` FROM `" + table + "-chest` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL;"); sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-chest. Deleted " + deleted + " entries."); } } catch (final Exception ex) { diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index aa84004e..7f8afbf8 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -1,12 +1,15 @@ package de.diddiz.LogBlock; -import static de.diddiz.LogBlock.Actor.actorFromString; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.events.BlockChangePreLogEvent; +import de.diddiz.util.Utils; + +import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.World; +import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; +import org.bukkit.block.data.BlockData; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; @@ -48,180 +51,224 @@ public class Consumer extends TimerTask { /** * Logs any block change. Don't try to combine broken and placed blocks. Queue two block changes or use the queueBLockReplace methods. * - * @param actor Actor responsible for making the change - * @param loc Location of the block change - * @param typeBefore Type of the block before the change - * @param typeAfter Type of the block after the change - * @param data Data of the block after the change + * @param actor + * Actor responsible for making the change + * @param loc + * Location of the block change + * @param typeBefore + * Type of the block before the change + * @param typeAfter + * Type of the block after the change + * @param data + * Data of the block after the change */ - public void queueBlock(Actor actor, Location loc, int typeBefore, int typeAfter, byte data) { - queueBlock(actor, loc, typeBefore, typeAfter, data, null, null); + public void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter) { + queueBlock(actor, loc, typeBefore, typeAfter, null, null); } /** * Logs a block break. The type afterwards is assumed to be 0 (air). * - * @param actor Actor responsible for breaking the block - * @param before Blockstate of the block before actually being destroyed. + * @param actor + * Actor responsible for breaking the block + * @param before + * Blockstate of the block before actually being destroyed. */ public void queueBlockBreak(Actor actor, BlockState before) { - queueBlockBreak(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData()); + queueBlockBreak(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData()); } /** * Logs a block break. The block type afterwards is assumed to be 0 (air). * - * @param actor Actor responsible for the block break - * @param loc Location of the broken block - * @param typeBefore Type of the block before the break - * @param dataBefore Data of the block before the break + * @param actor + * Actor responsible for the block break + * @param loc + * Location of the broken block + * @param typeBefore + * Type of the block before the break + * @param dataBefore + * Data of the block before the break */ - public void queueBlockBreak(Actor actor, Location loc, int typeBefore, byte dataBefore) { - queueBlock(actor, loc, typeBefore, 0, dataBefore); + public void queueBlockBreak(Actor actor, Location loc, BlockData typeBefore) { + queueBlock(actor, loc, typeBefore, null); } /** * Logs a block place. The block type before is assumed to be 0 (air). * - * @param actor Actor responsible for placing the block - * @param after Blockstate of the block after actually being placed. + * @param actor + * Actor responsible for placing the block + * @param after + * Blockstate of the block after actually being placed. */ public void queueBlockPlace(Actor actor, BlockState after) { - queueBlockPlace(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), after.getBlock().getTypeId(), after.getBlock().getData()); + queueBlockPlace(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), after.getBlockData()); } /** * Logs a block place. The block type before is assumed to be 0 (air). * - * @param actor Actor responsible for placing the block - * @param loc Location of the placed block - * @param type Type of the placed block - * @param data Data of the placed block + * @param actor + * Actor responsible for placing the block + * @param loc + * Location of the placed block + * @param type + * Type of the placed block + * @param data + * Data of the placed block */ - public void queueBlockPlace(Actor actor, Location loc, int type, byte data) { - queueBlock(actor, loc, 0, type, data); + public void queueBlockPlace(Actor actor, Location loc, BlockData type) { + queueBlock(actor, loc, null, type); } /** * Logs a block being replaced from the before and after {@link org.bukkit.block.BlockState}s * - * @param actor Actor responsible for replacing the block - * @param before Blockstate of the block before actually being destroyed. - * @param after Blockstate of the block after actually being placed. + * @param actor + * Actor responsible for replacing the block + * @param before + * Blockstate of the block before actually being destroyed. + * @param after + * Blockstate of the block after actually being placed. */ public void queueBlockReplace(Actor actor, BlockState before, BlockState after) { - queueBlockReplace(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData(), after.getTypeId(), after.getRawData()); + queueBlockReplace(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), after.getBlockData()); } /** * Logs a block being replaced from the before {@link org.bukkit.block.BlockState} and the type and data after * - * @param actor Actor responsible for replacing the block - * @param before Blockstate of the block before being replaced. - * @param typeAfter Type of the block after being replaced - * @param dataAfter Data of the block after being replaced + * @param actor + * Actor responsible for replacing the block + * @param before + * Blockstate of the block before being replaced. + * @param typeAfter + * Type of the block after being replaced + * @param dataAfter + * Data of the block after being replaced */ - public void queueBlockReplace(Actor actor, BlockState before, int typeAfter, byte dataAfter) { - queueBlockReplace(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData(), typeAfter, dataAfter); + public void queueBlockReplace(Actor actor, BlockState before, BlockData typeAfter) { + queueBlockReplace(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), typeAfter); } /** * Logs a block being replaced from the type and data before and the {@link org.bukkit.block.BlockState} after * - * @param actor Actor responsible for replacing the block - * @param typeBefore Type of the block before being replaced - * @param dataBefore Data of the block before being replaced - * @param after Blockstate of the block after actually being placed. + * @param actor + * Actor responsible for replacing the block + * @param typeBefore + * Type of the block before being replaced + * @param dataBefore + * Data of the block before being replaced + * @param after + * Blockstate of the block after actually being placed. */ - public void queueBlockReplace(Actor actor, int typeBefore, byte dataBefore, BlockState after) { - queueBlockReplace(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), typeBefore, dataBefore, after.getTypeId(), after.getRawData()); + public void queueBlockReplace(Actor actor, BlockData typeBefore, BlockState after) { + queueBlockReplace(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), typeBefore, after.getBlockData()); } - public void queueBlockReplace(Actor actor, Location loc, int typeBefore, byte dataBefore, int typeAfter, byte dataAfter) { - if (dataBefore == 0 && (typeBefore != typeAfter)) { - queueBlock(actor, loc, typeBefore, typeAfter, dataAfter); - } else { - queueBlockBreak(actor, loc, typeBefore, dataBefore); - queueBlockPlace(actor, loc, typeAfter, dataAfter); - } + public void queueBlockReplace(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter) { + queueBlockBreak(actor, loc, typeBefore); + queueBlockPlace(actor, loc, typeAfter); } /** * Logs an actor interacting with a container block's inventory * - * @param actor The actor interacting with the container - * @param container The respective container. Must be an instance of an InventoryHolder. - * @param itemType Type of the item taken/stored - * @param itemAmount Amount of the item taken/stored - * @param itemData Data of the item taken/stored + * @param actor + * The actor interacting with the container + * @param container + * The respective container. Must be an instance of an InventoryHolder. + * @param itemType + * Type of the item taken/stored + * @param itemAmount + * Amount of the item taken/stored + * @param itemData + * Data of the item taken/stored */ - public void queueChestAccess(Actor actor, BlockState container, short itemType, short itemAmount, short itemData) { + public void queueChestAccess(Actor actor, BlockState container, ItemStack itemStack, boolean remove) { if (!(container instanceof InventoryHolder)) { throw new IllegalArgumentException("Container must be instanceof InventoryHolder"); } - queueChestAccess(actor, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getTypeId(), itemType, itemAmount, itemData); + queueChestAccess(actor, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getBlockData(), itemStack, remove); } /** * Logs an actor interacting with a container block's inventory * - * @param actor The actor interacting with the container - * @param loc The location of the container block - * @param type Type id of the container. - * @param itemType Type of the item taken/stored - * @param itemAmount Amount of the item taken/stored - * @param itemData Data of the item taken/stored + * @param actor + * The actor interacting with the container + * @param loc + * The location of the container block + * @param type + * Type id of the container. + * @param itemType + * Type of the item taken/stored + * @param itemAmount + * Amount of the item taken/stored + * @param itemData + * Data of the item taken/stored */ - public void queueChestAccess(Actor actor, Location loc, int type, short itemType, short itemAmount, short itemData) { - queueBlock(actor, loc, type, type, (byte) 0, null, new ChestAccess(itemType, itemAmount, itemData)); + public void queueChestAccess(Actor actor, Location loc, BlockData type, ItemStack itemStack, boolean remove) { + queueBlock(actor, loc, type, type, null, new ChestAccess(itemStack, remove)); } /** * Logs a container block break. The block type before is assumed to be o (air). All content is assumed to be taken. * - * @param actor The actor breaking the container - * @param container Must be an instance of InventoryHolder + * @param actor + * The actor breaking the container + * @param container + * Must be an instance of InventoryHolder */ public void queueContainerBreak(Actor actor, BlockState container) { if (!(container instanceof InventoryHolder)) { return; } - queueContainerBreak(actor, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getTypeId(), container.getRawData(), ((InventoryHolder) container).getInventory()); + queueContainerBreak(actor, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getBlockData(), ((InventoryHolder) container).getInventory()); } /** * Logs a container block break. The block type before is assumed to be o (air). All content is assumed to be taken. * - * @param actor The actor responsible for breaking the container - * @param loc The location of the inventory block - * @param type The type of the container block - * @param data The data of the container block - * @param inv The inventory of the container block + * @param actor + * The actor responsible for breaking the container + * @param loc + * The location of the inventory block + * @param type + * The type of the container block + * @param data + * The data of the container block + * @param inv + * The inventory of the container block */ - public void queueContainerBreak(Actor actor, Location loc, int type, byte data, Inventory inv) { + public void queueContainerBreak(Actor actor, Location loc, BlockData type, Inventory inv) { final ItemStack[] items = compressInventory(inv.getContents()); for (final ItemStack item : items) { - queueChestAccess(actor, loc, type, (short) item.getTypeId(), (short) (item.getAmount() * -1), rawData(item)); + queueChestAccess(actor, loc, type, item, true); } - queueBlockBreak(actor, loc, type, data); + queueBlockBreak(actor, loc, type); } /** - * @param killer Can't be null - * @param victim Can't be null + * @param killer + * Can't be null + * @param victim + * Can't be null */ public void queueKill(Entity killer, Entity victim) { if (killer == null || victim == null) { return; } - int weapon = 0; + ItemStack weapon = null; Actor killerActor = Actor.actorFromEntity(killer); // If it's a projectile kill we want to manually assign the weapon, so check for player before converting a projectile to its source - if (killer instanceof Player && ((Player) killer).getItemInHand() != null) { - weapon = ((Player) killer).getItemInHand().getTypeId(); + if (killer instanceof Player && ((Player) killer).getInventory().getItemInMainHand() != null) { + weapon = ((Player) killer).getInventory().getItemInMainHand(); } if (killer instanceof Projectile) { - weapon = itemIDfromProjectileEntity(killer); + weapon = new ItemStack(itemIDfromProjectileEntity(killer)); ProjectileSource ps = ((Projectile) killer).getShooter(); if (ps == null) { killerActor = Actor.actorFromEntity(killer); @@ -236,92 +283,99 @@ public void queueKill(Entity killer, Entity victim) { /** * This form should only be used when the killer is not an entity e.g. for fall or suffocation damage * - * @param killer Can't be null - * @param victim Can't be null + * @param killer + * Can't be null + * @param victim + * Can't be null */ public void queueKill(Actor killer, Entity victim) { if (killer == null || victim == null) { return; } - queueKill(victim.getLocation(), killer, Actor.actorFromEntity(victim), 0); + queueKill(victim.getLocation(), killer, Actor.actorFromEntity(victim), null); } /** - * @param world World the victim was inside. - * @param killer Name of the killer. Can be null. - * @param victim Name of the victim. Can't be null. - * @param weapon Item id of the weapon. 0 for no weapon. - * @deprecated Use {@link #queueKill(org.bukkit.Location, de.diddiz.LogBlock.Actor, de.diddiz.LogBlock.Actor, int)} - * instead + * @param location + * Location of the victim. + * @param killer + * Killer Actor. Can be null. + * @param victim + * Victim Actor. Can't be null. + * @param weapon + * Item id of the weapon. 0 for no weapon. */ - @Deprecated - public void queueKill(World world, Actor killer, Actor victim, int weapon) { - queueKill(new Location(world, 0, 0, 0), killer, victim, weapon); - } - - /** - * @param location Location of the victim. - * @param killer Killer Actor. Can be null. - * @param victim Victim Actor. Can't be null. - * @param weapon Item id of the weapon. 0 for no weapon. - */ - public void queueKill(Location location, Actor killer, Actor victim, int weapon) { + public void queueKill(Location location, Actor killer, Actor victim, ItemStack weapon) { if (victim == null || !isLogged(location.getWorld())) { return; } - queue.add(new KillRow(location, killer == null ? null : killer, victim, weapon)); + queue.add(new KillRow(location, killer == null ? null : killer, victim, MaterialConverter.getOrAddMaterialId(weapon.getType().getKey().toString()))); } /** * Logs an actor breaking a sign along with its contents * - * @param actor Actor responsible for breaking the sign - * @param loc Location of the broken sign - * @param type Type of the sign. Must be 63 or 68. - * @param data Data of the sign being broken - * @param lines The four lines on the sign. + * @param actor + * Actor responsible for breaking the sign + * @param loc + * Location of the broken sign + * @param type + * Type of the sign. Must be 63 or 68. + * @param data + * Data of the sign being broken + * @param lines + * The four lines on the sign. */ - public void queueSignBreak(Actor actor, Location loc, int type, byte data, String[] lines) { - if (type != 63 && type != 68 || lines == null || lines.length != 4) { + public void queueSignBreak(Actor actor, Location loc, BlockData type, String[] lines) { + if ((type.getMaterial() != Material.SIGN && type.getMaterial() != Material.WALL_SIGN) || lines == null || lines.length != 4) { return; } - queueBlock(actor, loc, type, 0, data, lines[0] + "\0" + lines[1] + "\0" + lines[2] + "\0" + lines[3], null); + queueBlock(actor, loc, type, null, lines[0] + "\0" + lines[1] + "\0" + lines[2] + "\0" + lines[3], null); } /** * Logs an actor breaking a sign along with its contents * - * @param actor Actor responsible for breaking the sign - * @param sign The sign being broken + * @param actor + * Actor responsible for breaking the sign + * @param sign + * The sign being broken */ public void queueSignBreak(Actor actor, Sign sign) { - queueSignBreak(actor, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getTypeId(), sign.getRawData(), sign.getLines()); + queueSignBreak(actor, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getBlockData(), sign.getLines()); } /** * Logs an actor placing a sign along with its contents * - * @param actor Actor placing the sign - * @param loc Location of the placed sign - * @param type Type of the sign. Must be 63 or 68. - * @param data Data of the placed sign block - * @param lines The four lines on the sign. + * @param actor + * Actor placing the sign + * @param loc + * Location of the placed sign + * @param type + * Type of the sign. Must be 63 or 68. + * @param data + * Data of the placed sign block + * @param lines + * The four lines on the sign. */ - public void queueSignPlace(Actor actor, Location loc, int type, byte data, String[] lines) { - if (type != 63 && type != 68 || lines == null || lines.length != 4) { + public void queueSignPlace(Actor actor, Location loc, BlockData type, String[] lines) { + if ((type.getMaterial() != Material.SIGN && type.getMaterial() != Material.WALL_SIGN) || lines == null || lines.length != 4) { return; } - queueBlock(actor, loc, 0, type, data, lines[0] + "\0" + lines[1] + "\0" + lines[2] + "\0" + lines[3], null); + queueBlock(actor, loc, null, type, lines[0] + "\0" + lines[1] + "\0" + lines[2] + "\0" + lines[3], null); } /** * Logs an actor placing a sign along with its contents * - * @param actor Actor placing the sign - * @param sign The palced sign object + * @param actor + * Actor placing the sign + * @param sign + * The palced sign object */ public void queueSignPlace(Actor actor, Sign sign) { - queueSignPlace(actor, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getTypeId(), sign.getRawData(), sign.getLines()); + queueSignPlace(actor, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getBlockData(), sign.getLines()); } public void queueChat(Actor player, String message) { @@ -344,218 +398,12 @@ public void queueLeave(Player player) { queue.add(new PlayerLeaveRow(player)); } - // Deprecated methods re-added for API compatability - - /** - * Logs any block change. Don't try to combine broken and placed blocks. - * Queue two block changes or use the queueBLockReplace methods. - * - * @deprecated Use - * {@link #queueBlock(de.diddiz.LogBlock.Actor, org.bukkit.Location, int, int, byte)} - * which supports UUIDs - */ - public void queueBlock(String playerName, Location loc, int typeBefore, int typeAfter, byte data) { - queueBlock(actorFromString(playerName), loc, typeBefore, typeAfter, data); - } - - /** - * Logs a block break. The type afterwards is assumed to be 0 (air). - * - * @param before Blockstate of the block before actually being destroyed. - * @deprecated Use - * {@link #queueBlockBreak(de.diddiz.LogBlock.Actor, org.bukkit.block.BlockState)} - * which supports UUIDs - */ - public void queueBlockBreak(String playerName, BlockState before) { - queueBlockBreak(actorFromString(playerName), before); - - } - - /** - * Logs a block break. The block type afterwards is assumed to be 0 (air). - * - * @deprecated Use {@link #queueBlockBreak(de.diddiz.LogBlock.Actor, org.bukkit.Location, int, byte)} - * which supports UUIDs - */ - public void queueBlockBreak(String playerName, Location loc, int typeBefore, byte dataBefore) { - queueBlockBreak(actorFromString(playerName), loc, typeBefore, dataBefore); - } - - /** - * Logs a block place. The block type before is assumed to be 0 (air). - * - * @param after Blockstate of the block after actually being placed. - * @depracated Use {@link #queueBlockPlace(de.diddiz.LogBlock.Actor, org.bukkit.block.BlockState)} - * which supports UUIDs - */ - public void queueBlockPlace(String playerName, BlockState after) { - queueBlockPlace(actorFromString(playerName), after); - } - - /** - * Logs a block place. The block type before is assumed to be 0 (air). - * @deprecated Use {@link #queueBlockPlace(de.diddiz.LogBlock.Actor, org.bukkit.Location, int, byte)} - * which supports UUIDs - */ - public void queueBlockPlace(String playerName, Location loc, int type, byte data) { - queueBlockPlace(actorFromString(playerName), loc, type, data); - } - - /** - * @param before Blockstate of the block before actually being destroyed. - * @param after Blockstate of the block after actually being placed. - * @deprecated Use {@link #queueBlockReplace(de.diddiz.LogBlock.Actor, org.bukkit.block.BlockState, org.bukkit.block.BlockState)} - * which supports UUIDs - */ - public void queueBlockReplace(String playerName, BlockState before, BlockState after) { - queueBlockReplace(actorFromString(playerName), before, after); - } - - /** - * @param before Blockstate of the block before actually being destroyed. - * @deprecated Use {@link #queueBlockReplace(de.diddiz.LogBlock.Actor, org.bukkit.block.BlockState, int, byte)} - * which supports UUIDs - */ - public void queueBlockReplace(String playerName, BlockState before, int typeAfter, byte dataAfter) { - queueBlockReplace(actorFromString(playerName), before, typeAfter, dataAfter); - } - - /** - * @param after Blockstate of the block after actually being placed. - * @deprecated {@link #queueBlockReplace(de.diddiz.LogBlock.Actor, int, byte, org.bukkit.block.BlockState)} - * which supports UUIDs - */ - public void queueBlockReplace(String playerName, int typeBefore, byte dataBefore, BlockState after) { - queueBlockReplace(actorFromString(playerName), typeBefore, dataBefore, after); + public void queueAddMaterialMapping(int key, String material) { + queue.add(new AddMaterialRow(key, material)); } - /** - * @deprecated use {@link #queueBlockReplace(de.diddiz.LogBlock.Actor, org.bukkit.Location, int, byte, int, byte)} - * which supports UUIDs - */ - public void queueBlockReplace(String playerName, Location loc, int typeBefore, byte dataBefore, int typeAfter, byte dataAfter) { - queueBlockReplace(actorFromString(playerName),loc,typeBefore,dataBefore,typeAfter,dataAfter); - } - - /** - * @param container The respective container. Must be an instance of an - * InventoryHolder. - * @deprecated Use {@link #queueChestAccess(de.diddiz.LogBlock.Actor, org.bukkit.block.BlockState, short, short, short)} - * which supports UUIDs - */ - public void queueChestAccess(String playerName, BlockState container, short itemType, short itemAmount, short itemData) { - queueChestAccess(actorFromString(playerName),container,itemType,itemAmount,itemData); - } - - /** - * @param type Type id of the container. - * @deprecated Use {@link #queueChestAccess(de.diddiz.LogBlock.Actor, org.bukkit.Location, int, short, short, short)} - * which supports UUIDs - */ - public void queueChestAccess(String playerName, Location loc, int type, short itemType, short itemAmount, short itemData) { - queueChestAccess(actorFromString(playerName), loc, type, itemType, itemAmount, itemData); - } - - /** - * Logs a container block break. The block type before is assumed to be o - * (air). All content is assumed to be taken. - * - * @param container Must be an instance of InventoryHolder - * @deprecated Use {@link #queueContainerBreak(de.diddiz.LogBlock.Actor, org.bukkit.block.BlockState)} - * which supports UUIDs - */ - public void queueContainerBreak(String playerName, BlockState container) { - queueContainerBreak(actorFromString(playerName), container); - } - - /** - * Logs a container block break. The block type before is assumed to be o - * (air). All content is assumed to be taken. - * @deprecated Use {@link #queueContainerBreak(de.diddiz.LogBlock.Actor, org.bukkit.Location, int, byte, org.bukkit.inventory.Inventory)} - * which supports UUIDs - */ - public void queueContainerBreak(String playerName, Location loc, int type, byte data, Inventory inv) { - queueContainerBreak(actorFromString(playerName),loc,type,data,inv); - } - - /** - * This form should only be used when the killer is not an entity e.g. for - * fall or suffocation damage - * - * @param killer Can't be null - * @param victim Can't be null - * @deprecated Use {@link #queueKill(de.diddiz.LogBlock.Actor, org.bukkit.entity.Entity)} - * which supports UUIDs - */ - public void queueKill(String killer, Entity victim) { - queueKill(actorFromString(killer),victim); - } - - /** - * @param world World the victim was inside. - * @param killerName Name of the killer. Can be null. - * @param victimName Name of the victim. Can't be null. - * @param weapon Item id of the weapon. 0 for no weapon. - * @deprecated Use {@link #queueKill(org.bukkit.Location, de.diddiz.LogBlock.Actor, de.diddiz.LogBlock.Actor, int)} instead - */ - @Deprecated - public void queueKill(World world, String killerName, String victimName, int weapon) { - queueKill(world,actorFromString(killerName),actorFromString(victimName),weapon); - } - - /** - * @param location Location of the victim. - * @param killerName Name of the killer. Can be null. - * @param victimName Name of the victim. Can't be null. - * @param weapon Item id of the weapon. 0 for no weapon. - * @deprecated Use {@link #queueKill(org.bukkit.Location, de.diddiz.LogBlock.Actor, de.diddiz.LogBlock.Actor, int)} - * which supports UUIDs - */ - public void queueKill(Location location, String killerName, String victimName, int weapon) { - queueKill(location,actorFromString(killerName),actorFromString(victimName),weapon); - } - - /** - * @param type Type of the sign. Must be 63 or 68. - * @param lines The four lines on the sign. - * @deprecated Use {@link #queueSignBreak(de.diddiz.LogBlock.Actor, org.bukkit.Location, int, byte, java.lang.String[])} - * which supports UUIDs - */ - public void queueSignBreak(String playerName, Location loc, int type, byte data, String[] lines) { - queueSignBreak(actorFromString(playerName),loc,type,data,lines); - } - - /** - * @deprecated Use {@link #queueSignBreak(de.diddiz.LogBlock.Actor, org.bukkit.block.Sign)} - * which supports UUIDs - */ - public void queueSignBreak(String playerName, Sign sign) { - queueSignBreak(actorFromString(playerName),sign); - } - - /** - * @param type Type of the sign. Must be 63 or 68. - * @param lines The four lines on the sign. - * @deprecated Use {@link #queueSignPlace(de.diddiz.LogBlock.Actor, org.bukkit.Location, int, byte, java.lang.String[])} - * which supports UUIDs - */ - public void queueSignPlace(String playerName, Location loc, int type, byte data, String[] lines) { - queueSignPlace(actorFromString(playerName),loc,type,data,lines); - } - - /** - * @deprecated Use {@link #queueSignPlace(de.diddiz.LogBlock.Actor, org.bukkit.block.Sign)} - * which supports UUIDs - */ - public void queueSignPlace(String playerName, Sign sign) { - queueSignPlace(actorFromString(playerName),sign); - } -/** - * @deprecated Use {@link #queueChat(de.diddiz.LogBlock.Actor, java.lang.String)} - * which supports UUIDs - */ - public void queueChat(String player, String message) { - queueChat(actorFromString(player),message); + public void queueAddBlockStateMapping(int key, String blockState) { + queue.add(new AddBlockStateRow(key, blockState)); } @Override @@ -564,25 +412,24 @@ public synchronized void run() { return; } long startTime = System.currentTimeMillis(); - int startSize = queue.size(); - - final Connection conn = logblock.getConnection(); + // int startSize = queue.size(); + int count = 0; + Connection conn = null; Statement state = null; - if (Config.queueWarningSize > 0 && queue.size() >= Config.queueWarningSize) { - getLogger().info("[Consumer] Queue overloaded. Size: " + getQueueSize()); - } + try { - int count = 0; + conn = logblock.getConnection(); + if (Config.queueWarningSize > 0 && queue.size() >= Config.queueWarningSize) { + getLogger().info("[Consumer] Queue overloaded. Size: " + getQueueSize()); + } - try { if (conn == null) { return; } conn.setAutoCommit(false); state = conn.createStatement(); final long start = System.currentTimeMillis(); - process: - while (!queue.isEmpty() && (System.currentTimeMillis() - start < timePerRun || count < forceToProcessAtLeast)) { + process: while (!queue.isEmpty() && (System.currentTimeMillis() - start < timePerRun || count < forceToProcessAtLeast)) { final Row r = queue.poll(); if (r == null) { continue; @@ -738,11 +585,16 @@ private boolean addPlayer(Statement state, Actor actor) throws SQLException { return playerIds.containsKey(actor); } - private void queueBlock(Actor actor, Location loc, int typeBefore, int typeAfter, byte data, String signtext, ChestAccess ca) { - + private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter, String signtext, ChestAccess ca) { + if (typeBefore == null) { + typeBefore = Bukkit.createBlockData(Material.AIR); + } + if (typeAfter == null) { + typeAfter = Bukkit.createBlockData(Material.AIR); + } if (Config.fireCustomEvents) { // Create and call the event - BlockChangePreLogEvent event = new BlockChangePreLogEvent(actor, loc, typeBefore, typeAfter, data, signtext, ca); + BlockChangePreLogEvent event = new BlockChangePreLogEvent(actor, loc, typeBefore, typeAfter, signtext, ca); logblock.getServer().getPluginManager().callEvent(event); if (event.isCancelled()) { return; @@ -753,15 +605,22 @@ private void queueBlock(Actor actor, Location loc, int typeBefore, int typeAfter loc = event.getLocation(); typeBefore = event.getTypeBefore(); typeAfter = event.getTypeAfter(); - data = event.getData(); signtext = event.getSignText(); ca = event.getChestAccess(); } // Do this last so LogBlock still has final say in what is being added - if (actor == null || loc == null || typeBefore < 0 || typeAfter < 0 || (Config.safetyIdCheck && (typeBefore > 255 || typeAfter > 255)) || hiddenPlayers.contains(actor.getName().toLowerCase()) || !isLogged(loc.getWorld()) || typeBefore != typeAfter && hiddenBlocks.contains(typeBefore) && hiddenBlocks.contains(typeAfter)) { + if (actor == null || loc == null || typeBefore == null || typeAfter == null || hiddenPlayers.contains(actor.getName().toLowerCase()) || !isLogged(loc.getWorld()) || typeBefore != typeAfter && hiddenBlocks.contains(typeBefore.getMaterial()) && hiddenBlocks.contains(typeAfter.getMaterial())) { return; } - queue.add(new BlockRow(loc, actor, typeBefore, typeAfter, data, signtext, ca)); + + String replacedString = typeBefore.getAsString(); + int replacedMaterialId = MaterialConverter.getOrAddMaterialId(replacedString); + int replacedStateId = MaterialConverter.getOrAddBlockStateId(replacedString); + String typeString = typeAfter.getAsString(); + int typeMaterialId = MaterialConverter.getOrAddMaterialId(typeString); + int typeStateId = MaterialConverter.getOrAddBlockStateId(typeString); + + queue.add(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, typeMaterialId, typeStateId, signtext, ca)); } private String playerID(Actor actor) { @@ -811,31 +670,33 @@ private interface MergeableRow extends PreparedStatementRow { private class BlockRow extends BlockChange implements MergeableRow { private Connection connection; - public BlockRow(Location loc, Actor actor, int replaced, int type, byte data, String signtext, ChestAccess ca) { - super(System.currentTimeMillis() / 1000, loc, actor, replaced, type, data, signtext, ca); + public BlockRow(Location loc, Actor actor, int replaced, int replacedData, int type, int typeData, String signtext, ChestAccess ca) { + super(System.currentTimeMillis() / 1000, loc, actor, replaced, replacedData, type, typeData, signtext, ca); } @Override public String[] getInserts() { final String table = getWorldConfig(loc.getWorld()).table; final String[] inserts = new String[ca != null || signtext != null ? 2 : 1]; - inserts[0] = "INSERT INTO `" + table + "` (date, playerid, replaced, type, data, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(actor) + ", " + replaced + ", " + type + ", " + data + ", '" + loc.getBlockX() + "', " + safeY(loc) + ", '" + loc.getBlockZ() + "');"; + + inserts[0] = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(actor) + ", " + replacedMaterial + ", " + replacedData + ", " + typeMaterial + ", " + typeData + ", '" + loc.getBlockX() + + "', " + safeY(loc) + ", '" + loc.getBlockZ() + "');"; if (signtext != null) { inserts[1] = "INSERT INTO `" + table + "-sign` (id, signtext) values (LAST_INSERT_ID(), '" + mysqlTextEscape(signtext) + "');"; } else if (ca != null) { - inserts[1] = "INSERT INTO `" + table + "-chest` (id, itemtype, itemamount, itemdata) values (LAST_INSERT_ID(), " + ca.itemType + ", " + ca.itemAmount + ", " + ca.itemData + ");"; + inserts[1] = "INSERT INTO `" + table + "-chestdata` (id, item, itemremoved) values (LAST_INSERT_ID(), '" + Utils.mysqlEscapeBytes(Utils.saveItemStack(ca.itemStack)) + "', " + (ca.remove ? 1 : 0) + ");"; } return inserts; } @Override public String[] getPlayers() { - return new String[]{actor.getName()}; + return new String[] { actor.getName() }; } @Override public Actor[] getActors() { - return new Actor[]{actor}; + return new Actor[] { actor }; } @Override @@ -850,14 +711,15 @@ public void executeStatements() throws SQLException { PreparedStatement ps1 = null; PreparedStatement ps = null; try { - ps1 = connection.prepareStatement("INSERT INTO `" + table + "` (date, playerid, replaced, type, data, x, y, z) VALUES(FROM_UNIXTIME(?), " + playerID(actor) + ", ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); + ps1 = connection.prepareStatement("INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replacedData, type, typeData, x, y, z) VALUES(FROM_UNIXTIME(?), " + playerID(actor) + ", ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); ps1.setLong(1, date); - ps1.setInt(2, replaced); - ps1.setInt(3, type); - ps1.setInt(4, data); - ps1.setInt(5, loc.getBlockX()); - ps1.setInt(6, safeY(loc)); - ps1.setInt(7, loc.getBlockZ()); + ps1.setInt(2, replacedMaterial); + ps1.setInt(3, replacedData); + ps1.setInt(4, typeMaterial); + ps1.setInt(5, typeData); + ps1.setInt(6, loc.getBlockX()); + ps1.setInt(7, safeY(loc)); + ps1.setInt(8, loc.getBlockZ()); ps1.executeUpdate(); int id; @@ -871,11 +733,10 @@ public void executeStatements() throws SQLException { ps.setInt(2, id); ps.executeUpdate(); } else if (ca != null) { - ps = connection.prepareStatement("INSERT INTO `" + table + "-chest` (itemtype, itemamount, itemdata, id) values (?, ?, ?, ?)"); - ps.setInt(1, ca.itemType); - ps.setInt(2, ca.itemAmount); - ps.setInt(3, ca.itemData); - ps.setInt(4, id); + ps = connection.prepareStatement("INSERT INTO `" + table + "-chestdata` (item, itemremove, id) values (?, ?, ?)"); + ps.setBytes(1, Utils.saveItemStack(ca.itemStack)); + ps.setInt(2, ca.remove ? 1 : 0); + ps.setInt(3, id); ps.executeUpdate(); } } catch (final SQLException ex) { @@ -954,16 +815,17 @@ public void setConnection(Connection connection) { public void executeStatements() throws SQLException { PreparedStatement ps = null; try { - ps = connection.prepareStatement("INSERT INTO `" + table + "` (date, playerid, replaced, type, data, x, y, z) VALUES(FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?)"); + ps = connection.prepareStatement("INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replacedData, type, typeData, x, y, z) VALUES(FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"); for (BlockRow row : rows) { ps.setLong(1, row.date); ps.setInt(2, playerIds.get(row.actor)); - ps.setInt(3, row.replaced); - ps.setInt(4, row.type); - ps.setInt(5, row.data); - ps.setInt(6, row.loc.getBlockX()); - ps.setInt(7, safeY(row.loc)); - ps.setInt(8, row.loc.getBlockZ()); + ps.setInt(3, row.replacedMaterial); + ps.setInt(4, row.replacedData); + ps.setInt(5, row.typeMaterial); + ps.setInt(6, row.typeData); + ps.setInt(7, row.loc.getBlockX()); + ps.setInt(8, safeY(row.loc)); + ps.setInt(9, row.loc.getBlockZ()); ps.addBatch(); } ps.executeBatch(); @@ -1041,17 +903,18 @@ private class KillRow implements Row { @Override public String[] getInserts() { - return new String[]{"INSERT INTO `" + getWorldConfig(loc.getWorld()).table + "-kills` (date, killer, victim, weapon, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(killer) + ", " + playerID(victim) + ", " + weapon + ", " + loc.getBlockX() + ", " + safeY(loc) + ", " + loc.getBlockZ() + ");"}; + return new String[] { "INSERT INTO `" + getWorldConfig(loc.getWorld()).table + "-kills` (date, killer, victim, weapon, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(killer) + ", " + playerID(victim) + ", " + weapon + ", " + loc.getBlockX() + ", " + safeY(loc) + ", " + + loc.getBlockZ() + ");" }; } @Override public String[] getPlayers() { - return new String[]{killer.getName(), victim.getName()}; + return new String[] { killer.getName(), victim.getName() }; } @Override public Actor[] getActors() { - return new Actor[]{killer, victim}; + return new Actor[] { killer, victim }; } } @@ -1064,17 +927,17 @@ private class ChatRow extends ChatMessage implements PreparedStatementRow { @Override public String[] getInserts() { - return new String[]{"INSERT INTO `lb-chat` (date, playerid, message) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(player) + ", '" + mysqlTextEscape(message) + "');"}; + return new String[] { "INSERT INTO `lb-chat` (date, playerid, message) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(player) + ", '" + mysqlTextEscape(message) + "');" }; } @Override public String[] getPlayers() { - return new String[]{player.getName()}; + return new String[] { player.getName() }; } @Override public Actor[] getActors() { - return new Actor[]{player}; + return new Actor[] { player }; } @Override @@ -1136,24 +999,24 @@ private class PlayerJoinRow implements Row { @Override public String[] getInserts() { if (logPlayerInfo) { - return new String[]{"UPDATE `lb-players` SET lastlogin = FROM_UNIXTIME(" + lastLogin + "), firstlogin = IF(firstlogin = 0, FROM_UNIXTIME(" + lastLogin + "), firstlogin), ip = '" + ip + "', playername = '" + mysqlTextEscape(player.getName()) + "' WHERE UUID = '" + player.getUUID() + "';"}; + return new String[] { + "UPDATE `lb-players` SET lastlogin = FROM_UNIXTIME(" + lastLogin + "), firstlogin = IF(firstlogin = 0, FROM_UNIXTIME(" + lastLogin + "), firstlogin), ip = '" + ip + "', playername = '" + mysqlTextEscape(player.getName()) + "' WHERE UUID = '" + player.getUUID() + "';" }; } - return new String[]{"UPDATE `lb-players` SET playername = '" + mysqlTextEscape(player.getName()) + "' WHERE UUID = '" + player.getUUID() + "';"}; + return new String[] { "UPDATE `lb-players` SET playername = '" + mysqlTextEscape(player.getName()) + "' WHERE UUID = '" + player.getUUID() + "';" }; } @Override public String[] getPlayers() { - return new String[]{player.getName()}; + return new String[] { player.getName() }; } @Override public Actor[] getActors() { - return new Actor[]{player}; + return new Actor[] { player }; } } private class PlayerLeaveRow implements Row { - ; private final long leaveTime; private final Actor actor; @@ -1165,26 +1028,78 @@ private class PlayerLeaveRow implements Row { @Override public String[] getInserts() { if (logPlayerInfo) { - return new String[]{"UPDATE `lb-players` SET onlinetime = onlinetime + TIMESTAMPDIFF(SECOND, lastlogin, FROM_UNIXTIME('" + leaveTime + "')), playername = '" + mysqlTextEscape(actor.getName()) + "' WHERE lastlogin > 0 && UUID = '" + actor.getUUID() + "';"}; + return new String[] { "UPDATE `lb-players` SET onlinetime = onlinetime + TIMESTAMPDIFF(SECOND, lastlogin, FROM_UNIXTIME('" + leaveTime + "')), playername = '" + mysqlTextEscape(actor.getName()) + "' WHERE lastlogin > 0 && UUID = '" + actor.getUUID() + "';" }; } - return new String[]{"UPDATE `lb-players` SET playername = '" + mysqlTextEscape(actor.getName()) + "' WHERE UUID = '" + actor.getUUID() + "';"}; + return new String[] { "UPDATE `lb-players` SET playername = '" + mysqlTextEscape(actor.getName()) + "' WHERE UUID = '" + actor.getUUID() + "';" }; + } + + @Override + public String[] getPlayers() { + return new String[] { actor.getName() }; + } + + @Override + public Actor[] getActors() { + return new Actor[] { actor }; + } + } + + private class AddMaterialRow implements Row { + private final int key; + private final String material; + + AddMaterialRow(int key, String material) { + this.key = key; + this.material = material; + } + + @Override + public String[] getInserts() { + return new String[] { "INSERT INTO `lb-materials` (id, name) VALUES (" + key + ",'" + mysqlTextEscape(material) + "');" }; } @Override public String[] getPlayers() { - return new String[]{actor.getName()}; + return new String[0]; } @Override public Actor[] getActors() { - return new Actor[]{actor}; + return new Actor[0]; } } - - private int safeY(Location loc) { + + private class AddBlockStateRow implements Row { + private final int key; + private final String blockstate; + + AddBlockStateRow(int key, String blockstate) { + this.key = key; + this.blockstate = blockstate; + } + + @Override + public String[] getInserts() { + return new String[] { "INSERT INTO `lb-blockstates` (id, name) VALUES (" + key + ",'" + mysqlTextEscape(blockstate) + "');" }; + } + + @Override + public String[] getPlayers() { + return new String[0]; + } + + @Override + public Actor[] getActors() { + return new Actor[0]; + } + } + + private int safeY(Location loc) { int safeY = loc.getBlockY(); - if (safeY<0) safeY = 0; - if (safeY>65535) safeY=65535; + if (safeY < 0) + safeY = 0; + if (safeY > 65535) + safeY = 65535; return safeY; } } diff --git a/src/main/java/de/diddiz/LogBlock/Kill.java b/src/main/java/de/diddiz/LogBlock/Kill.java index 3e58631f..11ea97f8 100755 --- a/src/main/java/de/diddiz/LogBlock/Kill.java +++ b/src/main/java/de/diddiz/LogBlock/Kill.java @@ -2,7 +2,7 @@ import de.diddiz.LogBlock.config.Config; import org.bukkit.Location; -import org.bukkit.inventory.ItemStack; +import org.bukkit.Material; import java.sql.ResultSet; import java.sql.SQLException; @@ -41,7 +41,7 @@ public String toString() { if (loc != null) { msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ()); } - String weaponName = prettyItemName(new ItemStack(weapon)); + String weaponName = prettyItemName(MaterialConverter.getMaterial(weapon)); msg.append(" with " + weaponName); // + ("aeiou".contains(weaponName.substring(0, 1)) ? "an " : "a " ) return msg.toString(); } @@ -56,11 +56,10 @@ public String getMessage() { return toString(); } - public String prettyItemName(ItemStack i) { - String item = i.getType().toString().replace('_', ' ').toLowerCase(); - if (item.equals("air")) { - item = "fist"; + public String prettyItemName(Material t) { + if (t == null || t == Material.AIR) { + return "fist"; } - return item; + return t.toString().replace('_', ' ').toLowerCase(); } } diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index d1a319b9..2567c198 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -2,9 +2,11 @@ import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.listeners.*; +import de.diddiz.util.BukkitUtils; import de.diddiz.util.MySQLConnectionPool; import de.diddiz.worldedit.WorldEditLoggingHook; import org.bukkit.ChatColor; +import org.bukkit.Material; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -24,7 +26,6 @@ import java.util.logging.Level; import static de.diddiz.LogBlock.config.Config.*; -import static de.diddiz.util.MaterialName.materialName; import static org.bukkit.Bukkit.getPluginManager; public class LogBlock extends JavaPlugin { @@ -77,6 +78,7 @@ public void onLoad() { load(this); } updater.checkTables(); + MaterialConverter.initializeMaterials(getConnection()); } catch (final NullPointerException ex) { getLogger().log(Level.SEVERE, "Error while loading: ", ex); } catch (final Exception ex) { @@ -89,7 +91,8 @@ public void onLoad() { @Override public void onEnable() { - materialName(0); // Force static code to run + MaterialConverter.getOrAddMaterialId(Material.AIR.getKey()); // AIR must be the first entry + BukkitUtils.isDoublePlant(Material.AIR); // Force static code to run final PluginManager pm = getPluginManager(); if (errorAtLoading) { pm.disablePlugin(this); @@ -201,9 +204,6 @@ private void registerEvents() { if (isLogging(Logging.GRASSGROWTH) || isLogging(Logging.MYCELIUMSPREAD) || isLogging(Logging.VINEGROWTH) || isLogging(Logging.MUSHROOMSPREAD)) { pm.registerEvents(new BlockSpreadLogging(this), this); } - if (isLogging(Logging.LOCKEDCHESTDECAY)) { - pm.registerEvents(new LockedChestDecayLogging(this), this); - } } @Override diff --git a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java new file mode 100644 index 00000000..57cef288 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java @@ -0,0 +1,129 @@ +package de.diddiz.LogBlock; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Arrays; +import java.util.HashMap; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.block.data.BlockData; + +public class MaterialConverter { + private static String[] idToMaterial = new String[10]; + private static HashMap materialToID = new HashMap<>(); + private static int nextMaterialId; + + private static String[] idToBlockState = new String[10]; + private static HashMap blockStateToID = new HashMap<>(); + private static int nextBlockStateId; + + public synchronized static int getOrAddMaterialId(NamespacedKey nameSpaceKey) { + return getOrAddMaterialId(nameSpaceKey.toString()); + } + + public synchronized static int getOrAddMaterialId(String blockDataString) { + String materialString = blockDataString; + int dataPart = blockDataString.indexOf("["); + if (dataPart >= 0) { + materialString = blockDataString.substring(0, dataPart); + } + Integer key = materialToID.get(materialString); + if (key == null) { + key = nextMaterialId++; + materialToID.put(materialString, key); + int length = idToMaterial.length; + while (length <= key) { + length = (length * 3 / 2) + 5; + } + if (length > idToMaterial.length) { + idToMaterial = Arrays.copyOf(idToMaterial, length); + } + idToMaterial[key] = materialString; + LogBlock.getInstance().getConsumer().queueAddMaterialMapping(key, materialString); + } + return key.intValue(); + } + + public synchronized static int getOrAddBlockStateId(String blockDataString) { + int dataPart = blockDataString.indexOf("["); + if (dataPart < 0) { + return -1; + } + String materialString = blockDataString.substring(dataPart); + Integer key = blockStateToID.get(materialString); + if (key == null) { + key = nextBlockStateId++; + blockStateToID.put(materialString, key); + int length = idToBlockState.length; + while (length <= key) { + length = (length * 3 / 2) + 5; + } + if (length > idToBlockState.length) { + idToBlockState = Arrays.copyOf(idToBlockState, length); + } + idToBlockState[key] = materialString; + LogBlock.getInstance().getConsumer().queueAddBlockStateMapping(key, materialString); + } + return key.intValue(); + } + + public synchronized static BlockData getBlockData(int materialId, int blockStateId) { + String material = idToMaterial[materialId]; + if (blockStateId >= 0) { + material = material + idToBlockState[blockStateId]; + } + return Bukkit.createBlockData(material); + } + + public static Material getMaterial(int materialId) { + return getBlockData(materialId, -1).getMaterial(); + } + + public static void initializeMaterials(Connection connection) throws SQLException { + Statement smt = connection.createStatement(); + ResultSet rs = smt.executeQuery("SELECT id, name FROM `lb-materials`"); + while (rs.next()) { + int key = rs.getInt(1); + String materialString = rs.getString(2); + + materialToID.put(materialString, key); + int length = idToMaterial.length; + while (length <= key) { + length = (length * 3 / 2) + 5; + } + if (length > idToMaterial.length) { + idToMaterial = Arrays.copyOf(idToMaterial, length); + } + idToMaterial[key] = materialString; + if (nextMaterialId <= key) { + nextMaterialId = key + 1; + } + } + rs.close(); + rs = smt.executeQuery("SELECT id, name FROM `lb-blockstates`"); + while (rs.next()) { + int key = rs.getInt(1); + String materialString = rs.getString(2); + + blockStateToID.put(materialString, key); + int length = idToBlockState.length; + while (length <= key) { + length = (length * 3 / 2) + 5; + } + if (length > idToBlockState.length) { + idToBlockState = Arrays.copyOf(idToBlockState, length); + } + idToBlockState[key] = materialString; + if (nextBlockStateId <= key) { + nextBlockStateId = key + 1; + } + } + rs.close(); + smt.close(); + connection.close(); + } +} diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index d72ae77c..43571ef9 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -1,6 +1,5 @@ package de.diddiz.LogBlock; -import de.diddiz.util.Block; import de.diddiz.util.Utils; import de.diddiz.worldedit.RegionContainer; import org.bukkit.Location; @@ -15,9 +14,6 @@ import static de.diddiz.LogBlock.Session.getSession; import static de.diddiz.LogBlock.config.Config.*; import static de.diddiz.util.BukkitUtils.friendlyWorldname; -import static de.diddiz.util.BukkitUtils.getBlockEquivalents; -import static de.diddiz.util.MaterialName.materialName; -import static de.diddiz.util.MaterialName.typeFromName; import static de.diddiz.util.Utils.*; public final class QueryParams implements Cloneable { @@ -32,7 +28,7 @@ public final class QueryParams implements Cloneable { public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, excludeBlocksMode = false, prepareToolQuery = false, silent = false; public RegionContainer sel = null; public SummarizationMode sum = SummarizationMode.NONE; - public List types = new ArrayList(); + public List types = new ArrayList(); public World world = null; public String match = null; public boolean needCount = false, needId = false, needDate = false, needType = false, needData = false, needPlayer = false, needCoords = false, needSignText = false, needChestAccess = false, needMessage = false, needKiller = false, needVictim = false, needWeapon = false; @@ -129,7 +125,7 @@ public String getQuery() { select += "COUNT(*) AS count"; } else { if (needId) { - select += "`" + getTable() + "`.id, "; + select += "`" + getTable() + "`-blocks.id, "; } if (needDate) { select += "date, "; @@ -138,7 +134,7 @@ public String getQuery() { select += "replaced, type, "; } if (needData) { - select += "data, "; + select += "replacedData, typeData, "; } if (needPlayer) { select += "playername, UUID, "; @@ -150,11 +146,11 @@ public String getQuery() { select += "signtext, "; } if (needChestAccess) { - select += "itemtype, itemamount, itemdata, "; + select += "item, itemremove, "; } select = select.substring(0, select.length() - 2); } - String from = "FROM `" + getTable() + "` "; + String from = "FROM `" + getTable() + "-blocks` "; if (needPlayer || players.size() > 0) { from += "INNER JOIN `lb-players` USING (playerid) "; } @@ -165,16 +161,16 @@ public String getQuery() { // If BlockChangeType is CHESTACCESS, we can use more efficient query { if (bct == BlockChangeType.CHESTACCESS) { - from += "RIGHT JOIN `" + getTable() + "-chest` USING (id) "; + from += "RIGHT JOIN `" + getTable() + "-chestdata` USING (id) "; } else { - from += "LEFT JOIN `" + getTable() + "-chest` USING (id) "; + from += "LEFT JOIN `" + getTable() + "-chestdata` USING (id) "; } } return select + " " + from + getWhere() + "ORDER BY date " + order + ", id " + order + " " + getLimit(); } else if (sum == SummarizationMode.TYPES) { - return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.CREATED) + "GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); + return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.CREATED) + "GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); } else { - return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "` " + getWhere(BlockChangeType.CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "` " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); + return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); } } @@ -197,7 +193,7 @@ public String getTitle() { } final String[] blocknames = new String[types.size()]; for (int i = 0; i < types.size(); i++) { - blocknames[i] = materialName(types.get(i).getBlock()); + blocknames[i] = types.get(i).name(); } title.append(listing(blocknames, ", ", " and ")).append(" "); } else { @@ -363,13 +359,9 @@ public String getWhere(BlockChangeType blockChangeType) { where.append("NOT "); } where.append('('); - for (final Block block : types) { - where.append("((type = ").append(block.getBlock()).append(" OR replaced = ").append(block.getBlock()); - if (block.getData() != -1) { - where.append(") AND data = ").append(block.getData()); - } else { - where.append(")"); - } + for (final Material block : types) { + where.append("((type = ").append(MaterialConverter.getOrAddMaterialId(block.getKey())).append(" OR replaced = ").append(MaterialConverter.getOrAddMaterialId(block.getKey())); + where.append(")"); where.append(") OR "); } where.delete(where.length() - 4, where.length() - 1); @@ -382,13 +374,9 @@ public String getWhere(BlockChangeType blockChangeType) { where.append("NOT "); } where.append('('); - for (final Block block : types) { - where.append("((type = ").append(block.getBlock()).append(" OR replaced = ").append(block.getBlock()); - if (block.getData() != -1) { - where.append(") AND data = ").append(block.getData()); - } else { - where.append(")"); - } + for (final Material block : types) { + where.append("((type = ").append(MaterialConverter.getOrAddMaterialId(block.getKey())).append(" OR replaced = ").append(MaterialConverter.getOrAddMaterialId(block.getKey())); + where.append(")"); where.append(") OR "); } where.delete(where.length() - 4, where.length()); @@ -402,13 +390,9 @@ public String getWhere(BlockChangeType blockChangeType) { where.append("NOT "); } where.append('('); - for (final Block block : types) { - where.append("((type = ").append(block.getBlock()); - if (block.getData() != -1) { - where.append(") AND data = ").append(block.getData()); - } else { - where.append(")"); - } + for (final Material block : types) { + where.append("((type = ").append(MaterialConverter.getOrAddMaterialId(block.getKey())); + where.append(")"); where.append(") OR "); } where.delete(where.length() - 4, where.length()); @@ -422,13 +406,9 @@ public String getWhere(BlockChangeType blockChangeType) { where.append("NOT "); } where.append('('); - for (final Block block : types) { - where.append("((replaced = ").append(block.getBlock()); - if (block.getData() != -1) { - where.append(") AND data = ").append(block.getData()); - } else { - where.append(")"); - } + for (final Material block : types) { + where.append("((replaced = ").append(MaterialConverter.getOrAddMaterialId(block.getKey())); + where.append(")"); where.append(") OR "); } where.delete(where.length() - 4, where.length()); @@ -442,19 +422,17 @@ public String getWhere(BlockChangeType blockChangeType) { where.append("NOT "); } where.append('('); - for (final Block block : types) { - where.append("((itemtype = ").append(block.getBlock()); - if (block.getData() != -1) { - where.append(") AND itemdata = ").append(block.getData()); - } else { - where.append(")"); - } + for (final Material block : types) { + where.append("((itemtype = ").append(MaterialConverter.getOrAddMaterialId(block.getKey())); + where.append(")"); where.append(") OR "); } where.delete(where.length() - 4, where.length()); where.append(") AND "); } break; + default: + break; } if (loc != null) { if (radius == 0) { @@ -625,17 +603,10 @@ public void parseArgs(CommandSender sender, List args) throws IllegalArg } for (final String weaponName : values) { Material mat = Material.matchMaterial(weaponName); - if (mat == null) { - try { - mat = Material.getMaterial(Integer.parseInt(weaponName)); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("Data type not a valid number: '" + weaponName + "'"); - } - } if (mat == null) { throw new IllegalArgumentException("No material matching: '" + weaponName + "'"); } - types.add(new Block(mat.getId(), -1)); + types.add(mat); } needWeapon = true; } else if (param.equals("block") || param.equals("type")) { @@ -647,29 +618,9 @@ public void parseArgs(CommandSender sender, List args) throws IllegalArg excludeBlocksMode = true; blockName = blockName.substring(1); } - if (blockName.contains(":")) { - String[] blockNameSplit = blockName.split(":"); - if (blockNameSplit.length > 2) { - throw new IllegalArgumentException("No material matching: '" + blockName + "'"); - } - final int data; - try { - data = Integer.parseInt(blockNameSplit[1]); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("Data type not a valid number: '" + blockNameSplit[1] + "'"); - } - if (data > 255 || data < 0) { - throw new IllegalArgumentException("Data type out of range (0-255): '" + data + "'"); - } - final Material mat = Material.matchMaterial(blockNameSplit[0]); - if (mat == null) { - throw new IllegalArgumentException("No material matching: '" + blockName + "'"); - } - types.add(new Block(mat.getId(), data)); - } else { - final Material mat = Material.matchMaterial(blockName); - types.add(new Block(typeFromName(blockName), -1)); - } + + final Material mat = Material.matchMaterial(blockName); + types.add(mat); } } else if (param.equals("area")) { if (player == null && !prepareToolQuery && loc == null) { @@ -791,24 +742,6 @@ public void parseArgs(CommandSender sender, List args) throws IllegalArg throw new IllegalArgumentException("Kill logging not enabled for world '" + world.getName() + "'"); } } - if (types.size() > 0) { - for (final Set equivalent : getBlockEquivalents()) { - boolean found = false; - for (final Block block : types) { - if (equivalent.contains(block.getBlock())) { - found = true; - break; - } - } - if (found) { - for (final Integer type : equivalent) { - if (!Block.inList(types, type)) { - types.add(new Block(type, -1)); - } - } - } - } - } if (!prepareToolQuery && bct != BlockChangeType.CHAT) { if (world == null) { throw new IllegalArgumentException("No world specified"); @@ -842,7 +775,7 @@ protected QueryParams clone() { try { final QueryParams params = (QueryParams) super.clone(); params.players = new ArrayList(players); - params.types = new ArrayList(types); + params.types = new ArrayList(types); return params; } catch (final CloneNotSupportedException ex) { } diff --git a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java index f6dfa0db..919949a3 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java @@ -6,11 +6,10 @@ import java.sql.ResultSet; import java.sql.SQLException; -import static de.diddiz.util.MaterialName.materialName; import static de.diddiz.util.Utils.spaces; public class SummedBlockChanges implements LookupCacheElement { - private final String group; + private final int type; private final int created, destroyed; private final float spaceFactor; private final Actor actor; @@ -18,7 +17,7 @@ public class SummedBlockChanges implements LookupCacheElement { public SummedBlockChanges(ResultSet rs, QueryParams p, float spaceFactor) throws SQLException { // Actor currently useless here as we don't yet output UUID in results anywhere actor = p.sum == SummarizationMode.PLAYERS ? new Actor(rs) : null; - group = actor == null ? materialName(rs.getInt("type")) : actor.getName(); + type = p.sum == SummarizationMode.TYPES ? rs.getInt("type") : 0; created = rs.getInt("created"); destroyed = rs.getInt("destroyed"); this.spaceFactor = spaceFactor; @@ -31,6 +30,6 @@ public Location getLocation() { @Override public String getMessage() { - return created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)) + destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)) + group; + return created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)) + destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)) + (actor != null ? actor.getName() : MaterialConverter.getMaterial(type).toString()); } } diff --git a/src/main/java/de/diddiz/LogBlock/Tool.java b/src/main/java/de/diddiz/LogBlock/Tool.java index e84c9824..17055b96 100644 --- a/src/main/java/de/diddiz/LogBlock/Tool.java +++ b/src/main/java/de/diddiz/LogBlock/Tool.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock; +import org.bukkit.Material; import org.bukkit.permissions.PermissionDefault; import java.util.List; @@ -9,13 +10,13 @@ public class Tool { public final List aliases; public final ToolBehavior leftClickBehavior, rightClickBehavior; public final boolean defaultEnabled; - public final int item; + public final Material item; public final boolean canDrop; public final QueryParams params; public final ToolMode mode; public final PermissionDefault permissionDefault; - public Tool(String name, List aliases, ToolBehavior leftClickBehavior, ToolBehavior rightClickBehavior, boolean defaultEnabled, int item, boolean canDrop, QueryParams params, ToolMode mode, PermissionDefault permissionDefault) { + public Tool(String name, List aliases, ToolBehavior leftClickBehavior, ToolBehavior rightClickBehavior, boolean defaultEnabled, Material item, boolean canDrop, QueryParams params, ToolMode mode, PermissionDefault permissionDefault) { this.name = name; this.aliases = aliases; this.leftClickBehavior = leftClickBehavior; diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index d7dffdf2..b0950ffe 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -312,9 +312,11 @@ boolean update() { players.clear(); names.clear(); getLogger().info("Processed " + Integer.toString(done) + " out of " + total); + rs.close(); rs = st.executeQuery("SELECT playerid,playername FROM `lb-players` WHERE LENGTH(UUID)=0 LIMIT " + Integer.toString(UUID_CONVERT_BATCH_SIZE)); } } + rs.close(); st.close(); conn.close(); @@ -443,10 +445,13 @@ void checkTables() throws SQLException { if (isLogging(Logging.CHAT)) { createTable(dbm, 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)) ENGINE=MyISAM DEFAULT CHARSET " + charset); } + createTable(dbm, state, "lb-materials", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) ENGINE=MyISAM DEFAULT CHARSET " + charset); + createTable(dbm, state, "lb-blockstates", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) ENGINE=MyISAM DEFAULT CHARSET " + charset); + for (final WorldConfig wcfg : getLoggedWorlds()) { - createTable(dbm, state, wcfg.table, "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced TINYINT UNSIGNED NOT NULL, type TINYINT UNSIGNED NOT NULL, data TINYINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))"); + createTable(dbm, state, wcfg.table + "-blocks", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced SMALLINT UNSIGNED NOT NULL, replacedData SMALLINT NOT NULL, type SMALLINT UNSIGNED NOT NULL, typeData SMALLINT NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))"); createTable(dbm, state, wcfg.table + "-sign", "(id INT UNSIGNED NOT NULL, signtext VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); - createTable(dbm, state, wcfg.table + "-chest", "(id INT UNSIGNED NOT NULL, itemtype SMALLINT UNSIGNED NOT NULL, itemamount SMALLINT NOT NULL, itemdata SMALLINT NOT NULL, PRIMARY KEY (id))"); + createTable(dbm, state, wcfg.table + "-chestdata", "(id INT UNSIGNED NOT NULL, item MEDIUMBLOB, itemremove TINYINT, PRIMARY KEY (id))"); if (wcfg.isLogging(Logging.KILL)) { createTable(dbm, state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id))"); } diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 7ddc83d1..8f11909b 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -8,12 +8,15 @@ import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.Bed; +import org.bukkit.block.data.type.Bed.Part; +import org.bukkit.block.data.type.Piston; +import org.bukkit.block.data.type.PistonHead; +import org.bukkit.block.data.type.TechnicalPiston.Type; import org.bukkit.command.CommandSender; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; -import org.bukkit.material.Bed; -import org.bukkit.material.PistonBaseMaterial; -import org.bukkit.material.PistonExtensionMaterial; import java.io.File; import java.io.PrintWriter; @@ -27,7 +30,6 @@ import static de.diddiz.LogBlock.config.Config.dontRollback; import static de.diddiz.LogBlock.config.Config.replaceAnyway; import static de.diddiz.util.BukkitUtils.*; -import static de.diddiz.util.MaterialName.materialName; import static org.bukkit.Bukkit.getLogger; public class WorldEditor implements Runnable { @@ -70,8 +72,8 @@ public void setSender(CommandSender sender) { this.sender = sender; } - public void queueEdit(int x, int y, int z, int replaced, int type, byte data, String signtext, short itemType, short itemAmount, short itemData) { - edits.add(new Edit(0, new Location(world, x, y, z), null, replaced, type, data, signtext, new ChestAccess(itemType, itemAmount, itemData))); + public void queueEdit(int x, int y, int z, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess item) { + edits.add(new Edit(0, new Location(world, x, y, z), null, replaced, replaceData, type, typeData, signtext, item)); } public long getElapsedTime() { @@ -106,6 +108,8 @@ public synchronized void run() { case BLACKLISTED: blacklistCollisions++; break; + case NO_ACTION: + break; } } catch (final WorldEditorException ex) { errorList.add(ex); @@ -145,48 +149,49 @@ private static enum PerformResult { } private class Edit extends BlockChange { - public Edit(long time, Location loc, Actor actor, int replaced, int type, byte data, String signtext, ChestAccess ca) { - super(time, loc, actor, replaced, type, data, signtext, ca); + public Edit(long time, Location loc, Actor actor, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess ca) { + super(time, loc, actor, replaced, replaceData, type, typeData, signtext, ca); } PerformResult perform() throws WorldEditorException { - if (dontRollback.contains(replaced)) { + BlockData replacedBlock = MaterialConverter.getBlockData(this.replacedMaterial, replacedData); + BlockData setBlock = MaterialConverter.getBlockData(this.typeMaterial, typeData); + // action: set to replaced + + if (dontRollback.contains(replacedBlock.getMaterial())) { return PerformResult.BLACKLISTED; } final Block block = loc.getBlock(); - if (replaced == 0 && block.getTypeId() == 0) { + if (replacedBlock.getMaterial() == Material.AIR && block.getType() == Material.AIR) { return PerformResult.NO_ACTION; } final BlockState state = block.getState(); if (!world.isChunkLoaded(block.getChunk())) { world.loadChunk(block.getChunk()); } - if (type == replaced) { - if (type == 0) { - if (!block.setTypeId(0)) { - throw new WorldEditorException(block.getTypeId(), 0, block.getLocation()); - } + if (setBlock.equals(replacedBlock)) { + if (setBlock.getMaterial() == Material.AIR) { + block.setType(Material.AIR); } else if (ca != null) { - if (getContainerBlocks().contains(Material.getMaterial(type))) { + if (state instanceof InventoryHolder) { int leftover; try { - leftover = modifyContainer(state, new ItemStack(ca.itemType, -ca.itemAmount, ca.itemData)); + leftover = modifyContainer(state, new ItemStack(ca.itemStack), !ca.remove); // Special-case blocks which might be double chests - if (leftover > 0 && (type == 54 || type == 146)) { + if (leftover > 0 && (setBlock.getMaterial() == Material.CHEST || setBlock.getMaterial() == Material.TRAPPED_CHEST)) { for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) { - if (block.getRelative(face).getTypeId() == type) { - leftover = modifyContainer(block.getRelative(face).getState(), new ItemStack(ca.itemType, ca.itemAmount < 0 ? leftover : -leftover, ca.itemData)); + if (block.getRelative(face).getType() == setBlock.getMaterial()) { + ItemStack remaining = new ItemStack(ca.itemStack); + remaining.setAmount(leftover); + leftover = modifyContainer(block.getRelative(face).getState(), remaining, !ca.remove); } } } } catch (final Exception ex) { throw new WorldEditorException(ex.getMessage(), block.getLocation()); } - if (false /*!state.update()*/) { // Raw inventory doesn't need update, really should be using snapshot inventory however. Do this for backwards compat with < 1.12.1 - throw new WorldEditorException("Failed to update inventory of " + materialName(block.getTypeId()), block.getLocation()); - } - if (leftover > 0 && ca.itemAmount < 0) { - throw new WorldEditorException("Not enough space left in " + materialName(block.getTypeId()), block.getLocation()); + if (leftover > 0 && ca.remove) { + throw new WorldEditorException("Not enough space left in " + block.getType(), block.getLocation()); } } } else { @@ -194,24 +199,18 @@ PerformResult perform() throws WorldEditorException { } return PerformResult.SUCCESS; } - if (!(equalTypes(block.getTypeId(), type) || replaceAnyway.contains(block.getTypeId()))) { + if (block.getType() != setBlock.getMaterial() && !replaceAnyway.contains(block.getType())) { return PerformResult.NO_ACTION; } if (state instanceof InventoryHolder) { ((InventoryHolder) state).getInventory().clear(); state.update(); } - if (block.getTypeId() == replaced) { - if (block.getData() != (type == 0 ? data : (byte) 0)) { - block.setData(type == 0 ? data : (byte) 0, true); - } else { - return PerformResult.NO_ACTION; - } - } else if (!block.setTypeIdAndData(replaced, type == 0 ? data : (byte) 0, true)) { - throw new WorldEditorException(block.getTypeId(), replaced, block.getLocation()); - } - final int curtype = block.getTypeId(); - if (signtext != null && (curtype == 63 || curtype == 68)) { + block.setBlockData(replacedBlock); + BlockData newData = block.getBlockData(); + + final Material curtype = block.getType(); + if (signtext != null && (curtype == Material.SIGN || curtype == Material.WALL_SIGN)) { final Sign sign = (Sign) block.getState(); final String[] lines = signtext.split("\0", 4); if (lines.length < 4) { @@ -221,28 +220,36 @@ PerformResult perform() throws WorldEditorException { sign.setLine(i, lines[i]); } if (!sign.update()) { - throw new WorldEditorException("Failed to update signtext of " + materialName(block.getTypeId()), block.getLocation()); + throw new WorldEditorException("Failed to update signtext of " + block.getType(), block.getLocation()); } - } else if (curtype == 26) { - final Bed bed = (Bed) block.getState().getData(); - final Block secBlock = bed.isHeadOfBed() ? block.getRelative(bed.getFacing().getOppositeFace()) : block.getRelative(bed.getFacing()); - if (secBlock.getTypeId() == 0 && !secBlock.setTypeIdAndData(26, (byte) (bed.getData() | 8), true)) { - throw new WorldEditorException(secBlock.getTypeId(), 26, secBlock.getLocation()); + } else if (newData instanceof Bed) { + final Bed bed = (Bed) newData; + final Block secBlock = bed.getPart() == Part.HEAD ? block.getRelative(bed.getFacing().getOppositeFace()) : block.getRelative(bed.getFacing()); + if (secBlock.isEmpty()) { + Bed bed2 = (Bed) bed.clone(); + bed2.setPart(bed.getPart() == Part.HEAD ? Part.FOOT : Part.HEAD); + secBlock.setBlockData(bed2); } - } else if ((curtype == 29 || curtype == 33) && (block.getData() & 8) > 0) { - final PistonBaseMaterial piston = (PistonBaseMaterial) block.getState().getData(); - final Block secBlock = block.getRelative(piston.getFacing()); - if (secBlock.getTypeId() == 0 && !secBlock.setTypeIdAndData(34, curtype == 29 ? (byte) (block.getData() | 8) : (byte) (block.getData() & ~8), true)) { - throw new WorldEditorException(secBlock.getTypeId(), 34, secBlock.getLocation()); + } else if ((curtype == Material.PISTON || curtype == Material.STICKY_PISTON)) { + Piston piston = (Piston) newData; + if (piston.isExtended()) { + final Block secBlock = block.getRelative(piston.getFacing()); + if (secBlock.isEmpty()) { + PistonHead head = (PistonHead) Material.PISTON_HEAD.createBlockData(); + head.setFacing(piston.getFacing()); + head.setType(curtype == Material.PISTON ? Type.NORMAL : Type.STICKY); + secBlock.setBlockData(head); + } } - } else if (curtype == 34) { - final PistonExtensionMaterial piston = (PistonExtensionMaterial) block.getState().getData(); - final Block secBlock = block.getRelative(piston.getFacing().getOppositeFace()); - if (secBlock.getTypeId() == 0 && !secBlock.setTypeIdAndData(piston.isSticky() ? 29 : 33, (byte) (block.getData() | 8), true)) { - throw new WorldEditorException(secBlock.getTypeId(), piston.isSticky() ? 29 : 33, secBlock.getLocation()); + } else if (curtype == Material.PISTON_HEAD) { + PistonHead head = (PistonHead) newData; + final Block secBlock = block.getRelative(head.getFacing().getOppositeFace()); + if (secBlock.isEmpty()) { + Piston piston = (Piston) (head.getType() == Type.NORMAL ? Material.PISTON : Material.STICKY_PISTON).createBlockData(); + piston.setFacing(head.getFacing()); + piston.setExtended(true); + secBlock.setBlockData(piston); } - } else if (curtype == 18 && (block.getData() & 8) > 0) { - block.setData((byte) (block.getData() & 0xF7)); } return PerformResult.SUCCESS; } @@ -252,8 +259,8 @@ PerformResult perform() throws WorldEditorException { public static class WorldEditorException extends Exception implements LookupCacheElement { private final Location loc; - public WorldEditorException(int typeBefore, int typeAfter, Location loc) { - this("Failed to replace " + materialName(typeBefore) + " with " + materialName(typeAfter), loc); + public WorldEditorException(Material typeBefore, Material typeAfter, Location loc) { + this("Failed to replace " + typeBefore.name() + " with " + typeAfter.name(), loc); } public WorldEditorException(String msg, Location loc) { diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index ed6cbaea..cc4e4bb4 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -32,15 +32,15 @@ public class Config { public static boolean dumpDeletedLog; public static boolean logCreeperExplosionsAsPlayerWhoTriggeredThese, logPlayerInfo; public static LogKillsLevel logKillsLevel; - public static Set dontRollback, replaceAnyway; + public static Set dontRollback, replaceAnyway; public static int rollbackMaxTime, rollbackMaxArea; public static Map toolsByName; - public static Map toolsByType; + public static Map toolsByType; public static int defaultDist, defaultTime; public static int linesPerPage, linesLimit; public static boolean askRollbacks, askRedos, askClearLogs, askClearLogAfterRollback, askRollbackAfterBan; public static String banPermission; - public static Set hiddenBlocks; + public static Set hiddenBlocks; public static Set hiddenPlayers; public static Set ignoredChat; public static SimpleDateFormat formatter; @@ -161,21 +161,37 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti for (final String playerName : config.getStringList("logging.hiddenPlayers")) { hiddenPlayers.add(playerName.toLowerCase().trim()); } - hiddenBlocks = new HashSet(); - for (final Object blocktype : config.getList("logging.hiddenBlocks")) { - final Material mat = Material.matchMaterial(String.valueOf(blocktype)); + hiddenBlocks = new HashSet(); + for (final String blocktype : config.getStringList("logging.hiddenBlocks")) { + final Material mat = Material.matchMaterial(blocktype); if (mat != null) { - hiddenBlocks.add(mat.getId()); + hiddenBlocks.add(mat); } else { - throw new DataFormatException("Not a valid material: '" + blocktype + "'"); + throw new DataFormatException("Not a valid material in hiddenBlocks: '" + blocktype + "'"); } } ignoredChat = new HashSet(); for (String chatCommand : config.getStringList("logging.ignoredChat")) { ignoredChat.add(chatCommand); } - dontRollback = new HashSet(config.getIntegerList("rollback.dontRollback")); - replaceAnyway = new HashSet(config.getIntegerList("rollback.replaceAnyway")); + dontRollback = new HashSet(); + for (String e : config.getStringList("rollback.dontRollback")) { + Material mat = Material.matchMaterial(e); + if (mat != null) { + dontRollback.add(mat); + } else { + throw new DataFormatException("Not a valid material in dontRollback: '" + e + "'"); + } + } + replaceAnyway = new HashSet(); + for (String e : config.getStringList("rollback.replaceAnyway")) { + Material mat = Material.matchMaterial(e); + if (mat != null) { + replaceAnyway.add(mat); + } else { + throw new DataFormatException("Not a valid material in replaceAnyway: '" + e + "'"); + } + } rollbackMaxTime = parseTimeSpec(config.getString("rollback.maxTime").split(" ")); rollbackMaxArea = config.getInt("rollback.maxArea", 50); defaultDist = config.getInt("lookup.defaultDist", 20); @@ -199,7 +215,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti final ToolBehavior leftClickBehavior = ToolBehavior.valueOf(tSec.getString("leftClickBehavior").toUpperCase()); final ToolBehavior rightClickBehavior = ToolBehavior.valueOf(tSec.getString("rightClickBehavior").toUpperCase()); final boolean defaultEnabled = tSec.getBoolean("defaultEnabled", false); - final int item = tSec.getInt("item", 0); + final Material item = Material.matchMaterial(tSec.getString("item","OAK_LOG")); final boolean canDrop = tSec.getBoolean("canDrop", false); final QueryParams params = new QueryParams(logblock); params.prepareToolQuery = true; @@ -212,7 +228,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti } } toolsByName = new HashMap(); - toolsByType = new HashMap(); + toolsByType = new HashMap(); for (final Tool tool : tools) { toolsByType.put(tool.item, tool); toolsByName.put(tool.name.toLowerCase(), tool); diff --git a/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java b/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java index 5decd897..ade7807b 100644 --- a/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java +++ b/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java @@ -3,26 +3,27 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.ChestAccess; import org.apache.commons.lang.Validate; +import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; import org.bukkit.event.HandlerList; public class BlockChangePreLogEvent extends PreLogEvent { private static final HandlerList handlers = new HandlerList(); private Location location; - private int typeBefore, typeAfter; - private byte data; + private BlockData typeBefore, typeAfter; private String signText; private ChestAccess chestAccess; - public BlockChangePreLogEvent(Actor owner, Location location, int typeBefore, int typeAfter, byte data, + public BlockChangePreLogEvent(Actor owner, Location location, BlockData typeBefore, BlockData typeAfter, String signText, ChestAccess chestAccess) { super(owner); this.location = location; this.typeBefore = typeBefore; this.typeAfter = typeAfter; - this.data = data; this.signText = signText; this.chestAccess = chestAccess; } @@ -37,36 +38,30 @@ public void setLocation(Location location) { this.location = location; } - public int getTypeBefore() { + public BlockData getTypeBefore() { return typeBefore; } - public void setTypeBefore(int typeBefore) { - + public void setTypeBefore(BlockData typeBefore) { + if (typeBefore == null) { + typeBefore = Bukkit.createBlockData(Material.AIR); + } this.typeBefore = typeBefore; } - public int getTypeAfter() { + public BlockData getTypeAfter() { return typeAfter; } - public void setTypeAfter(int typeAfter) { - + public void setTypeAfter(BlockData typeAfter) { + if (typeAfter == null) { + typeAfter = Bukkit.createBlockData(Material.AIR); + } this.typeAfter = typeAfter; } - public byte getData() { - - return data; - } - - public void setData(byte data) { - - this.data = data; - } - public String getSignText() { return signText; @@ -90,13 +85,13 @@ public void setSignText(String[] signText) { private boolean isValidSign() { - if ((typeAfter == 63 || typeAfter == 68) && typeBefore == 0) { + if ((typeAfter.getMaterial() == Material.SIGN || typeAfter.getMaterial() == Material.WALL_SIGN) && typeBefore.getMaterial() == Material.AIR) { return true; } - if ((typeBefore == 63 || typeBefore == 68) && typeAfter == 0) { + if ((typeBefore.getMaterial() == Material.SIGN || typeBefore.getMaterial() == Material.WALL_SIGN) && typeAfter.getMaterial() == Material.AIR) { return true; } - if ((typeAfter == 63 || typeAfter == 68) && typeBefore == typeAfter) { + if ((typeAfter.getMaterial() == Material.SIGN || typeAfter.getMaterial() == Material.WALL_SIGN) && typeBefore.equals(typeAfter)) { return true; } return false; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BanListener.java b/src/main/java/de/diddiz/LogBlock/listeners/BanListener.java index f7c29693..9f50afb2 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BanListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BanListener.java @@ -29,7 +29,7 @@ public void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event) p.setPlayer(split[1].equalsIgnoreCase("g") ? split[2] : split[1]); p.since = 0; p.silent = false; - getScheduler().scheduleAsyncDelayedTask(logblock, new Runnable() { + getScheduler().runTaskAsynchronously(logblock, new Runnable() { @Override public void run() { for (final World world : logblock.getServer().getWorlds()) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java index b27db533..e89d0a66 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java @@ -5,6 +5,8 @@ import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.util.BukkitUtils; + +import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.block.Block; @@ -34,10 +36,9 @@ public void onBlockBreak(BlockBreakEvent event) { final Actor actor = Actor.actorFromEntity(event.getPlayer()); final Block origin = event.getBlock(); - final int typeId = origin.getTypeId(); final Material type = origin.getType(); - if (wcfg.isLogging(Logging.SIGNTEXT) && (typeId == 63 || typeId == 68)) { + if (wcfg.isLogging(Logging.SIGNTEXT) && (type == Material.SIGN || type == Material.WALL_SIGN)) { consumer.queueSignBreak(actor, (Sign) origin.getState()); } else if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.getContainerBlocks().contains(type)) { consumer.queueContainerBreak(actor, origin.getState()); @@ -46,7 +47,7 @@ public void onBlockBreak(BlockBreakEvent event) { if (event.getPlayer().getGameMode().equals(GameMode.CREATIVE)) { consumer.queueBlockBreak(actor, origin.getState()); } else { - consumer.queueBlockReplace(actor, origin.getState(), 9, (byte) 0); + consumer.queueBlockReplace(actor, origin.getState(), Bukkit.createBlockData(Material.WATER)); } } else { smartLogBlockBreak(consumer, actor, origin); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java index c5325379..1324319b 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java @@ -5,6 +5,8 @@ import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.util.BukkitUtils; + +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.BlockFace; @@ -32,7 +34,7 @@ public void onBlockPlace(BlockPlaceEvent event) { final Actor actor = Actor.actorFromEntity(event.getPlayer()); //Handle falling blocks - if (BukkitUtils.getRelativeTopFallables().contains(type)) { + if (type.hasGravity()) { // Catch placed blocks overwriting something if (before.getType() != Material.AIR) { @@ -55,9 +57,9 @@ public void onBlockPlace(BlockPlaceEvent event) { // Run this check to avoid false positives if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) { if (finalLoc.getBlock().getType() == Material.AIR || finalLoc.equals(event.getBlock().getLocation())) { - consumer.queueBlockPlace(actor, finalLoc, type.getId(), event.getBlock().getData()); + consumer.queueBlockPlace(actor, finalLoc, event.getBlock().getBlockData()); } else { - consumer.queueBlockReplace(actor, finalLoc, finalLoc.getBlock().getTypeId(), finalLoc.getBlock().getData(), type.getId(), event.getBlock().getData()); + consumer.queueBlockReplace(actor, finalLoc, finalLoc.getBlock().getBlockData(), event.getBlock().getBlockData()); } } } @@ -65,7 +67,7 @@ public void onBlockPlace(BlockPlaceEvent event) { } //Sign logging is handled elsewhere - if (wcfg.isLogging(Logging.SIGNTEXT) && (type.getId() == 63 || type.getId() == 68)) { + if (wcfg.isLogging(Logging.SIGNTEXT) && (type == Material.SIGN || type == Material.WALL_SIGN)) { return; } @@ -73,7 +75,7 @@ public void onBlockPlace(BlockPlaceEvent event) { LogBlock.getInstance().getServer().getScheduler().scheduleSyncDelayedTask(LogBlock.getInstance(), new Runnable() { @Override public void run() { - if (before.getTypeId() == 0) { + if (before.getType() == Material.AIR) { consumer.queueBlockPlace(actor, after); } else { consumer.queueBlockReplace(actor, before, after); @@ -86,7 +88,7 @@ public void run() { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) { if (isLogging(event.getPlayer().getWorld(), Logging.BLOCKPLACE)) { - consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getRelative(event.getBlockFace()).getLocation(), event.getBucket() == Material.WATER_BUCKET ? 9 : 11, (byte) 0); + consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getRelative(event.getBlockFace()).getLocation(), Bukkit.createBlockData(event.getBucket() == Material.WATER_BUCKET ? Material.WATER : Material.LAVA)); } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java index ca3d9232..02937180 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java @@ -32,7 +32,7 @@ public void onBlockSpread(BlockSpreadEvent event) { } name = "GrassGrowth"; break; - case MYCEL: + case MYCELIUM: if (!isLogging(world, Logging.MYCELIUMSPREAD)) { return; } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index 3ada3b90..50527add 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -4,6 +4,7 @@ import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.block.DoubleChest; import org.bukkit.entity.HumanEntity; @@ -42,7 +43,9 @@ public void onInventoryClose(InventoryCloseEvent event) { final ItemStack[] diff = compareInventories(before, after); final Location loc = getInventoryHolderLocation(holder); for (final ItemStack item : diff) { - consumer.queueChestAccess(Actor.actorFromEntity(player), loc, loc.getWorld().getBlockTypeIdAt(loc), (short) item.getTypeId(), (short) item.getAmount(), rawData(item)); + ItemStack item2 = item.clone(); + item2.setAmount(Math.abs(item.getAmount())); + consumer.queueChestAccess(Actor.actorFromEntity(player), loc, loc.getWorld().getBlockAt(loc).getBlockData(), item2, item.getAmount() < 0); } containers.remove(player); } @@ -58,7 +61,7 @@ public void onInventoryOpen(InventoryOpenEvent event) { if (event.getInventory() != null) { InventoryHolder holder = event.getInventory().getHolder(); if (holder instanceof BlockState || holder instanceof DoubleChest) { - if (getInventoryHolderType(holder) != 58) { + if (getInventoryHolderType(holder) != Material.CRAFTING_TABLE) { containers.put(event.getPlayer(), compressInventory(event.getInventory().getContents())); } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java index ea0cab00..b4bfc60a 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java @@ -36,22 +36,18 @@ public void onEntityInteract(EntityInteractEvent event) { if (wcfg != null) { final Block clicked = event.getBlock(); final Material type = clicked.getType(); - final int typeId = type.getId(); - final byte blockData = clicked.getData(); final Location loc = clicked.getLocation(); - switch (type) { - case SOIL: - if (wcfg.isLogging(Logging.CREATURECROPTRAMPLE)) { - // 3 = Dirt ID - consumer.queueBlock(Actor.actorFromEntity(entityType), loc, typeId, 3, blockData); - // Log the crop on top as being broken - Block trampledCrop = clicked.getRelative(BlockFace.UP); - if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) { - consumer.queueBlockBreak(new Actor("CreatureTrample"), trampledCrop.getState()); - } + if (type == Material.FARMLAND) { + if (wcfg.isLogging(Logging.CREATURECROPTRAMPLE)) { + // 3 = Dirt ID + consumer.queueBlock(Actor.actorFromEntity(entityType), loc, type.createBlockData(), Material.DIRT.createBlockData()); + // Log the crop on top as being broken + Block trampledCrop = clicked.getRelative(BlockFace.UP); + if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) { + consumer.queueBlockBreak(new Actor("CreatureTrample"), trampledCrop.getState()); } - break; + } } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java index 9fc14baa..5b89ad44 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java @@ -18,7 +18,7 @@ public EndermenLogging(LogBlock 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.getTo().getId(), (byte) 0); // Figure out how to get the data of the placed block; + consumer.queueBlockReplace(new Actor("Enderman"), event.getBlock().getState(), event.getBlockData()); // Figure out how to get the data of the placed block; } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index e53b5568..a9d7d31a 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -99,10 +99,10 @@ public void onEntityExplode(EntityExplodeEvent event) { } } for (final Block block : event.blockList()) { - final int type = block.getTypeId(); - if (wcfg.isLogging(Logging.SIGNTEXT) & (type == 63 || type == 68)) { + final Material type = block.getType(); + if (wcfg.isLogging(Logging.SIGNTEXT) & (type == Material.SIGN || type == Material.WALL_SIGN)) { consumer.queueSignBreak(actor, (Sign) block.getState()); - } else if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(Material.getMaterial(type)))) { + } else if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(type))) { consumer.queueContainerBreak(actor, block.getState()); } else { consumer.queueBlockBreak(actor, block.getState()); @@ -122,10 +122,10 @@ public void onBlockExplode(BlockExplodeEvent event) { } Actor actor = new Actor("Explosion"); - final int type = block.getTypeId(); - if (wcfg.isLogging(Logging.SIGNTEXT) & (type == 63 || type == 68)) { + final Material type = block.getType(); + if (wcfg.isLogging(Logging.SIGNTEXT) & (type == Material.SIGN || type == Material.WALL_SIGN)) { consumer.queueSignBreak(actor, (Sign) block.getState()); - } else if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(Material.getMaterial(type)))) { + } else if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(type))) { consumer.queueContainerBreak(actor, block.getState()); } else { consumer.queueBlockBreak(actor, block.getState()); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index ec1efc51..750b73dc 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -4,20 +4,20 @@ import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; +import de.diddiz.util.BukkitUtils; + +import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Levelled; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockFromToEvent; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - import static de.diddiz.LogBlock.config.Config.getWorldConfig; public class FluidFlowLogging extends LoggingListener { - private static final Set nonFluidProofBlocks = new HashSet(Arrays.asList(27, 28, 31, 32, 37, 38, 39, 40, 50, 51, 55, 59, 66, 69, 70, 75, 76, 78, 93, 94, 104, 105, 106)); public FluidFlowLogging(LogBlock lb) { super(lb); @@ -27,43 +27,59 @@ public FluidFlowLogging(LogBlock lb) { public void onBlockFromTo(BlockFromToEvent event) { final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld()); if (wcfg != null) { + final BlockData blockDataFrom = event.getBlock().getBlockData(); + final Material typeFrom = blockDataFrom.getMaterial(); + final Block to = event.getToBlock(); - final int typeFrom = event.getBlock().getTypeId(); - final int typeTo = to.getTypeId(); - final boolean canFlow = typeTo == 0 || nonFluidProofBlocks.contains(typeTo); - if (typeFrom == 10 || typeFrom == 11) { + final Material typeTo = to.getType(); + final boolean canFlow = typeTo == Material.AIR || BukkitUtils.getNonFluidProofBlocks().contains(typeTo); + if (typeFrom == Material.LAVA) { + Levelled levelledFrom = (Levelled)blockDataFrom; if (canFlow && wcfg.isLogging(Logging.LAVAFLOW)) { - if (isSurroundedByWater(to) && event.getBlock().getData() <= 2) { - consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), 4, (byte) 0); - } else if (typeTo == 0) { - consumer.queueBlockPlace(new Actor("LavaFlow"), to.getLocation(), 10, (byte) (event.getBlock().getData() + 1)); + if (isSurroundedByWater(to) && levelledFrom.getLevel() <= 2) { + consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), Material.COBBLESTONE.createBlockData()); } else { - consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), 10, (byte) (event.getBlock().getData() + 1)); + Levelled newBlock = (Levelled) blockDataFrom.clone(); + newBlock.setLevel(levelledFrom.getLevel() + 1); + if (typeTo == Material.AIR) { + consumer.queueBlockPlace(new Actor("LavaFlow"), to.getLocation(), newBlock); + } else { + consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), newBlock); + } } - } else if (typeTo == 8 || typeTo == 9) { + } else if (typeTo == Material.WATER) { if (event.getFace() == BlockFace.DOWN) { - consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), 1, (byte) 0); + consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), Material.STONE.createBlockData()); } else { - consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), 4, (byte) 0); + consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), Material.COBBLESTONE.createBlockData()); } } - } else if ((typeFrom == 8 || typeFrom == 9) && wcfg.isLogging(Logging.WATERFLOW)) { - if (typeTo == 0) { - consumer.queueBlockPlace(new Actor("WaterFlow"), to.getLocation(), 8, (byte) (event.getBlock().getData() + 1)); - } else if (nonFluidProofBlocks.contains(typeTo)) { - consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), 8, (byte) (event.getBlock().getData() + 1)); - } else if (typeTo == 10 || typeTo == 11) { - if (to.getData() == 0) { - consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), 49, (byte) 0); + } else if ((typeFrom == Material.WATER) && wcfg.isLogging(Logging.WATERFLOW)) { + Levelled levelledFrom = (Levelled)blockDataFrom; + Levelled newBlock = (Levelled) blockDataFrom.clone(); + newBlock.setLevel(levelledFrom.getLevel() + 1); + if (typeTo == Material.AIR) { + consumer.queueBlockPlace(new Actor("WaterFlow"), to.getLocation(), newBlock); + } else if (BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { + consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), newBlock); + } else if (typeTo == Material.LAVA) { + int toLevel = ((Levelled)to.getBlockData()).getLevel(); + if (toLevel == 0) { + consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), Material.OBSIDIAN.createBlockData()); } else if (event.getFace() == BlockFace.DOWN) { - consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), 1, (byte) 0); + consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), Material.STONE.createBlockData()); } } - if (typeTo == 0 || nonFluidProofBlocks.contains(typeTo)) { + if (typeTo == Material.AIR || BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { for (final BlockFace face : new BlockFace[]{BlockFace.DOWN, BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH}) { final Block lower = to.getRelative(face); - if (lower.getTypeId() == 10 || lower.getTypeId() == 11) { - consumer.queueBlockReplace(new Actor("WaterFlow"), lower.getState(), lower.getData() == 0 ? 49 : 4, (byte) 0); + if (lower.getType() == Material.LAVA) { + int toLevel = ((Levelled)lower.getBlockData()).getLevel(); + if (toLevel == 0) { + consumer.queueBlockReplace(new Actor("WaterFlow"), lower.getState(), Material.OBSIDIAN.createBlockData()); + } else if (event.getFace() == BlockFace.DOWN) { + consumer.queueBlockReplace(new Actor("WaterFlow"), lower.getState(), Material.STONE.createBlockData()); + } } } } @@ -73,8 +89,7 @@ public void onBlockFromTo(BlockFromToEvent event) { private static boolean isSurroundedByWater(Block block) { for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH}) { - final int type = block.getRelative(face).getTypeId(); - if (type == 8 || type == 9) { + if(block.getRelative(face).getType() == Material.WATER) { return true; } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index dd3e350f..8bfc2113 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -7,8 +7,10 @@ import de.diddiz.util.BukkitUtils; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; +import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -30,66 +32,70 @@ public void onPlayerInteract(PlayerInteractEvent event) { if (clicked == null) { return; } - final Material type = clicked.getType(); - final int typeId = type.getId(); - final byte blockData = clicked.getData(); + final BlockData blockData = clicked.getBlockData(); + final Material type = blockData.getMaterial(); final Player player = event.getPlayer(); final Location loc = clicked.getLocation(); switch (type) { - case LEVER: - case WOOD_BUTTON: - case STONE_BUTTON: - if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); - } - break; - case FENCE_GATE: - case WOODEN_DOOR: - case TRAP_DOOR: + case OAK_FENCE_GATE: + case SPRUCE_FENCE_GATE: + case BIRCH_FENCE_GATE: + case JUNGLE_FENCE_GATE: + case ACACIA_FENCE_GATE: + case DARK_OAK_FENCE_GATE: + case OAK_TRAPDOOR: + case SPRUCE_TRAPDOOR: + case BIRCH_TRAPDOOR: + case JUNGLE_TRAPDOOR: + case ACACIA_TRAPDOOR: + case DARK_OAK_TRAPDOOR: if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); } break; - case CAKE_BLOCK: + case CAKE: if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); } break; case NOTE_BLOCK: if (wcfg.isLogging(Logging.NOTEBLOCKINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); } break; - case DIODE_BLOCK_OFF: - case DIODE_BLOCK_ON: + case REPEATER: if (wcfg.isLogging(Logging.DIODEINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); } break; - case REDSTONE_COMPARATOR_OFF: - case REDSTONE_COMPARATOR_ON: + case COMPARATOR: if (wcfg.isLogging(Logging.COMPARATORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); } break; - case WOOD_PLATE: - case STONE_PLATE: - case IRON_PLATE: - case GOLD_PLATE: + case OAK_PRESSURE_PLATE: + case SPRUCE_PRESSURE_PLATE: + case BIRCH_PRESSURE_PLATE: + case JUNGLE_PRESSURE_PLATE: + case ACACIA_PRESSURE_PLATE: + case DARK_OAK_PRESSURE_PLATE: + case STONE_PRESSURE_PLATE: + case HEAVY_WEIGHTED_PRESSURE_PLATE: + case LIGHT_WEIGHTED_PRESSURE_PLATE: if (wcfg.isLogging(Logging.PRESUREPLATEINTERACT) && event.getAction() == Action.PHYSICAL) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); } break; case TRIPWIRE: if (wcfg.isLogging(Logging.TRIPWIREINTERACT) && event.getAction() == Action.PHYSICAL) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); } break; - case SOIL: + case FARMLAND: if (wcfg.isLogging(Logging.CROPTRAMPLE) && event.getAction() == Action.PHYSICAL) { // 3 = Dirt ID - consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, 3, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.DIRT.createBlockData()); // Log the crop on top as being broken Block trampledCrop = clicked.getRelative(BlockFace.UP); if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) { @@ -97,6 +103,17 @@ public void onPlayerInteract(PlayerInteractEvent event) { } } break; + default: + if (Tag.BUTTONS.isTagged(type) || type == Material.LEVER) { + if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + } + } + if (Tag.WOODEN_DOORS.isTagged(type)) { + if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + } + } } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/LockedChestDecayLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/LockedChestDecayLogging.java deleted file mode 100644 index 159d12b3..00000000 --- a/src/main/java/de/diddiz/LogBlock/listeners/LockedChestDecayLogging.java +++ /dev/null @@ -1,26 +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.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.BlockFadeEvent; - -import static de.diddiz.LogBlock.config.Config.isLogging; - -public class LockedChestDecayLogging extends LoggingListener { - public LockedChestDecayLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockFade(BlockFadeEvent event) { - if (isLogging(event.getBlock().getWorld(), Logging.LOCKEDCHESTDECAY)) { - final int type = event.getBlock().getTypeId(); - if (type == 95) { - consumer.queueBlockReplace(new Actor("LockedChestDecay"), event.getBlock().getState(), event.getNewState()); - } - } - } -} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java index 4d808dd4..593dbcf8 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java @@ -17,7 +17,7 @@ public SignChangeLogging(LogBlock lb) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSignChange(SignChangeEvent event) { if (isLogging(event.getBlock().getWorld(), Logging.SIGNTEXT)) { - consumer.queueSignPlace(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getLocation(), event.getBlock().getTypeId(), event.getBlock().getData(), event.getLines()); + consumer.queueSignPlace(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getLocation(), event.getBlock().getBlockData(), event.getLines()); } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/SnowFadeLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/SnowFadeLogging.java index 8acc3eb0..1223893f 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/SnowFadeLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/SnowFadeLogging.java @@ -3,6 +3,8 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; + +import org.bukkit.Material; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockFadeEvent; @@ -17,8 +19,8 @@ public SnowFadeLogging(LogBlock lb) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockFade(BlockFadeEvent event) { if (isLogging(event.getBlock().getWorld(), Logging.SNOWFADE)) { - final int type = event.getBlock().getTypeId(); - if (type == 78 || type == 79) { + final Material type = event.getBlock().getType(); + if (type == Material.SNOW || type == Material.ICE) { consumer.queueBlockReplace(new Actor("SnowFade"), event.getBlock().getState(), event.getNewState()); } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java index d3c4146b..d9abcef4 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java @@ -3,6 +3,8 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; + +import org.bukkit.Material; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockFormEvent; @@ -23,8 +25,8 @@ public SnowFormLogging(LogBlock lb) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockForm(BlockFormEvent event) { if (isLogging(event.getBlock().getWorld(), Logging.SNOWFORM)) { - final int type = event.getNewState().getTypeId(); - if (type == 78 || type == 79) { + final Material type = event.getNewState().getType(); + if (type == Material.SNOW || type == Material.ICE) { consumer.queueBlockReplace(new Actor("SnowForm"), event.getBlock().getState(), event.getNewState()); } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java index 06dcab83..af4073f1 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java @@ -3,6 +3,7 @@ import de.diddiz.LogBlock.*; import de.diddiz.worldedit.RegionContainer; import org.bukkit.ChatColor; +import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; @@ -34,7 +35,7 @@ public ToolListener(LogBlock logblock) { public void onPlayerInteract(PlayerInteractEvent event) { if (event.getMaterial() != null) { final Action action = event.getAction(); - final int type = event.getMaterial().getId(); + final Material type = event.getMaterial(); final Tool tool = toolsByType.get(type); final Player player = event.getPlayer(); if (tool != null && (action == Action.RIGHT_CLICK_BLOCK || action == Action.LEFT_CLICK_BLOCK) && logblock.hasPermission(player, "logblock.tools." + tool.name)) { @@ -52,12 +53,12 @@ public void onPlayerInteract(PlayerInteractEvent event) { params.sel = null; if (behavior == ToolBehavior.BLOCK) { params.setLocation(block.getRelative(event.getBlockFace()).getLocation()); - } else if ((block.getTypeId() != 54 && block.getTypeId() != 146) || tool.params.radius != 0) { + } else if ((block.getType() != Material.CHEST && block.getType() != Material.TRAPPED_CHEST) || tool.params.radius != 0) { params.setLocation(block.getLocation()); } else { if (logblock.getServer().getPluginManager().isPluginEnabled("WorldEdit")) { for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) { - if (block.getRelative(face).getTypeId() == block.getTypeId()) { + if (block.getRelative(face).getType() == block.getType()) { params.setSelection(RegionContainer.fromCorners(event.getPlayer().getWorld(), block.getLocation(), block.getRelative(face).getLocation())); } @@ -113,7 +114,7 @@ public void onPlayerDropItem(PlayerDropItemEvent event) { for (final Entry entry : session.toolData.entrySet()) { final Tool tool = entry.getKey(); final ToolData toolData = entry.getValue(); - final int item = event.getItemDrop().getItemStack().getTypeId(); + final Material item = event.getItemDrop().getItemStack().getType(); if (item == tool.item && toolData.enabled && !tool.canDrop) { player.sendMessage(ChatColor.RED + "You cannot drop this tool."); event.setCancelled(true); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java index fa74c934..3f8c9a8e 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java @@ -18,7 +18,7 @@ public WitherLogging(LogBlock 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.getTo().getId(), event.getData()); // Wither walked through a block. + consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), event.getBlock().getState(), event.getBlockData()); // Wither walked through a block. } } } diff --git a/src/main/java/de/diddiz/util/Block.java b/src/main/java/de/diddiz/util/Block.java deleted file mode 100644 index e59fce71..00000000 --- a/src/main/java/de/diddiz/util/Block.java +++ /dev/null @@ -1,34 +0,0 @@ -package de.diddiz.util; - -import java.util.List; - -public class Block { - private int block; - private int data; - - /** - * @param block The id of the block - * @param data The data for the block, -1 for any data - */ - public Block(int block, int data) { - this.block = block; - this.data = data; - } - - public int getBlock() { - return this.block; - } - - public int getData() { - return this.data; - } - - public static boolean inList(List types, int blockID) { - for (Block block : types) { - if (block.getBlock() == blockID) { - return true; - } - } - return false; - } -} diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 4fedab3e..6a43c9a8 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -4,6 +4,10 @@ import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.DoubleChest; +import org.bukkit.block.data.Bisected; +import org.bukkit.block.data.Bisected.Half; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.Stairs; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -15,21 +19,49 @@ import java.io.File; import java.util.*; -import static de.diddiz.util.MaterialName.materialName; - public class BukkitUtils { private static final Set> blockEquivalents; private static final Set relativeBreakable; private static final Set relativeTopBreakable; - private static final Set relativeTopFallables; private static final Set fallingEntityKillers; private static final Set cropBlocks; private static final Set containerBlocks; - - private static final Map projectileItems; + + private static final Set singleBlockPlants; + private static final Set doublePlants; + + private static final Set nonFluidProofBlocks; + + private static final Map projectileItems; static { + singleBlockPlants = EnumSet.noneOf(Material.class); + singleBlockPlants.add(Material.GRASS); + singleBlockPlants.add(Material.FERN); + singleBlockPlants.add(Material.DEAD_BUSH); + singleBlockPlants.add(Material.DANDELION); + singleBlockPlants.add(Material.POPPY); + singleBlockPlants.add(Material.BLUE_ORCHID); + singleBlockPlants.add(Material.ALLIUM); + singleBlockPlants.add(Material.AZURE_BLUET); + singleBlockPlants.add(Material.ORANGE_TULIP); + singleBlockPlants.add(Material.WHITE_TULIP); + singleBlockPlants.add(Material.PINK_TULIP); + singleBlockPlants.add(Material.RED_TULIP); + singleBlockPlants.add(Material.OXEYE_DAISY); + singleBlockPlants.add(Material.BROWN_MUSHROOM); + singleBlockPlants.add(Material.RED_MUSHROOM); + + doublePlants = EnumSet.noneOf(Material.class); + doublePlants.add(Material.TALL_GRASS); + doublePlants.add(Material.LARGE_FERN); + doublePlants.add(Material.TALL_SEAGRASS); + doublePlants.add(Material.ROSE_BUSH); + doublePlants.add(Material.LILAC); + doublePlants.add(Material.SUNFLOWER); + doublePlants.add(Material.PEONY); + blockEquivalents = new HashSet>(7); blockEquivalents.add(new HashSet(Arrays.asList(2, 3, 60))); blockEquivalents.add(new HashSet(Arrays.asList(8, 9, 79))); @@ -40,108 +72,93 @@ public class BukkitUtils { blockEquivalents.add(new HashSet(Arrays.asList(93, 94))); // Blocks that break when they are attached to a block - relativeBreakable = new HashSet(11); + relativeBreakable = EnumSet.noneOf(Material.class); relativeBreakable.add(Material.WALL_SIGN); relativeBreakable.add(Material.LADDER); relativeBreakable.add(Material.STONE_BUTTON); - relativeBreakable.add(Material.WOOD_BUTTON); - relativeBreakable.add(Material.REDSTONE_TORCH_ON); - relativeBreakable.add(Material.REDSTONE_TORCH_OFF); + relativeBreakable.addAll(Tag.WOODEN_BUTTONS.getValues()); + relativeBreakable.add(Material.REDSTONE_WALL_TORCH); relativeBreakable.add(Material.LEVER); - relativeBreakable.add(Material.TORCH); - relativeBreakable.add(Material.TRAP_DOOR); + relativeBreakable.add(Material.WALL_TORCH); relativeBreakable.add(Material.TRIPWIRE_HOOK); relativeBreakable.add(Material.COCOA); // Blocks that break when they are on top of a block - relativeTopBreakable = new HashSet(33); - relativeTopBreakable.add(Material.SAPLING); - relativeTopBreakable.add(Material.LONG_GRASS); - relativeTopBreakable.add(Material.DEAD_BUSH); - relativeTopBreakable.add(Material.YELLOW_FLOWER); - relativeTopBreakable.add(Material.RED_ROSE); - relativeTopBreakable.add(Material.BROWN_MUSHROOM); - relativeTopBreakable.add(Material.RED_MUSHROOM); - relativeTopBreakable.add(Material.CROPS); + relativeTopBreakable = EnumSet.noneOf(Material.class); + relativeTopBreakable.addAll(Tag.SAPLINGS.getValues()); + relativeTopBreakable.addAll(singleBlockPlants); + relativeTopBreakable.add(Material.WHEAT); relativeTopBreakable.add(Material.POTATO); relativeTopBreakable.add(Material.CARROT); - relativeTopBreakable.add(Material.WATER_LILY); + relativeTopBreakable.add(Material.LILY_PAD); relativeTopBreakable.add(Material.CACTUS); - relativeTopBreakable.add(Material.SUGAR_CANE_BLOCK); + relativeTopBreakable.add(Material.SUGAR_CANE); relativeTopBreakable.add(Material.FLOWER_POT); relativeTopBreakable.add(Material.POWERED_RAIL); relativeTopBreakable.add(Material.DETECTOR_RAIL); relativeTopBreakable.add(Material.ACTIVATOR_RAIL); - relativeTopBreakable.add(Material.RAILS); + relativeTopBreakable.add(Material.RAIL); relativeTopBreakable.add(Material.REDSTONE_WIRE); - relativeTopBreakable.add(Material.SIGN_POST); - relativeTopBreakable.add(Material.STONE_PLATE); - relativeTopBreakable.add(Material.WOOD_PLATE); - relativeTopBreakable.add(Material.IRON_PLATE); - relativeTopBreakable.add(Material.GOLD_PLATE); + relativeTopBreakable.add(Material.SIGN); + relativeTopBreakable.add(Material.STONE_PRESSURE_PLATE); + relativeTopBreakable.addAll(Tag.WOODEN_PRESSURE_PLATES.getValues()); + relativeTopBreakable.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); + relativeTopBreakable.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); relativeTopBreakable.add(Material.SNOW); - relativeTopBreakable.add(Material.DIODE_BLOCK_ON); - relativeTopBreakable.add(Material.DIODE_BLOCK_OFF); - relativeTopBreakable.add(Material.REDSTONE_COMPARATOR_ON); - relativeTopBreakable.add(Material.REDSTONE_COMPARATOR_OFF); - relativeTopBreakable.add(Material.WOODEN_DOOR); - relativeTopBreakable.add(Material.IRON_DOOR_BLOCK); - relativeTopBreakable.add(Material.CARPET); - relativeTopBreakable.add(Material.DOUBLE_PLANT); - - // Blocks that fall - relativeTopFallables = new HashSet(4); - relativeTopFallables.add(Material.SAND); - relativeTopFallables.add(Material.GRAVEL); - relativeTopFallables.add(Material.DRAGON_EGG); - relativeTopFallables.add(Material.ANVIL); - relativeTopFallables.add(Material.CONCRETE_POWDER); + relativeTopBreakable.add(Material.REPEATER); + relativeTopBreakable.add(Material.COMPARATOR); + relativeTopBreakable.add(Material.TORCH); + relativeTopBreakable.add(Material.WALL_TORCH); + relativeTopBreakable.add(Material.REDSTONE_TORCH); + relativeTopBreakable.add(Material.REDSTONE_WALL_TORCH); + relativeTopBreakable.addAll(Tag.WOODEN_DOORS.getValues()); + relativeTopBreakable.add(Material.IRON_DOOR); + relativeTopBreakable.addAll(Tag.CARPETS.getValues()); + relativeTopBreakable.addAll(doublePlants); // Blocks that break falling entities - fallingEntityKillers = new HashSet(32); - fallingEntityKillers.add(Material.SIGN_POST); + fallingEntityKillers = EnumSet.noneOf(Material.class); + fallingEntityKillers.add(Material.SIGN); fallingEntityKillers.add(Material.WALL_SIGN); - fallingEntityKillers.add(Material.STONE_PLATE); - fallingEntityKillers.add(Material.WOOD_PLATE); - fallingEntityKillers.add(Material.IRON_PLATE); - fallingEntityKillers.add(Material.GOLD_PLATE); - fallingEntityKillers.add(Material.SAPLING); - fallingEntityKillers.add(Material.YELLOW_FLOWER); - fallingEntityKillers.add(Material.RED_ROSE); - fallingEntityKillers.add(Material.CROPS); + fallingEntityKillers.addAll(Tag.WOODEN_PRESSURE_PLATES.getValues()); + fallingEntityKillers.add(Material.STONE_PRESSURE_PLATE); + fallingEntityKillers.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); + fallingEntityKillers.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); + fallingEntityKillers.addAll(Tag.SAPLINGS.getValues()); + fallingEntityKillers.addAll(singleBlockPlants); + fallingEntityKillers.add(Material.WHEAT); fallingEntityKillers.add(Material.CARROT); fallingEntityKillers.add(Material.POTATO); - fallingEntityKillers.add(Material.RED_MUSHROOM); - fallingEntityKillers.add(Material.BROWN_MUSHROOM); - fallingEntityKillers.add(Material.STEP); - fallingEntityKillers.add(Material.WOOD_STEP); + fallingEntityKillers.add(Material.BEETROOT); + fallingEntityKillers.add(Material.NETHER_WART); + fallingEntityKillers.addAll(Tag.SLABS.getValues()); fallingEntityKillers.add(Material.TORCH); + fallingEntityKillers.add(Material.WALL_TORCH); fallingEntityKillers.add(Material.FLOWER_POT); fallingEntityKillers.add(Material.POWERED_RAIL); fallingEntityKillers.add(Material.DETECTOR_RAIL); fallingEntityKillers.add(Material.ACTIVATOR_RAIL); - fallingEntityKillers.add(Material.RAILS); + fallingEntityKillers.add(Material.RAIL); fallingEntityKillers.add(Material.LEVER); fallingEntityKillers.add(Material.REDSTONE_WIRE); - fallingEntityKillers.add(Material.REDSTONE_TORCH_ON); - fallingEntityKillers.add(Material.REDSTONE_TORCH_OFF); - fallingEntityKillers.add(Material.DIODE_BLOCK_ON); - fallingEntityKillers.add(Material.DIODE_BLOCK_OFF); - fallingEntityKillers.add(Material.REDSTONE_COMPARATOR_ON); - fallingEntityKillers.add(Material.REDSTONE_COMPARATOR_OFF); + fallingEntityKillers.add(Material.REDSTONE_TORCH); + fallingEntityKillers.add(Material.REDSTONE_WALL_TORCH); + fallingEntityKillers.add(Material.REPEATER); + fallingEntityKillers.add(Material.COMPARATOR); fallingEntityKillers.add(Material.DAYLIGHT_DETECTOR); - fallingEntityKillers.add(Material.CARPET); + fallingEntityKillers.addAll(Tag.CARPETS.getValues()); // Crop Blocks - cropBlocks = new HashSet(5); - cropBlocks.add(Material.CROPS); + cropBlocks = EnumSet.noneOf(Material.class); + cropBlocks.add(Material.WHEAT); cropBlocks.add(Material.MELON_STEM); cropBlocks.add(Material.PUMPKIN_STEM); cropBlocks.add(Material.CARROT); cropBlocks.add(Material.POTATO); + cropBlocks.add(Material.BEETROOT); // Container Blocks - containerBlocks = new HashSet(6); + containerBlocks = EnumSet.noneOf(Material.class); containerBlocks.add(Material.CHEST); containerBlocks.add(Material.TRAPPED_CHEST); containerBlocks.add(Material.DISPENSER); @@ -149,11 +166,10 @@ public class BukkitUtils { containerBlocks.add(Material.HOPPER); containerBlocks.add(Material.BREWING_STAND); containerBlocks.add(Material.FURNACE); - containerBlocks.add(Material.BURNING_FURNACE); containerBlocks.add(Material.BEACON); containerBlocks.add(Material.BLACK_SHULKER_BOX); containerBlocks.add(Material.BLUE_SHULKER_BOX); - containerBlocks.add(Material.SILVER_SHULKER_BOX); + containerBlocks.add(Material.LIGHT_GRAY_SHULKER_BOX); containerBlocks.add(Material.BROWN_SHULKER_BOX); containerBlocks.add(Material.CYAN_SHULKER_BOX); containerBlocks.add(Material.GRAY_SHULKER_BOX); @@ -171,17 +187,49 @@ public class BukkitUtils { // containerBlocks.add(Material.ENDER_CHEST); // It doesn't seem like you could injure people with some of these, but they exist, so.... - projectileItems = new EnumMap(EntityType.class); - projectileItems.put(EntityType.ARROW, 262); - projectileItems.put(EntityType.EGG, 344); - projectileItems.put(EntityType.ENDER_PEARL, 368); - projectileItems.put(EntityType.SMALL_FIREBALL, 385); // Fire charge - projectileItems.put(EntityType.FIREBALL, 385); // Fire charge - projectileItems.put(EntityType.FISHING_HOOK, 346); - projectileItems.put(EntityType.SNOWBALL, 332); - projectileItems.put(EntityType.SPLASH_POTION, 373); - projectileItems.put(EntityType.THROWN_EXP_BOTTLE, 384); - projectileItems.put(EntityType.WITHER_SKULL, 397); + projectileItems = new EnumMap(EntityType.class); + projectileItems.put(EntityType.ARROW, Material.ARROW); + projectileItems.put(EntityType.EGG, Material.EGG); + 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_HOOK, Material.FISHING_ROD); + projectileItems.put(EntityType.SNOWBALL, Material.SNOWBALL); + projectileItems.put(EntityType.SPLASH_POTION, Material.SPLASH_POTION); + projectileItems.put(EntityType.THROWN_EXP_BOTTLE, Material.EXPERIENCE_BOTTLE); + projectileItems.put(EntityType.WITHER_SKULL, Material.WITHER_SKELETON_SKULL); + + nonFluidProofBlocks = EnumSet.noneOf(Material.class); + nonFluidProofBlocks.addAll(singleBlockPlants); + nonFluidProofBlocks.addAll(doublePlants); + nonFluidProofBlocks.add(Material.REDSTONE_WALL_TORCH); + nonFluidProofBlocks.add(Material.LEVER); + nonFluidProofBlocks.add(Material.WALL_TORCH); + nonFluidProofBlocks.add(Material.TRIPWIRE_HOOK); + nonFluidProofBlocks.add(Material.COCOA); + nonFluidProofBlocks.addAll(Tag.WOODEN_PRESSURE_PLATES.getValues()); + nonFluidProofBlocks.add(Material.STONE_PRESSURE_PLATE); + nonFluidProofBlocks.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); + nonFluidProofBlocks.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); + nonFluidProofBlocks.addAll(Tag.SAPLINGS.getValues()); + nonFluidProofBlocks.add(Material.WHEAT); + nonFluidProofBlocks.add(Material.CARROT); + nonFluidProofBlocks.add(Material.POTATO); + nonFluidProofBlocks.add(Material.BEETROOT); + nonFluidProofBlocks.add(Material.NETHER_WART); + nonFluidProofBlocks.add(Material.TORCH); + nonFluidProofBlocks.add(Material.FLOWER_POT); + nonFluidProofBlocks.add(Material.POWERED_RAIL); + nonFluidProofBlocks.add(Material.DETECTOR_RAIL); + nonFluidProofBlocks.add(Material.ACTIVATOR_RAIL); + nonFluidProofBlocks.add(Material.RAIL); + nonFluidProofBlocks.add(Material.LEVER); + nonFluidProofBlocks.add(Material.REDSTONE_WIRE); + nonFluidProofBlocks.add(Material.REDSTONE_TORCH); + nonFluidProofBlocks.add(Material.REPEATER); + nonFluidProofBlocks.add(Material.COMPARATOR); + nonFluidProofBlocks.add(Material.DAYLIGHT_DETECTOR); + nonFluidProofBlocks.addAll(Tag.CARPETS.getValues()); } @@ -206,26 +254,20 @@ public static List getBlocksNearby(org.bukkit.block.Block block, Set 5; - case IRON_DOOR_BLOCK: - case WOODEN_DOOR: - return data == 8 || data == 9; - default: - return false; + public static boolean isTop(BlockData data) { + if (data instanceof Bisected && !(data instanceof Stairs)) { + return ((Bisected) data).getHalf() == Half.TOP; } + return false; } - public static int getInventoryHolderType(InventoryHolder holder) { + public static Material getInventoryHolderType(InventoryHolder holder) { if (holder instanceof DoubleChest) { return getInventoryHolderType(((DoubleChest) holder).getLeftSide()); } else if (holder instanceof BlockState) { - return ((BlockState) holder).getTypeId(); + return ((BlockState) holder).getType(); } else { - return -1; + return null; } } @@ -243,6 +285,16 @@ public static ItemStack[] compareInventories(ItemStack[] items1, ItemStack[] ite final ItemStackComparator comperator = new ItemStackComparator(); final ArrayList diff = new ArrayList(); final int l1 = items1.length, l2 = items2.length; + for (int i = 0; i < l1; i++) { + if (items1[i] != null) { + items1[i] = new ItemStack(items1[i]); + } + } + for (int i = 0; i < l2; i++) { + if (items2[i] != null) { + items2[i] = new ItemStack(items2[i]); + } + } int c1 = 0, c2 = 0; while (c1 < l1 || c2 < l2) { if (c1 >= l1) { @@ -281,18 +333,16 @@ public static ItemStack[] compressInventory(ItemStack[] items) { final ArrayList compressed = new ArrayList(); for (final ItemStack item : items) { if (item != null) { - final int type = item.getTypeId(); - final short data = rawData(item); boolean found = false; for (final ItemStack item2 : compressed) { - if (type == item2.getTypeId() && data == rawData(item2)) { + if (item2.isSimilar(item)) { item2.setAmount(item2.getAmount() + item.getAmount()); found = true; break; } } if (!found) { - compressed.add(new ItemStack(type, item.getAmount(), data)); + compressed.add(item.clone()); } } } @@ -328,13 +378,13 @@ public static Set getRelativeTopBreakabls() { return relativeTopBreakable; } - public static Set getRelativeTopFallables() { - return relativeTopFallables; - } - public static Set getFallingEntityKillers() { return fallingEntityKillers; } + + public static Set getNonFluidProofBlocks() { + return nonFluidProofBlocks; + } public static Set getCropBlocks() { return cropBlocks; @@ -354,18 +404,18 @@ public static String entityName(Entity entity) { return entity.getClass().getSimpleName().substring(5); } - public static void giveTool(Player player, int type) { + public static void giveTool(Player player, Material type) { final Inventory inv = player.getInventory(); if (inv.contains(type)) { - player.sendMessage(ChatColor.RED + "You have already a " + materialName(type)); + player.sendMessage(ChatColor.RED + "You have already a " + type.name()); } else { final int free = inv.firstEmpty(); if (free >= 0) { - if (player.getItemInHand() != null && player.getItemInHand().getTypeId() != 0) { - inv.setItem(free, player.getItemInHand()); + if (player.getInventory().getItemInMainHand() != null && player.getInventory().getItemInMainHand().getType() != Material.AIR) { + inv.setItem(free, player.getInventory().getItemInMainHand()); } - player.setItemInHand(new ItemStack(type, 1)); - player.sendMessage(ChatColor.GREEN + "Here's your " + materialName(type)); + player.getInventory().setItemInMainHand(new ItemStack(type)); + player.sendMessage(ChatColor.GREEN + "Here's your " + type.name()); } else { player.sendMessage(ChatColor.RED + "You have no empty slot in your inventory"); } @@ -384,22 +434,21 @@ public static int saveSpawnHeight(Location loc) { } final int x = loc.getBlockX(), z = loc.getBlockZ(); int y = loc.getBlockY(); - boolean lower = world.getBlockTypeIdAt(x, y, z) == 0, upper = world.getBlockTypeIdAt(x, y + 1, z) == 0; + boolean lower = world.getBlockAt(x, y, z).isEmpty(), upper = world.getBlockAt(x, y + 1, z).isEmpty(); while ((!lower || !upper) && y != 127) { lower = upper; - upper = world.getBlockTypeIdAt(x, ++y, z) == 0; + upper = world.getBlockAt(x, ++y, z).isEmpty(); } - while (world.getBlockTypeIdAt(x, y - 1, z) == 0 && y != 0) { + while (world.getBlockAt(x, y - 1, z).isEmpty() && y != 0) { y--; } return y; } - public static int modifyContainer(BlockState b, ItemStack item) { + public static int modifyContainer(BlockState b, ItemStack item, boolean remove) { if (b instanceof InventoryHolder) { final Inventory inv = ((InventoryHolder) b).getInventory(); - if (item.getAmount() < 0) { - item.setAmount(-item.getAmount()); + if (remove) { final ItemStack tmp = inv.removeItem(item).get(0); return tmp != null ? tmp.getAmount() : 0; } else if (item.getAmount() > 0) { @@ -416,9 +465,9 @@ public static boolean canFall(World world, int x, int y, int z) { // Air if (mat == Material.AIR) { return true; - } else if (mat == Material.WATER || mat == Material.STATIONARY_WATER || mat == Material.LAVA || mat == Material.STATIONARY_LAVA) { // Fluids + } else if (mat == Material.WATER || mat == Material.LAVA) { // Fluids return true; - } else if (getFallingEntityKillers().contains(mat) || mat == Material.FIRE || mat == Material.VINE || mat == Material.LONG_GRASS || mat == Material.DEAD_BUSH) { // Misc. + } else if (getFallingEntityKillers().contains(mat) || mat == Material.FIRE || mat == Material.VINE || doublePlants.contains(mat) || mat == Material.DEAD_BUSH) { // Misc. return true; } return false; @@ -427,26 +476,15 @@ public static boolean canFall(World world, int x, int y, int z) { public static class ItemStackComparator implements Comparator { @Override public int compare(ItemStack a, ItemStack b) { - final int aType = a.getTypeId(), bType = b.getTypeId(); - if (aType < bType) { - return -1; - } - if (aType > bType) { - return 1; - } - final short aData = rawData(a), bData = rawData(b); - if (aData < bData) { - return -1; - } - if (aData > bData) { - return 1; - } - return 0; + return a.getType().name().compareTo(b.getType().name()); } } - public static int itemIDfromProjectileEntity(Entity e) { - Integer i = projectileItems.get(e.getType()); - return (i == null) ? 0 : i; + public static Material itemIDfromProjectileEntity(Entity e) { + return projectileItems.get(e.getType()); + } + + public static boolean isDoublePlant(Material m) { + return doublePlants.contains(m); } } diff --git a/src/main/java/de/diddiz/util/ComparableVersion.java b/src/main/java/de/diddiz/util/ComparableVersion.java index 46ac027c..406b0098 100644 --- a/src/main/java/de/diddiz/util/ComparableVersion.java +++ b/src/main/java/de/diddiz/util/ComparableVersion.java @@ -257,6 +257,8 @@ private static class ListItem extends ArrayList implements Item { + private static final long serialVersionUID = 5914575811857700009L; + public int getType() { return LIST_ITEM; diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index 51a0e448..6a58d92d 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -6,11 +6,12 @@ import de.diddiz.LogBlock.config.WorldConfig; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockState; import org.bukkit.block.Sign; -import org.bukkit.material.*; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Directional; import java.util.List; @@ -30,7 +31,7 @@ public static void smartLogFallables(Consumer consumer, Actor actor, Block origi Block checkBlock = origin.getRelative(BlockFace.UP); int up = 0; final int highestBlock = checkBlock.getWorld().getHighestBlockYAt(checkBlock.getLocation()); - while (BukkitUtils.getRelativeTopFallables().contains(checkBlock.getType())) { + while (checkBlock.getType().hasGravity()) { // Record this block as falling consumer.queueBlockBreak(actor, checkBlock.getState()); @@ -49,10 +50,10 @@ public static void smartLogFallables(Consumer consumer, Actor actor, Block origi // Run this check to avoid false positives if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) { finalLoc.add(0, up, 0); // Add this here after checking for block breakers - if (finalLoc.getBlock().getType() == Material.AIR || BukkitUtils.getRelativeTopFallables().contains(finalLoc.getBlock().getType())) { - consumer.queueBlockPlace(actor, finalLoc, checkBlock.getTypeId(), checkBlock.getData()); + if (finalLoc.getBlock().getType() == Material.AIR) { + consumer.queueBlockPlace(actor, finalLoc, checkBlock.getBlockData()); } else { - consumer.queueBlockReplace(actor, finalLoc, finalLoc.getBlock().getTypeId(), finalLoc.getBlock().getData(), checkBlock.getTypeId(), checkBlock.getData()); + consumer.queueBlockReplace(actor, finalLoc, finalLoc.getBlock().getBlockData(), checkBlock.getBlockData()); } up++; } @@ -73,28 +74,28 @@ public static void smartLogBlockBreak(Consumer consumer, Actor actor, Block orig Block checkBlock = origin.getRelative(BlockFace.UP); if (BukkitUtils.getRelativeTopBreakabls().contains(checkBlock.getType())) { - if (wcfg.isLogging(Logging.SIGNTEXT) && checkBlock.getType() == Material.SIGN_POST) { + if (wcfg.isLogging(Logging.SIGNTEXT) && checkBlock.getType() == Material.SIGN) { consumer.queueSignBreak(actor, (Sign) checkBlock.getState()); - } else if (checkBlock.getType() == Material.IRON_DOOR_BLOCK || checkBlock.getType() == Material.WOODEN_DOOR) { + } else if (checkBlock.getType() == Material.IRON_DOOR || Tag.WOODEN_DOORS.isTagged(checkBlock.getType())) { Block doorBlock = checkBlock; // If the doorBlock is the top half a door the player simply punched a door // this will be handled later. - if (!BukkitUtils.isTop(doorBlock.getType(), doorBlock.getData())) { + if (!BukkitUtils.isTop(doorBlock.getBlockData())) { doorBlock = doorBlock.getRelative(BlockFace.UP); // Fall back check just in case the top half wasn't a door - if (doorBlock.getType() == Material.IRON_DOOR_BLOCK || doorBlock.getType() == Material.WOODEN_DOOR) { + if (doorBlock.getType() == Material.IRON_DOOR || Tag.WOODEN_DOORS.isTagged(doorBlock.getType())) { consumer.queueBlockBreak(actor, doorBlock.getState()); } consumer.queueBlockBreak(actor, checkBlock.getState()); } - } else if (checkBlock.getType() == Material.DOUBLE_PLANT) { + } else if (BukkitUtils.isDoublePlant(checkBlock.getType())) { Block plantBlock = checkBlock; // If the plantBlock is the top half of a double plant the player simply // punched the plant this will be handled later. - if (!BukkitUtils.isTop(plantBlock.getType(), plantBlock.getData())) { + if (!BukkitUtils.isTop(plantBlock.getBlockData())) { plantBlock = plantBlock.getRelative(BlockFace.UP); // Fall back check just in case the top half wasn't a plant - if (plantBlock.getType() == Material.DOUBLE_PLANT) { + if (BukkitUtils.isDoublePlant(plantBlock.getType())) { consumer.queueBlockBreak(actor, plantBlock.getState()); } consumer.queueBlockBreak(actor, checkBlock.getState()); @@ -107,93 +108,45 @@ public static void smartLogBlockBreak(Consumer consumer, Actor actor, Block orig List relativeBreakables = BukkitUtils.getBlocksNearby(origin, BukkitUtils.getRelativeBreakables()); if (relativeBreakables.size() != 0) { for (Location location : relativeBreakables) { - final Material blockType = location.getBlock().getType(); - final BlockState blockState = location.getBlock().getState(); - final MaterialData data = blockState.getData(); - switch (blockType) { - case REDSTONE_TORCH_ON: - case REDSTONE_TORCH_OFF: - if (blockState.getBlock().getRelative(((RedstoneTorch) data).getAttachedFace()).equals(origin)) { - consumer.queueBlockBreak(actor, blockState); + Block block = location.getBlock(); + BlockData blockData = block.getBlockData(); + if (blockData instanceof Directional) { + if (block.getRelative(((Directional) blockData).getFacing()).equals(origin)) { + if (wcfg.isLogging(Logging.SIGNTEXT) && block.getType() == Material.WALL_SIGN) { + consumer.queueSignBreak(actor, (Sign) block.getState()); + } else { + consumer.queueBlockBreak(actor, block.getState()); } - break; - case TORCH: - if (blockState.getBlock().getRelative(((Torch) data).getAttachedFace()).equals(origin)) { - consumer.queueBlockBreak(actor, blockState); - } - break; - case COCOA: - if (blockState.getBlock().getRelative(((CocoaPlant) data).getAttachedFace().getOppositeFace()).equals(origin)) { - consumer.queueBlockBreak(actor, blockState); - } - break; - case LADDER: - if (blockState.getBlock().getRelative(((Ladder) data).getAttachedFace()).equals(origin)) { - consumer.queueBlockBreak(actor, blockState); - } - break; - case LEVER: - if (blockState.getBlock().getRelative(((Lever) data).getAttachedFace()).equals(origin)) { - consumer.queueBlockBreak(actor, blockState); - } - break; - case TRIPWIRE_HOOK: - if (blockState.getBlock().getRelative(((TripwireHook) data).getAttachedFace()).equals(origin)) { - consumer.queueBlockBreak(actor, blockState); - } - break; - case WOOD_BUTTON: - case STONE_BUTTON: - if (blockState.getBlock().getRelative(((Button) data).getAttachedFace()).equals(origin)) { - consumer.queueBlockBreak(actor, blockState); - } - break; - case WALL_SIGN: - if (blockState.getBlock().getRelative(((org.bukkit.material.Sign) data).getAttachedFace()).equals(origin)) { - if (wcfg.isLogging(Logging.SIGNTEXT)) { - consumer.queueSignBreak(actor, (Sign) blockState); - } else { - consumer.queueBlockBreak(actor, blockState); - } - } - break; - case TRAP_DOOR: - if (blockState.getBlock().getRelative(((TrapDoor) data).getAttachedFace()).equals(origin)) { - consumer.queueBlockBreak(actor, blockState); - } - break; - default: - consumer.queueBlockBreak(actor, blockState); - break; + } } } } // Special door check - if (origin.getType() == Material.IRON_DOOR_BLOCK || origin.getType() == Material.WOODEN_DOOR) { + if (origin.getType() == Material.IRON_DOOR || Tag.WOODEN_DOORS.isTagged(origin.getType())) { Block doorBlock = origin; // Up or down? - if (!BukkitUtils.isTop(doorBlock.getType(), doorBlock.getData())) { + if (!BukkitUtils.isTop(doorBlock.getBlockData())) { doorBlock = doorBlock.getRelative(BlockFace.UP); } else { doorBlock = doorBlock.getRelative(BlockFace.DOWN); } - if (doorBlock.getType() == Material.IRON_DOOR_BLOCK || doorBlock.getType() == Material.WOODEN_DOOR) { + if (doorBlock.getType() == Material.IRON_DOOR || Tag.WOODEN_DOORS.isTagged(doorBlock.getType())) { consumer.queueBlockBreak(actor, doorBlock.getState()); } - } else if (origin.getType() == Material.DOUBLE_PLANT) { // Special double plant check + } else if (BukkitUtils.isDoublePlant(origin.getType())) { // Special double plant check Block plantBlock = origin; // Up or down? - if (!BukkitUtils.isTop(origin.getType(), origin.getData())) { + if (!BukkitUtils.isTop(origin.getBlockData())) { plantBlock = plantBlock.getRelative(BlockFace.UP); } else { plantBlock = plantBlock.getRelative(BlockFace.DOWN); } - if (plantBlock.getType() == Material.DOUBLE_PLANT) { + if (BukkitUtils.isDoublePlant(plantBlock.getType())) { consumer.queueBlockBreak(actor, plantBlock.getState()); } } diff --git a/src/main/java/de/diddiz/util/MaterialName.java b/src/main/java/de/diddiz/util/MaterialName.java deleted file mode 100644 index 9d6fe22d..00000000 --- a/src/main/java/de/diddiz/util/MaterialName.java +++ /dev/null @@ -1,280 +0,0 @@ -package de.diddiz.util; - -import de.diddiz.LogBlock.LogBlock; -import org.bukkit.Material; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.material.MaterialData; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Level; - -import static de.diddiz.util.Utils.isInt; -import static de.diddiz.util.Utils.isShort; -import static org.bukkit.Bukkit.getLogger; - -public class MaterialName { - private static final String[] COLORS = {"white", "orange", "magenta", "light blue", "yellow", "lime", "pink", "gray", "silver", "cyan", "purple", "blue", "brown", "green", "red", "black"}; - private static final Map materialNames = new HashMap(); - private static final Map> materialDataNames = new HashMap>(); - private static final Map nameTypes = new HashMap(); - - static { - // Add all known materials - for (final Material mat : Material.values()) { - materialNames.put(mat.getId(), mat.toString().replace('_', ' ').toLowerCase()); - } - // Load config - final File file = new File(LogBlock.getInstance().getDataFolder(), "materials.yml"); - final YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file); - if (cfg.getKeys(false).isEmpty()) { - // Generate defaults - cfg.options().header("Add block or item names you want to be overridden or also names for custom blocks"); - cfg.set("1.1", "granite"); - cfg.set("1.2", "polished granite"); - cfg.set("1.3", "diorite"); - cfg.set("1.4", "polished diorite"); - cfg.set("1.5", "andesite"); - cfg.set("1.6", "polished andesite"); - cfg.set("5.0", "oak wood"); - cfg.set("5.1", "spruce wood"); - cfg.set("5.2", "birch wood"); - cfg.set("5.3", "jungle wood"); - cfg.set("5.4", "acacia wood"); - cfg.set("5.5", "dark oak wood"); - cfg.set("3.1", "coarse dirt"); - cfg.set("3.2", "podzol"); - cfg.set("6.1", "redwood sapling"); - cfg.set("6.2", "birch sapling"); - cfg.set("6.3", "jungle sapling"); - cfg.set("6.4", "acacia sapling"); - cfg.set("6.5", "dark oak sapling"); - cfg.set("9", "water"); - cfg.set("11", "lava"); - cfg.set("12.1", "red sand"); - cfg.set("17.0", "oak log"); - cfg.set("17.1", "spruce log"); - cfg.set("17.2", "birch log"); - cfg.set("17.3", "jungle log"); - cfg.set("17.4", "oak log"); - cfg.set("17.5", "spruce log"); - cfg.set("17.6", "birch log"); - cfg.set("17.7", "jungle log"); - cfg.set("17.8", "oak log"); - cfg.set("17.9", "spruce log"); - cfg.set("17.10", "birch log"); - cfg.set("17.11", "jungle log"); - cfg.set("17.12", "oak log"); - cfg.set("17.13", "spruce log"); - cfg.set("17.14", "birch log"); - cfg.set("17.15", "jungle log"); - cfg.set("18.1", "spruce leaves"); - cfg.set("18.2", "birch leaves"); - cfg.set("18.3", "jungle leaves"); - cfg.set("18.4", "oak leaves"); - cfg.set("18.5", "spruce leaves"); - cfg.set("18.6", "birch leaves"); - cfg.set("18.7", "jungle leaves"); - cfg.set("18.8", "oak leaves"); - cfg.set("18.9", "spruce leaves"); - cfg.set("18.10", "birch leaves"); - cfg.set("18.11", "jungle leaves"); - cfg.set("18.12", "oak leaves"); - cfg.set("18.13", "spruce leaves"); - cfg.set("18.14", "birch leaves"); - cfg.set("18.15", "jungle leaves"); - cfg.set("19.1", "wet sponge"); - cfg.set("37.0", "dandelion"); - cfg.set("38.0", "poppy"); - cfg.set("38.1", "blue orchid"); - cfg.set("38.2", "allium"); - cfg.set("38.3", "azure bluet"); - cfg.set("38.4", "red tulip"); - cfg.set("38.5", "orange tulip"); - cfg.set("38.6", "white tulip"); - cfg.set("38.7", "pink tulip"); - cfg.set("38.8", "oxeye daisy"); - cfg.set("24.1", "chiseled sandstone"); - cfg.set("24.2", "smooth sandstone"); - cfg.set("31.0", "dead bush"); - cfg.set("31.1", "tall grass"); - cfg.set("31.2", "fern"); - cfg.set("98.0", "stone brick"); - cfg.set("98.1", "mossy stone brick"); - cfg.set("98.2", "cracked stone brick"); - cfg.set("98.3", "chiseled stone brick"); - cfg.set("125.0", "oak double step"); - cfg.set("125.1", "spruce double step"); - cfg.set("125.2", "birch double step"); - cfg.set("125.3", "jungle double step"); - cfg.set("125.4", "acacia double step"); - cfg.set("125.5", "dark oak double step"); - cfg.set("126.0", "oak step"); - cfg.set("126.1", "spruce step"); - cfg.set("126.2", "birch step"); - cfg.set("126.3", "jungle step"); - cfg.set("126.4", "acacia step"); - cfg.set("126.5", "dark oak step"); - cfg.set("126.8", "oak step"); - cfg.set("126.9", "spruce step"); - cfg.set("126.10", "birch step"); - cfg.set("126.11", "jungle step"); - cfg.set("126.12", "acacia step"); - cfg.set("126.13", "dark oak step"); - cfg.set("139.1", "mossy cobble wall"); - cfg.set("155.1", "chiseled quartz block"); - cfg.set("155.2", "pillar quartz block"); - cfg.set("155.3", "pillar quartz block"); - cfg.set("155.4", "pillar quartz block"); - cfg.set("161.0", "acacia leaves"); - cfg.set("161.1", "dark oak leaves"); - cfg.set("161.4", "acacia leaves"); - cfg.set("161.5", "dark oak leaves"); - cfg.set("161.8", "acacia leaves"); - cfg.set("161.9", "dark oak leaves"); - cfg.set("161.12", "acacia leaves"); - cfg.set("161.13", "dark oak leaves"); - cfg.set("162.0", "acacia log"); - cfg.set("162.1", "dark oak log"); - cfg.set("162.4", "acacia log"); - cfg.set("162.5", "dark oak log"); - cfg.set("162.8", "acacia log"); - cfg.set("162.9", "dark oak log"); - cfg.set("162.12", "acacia log"); - cfg.set("162.13", "dark oak log"); - cfg.set("168.1", "prismarine brick"); - cfg.set("168.2", "dark prismarine"); - cfg.set("181.0", "red sandstone double step"); - cfg.set("181.8", "smooth red sandstone double step"); - cfg.set("162.13", "dark oak log"); - cfg.set("175.0", "sunflower"); - cfg.set("175.1", "lilac"); - cfg.set("175.2", "double tall grass"); - cfg.set("175.3", "large fern"); - cfg.set("175.4", "rose bush"); - cfg.set("175.5", "peony"); - cfg.set("175.8", "sunflower"); - cfg.set("175.9", "lilac"); - cfg.set("175.10", "double tall grass"); - cfg.set("175.11", "large fern"); - cfg.set("175.12", "rose bush"); - cfg.set("175.13", "peony"); - cfg.set("179.1", "chiseled sandstone"); - cfg.set("179.2", "smooth sandstone"); - cfg.set("263.1", "charcoal"); - for (byte i = 0; i < 10; i++) { - cfg.set("43." + i, toReadable(Material.DOUBLE_STEP.getNewData(i))); - } - cfg.set("43.8", "stone double step"); - cfg.set("43.9", "sandstone double step"); - cfg.set("43.15", "quartz double step"); - for (byte i = 0; i < 8; i++) { - cfg.set("44." + i, toReadable(Material.STEP.getNewData(i))); - // The second half of this data list should read the same as the first half - cfg.set("44." + (i + 7), toReadable(Material.STEP.getNewData(i))); - } - for (byte i = 0; i < 16; i++) { - cfg.set("351." + i, toReadable(Material.INK_SACK.getNewData(i))); - cfg.set("35." + i, COLORS[i] + " wool"); - cfg.set("159." + i, COLORS[i] + " stained terracotta"); - cfg.set("95." + i, COLORS[i] + " stained glass"); - cfg.set("160." + i, COLORS[i] + " stained glass pane"); - cfg.set("171." + i, COLORS[i] + " carpet"); - cfg.set("251." + i, COLORS[i] + " concrete"); - cfg.set("252." + i, COLORS[i] + " concrete powder"); - } - for (byte i = 0; i < 6; i++) { - cfg.set("125." + i, toReadable(Material.WOOD_DOUBLE_STEP.getNewData(i))); - cfg.set("126." + i, toReadable(Material.WOOD_STEP.getNewData(i))); - cfg.set("126." + i + 8, toReadable(Material.WOOD_STEP.getNewData(i))); - } - try { - cfg.save(file); - } catch (final IOException ex) { - getLogger().log(Level.WARNING, "Unable to save material.yml: ", ex); - } - } - if (cfg.getString("252.1") == null) { - getLogger().info("[Logblock-names] Logblock's default materials.yml file has been updated with more names"); - getLogger().info("[Logblock-names] Consider deleting your current materials.yml file to allow it to be recreated"); - } - for (final String entry : cfg.getKeys(false)) { - if (isInt(entry)) { - if (cfg.isString(entry)) { - materialNames.put(Integer.valueOf(entry), cfg.getString(entry)); - nameTypes.put(cfg.getString(entry), Integer.valueOf(entry)); - } else if (cfg.isConfigurationSection(entry)) { - final Map dataNames = new HashMap(); - materialDataNames.put(Integer.valueOf(entry), dataNames); - final ConfigurationSection sec = cfg.getConfigurationSection(entry); - for (final String data : sec.getKeys(false)) { - if (isShort(data)) { - if (sec.isString(data)) { - dataNames.put(Short.valueOf(data), sec.getString(data)); - nameTypes.put(sec.getString(data), Integer.valueOf(entry)); - } else { - getLogger().warning("Parsing materials.yml: '" + data + "' is not a string."); - } - } else { - getLogger().warning("Parsing materials.yml: '" + data + "' is no valid material data"); - } - } - } else { - getLogger().warning("Parsing materials.yml: '" + entry + "' is neither a string nor a section."); - } - } else { - getLogger().warning("Parsing materials.yml: '" + entry + "' is no valid material id"); - } - } - } - - /** - * Returns the name of a material based on its id - * - * @param type The type of the material - * @return Name of the material, or if it's unknown, the id. - */ - public static String materialName(int type) { - return materialNames.containsKey(type) ? materialNames.get(type) : String.valueOf(type); - } - - /** - * Returns the name of a material based on its id and data - * - * @param type The type of the material - * @param data The data of the material - * @return Name of the material regarding it's data, or if it's unknown, the basic name. - */ - public static String materialName(int type, short data) { - final Map dataNames = materialDataNames.get(type); - if (dataNames != null) { - if (dataNames.containsKey(data)) { - return dataNames.get(data); - } - } - return materialName(type); - } - - public static Integer typeFromName(String name) { - Integer answer = nameTypes.get(toReadable(name)); - if (answer != null) { - return answer; - } - final Material mat = Material.matchMaterial(name); - if (mat == null) { - throw new IllegalArgumentException("No material matching: '" + name + "'"); - } - return mat.getId(); - } - - private static String toReadable(MaterialData matData) { - return matData.toString().toLowerCase().replace('_', ' ').replaceAll("[^a-z ]", ""); - } - - private static String toReadable(String matData) { - return matData.toLowerCase().replace('_', ' ').replaceAll("[^a-z ]", ""); - } -} diff --git a/src/main/java/de/diddiz/util/MySQLConnectionPool.java b/src/main/java/de/diddiz/util/MySQLConnectionPool.java index 0f7c976f..b7e944c4 100644 --- a/src/main/java/de/diddiz/util/MySQLConnectionPool.java +++ b/src/main/java/de/diddiz/util/MySQLConnectionPool.java @@ -11,7 +11,7 @@ public class MySQLConnectionPool implements Closeable { private final HikariDataSource ds; - public MySQLConnectionPool(String url, String user, String password) throws ClassNotFoundException { + public MySQLConnectionPool(String url, String user, String password) { this.ds = new HikariDataSource(); ds.setJdbcUrl(url); ds.setUsername(user); diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index 12349af0..849d56f7 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -1,13 +1,25 @@ package de.diddiz.util; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import org.bukkit.Material; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemStack; public class Utils { public static String newline = System.getProperty("line.separator"); @@ -192,8 +204,55 @@ public boolean accept(File dir, String name) { } } + private final static char[] hexArray = "0123456789ABCDEF".toCharArray(); + + public static String mysqlEscapeBytes(byte[] bytes) { + char[] hexChars = new char[bytes.length * 2 + 2]; + hexChars[0] = '0'; + hexChars[1] = 'x'; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2 + 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 3] = hexArray[v & 0x0F]; + } + return new String(hexChars); + } + public static String mysqlTextEscape(String untrusted) { return untrusted.replace("\\", "\\\\").replace("'", "\\'"); } + public static ItemStack loadItemStack(byte[] data) { + if (data == null || data.length == 0) { + return null; + } + YamlConfiguration conf = new YamlConfiguration(); + try { + InputStreamReader reader = new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(data)), "UTF-8"); + conf.load(reader); + reader.close(); + return conf.getItemStack("stack"); + } catch (IOException | InvalidConfigurationException e) { + e.printStackTrace(); + } + return null; + } + + public static byte[] saveItemStack(ItemStack stack) { + if (stack == null || stack.getType() == Material.AIR) { + return null; + } + try { + YamlConfiguration conf = new YamlConfiguration(); + conf.set("stack", stack); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStreamWriter writer = new OutputStreamWriter(new GZIPOutputStream(baos), "UTF-8"); + writer.write(conf.saveToString()); + writer.close(); + return baos.toByteArray(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } } diff --git a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java index 0bdef234..976f05b5 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java @@ -13,12 +13,7 @@ import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.Config; import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.block.Sign; import java.util.logging.Level; @@ -88,32 +83,33 @@ protected void onBlockChange(Vector pt, BaseBlock block) { return; } - Location location = new Location(world, pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - Block origin = location.getBlock(); - int typeBefore = origin.getTypeId(); - byte dataBefore = origin.getData(); - // If we're dealing with a sign, store the block state to read the text off - BlockState stateBefore = null; - if (typeBefore == Material.SIGN_POST.getId() || typeBefore == Material.SIGN.getId()) { - stateBefore = origin.getState(); - } - - // Check to see if we've broken a sign - if (Config.isLogging(location.getWorld().getName(), Logging.SIGNTEXT) && (typeBefore == Material.SIGN_POST.getId() || typeBefore == Material.SIGN.getId())) { - plugin.getConsumer().queueSignBreak(lbActor, (Sign) stateBefore); - if (block.getType() != Material.AIR.getId()) { - plugin.getConsumer().queueBlockPlace(lbActor, location, block.getType(), (byte) block.getData()); - } - } else { - if (dataBefore != 0) { - plugin.getConsumer().queueBlockBreak(lbActor, location, typeBefore, dataBefore); - if (block.getType() != Material.AIR.getId()) { - plugin.getConsumer().queueBlockPlace(lbActor, location, block.getType(), (byte) block.getData()); - } - } else { - plugin.getConsumer().queueBlock(lbActor, location, typeBefore, block.getType(), (byte) block.getData()); - } - } + // FIXME wait for updated worldedit + // Location location = new Location(world, pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + // Block origin = location.getBlock(); + // Material typeBefore = origin.getType(); + // byte dataBefore = origin.getData(); + // // If we're dealing with a sign, store the block state to read the text off + // BlockState stateBefore = null; + // if (typeBefore == Material.SIGN || typeBefore == Material.WALL_SIGN) { + // stateBefore = origin.getState(); + // } + // + // // Check to see if we've broken a sign + // if (Config.isLogging(location.getWorld().getName(), Logging.SIGNTEXT) && (typeBefore == Material.SIGN || typeBefore == Material.WALL_SIGN)) { + // plugin.getConsumer().queueSignBreak(lbActor, (Sign) stateBefore); + // if (block.getType() != Material.AIR.getId()) { + // plugin.getConsumer().queueBlockPlace(lbActor, location, block.getType(), (byte) block.getData()); + // } + // } else { + // if (dataBefore != 0) { + // plugin.getConsumer().queueBlockBreak(lbActor, location, typeBefore, dataBefore); + // if (block.getType() != Material.AIR.getId()) { + // plugin.getConsumer().queueBlockPlace(lbActor, location, block.getType(), (byte) block.getData()); + // } + // } else { + // plugin.getConsumer().queueBlock(lbActor, location, typeBefore, block.getType(), (byte) block.getData()); + // } + // } } }); } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 7b908bbf..f3dcab98 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -6,6 +6,7 @@ website: http://dev.bukkit.org/server-mods/logblock/ main: de.diddiz.LogBlock.LogBlock description: ${project.description} softdepend: [LogBlockQuestioner, WorldEdit] +api-version: 1.13 commands: lb: description: 'LogBlock plugin commands' From 51505cf34ad731261f6fa1a4e5438f0a76cb1697 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 21 Jul 2018 03:22:11 +0200 Subject: [PATCH 011/399] Better rollback of doors --- src/main/java/de/diddiz/LogBlock/WorldEditor.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 8f11909b..f4c736a0 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -8,9 +8,11 @@ import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; +import org.bukkit.block.data.Bisected.Half; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.Bed; import org.bukkit.block.data.type.Bed.Part; +import org.bukkit.block.data.type.Door; import org.bukkit.block.data.type.Piston; import org.bukkit.block.data.type.PistonHead; import org.bukkit.block.data.type.TechnicalPiston.Type; @@ -194,6 +196,8 @@ PerformResult perform() throws WorldEditorException { throw new WorldEditorException("Not enough space left in " + block.getType(), block.getLocation()); } } + } else if (!block.getBlockData().equals(replacedBlock)) { + block.setBlockData(replacedBlock); } else { return PerformResult.NO_ACTION; } @@ -208,7 +212,7 @@ PerformResult perform() throws WorldEditorException { } block.setBlockData(replacedBlock); BlockData newData = block.getBlockData(); - + final Material curtype = block.getType(); if (signtext != null && (curtype == Material.SIGN || curtype == Material.WALL_SIGN)) { final Sign sign = (Sign) block.getState(); @@ -230,6 +234,14 @@ PerformResult perform() throws WorldEditorException { bed2.setPart(bed.getPart() == Part.HEAD ? Part.FOOT : Part.HEAD); secBlock.setBlockData(bed2); } + } else if (newData instanceof Door) { + final Door door = (Door) newData; + final Block secBlock = door.getHalf() == Half.TOP ? block.getRelative(BlockFace.DOWN) : block.getRelative(BlockFace.UP); + if (secBlock.isEmpty()) { + Door door2 = (Door) door.clone(); + door2.setHalf(door.getHalf() == Half.TOP ? Half.BOTTOM : Half.TOP); + secBlock.setBlockData(door2); + } } else if ((curtype == Material.PISTON || curtype == Material.STICKY_PISTON)) { Piston piston = (Piston) newData; if (piston.isExtended()) { From 0792fbd32a7b5ffad5f1d68914574066da4d4c22 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 21 Jul 2018 14:30:44 +0200 Subject: [PATCH 012/399] Not every material has a BlockData --- .../de/diddiz/LogBlock/MaterialConverter.java | 16 +- .../java/de/diddiz/LogBlock/WorldEditor.java | 579 +++++++++--------- 2 files changed, 306 insertions(+), 289 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java index 57cef288..d392699e 100644 --- a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java +++ b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java @@ -20,6 +20,16 @@ public class MaterialConverter { private static String[] idToBlockState = new String[10]; private static HashMap blockStateToID = new HashMap<>(); private static int nextBlockStateId; + + private static HashMap materialKeyToMaterial = new HashMap<>(); + + static { + for (Material m : Material.values()) { + if (!m.name().startsWith("LEGACY_") && m.getKey() != null) { + materialKeyToMaterial.put(m.getKey().toString(), m); + } + } + } public synchronized static int getOrAddMaterialId(NamespacedKey nameSpaceKey) { return getOrAddMaterialId(nameSpaceKey.toString()); @@ -80,7 +90,11 @@ public synchronized static BlockData getBlockData(int materialId, int blockState } public static Material getMaterial(int materialId) { - return getBlockData(materialId, -1).getMaterial(); + String material = idToMaterial[materialId]; + if (materialId >= 0) { + material = material + idToBlockState[materialId]; + } + return materialKeyToMaterial.get(material); } public static void initializeMaterials(Connection connection) throws SQLException { diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index f4c736a0..5cd9c033 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -1,288 +1,291 @@ -package de.diddiz.LogBlock; - -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockState; -import org.bukkit.block.Sign; -import org.bukkit.block.data.Bisected.Half; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.type.Bed; -import org.bukkit.block.data.type.Bed.Part; -import org.bukkit.block.data.type.Door; -import org.bukkit.block.data.type.Piston; -import org.bukkit.block.data.type.PistonHead; -import org.bukkit.block.data.type.TechnicalPiston.Type; -import org.bukkit.command.CommandSender; -import org.bukkit.inventory.InventoryHolder; -import org.bukkit.inventory.ItemStack; - -import java.io.File; -import java.io.PrintWriter; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Queue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.logging.Level; - -import static de.diddiz.LogBlock.config.Config.dontRollback; -import static de.diddiz.LogBlock.config.Config.replaceAnyway; -import static de.diddiz.util.BukkitUtils.*; -import static org.bukkit.Bukkit.getLogger; - -public class WorldEditor implements Runnable { - private final LogBlock logblock; - private final Queue edits = new LinkedBlockingQueue(); - private final World world; - - /** - * The player responsible for editing the world, used to report progress - */ - private CommandSender sender; - private int taskID; - private int successes = 0, blacklistCollisions = 0; - private long elapsedTime = 0; - public LookupCacheElement[] errors; - - public WorldEditor(LogBlock logblock, World world) { - this.logblock = logblock; - this.world = world; - } - - public int getSize() { - return edits.size(); - } - - public int getSuccesses() { - return successes; - } - - public int getErrors() { - return errors.length; - } - - public int getBlacklistCollisions() { - return blacklistCollisions; - } - - - public void setSender(CommandSender sender) { - this.sender = sender; - } - - public void queueEdit(int x, int y, int z, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess item) { - edits.add(new Edit(0, new Location(world, x, y, z), null, replaced, replaceData, type, typeData, signtext, item)); - } - - public long getElapsedTime() { - return elapsedTime; - } - - synchronized public void start() throws Exception { - final long start = System.currentTimeMillis(); - taskID = logblock.getServer().getScheduler().scheduleSyncRepeatingTask(logblock, this, 0, 1); - if (taskID == -1) { - throw new Exception("Failed to schedule task"); - } - try { - this.wait(); - } catch (final InterruptedException ex) { - throw new Exception("Interrupted"); - } - elapsedTime = System.currentTimeMillis() - start; - } - - @Override - public synchronized void run() { - final List errorList = new ArrayList(); - int counter = 0; - float size = edits.size(); - while (!edits.isEmpty() && counter < 100) { - try { - switch (edits.poll().perform()) { - case SUCCESS: - successes++; - break; - case BLACKLISTED: - blacklistCollisions++; - break; - case NO_ACTION: - break; - } - } catch (final WorldEditorException ex) { - errorList.add(ex); - } catch (final Exception ex) { - getLogger().log(Level.WARNING, "[WorldEditor] Exeption: ", ex); - } - counter++; - if (sender != null) { - 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); - } - } - } - if (edits.isEmpty()) { - logblock.getServer().getScheduler().cancelTask(taskID); - if (errorList.size() > 0) { - try { - final File file = new File("plugins/LogBlock/error/WorldEditor-" + new SimpleDateFormat("yy-MM-dd-HH-mm-ss").format(System.currentTimeMillis()) + ".log"); - file.getParentFile().mkdirs(); - final PrintWriter writer = new PrintWriter(file); - for (final LookupCacheElement err : errorList) { - writer.println(err.getMessage()); - } - writer.close(); - } catch (final Exception ex) { - } - } - errors = errorList.toArray(new WorldEditorException[errorList.size()]); - notify(); - } - } - - private static enum PerformResult { - SUCCESS, BLACKLISTED, NO_ACTION - } - - private class Edit extends BlockChange { - public Edit(long time, Location loc, Actor actor, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess ca) { - super(time, loc, actor, replaced, replaceData, type, typeData, signtext, ca); - } - - PerformResult perform() throws WorldEditorException { - BlockData replacedBlock = MaterialConverter.getBlockData(this.replacedMaterial, replacedData); - BlockData setBlock = MaterialConverter.getBlockData(this.typeMaterial, typeData); - // action: set to replaced - - if (dontRollback.contains(replacedBlock.getMaterial())) { - return PerformResult.BLACKLISTED; - } - final Block block = loc.getBlock(); - if (replacedBlock.getMaterial() == Material.AIR && block.getType() == Material.AIR) { - return PerformResult.NO_ACTION; - } - final BlockState state = block.getState(); - if (!world.isChunkLoaded(block.getChunk())) { - world.loadChunk(block.getChunk()); - } - if (setBlock.equals(replacedBlock)) { - if (setBlock.getMaterial() == Material.AIR) { - block.setType(Material.AIR); - } else if (ca != null) { - if (state instanceof InventoryHolder) { - int leftover; - try { - leftover = modifyContainer(state, new ItemStack(ca.itemStack), !ca.remove); - // Special-case blocks which might be double chests - if (leftover > 0 && (setBlock.getMaterial() == Material.CHEST || setBlock.getMaterial() == Material.TRAPPED_CHEST)) { - for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) { - if (block.getRelative(face).getType() == setBlock.getMaterial()) { - ItemStack remaining = new ItemStack(ca.itemStack); - remaining.setAmount(leftover); - leftover = modifyContainer(block.getRelative(face).getState(), remaining, !ca.remove); - } - } - } - } catch (final Exception ex) { - throw new WorldEditorException(ex.getMessage(), block.getLocation()); - } - if (leftover > 0 && ca.remove) { - throw new WorldEditorException("Not enough space left in " + block.getType(), block.getLocation()); - } - } - } else if (!block.getBlockData().equals(replacedBlock)) { - block.setBlockData(replacedBlock); - } else { - return PerformResult.NO_ACTION; - } - return PerformResult.SUCCESS; - } - if (block.getType() != setBlock.getMaterial() && !replaceAnyway.contains(block.getType())) { - return PerformResult.NO_ACTION; - } - if (state instanceof InventoryHolder) { - ((InventoryHolder) state).getInventory().clear(); - state.update(); - } - block.setBlockData(replacedBlock); - BlockData newData = block.getBlockData(); - - final Material curtype = block.getType(); - if (signtext != null && (curtype == Material.SIGN || curtype == Material.WALL_SIGN)) { - final Sign sign = (Sign) block.getState(); - final String[] lines = signtext.split("\0", 4); - if (lines.length < 4) { - return PerformResult.NO_ACTION; - } - for (int i = 0; i < 4; i++) { - sign.setLine(i, lines[i]); - } - if (!sign.update()) { - throw new WorldEditorException("Failed to update signtext of " + block.getType(), block.getLocation()); - } - } else if (newData instanceof Bed) { - final Bed bed = (Bed) newData; - final Block secBlock = bed.getPart() == Part.HEAD ? block.getRelative(bed.getFacing().getOppositeFace()) : block.getRelative(bed.getFacing()); - if (secBlock.isEmpty()) { - Bed bed2 = (Bed) bed.clone(); - bed2.setPart(bed.getPart() == Part.HEAD ? Part.FOOT : Part.HEAD); - secBlock.setBlockData(bed2); - } - } else if (newData instanceof Door) { - final Door door = (Door) newData; - final Block secBlock = door.getHalf() == Half.TOP ? block.getRelative(BlockFace.DOWN) : block.getRelative(BlockFace.UP); - if (secBlock.isEmpty()) { - Door door2 = (Door) door.clone(); - door2.setHalf(door.getHalf() == Half.TOP ? Half.BOTTOM : Half.TOP); - secBlock.setBlockData(door2); - } - } else if ((curtype == Material.PISTON || curtype == Material.STICKY_PISTON)) { - Piston piston = (Piston) newData; - if (piston.isExtended()) { - final Block secBlock = block.getRelative(piston.getFacing()); - if (secBlock.isEmpty()) { - PistonHead head = (PistonHead) Material.PISTON_HEAD.createBlockData(); - head.setFacing(piston.getFacing()); - head.setType(curtype == Material.PISTON ? Type.NORMAL : Type.STICKY); - secBlock.setBlockData(head); - } - } - } else if (curtype == Material.PISTON_HEAD) { - PistonHead head = (PistonHead) newData; - final Block secBlock = block.getRelative(head.getFacing().getOppositeFace()); - if (secBlock.isEmpty()) { - Piston piston = (Piston) (head.getType() == Type.NORMAL ? Material.PISTON : Material.STICKY_PISTON).createBlockData(); - piston.setFacing(head.getFacing()); - piston.setExtended(true); - secBlock.setBlockData(piston); - } - } - return PerformResult.SUCCESS; - } - } - - @SuppressWarnings("serial") - public static class WorldEditorException extends Exception implements LookupCacheElement { - private final Location loc; - - public WorldEditorException(Material typeBefore, Material typeAfter, Location loc) { - this("Failed to replace " + typeBefore.name() + " with " + typeAfter.name(), loc); - } - - public WorldEditorException(String msg, Location loc) { - super(msg + " at " + loc.getWorld().getName() + ":" + loc.getBlockX() + ":" + loc.getBlockY() + ":" + loc.getBlockZ()); - this.loc = loc; - } - - @Override - public Location getLocation() { - return loc; - } - } -} +package de.diddiz.LogBlock; + +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.block.Sign; +import org.bukkit.block.data.Bisected.Half; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.Bed; +import org.bukkit.block.data.type.Bed.Part; +import org.bukkit.block.data.type.Door; +import org.bukkit.block.data.type.Piston; +import org.bukkit.block.data.type.PistonHead; +import org.bukkit.block.data.type.TechnicalPiston.Type; +import org.bukkit.command.CommandSender; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; + +import java.io.File; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.logging.Level; + +import static de.diddiz.LogBlock.config.Config.dontRollback; +import static de.diddiz.LogBlock.config.Config.replaceAnyway; +import static de.diddiz.util.BukkitUtils.*; +import static org.bukkit.Bukkit.getLogger; + +public class WorldEditor implements Runnable { + private final LogBlock logblock; + private final Queue edits = new LinkedBlockingQueue(); + private final World world; + + /** + * The player responsible for editing the world, used to report progress + */ + private CommandSender sender; + private int taskID; + private int successes = 0, blacklistCollisions = 0; + private long elapsedTime = 0; + public LookupCacheElement[] errors; + + public WorldEditor(LogBlock logblock, World world) { + this.logblock = logblock; + this.world = world; + } + + public int getSize() { + return edits.size(); + } + + public int getSuccesses() { + return successes; + } + + public int getErrors() { + return errors.length; + } + + public int getBlacklistCollisions() { + return blacklistCollisions; + } + + + public void setSender(CommandSender sender) { + this.sender = sender; + } + + public void queueEdit(int x, int y, int z, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess item) { + edits.add(new Edit(0, new Location(world, x, y, z), null, replaced, replaceData, type, typeData, signtext, item)); + } + + public long getElapsedTime() { + return elapsedTime; + } + + synchronized public void start() throws Exception { + final long start = System.currentTimeMillis(); + taskID = logblock.getServer().getScheduler().scheduleSyncRepeatingTask(logblock, this, 0, 1); + if (taskID == -1) { + throw new Exception("Failed to schedule task"); + } + try { + this.wait(); + } catch (final InterruptedException ex) { + throw new Exception("Interrupted"); + } + elapsedTime = System.currentTimeMillis() - start; + } + + @Override + public synchronized void run() { + final List errorList = new ArrayList(); + int counter = 0; + float size = edits.size(); + while (!edits.isEmpty() && counter < 100) { + try { + switch (edits.poll().perform()) { + case SUCCESS: + successes++; + break; + case BLACKLISTED: + blacklistCollisions++; + break; + case NO_ACTION: + break; + } + } catch (final WorldEditorException ex) { + errorList.add(ex); + } catch (final Exception ex) { + getLogger().log(Level.WARNING, "[WorldEditor] Exeption: ", ex); + } + counter++; + if (sender != null) { + 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); + } + } + } + if (edits.isEmpty()) { + logblock.getServer().getScheduler().cancelTask(taskID); + if (errorList.size() > 0) { + try { + final File file = new File("plugins/LogBlock/error/WorldEditor-" + new SimpleDateFormat("yy-MM-dd-HH-mm-ss").format(System.currentTimeMillis()) + ".log"); + file.getParentFile().mkdirs(); + final PrintWriter writer = new PrintWriter(file); + for (final LookupCacheElement err : errorList) { + writer.println(err.getMessage()); + } + writer.close(); + } catch (final Exception ex) { + } + } + errors = errorList.toArray(new WorldEditorException[errorList.size()]); + notify(); + } + } + + private static enum PerformResult { + SUCCESS, BLACKLISTED, NO_ACTION + } + + private class Edit extends BlockChange { + public Edit(long time, Location loc, Actor actor, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess ca) { + super(time, loc, actor, replaced, replaceData, type, typeData, signtext, ca); + } + + PerformResult perform() throws WorldEditorException { + BlockData replacedBlock = MaterialConverter.getBlockData(this.replacedMaterial, replacedData); + BlockData setBlock = MaterialConverter.getBlockData(this.typeMaterial, typeData); + if (replacedBlock == null || setBlock == null) { + throw new WorldEditorException("Could not parse the material", loc.clone()); + } + // action: set to replaced + + if (dontRollback.contains(replacedBlock.getMaterial())) { + return PerformResult.BLACKLISTED; + } + final Block block = loc.getBlock(); + if (replacedBlock.getMaterial() == Material.AIR && block.getType() == Material.AIR) { + return PerformResult.NO_ACTION; + } + final BlockState state = block.getState(); + if (!world.isChunkLoaded(block.getChunk())) { + world.loadChunk(block.getChunk()); + } + if (setBlock.equals(replacedBlock)) { + if (setBlock.getMaterial() == Material.AIR) { + block.setType(Material.AIR); + } else if (ca != null) { + if (state instanceof InventoryHolder) { + int leftover; + try { + leftover = modifyContainer(state, new ItemStack(ca.itemStack), !ca.remove); + // Special-case blocks which might be double chests + if (leftover > 0 && (setBlock.getMaterial() == Material.CHEST || setBlock.getMaterial() == Material.TRAPPED_CHEST)) { + for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) { + if (block.getRelative(face).getType() == setBlock.getMaterial()) { + ItemStack remaining = new ItemStack(ca.itemStack); + remaining.setAmount(leftover); + leftover = modifyContainer(block.getRelative(face).getState(), remaining, !ca.remove); + } + } + } + } catch (final Exception ex) { + throw new WorldEditorException(ex.getMessage(), block.getLocation()); + } + if (leftover > 0 && ca.remove) { + throw new WorldEditorException("Not enough space left in " + block.getType(), block.getLocation()); + } + } + } else if (!block.getBlockData().equals(replacedBlock)) { + block.setBlockData(replacedBlock); + } else { + return PerformResult.NO_ACTION; + } + return PerformResult.SUCCESS; + } + if (block.getType() != setBlock.getMaterial() && !replaceAnyway.contains(block.getType())) { + return PerformResult.NO_ACTION; + } + if (state instanceof InventoryHolder) { + ((InventoryHolder) state).getInventory().clear(); + state.update(); + } + block.setBlockData(replacedBlock); + BlockData newData = block.getBlockData(); + + final Material curtype = block.getType(); + if (signtext != null && (curtype == Material.SIGN || curtype == Material.WALL_SIGN)) { + final Sign sign = (Sign) block.getState(); + final String[] lines = signtext.split("\0", 4); + if (lines.length < 4) { + return PerformResult.NO_ACTION; + } + for (int i = 0; i < 4; i++) { + sign.setLine(i, lines[i]); + } + if (!sign.update()) { + throw new WorldEditorException("Failed to update signtext of " + block.getType(), block.getLocation()); + } + } else if (newData instanceof Bed) { + final Bed bed = (Bed) newData; + final Block secBlock = bed.getPart() == Part.HEAD ? block.getRelative(bed.getFacing().getOppositeFace()) : block.getRelative(bed.getFacing()); + if (secBlock.isEmpty()) { + Bed bed2 = (Bed) bed.clone(); + bed2.setPart(bed.getPart() == Part.HEAD ? Part.FOOT : Part.HEAD); + secBlock.setBlockData(bed2); + } + } else if (newData instanceof Door) { + final Door door = (Door) newData; + final Block secBlock = door.getHalf() == Half.TOP ? block.getRelative(BlockFace.DOWN) : block.getRelative(BlockFace.UP); + if (secBlock.isEmpty()) { + Door door2 = (Door) door.clone(); + door2.setHalf(door.getHalf() == Half.TOP ? Half.BOTTOM : Half.TOP); + secBlock.setBlockData(door2); + } + } else if ((curtype == Material.PISTON || curtype == Material.STICKY_PISTON)) { + Piston piston = (Piston) newData; + if (piston.isExtended()) { + final Block secBlock = block.getRelative(piston.getFacing()); + if (secBlock.isEmpty()) { + PistonHead head = (PistonHead) Material.PISTON_HEAD.createBlockData(); + head.setFacing(piston.getFacing()); + head.setType(curtype == Material.PISTON ? Type.NORMAL : Type.STICKY); + secBlock.setBlockData(head); + } + } + } else if (curtype == Material.PISTON_HEAD) { + PistonHead head = (PistonHead) newData; + final Block secBlock = block.getRelative(head.getFacing().getOppositeFace()); + if (secBlock.isEmpty()) { + Piston piston = (Piston) (head.getType() == Type.NORMAL ? Material.PISTON : Material.STICKY_PISTON).createBlockData(); + piston.setFacing(head.getFacing()); + piston.setExtended(true); + secBlock.setBlockData(piston); + } + } + return PerformResult.SUCCESS; + } + } + + @SuppressWarnings("serial") + public static class WorldEditorException extends Exception implements LookupCacheElement { + private final Location loc; + + public WorldEditorException(Material typeBefore, Material typeAfter, Location loc) { + this("Failed to replace " + typeBefore.name() + " with " + typeAfter.name(), loc); + } + + public WorldEditorException(String msg, Location loc) { + super(msg + " at " + loc.getWorld().getName() + ":" + loc.getBlockX() + ":" + loc.getBlockY() + ":" + loc.getBlockZ()); + this.loc = loc; + } + + @Override + public Location getLocation() { + return loc; + } + } +} From 6d35da12e307e5a798e88a98a8ea96973739105d Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 21 Jul 2018 15:11:50 +0200 Subject: [PATCH 013/399] Access MaterialConverter only from main thread, avoid sync --- .../de/diddiz/LogBlock/MaterialConverter.java | 8 +- .../java/de/diddiz/LogBlock/QueryParams.java | 1696 +++++++++-------- 2 files changed, 856 insertions(+), 848 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java index d392699e..62010d20 100644 --- a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java +++ b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java @@ -31,11 +31,11 @@ public class MaterialConverter { } } - public synchronized static int getOrAddMaterialId(NamespacedKey nameSpaceKey) { + public static int getOrAddMaterialId(NamespacedKey nameSpaceKey) { return getOrAddMaterialId(nameSpaceKey.toString()); } - public synchronized static int getOrAddMaterialId(String blockDataString) { + public static int getOrAddMaterialId(String blockDataString) { String materialString = blockDataString; int dataPart = blockDataString.indexOf("["); if (dataPart >= 0) { @@ -58,7 +58,7 @@ public synchronized static int getOrAddMaterialId(String blockDataString) { return key.intValue(); } - public synchronized static int getOrAddBlockStateId(String blockDataString) { + public static int getOrAddBlockStateId(String blockDataString) { int dataPart = blockDataString.indexOf("["); if (dataPart < 0) { return -1; @@ -81,7 +81,7 @@ public synchronized static int getOrAddBlockStateId(String blockDataString) { return key.intValue(); } - public synchronized static BlockData getBlockData(int materialId, int blockStateId) { + public static BlockData getBlockData(int materialId, int blockStateId) { String material = idToMaterial[materialId]; if (blockStateId >= 0) { material = material + idToBlockState[blockStateId]; diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 43571ef9..b9d51148 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -1,844 +1,852 @@ -package de.diddiz.LogBlock; - -import de.diddiz.util.Utils; -import de.diddiz.worldedit.RegionContainer; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; - -import java.util.*; - -import static de.diddiz.LogBlock.Session.getSession; -import static de.diddiz.LogBlock.config.Config.*; -import static de.diddiz.util.BukkitUtils.friendlyWorldname; -import static de.diddiz.util.Utils.*; - -public final class QueryParams implements Cloneable { - private static final Set keywords = new HashSet(Arrays.asList("player".hashCode(), "area".hashCode(), "selection".hashCode(), "sel".hashCode(), "block".hashCode(), "type".hashCode(), "sum".hashCode(), "destroyed".hashCode(), "created".hashCode(), "chestaccess".hashCode(), "all".hashCode(), "time".hashCode(), "since".hashCode(), "before".hashCode(), "limit".hashCode(), "world".hashCode(), "asc".hashCode(), "desc".hashCode(), "last".hashCode(), "coords".hashCode(), "silent".hashCode(), "chat".hashCode(), "search".hashCode(), "match".hashCode(), "loc".hashCode(), "location".hashCode(), "kills".hashCode(), "killer".hashCode(), "victim".hashCode(), "both".hashCode())); - public BlockChangeType bct = BlockChangeType.BOTH; - public int limit = -1, before = 0, since = 0, radius = -1; - public Location loc = null; - public Order order = Order.DESC; - public List players = new ArrayList(); - public List killers = new ArrayList(); - public List victims = new ArrayList(); - public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, excludeBlocksMode = false, prepareToolQuery = false, silent = false; - public RegionContainer sel = null; - public SummarizationMode sum = SummarizationMode.NONE; - public List types = new ArrayList(); - public World world = null; - public String match = null; - public boolean needCount = false, needId = false, needDate = false, needType = false, needData = false, needPlayer = false, needCoords = false, needSignText = false, needChestAccess = false, needMessage = false, needKiller = false, needVictim = false, needWeapon = false; - private final LogBlock logblock; - - public QueryParams(LogBlock logblock) { - this.logblock = logblock; - } - - public QueryParams(LogBlock logblock, CommandSender sender, List args) throws IllegalArgumentException { - this.logblock = logblock; - parseArgs(sender, args); - } - - public static boolean isKeyWord(String param) { - return keywords.contains(param.toLowerCase().hashCode()); - } - - public String getLimit() { - return limit > 0 ? "LIMIT " + limit : ""; - } - - public String getQuery() { - if (bct == BlockChangeType.CHAT) { - String select = "SELECT "; - if (needCount) { - select += "COUNT(*) AS count"; - } else { - if (needId) { - select += "id, "; - } - if (needDate) { - select += "date, "; - } - if (needPlayer) { - select += "playername, UUID,"; - } - if (needMessage) { - select += "message, "; - } - select = select.substring(0, select.length() - 2); - } - String from = "FROM `lb-chat` "; - - if (needPlayer || players.size() > 0) { - from += "INNER JOIN `lb-players` USING (playerid) "; - } - return select + " " + from + getWhere() + "ORDER BY date " + order + ", id " + order + " " + getLimit(); - } - if (bct == BlockChangeType.KILLS) { - if (sum == SummarizationMode.NONE) { - String select = "SELECT "; - if (needCount) { - select += "COUNT(*) AS count"; - } else { - if (needId) { - select += "id, "; - } - if (needDate) { - select += "date, "; - } - if (needPlayer || needKiller) { - select += "killers.playername as killer, "; - } - if (needPlayer || needVictim) { - select += "victims.playername as victim, "; - } - if (needWeapon) { - select += "weapon, "; - } - if (needCoords) { - select += "x, y, z, "; - } - select = select.substring(0, select.length() - 2); - } - String from = "FROM `" + getTable() + "-kills` "; - - if (needPlayer || needKiller || killers.size() > 0) { - from += "INNER JOIN `lb-players` as killers ON (killer=killers.playerid) "; - } - - if (needPlayer || needVictim || victims.size() > 0) { - from += "INNER JOIN `lb-players` as victims ON (victim=victims.playerid) "; - } - - return select + " " + from + getWhere() + "ORDER BY date " + order + ", id " + order + " " + getLimit(); - } else if (sum == SummarizationMode.PLAYERS) { - return "SELECT playername, UUID, SUM(kills) AS kills, SUM(killed) AS killed FROM ((SELECT killer AS playerid, count(*) AS kills, 0 as killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY killer) UNION (SELECT victim AS playerid, 0 as kills, count(*) AS killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY victim)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(kills) + SUM(killed) " + order + " " + getLimit(); - } - } - if (sum == SummarizationMode.NONE) { - String select = "SELECT "; - if (needCount) { - select += "COUNT(*) AS count"; - } else { - if (needId) { - select += "`" + getTable() + "`-blocks.id, "; - } - if (needDate) { - select += "date, "; - } - if (needType) { - select += "replaced, type, "; - } - if (needData) { - select += "replacedData, typeData, "; - } - if (needPlayer) { - select += "playername, UUID, "; - } - if (needCoords) { - select += "x, y, z, "; - } - if (needSignText) { - select += "signtext, "; - } - if (needChestAccess) { - select += "item, itemremove, "; - } - select = select.substring(0, select.length() - 2); - } - String from = "FROM `" + getTable() + "-blocks` "; - if (needPlayer || players.size() > 0) { - from += "INNER JOIN `lb-players` USING (playerid) "; - } - if (needSignText) { - from += "LEFT JOIN `" + getTable() + "-sign` USING (id) "; - } - if (needChestAccess) - // If BlockChangeType is CHESTACCESS, we can use more efficient query - { - if (bct == BlockChangeType.CHESTACCESS) { - from += "RIGHT JOIN `" + getTable() + "-chestdata` USING (id) "; - } else { - from += "LEFT JOIN `" + getTable() + "-chestdata` USING (id) "; - } - } - return select + " " + from + getWhere() + "ORDER BY date " + order + ", id " + order + " " + getLimit(); - } else if (sum == SummarizationMode.TYPES) { - return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.CREATED) + "GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); - } else { - return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); - } - } - - public String getTable() { - return getWorldConfig(world).table; - } - - public String getTitle() { - final StringBuilder title = new StringBuilder(); - if (bct == BlockChangeType.CHESTACCESS) { - title.append("chest accesses "); - } else if (bct == BlockChangeType.CHAT) { - title.append("chat messages "); - } else if (bct == BlockChangeType.KILLS) { - title.append("kills "); - } else { - if (!types.isEmpty()) { - if (excludeBlocksMode) { - title.append("all blocks except "); - } - final String[] blocknames = new String[types.size()]; - for (int i = 0; i < types.size(); i++) { - blocknames[i] = types.get(i).name(); - } - title.append(listing(blocknames, ", ", " and ")).append(" "); - } else { - title.append("block "); - } - if (bct == BlockChangeType.CREATED) { - title.append("creations "); - } else if (bct == BlockChangeType.DESTROYED) { - title.append("destructions "); - } else { - title.append("changes "); - } - } - if (killers.size() > 10) { - title.append(excludeKillersMode ? "without" : "from").append(" many killers "); - } else if (!killers.isEmpty()) { - title.append(excludeKillersMode ? "without" : "from").append(" ").append(listing(killers.toArray(new String[killers.size()]), ", ", " and ")).append(" "); - } - if (victims.size() > 10) { - title.append(excludeVictimsMode ? "without" : "of").append(" many victims "); - } else if (!victims.isEmpty()) { - title.append(excludeVictimsMode ? "without" : "of").append(" victim").append(victims.size() != 1 ? "s" : "").append(" ").append(listing(victims.toArray(new String[victims.size()]), ", ", " and ")).append(" "); - } - if (players.size() > 10) { - title.append(excludePlayersMode ? "without" : "from").append(" many players "); - } else if (!players.isEmpty()) { - title.append(excludePlayersMode ? "without" : "from").append(" player").append(players.size() != 1 ? "s" : "").append(" ").append(listing(players.toArray(new String[players.size()]), ", ", " and ")).append(" "); - } - if (match != null && match.length() > 0) { - title.append("matching '").append(match).append("' "); - } - if (before > 0 && since > 0) { - title.append("between ").append(since).append(" and ").append(before).append(" minutes ago "); - } else if (since > 0) { - title.append("in the last ").append(since).append(" minutes "); - } else if (before > 0) { - title.append("more than ").append(before * -1).append(" minutes ago "); - } - if (loc != null) { - if (radius > 0) { - title.append("within ").append(radius).append(" blocks of ").append(prepareToolQuery ? "clicked block" : "location").append(" "); - } else if (radius == 0) { - title.append("at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ()).append(" "); - } - } else if (sel != null) { - title.append(prepareToolQuery ? "at double chest " : "inside selection "); - } else if (prepareToolQuery) { - if (radius > 0) { - title.append("within ").append(radius).append(" blocks of clicked block "); - } else if (radius == 0) { - title.append("at clicked block "); - } - } - if (world != null && !(sel != null && prepareToolQuery)) { - title.append("in ").append(friendlyWorldname(world.getName())).append(" "); - } - if (sum != SummarizationMode.NONE) { - title.append("summed up by ").append(sum == SummarizationMode.TYPES ? "blocks" : "players").append(" "); - } - title.deleteCharAt(title.length() - 1); - title.setCharAt(0, String.valueOf(title.charAt(0)).toUpperCase().toCharArray()[0]); - return title.toString(); - } - - public String getWhere() { - return getWhere(bct); - } - - public String getWhere(BlockChangeType blockChangeType) { - final StringBuilder where = new StringBuilder("WHERE "); - if (blockChangeType == BlockChangeType.CHAT) { - if (match != null && match.length() > 0) { - final boolean unlike = match.startsWith("-"); - if (match.length() > 3 && !unlike || match.length() > 4) { - where.append("MATCH (message) AGAINST ('").append(match).append("' IN BOOLEAN MODE) AND "); - } else { - where.append("message ").append(unlike ? "NOT " : "").append("LIKE '%").append(unlike ? match.substring(1) : match).append("%' AND "); - } - } - } else if (blockChangeType == BlockChangeType.KILLS) { - if (!players.isEmpty()) { - if (!excludePlayersMode) { - where.append('('); - for (final String killerName : players) { - where.append("killers.playername = '").append(killerName).append("' OR "); - } - for (final String victimName : players) { - where.append("victims.playername = '").append(victimName).append("' OR "); - } - where.delete(where.length() - 4, where.length()); - where.append(") AND "); - } else { - for (final String killerName : players) { - where.append("killers.playername != '").append(killerName).append("' AND "); - } - for (final String victimName : players) { - where.append("victims.playername != '").append(victimName).append("' AND "); - } - } - } - - if (!killers.isEmpty()) { - if (!excludeKillersMode) { - where.append('('); - for (final String killerName : killers) { - where.append("killers.playername = '").append(killerName).append("' OR "); - } - where.delete(where.length() - 4, where.length()); - where.append(") AND "); - } else { - for (final String killerName : killers) { - where.append("killers.playername != '").append(killerName).append("' AND "); - } - } - } - - if (!victims.isEmpty()) { - if (!excludeVictimsMode) { - where.append('('); - for (final String victimName : victims) { - where.append("victims.playername = '").append(victimName).append("' OR "); - } - where.delete(where.length() - 4, where.length()); - where.append(") AND "); - } else { - for (final String victimName : victims) { - where.append("victims.playername != '").append(victimName).append("' AND "); - } - } - } - - if (loc != null) { - if (radius == 0) { - compileLocationQuery( - where, - loc.getBlockX(), loc.getBlockX(), - loc.getBlockY(), loc.getBlockY(), - loc.getBlockZ(), loc.getBlockZ() - ); - } else if (radius > 0) { - compileLocationQuery( - where, - loc.getBlockX() - radius + 1, loc.getBlockX() + radius - 1, - loc.getBlockY() - radius + 1, loc.getBlockY() + radius - 1, - loc.getBlockZ() - radius + 1, loc.getBlockZ() + radius - 1 - ); - } - - } else if (sel != null) { - compileLocationQuery( - where, - sel.getSelection().getMinimumPoint().getBlockX(), sel.getSelection().getMaximumPoint().getBlockX(), - sel.getSelection().getMinimumPoint().getBlockY(), sel.getSelection().getMaximumPoint().getBlockY(), - sel.getSelection().getMinimumPoint().getBlockZ(), sel.getSelection().getMaximumPoint().getBlockZ() - ); - } - - } else { - switch (blockChangeType) { - case ALL: - if (!types.isEmpty()) { - if (excludeBlocksMode) { - where.append("NOT "); - } - where.append('('); - for (final Material block : types) { - where.append("((type = ").append(MaterialConverter.getOrAddMaterialId(block.getKey())).append(" OR replaced = ").append(MaterialConverter.getOrAddMaterialId(block.getKey())); - where.append(")"); - where.append(") OR "); - } - where.delete(where.length() - 4, where.length() - 1); - where.append(") AND "); - } - break; - case BOTH: - if (!types.isEmpty()) { - if (excludeBlocksMode) { - where.append("NOT "); - } - where.append('('); - for (final Material block : types) { - where.append("((type = ").append(MaterialConverter.getOrAddMaterialId(block.getKey())).append(" OR replaced = ").append(MaterialConverter.getOrAddMaterialId(block.getKey())); - where.append(")"); - where.append(") OR "); - } - where.delete(where.length() - 4, where.length()); - where.append(") AND "); - } - where.append("type != replaced AND "); - break; - case CREATED: - if (!types.isEmpty()) { - if (excludeBlocksMode) { - where.append("NOT "); - } - where.append('('); - for (final Material block : types) { - where.append("((type = ").append(MaterialConverter.getOrAddMaterialId(block.getKey())); - where.append(")"); - where.append(") OR "); - } - where.delete(where.length() - 4, where.length()); - where.append(") AND "); - } - where.append("type != 0 AND type != replaced AND "); - break; - case DESTROYED: - if (!types.isEmpty()) { - if (excludeBlocksMode) { - where.append("NOT "); - } - where.append('('); - for (final Material block : types) { - where.append("((replaced = ").append(MaterialConverter.getOrAddMaterialId(block.getKey())); - where.append(")"); - where.append(") OR "); - } - where.delete(where.length() - 4, where.length()); - where.append(") AND "); - } - where.append("replaced != 0 AND type != replaced AND "); - break; - case CHESTACCESS: - if (!types.isEmpty()) { - if (excludeBlocksMode) { - where.append("NOT "); - } - where.append('('); - for (final Material block : types) { - where.append("((itemtype = ").append(MaterialConverter.getOrAddMaterialId(block.getKey())); - where.append(")"); - where.append(") OR "); - } - where.delete(where.length() - 4, where.length()); - where.append(") AND "); - } - break; - default: - break; - } - if (loc != null) { - if (radius == 0) { - compileLocationQuery( - where, - loc.getBlockX(), loc.getBlockX(), - loc.getBlockY(), loc.getBlockY(), - loc.getBlockZ(), loc.getBlockZ() - ); - } else if (radius > 0) { - compileLocationQuery( - where, - loc.getBlockX() - radius + 1, loc.getBlockX() + radius - 1, - loc.getBlockY() - radius + 1, loc.getBlockY() + radius - 1, - loc.getBlockZ() - radius + 1, loc.getBlockZ() + radius - 1 - ); - } - - } else if (sel != null) { - compileLocationQuery( - where, - sel.getSelection().getMinimumPoint().getBlockX(), sel.getSelection().getMaximumPoint().getBlockX(), - sel.getSelection().getMinimumPoint().getBlockY(), sel.getSelection().getMaximumPoint().getBlockY(), - sel.getSelection().getMinimumPoint().getBlockZ(), sel.getSelection().getMaximumPoint().getBlockZ() - ); - } - - } - if (!players.isEmpty() && sum != SummarizationMode.PLAYERS && blockChangeType != BlockChangeType.KILLS) { - if (!excludePlayersMode) { - where.append('('); - for (final String playerName : players) { - where.append("playername = '").append(playerName).append("' OR "); - } - where.delete(where.length() - 4, where.length()); - where.append(") AND "); - } else { - for (final String playerName : players) { - where.append("playername != '").append(playerName).append("' AND "); - } - } - } - if (since > 0) { - where.append("date > date_sub(now(), INTERVAL ").append(since).append(" MINUTE) AND "); - } - if (before > 0) { - where.append("date < date_sub(now(), INTERVAL ").append(before).append(" MINUTE) AND "); - } - if (where.length() > 6) { - where.delete(where.length() - 4, where.length()); - } else { - where.delete(0, where.length()); - } - return where.toString(); - } - - private void compileLocationQuery(StringBuilder where, int blockX, int blockX2, int blockY, int blockY2, int blockZ, int blockZ2) { - compileLocationQueryPart(where, "x", blockX, blockX2); - where.append(" AND "); - compileLocationQueryPart(where, "y", blockY, blockY2); - where.append(" AND "); - compileLocationQueryPart(where, "z", blockZ, blockZ2); - where.append(" AND "); - } - - private void compileLocationQueryPart(StringBuilder where, String locValue, int loc, int loc2) { - int min = Math.min(loc, loc2); - int max = Math.max(loc2, loc); - - if (min == max) { - where.append(locValue).append(" = ").append(min); - } else if (max - min > 50) { - where.append(locValue).append(" >= ").append(min).append(" AND ").append(locValue).append(" <= ").append(max); - } else { - where.append(locValue).append(" in ("); - for (int c = min; c < max; c++) { - where.append(c).append(","); - } - where.append(max); - where.append(")"); - } - } - - public void parseArgs(CommandSender sender, List args) throws IllegalArgumentException { - if (args == null || args.isEmpty()) { - throw new IllegalArgumentException("No parameters specified."); - } - args = Utils.parseQuotes(args); - final Player player = sender instanceof Player ? (Player) sender : null; - final Session session = prepareToolQuery ? null : getSession(sender); - if (player != null && world == null) { - world = player.getWorld(); - } - for (int i = 0; i < args.size(); i++) { - final String param = args.get(i).toLowerCase(); - final String[] values = getValues(args, i + 1); - if (param.equals("last")) { - if (session.lastQuery == null) { - throw new IllegalArgumentException("This is your first command, you can't use last."); - } - merge(session.lastQuery); - } else if (param.equals("player")) { - if (values.length < 1) { - throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); - } - for (final String playerName : values) { - if (playerName.length() > 0) { - if (playerName.contains("!")) { - excludePlayersMode = true; - } - if (playerName.contains("\"")) { - players.add(playerName.replaceAll("[^a-zA-Z0-9_]", "")); - } else { - final List matches = logblock.getServer().matchPlayer(playerName); - if (matches.size() > 1) { - throw new IllegalArgumentException("Ambiguous playername '" + param + "'"); - } - players.add(matches.size() == 1 ? matches.get(0).getName() : playerName.replaceAll("[^a-zA-Z0-9_]", "")); - } - } - } - needPlayer = true; - } else if (param.equals("killer")) { - if (values.length < 1) { - throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); - } - for (final String killerName : values) { - if (killerName.length() > 0) { - if (killerName.contains("!")) { - excludeVictimsMode = true; - } - if (killerName.contains("\"")) { - killers.add(killerName.replaceAll("[^a-zA-Z0-9_]", "")); - } else { - final List matches = logblock.getServer().matchPlayer(killerName); - if (matches.size() > 1) { - throw new IllegalArgumentException("Ambiguous victimname '" + param + "'"); - } - killers.add(matches.size() == 1 ? matches.get(0).getName() : killerName.replaceAll("[^a-zA-Z0-9_]", "")); - } - } - } - needKiller = true; - } else if (param.equals("victim")) { - if (values.length < 1) { - throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); - } - for (final String victimName : values) { - if (victimName.length() > 0) { - if (victimName.contains("!")) { - excludeVictimsMode = true; - } - if (victimName.contains("\"")) { - victims.add(victimName.replaceAll("[^a-zA-Z0-9_]", "")); - } else { - final List matches = logblock.getServer().matchPlayer(victimName); - if (matches.size() > 1) { - throw new IllegalArgumentException("Ambiguous victimname '" + param + "'"); - } - victims.add(matches.size() == 1 ? matches.get(0).getName() : victimName.replaceAll("[^a-zA-Z0-9_]", "")); - } - } - } - needVictim = true; - } else if (param.equals("weapon")) { - if (values.length < 1) { - throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); - } - for (final String weaponName : values) { - Material mat = Material.matchMaterial(weaponName); - if (mat == null) { - throw new IllegalArgumentException("No material matching: '" + weaponName + "'"); - } - types.add(mat); - } - needWeapon = true; - } else if (param.equals("block") || param.equals("type")) { - if (values.length < 1) { - throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); - } - for (String blockName : values) { - if (blockName.startsWith("!")) { - excludeBlocksMode = true; - blockName = blockName.substring(1); - } - - final Material mat = Material.matchMaterial(blockName); - types.add(mat); - } - } else if (param.equals("area")) { - if (player == null && !prepareToolQuery && loc == null) { - throw new IllegalArgumentException("You have to be a player to use area, or specify a location first"); - } - if (values.length == 0) { - radius = defaultDist; - if (!prepareToolQuery && loc == null) { - loc = player.getLocation(); - } - } else { - if (!isInt(values[0])) { - throw new IllegalArgumentException("Not a number: '" + values[0] + "'"); - } - radius = Integer.parseInt(values[0]); - if (!prepareToolQuery && loc == null) { - loc = player.getLocation(); - } - } - } else if (param.equals("selection") || param.equals("sel")) { - if (player == null) { - throw new IllegalArgumentException("You have to ba a player to use selection"); - } - final Plugin we = player.getServer().getPluginManager().getPlugin("WorldEdit"); - if (we != null) { - setSelection(RegionContainer.fromPlayerSelection(player, we)); - } else { - throw new IllegalArgumentException("WorldEdit not found!"); - } - } else if (param.equals("time") || param.equals("since")) { - since = values.length > 0 ? parseTimeSpec(values) : defaultTime; - if (since == -1) { - throw new IllegalArgumentException("Failed to parse time spec for '" + param + "'"); - } - } else if (param.equals("before")) { - before = values.length > 0 ? parseTimeSpec(values) : defaultTime; - if (before == -1) { - throw new IllegalArgumentException("Faile to parse time spec for '" + param + "'"); - } - } else if (param.equals("sum")) { - if (values.length != 1) { - throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); - } - if (values[0].startsWith("p")) { - sum = SummarizationMode.PLAYERS; - } else if (values[0].startsWith("b")) { - sum = SummarizationMode.TYPES; - } else if (values[0].startsWith("n")) { - sum = SummarizationMode.NONE; - } else { - throw new IllegalArgumentException("Wrong summarization mode"); - } - } else if (param.equals("created")) { - bct = BlockChangeType.CREATED; - } else if (param.equals("destroyed")) { - bct = BlockChangeType.DESTROYED; - } else if (param.equals("both")) { - bct = BlockChangeType.BOTH; - } else if (param.equals("chestaccess")) { - bct = BlockChangeType.CHESTACCESS; - } else if (param.equals("chat")) { - bct = BlockChangeType.CHAT; - } else if (param.equals("kills")) { - bct = BlockChangeType.KILLS; - } else if (param.equals("all")) { - bct = BlockChangeType.ALL; - } else if (param.equals("limit")) { - if (values.length != 1) { - throw new IllegalArgumentException("Wrong count of arguments for '" + param + "'"); - } - if (!isInt(values[0])) { - throw new IllegalArgumentException("Not a number: '" + values[0] + "'"); - } - limit = Integer.parseInt(values[0]); - } else if (param.equals("world")) { - if (values.length != 1) { - throw new IllegalArgumentException("Wrong count of arguments for '" + param + "'"); - } - final World w = sender.getServer().getWorld(values[0].replace("\"", "")); - if (w == null) { - throw new IllegalArgumentException("There is no world called '" + values[0] + "'"); - } - world = w; - } else if (param.equals("asc")) { - order = Order.ASC; - } else if (param.equals("desc")) { - order = Order.DESC; - } else if (param.equals("coords")) { - needCoords = true; - } else if (param.equals("silent")) { - silent = true; - } else if (param.equals("search") || param.equals("match")) { - if (values.length == 0) { - throw new IllegalArgumentException("No arguments for '" + param + "'"); - } - match = mysqlTextEscape(join(values, " ")); - } else if (param.equals("loc") || param.equals("location")) { - final String[] vectors = values.length == 1 ? values[0].split(":") : values; - if (vectors.length != 3) { - throw new IllegalArgumentException("Wrong count arguments for '" + param + "'"); - } - for (final String vec : vectors) { - if (!isInt(vec)) { - throw new IllegalArgumentException("Not a number: '" + vec + "'"); - } - } - loc = new Location(null, Integer.valueOf(vectors[0]), Integer.valueOf(vectors[1]), Integer.valueOf(vectors[2])); - radius = 0; - } else { - throw new IllegalArgumentException("Not a valid argument: '" + param + "'"); - } - i += values.length; - } - if (bct == BlockChangeType.KILLS) { - if (world == null) { - throw new IllegalArgumentException("No world specified"); - } - if (!getWorldConfig(world).isLogging(Logging.KILL)) { - throw new IllegalArgumentException("Kill logging not enabled for world '" + world.getName() + "'"); - } - } - if (!prepareToolQuery && bct != BlockChangeType.CHAT) { - if (world == null) { - throw new IllegalArgumentException("No world specified"); - } - if (!isLogged(world)) { - throw new IllegalArgumentException("This world ('" + world.getName() + "') isn't logged"); - } - } - if (session != null) { - session.lastQuery = clone(); - } - } - - public void setLocation(Location loc) { - this.loc = loc; - world = loc.getWorld(); - } - - public void setSelection(RegionContainer container) { - this.sel = container; - world = sel.getSelection().getWorld(); - } - - public void setPlayer(String playerName) { - players.clear(); - players.add(playerName); - } - - @Override - protected QueryParams clone() { - try { - final QueryParams params = (QueryParams) super.clone(); - params.players = new ArrayList(players); - params.types = new ArrayList(types); - return params; - } catch (final CloneNotSupportedException ex) { - } - return null; - } - - private static String[] getValues(List args, int offset) { - // The variable i will store the last value's index - int i; - // Iterate over the all the values from the offset up till the end - for (i = offset; i < args.size(); i++) { - // We found a keyword, break here since anything after this isn't a value. - if (isKeyWord(args.get(i))) { - break; - } - } - // If there are no values, i.e there is a keyword immediately after the offset - // return an empty string array - if (i == offset) { - return new String[0]; - } - - final String[] values = new String[i - offset]; - for (int j = offset; j < i; j++) { - String value = args.get(j); - - // If the value is encapsulated in quotes, strip them - if (value.startsWith("\"") && value.endsWith("\"")) { - value = value.substring(1, value.length() - 1); - } - values[j - offset] = value; - } - return values; - } - - public void merge(QueryParams p) { - players = p.players; - excludePlayersMode = p.excludePlayersMode; - types = p.types; - loc = p.loc; - radius = p.radius; - sel = p.sel; - if (p.since != 0 || since != defaultTime) { - since = p.since; - } - before = p.before; - sum = p.sum; - bct = p.bct; - limit = p.limit; - world = p.world; - order = p.order; - match = p.match; - } - - public static enum BlockChangeType { - ALL, BOTH, CHESTACCESS, CREATED, DESTROYED, CHAT, KILLS - } - - public static enum Order { - ASC, DESC - } - - public static enum SummarizationMode { - NONE, PLAYERS, TYPES - } -} +package de.diddiz.LogBlock; + +import de.diddiz.util.Utils; +import de.diddiz.worldedit.RegionContainer; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +import java.util.*; + +import static de.diddiz.LogBlock.Session.getSession; +import static de.diddiz.LogBlock.config.Config.*; +import static de.diddiz.util.BukkitUtils.friendlyWorldname; +import static de.diddiz.util.Utils.*; + +public final class QueryParams implements Cloneable { + private static final Set keywords = new HashSet(Arrays.asList("player".hashCode(), "area".hashCode(), "selection".hashCode(), "sel".hashCode(), "block".hashCode(), "type".hashCode(), "sum".hashCode(), "destroyed".hashCode(), "created".hashCode(), "chestaccess".hashCode(), "all".hashCode(), "time".hashCode(), "since".hashCode(), "before".hashCode(), "limit".hashCode(), "world".hashCode(), "asc".hashCode(), "desc".hashCode(), "last".hashCode(), "coords".hashCode(), "silent".hashCode(), "chat".hashCode(), "search".hashCode(), "match".hashCode(), "loc".hashCode(), "location".hashCode(), "kills".hashCode(), "killer".hashCode(), "victim".hashCode(), "both".hashCode())); + public BlockChangeType bct = BlockChangeType.BOTH; + public int limit = -1, before = 0, since = 0, radius = -1; + public Location loc = null; + public Order order = Order.DESC; + public List players = new ArrayList(); + public List killers = new ArrayList(); + public List victims = new ArrayList(); + public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, excludeBlocksMode = false, prepareToolQuery = false, silent = false; + public RegionContainer sel = null; + public SummarizationMode sum = SummarizationMode.NONE; + public List types = new ArrayList(); + public List typeIds = new ArrayList(); + public World world = null; + public String match = null; + public boolean needCount = false, needId = false, needDate = false, needType = false, needData = false, needPlayer = false, needCoords = false, needSignText = false, needChestAccess = false, needMessage = false, needKiller = false, needVictim = false, needWeapon = false; + private final LogBlock logblock; + + public QueryParams(LogBlock logblock) { + this.logblock = logblock; + } + + public QueryParams(LogBlock logblock, CommandSender sender, List args) throws IllegalArgumentException { + this.logblock = logblock; + parseArgs(sender, args); + } + + public static boolean isKeyWord(String param) { + return keywords.contains(param.toLowerCase().hashCode()); + } + + public String getLimit() { + return limit > 0 ? "LIMIT " + limit : ""; + } + + public String getQuery() { + if (bct == BlockChangeType.CHAT) { + String select = "SELECT "; + if (needCount) { + select += "COUNT(*) AS count"; + } else { + if (needId) { + select += "id, "; + } + if (needDate) { + select += "date, "; + } + if (needPlayer) { + select += "playername, UUID,"; + } + if (needMessage) { + select += "message, "; + } + select = select.substring(0, select.length() - 2); + } + String from = "FROM `lb-chat` "; + + if (needPlayer || players.size() > 0) { + from += "INNER JOIN `lb-players` USING (playerid) "; + } + return select + " " + from + getWhere() + "ORDER BY date " + order + ", id " + order + " " + getLimit(); + } + if (bct == BlockChangeType.KILLS) { + if (sum == SummarizationMode.NONE) { + String select = "SELECT "; + if (needCount) { + select += "COUNT(*) AS count"; + } else { + if (needId) { + select += "id, "; + } + if (needDate) { + select += "date, "; + } + if (needPlayer || needKiller) { + select += "killers.playername as killer, "; + } + if (needPlayer || needVictim) { + select += "victims.playername as victim, "; + } + if (needWeapon) { + select += "weapon, "; + } + if (needCoords) { + select += "x, y, z, "; + } + select = select.substring(0, select.length() - 2); + } + String from = "FROM `" + getTable() + "-kills` "; + + if (needPlayer || needKiller || killers.size() > 0) { + from += "INNER JOIN `lb-players` as killers ON (killer=killers.playerid) "; + } + + if (needPlayer || needVictim || victims.size() > 0) { + from += "INNER JOIN `lb-players` as victims ON (victim=victims.playerid) "; + } + + return select + " " + from + getWhere() + "ORDER BY date " + order + ", id " + order + " " + getLimit(); + } else if (sum == SummarizationMode.PLAYERS) { + return "SELECT playername, UUID, SUM(kills) AS kills, SUM(killed) AS killed FROM ((SELECT killer AS playerid, count(*) AS kills, 0 as killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY killer) UNION (SELECT victim AS playerid, 0 as kills, count(*) AS killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY victim)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(kills) + SUM(killed) " + order + " " + getLimit(); + } + } + if (sum == SummarizationMode.NONE) { + String select = "SELECT "; + if (needCount) { + select += "COUNT(*) AS count"; + } else { + if (needId) { + select += "`" + getTable() + "`-blocks.id, "; + } + if (needDate) { + select += "date, "; + } + if (needType) { + select += "replaced, type, "; + } + if (needData) { + select += "replacedData, typeData, "; + } + if (needPlayer) { + select += "playername, UUID, "; + } + if (needCoords) { + select += "x, y, z, "; + } + if (needSignText) { + select += "signtext, "; + } + if (needChestAccess) { + select += "item, itemremove, "; + } + select = select.substring(0, select.length() - 2); + } + String from = "FROM `" + getTable() + "-blocks` "; + if (needPlayer || players.size() > 0) { + from += "INNER JOIN `lb-players` USING (playerid) "; + } + if (needSignText) { + from += "LEFT JOIN `" + getTable() + "-sign` USING (id) "; + } + if (needChestAccess) + // If BlockChangeType is CHESTACCESS, we can use more efficient query + { + if (bct == BlockChangeType.CHESTACCESS) { + from += "RIGHT JOIN `" + getTable() + "-chestdata` USING (id) "; + } else { + from += "LEFT JOIN `" + getTable() + "-chestdata` USING (id) "; + } + } + return select + " " + from + getWhere() + "ORDER BY date " + order + ", id " + order + " " + getLimit(); + } else if (sum == SummarizationMode.TYPES) { + return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.CREATED) + "GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); + } else { + return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); + } + } + + public String getTable() { + return getWorldConfig(world).table; + } + + public String getTitle() { + final StringBuilder title = new StringBuilder(); + if (bct == BlockChangeType.CHESTACCESS) { + title.append("chest accesses "); + } else if (bct == BlockChangeType.CHAT) { + title.append("chat messages "); + } else if (bct == BlockChangeType.KILLS) { + title.append("kills "); + } else { + if (!types.isEmpty()) { + if (excludeBlocksMode) { + title.append("all blocks except "); + } + final String[] blocknames = new String[types.size()]; + for (int i = 0; i < types.size(); i++) { + blocknames[i] = types.get(i).name(); + } + title.append(listing(blocknames, ", ", " and ")).append(" "); + } else { + title.append("block "); + } + if (bct == BlockChangeType.CREATED) { + title.append("creations "); + } else if (bct == BlockChangeType.DESTROYED) { + title.append("destructions "); + } else { + title.append("changes "); + } + } + if (killers.size() > 10) { + title.append(excludeKillersMode ? "without" : "from").append(" many killers "); + } else if (!killers.isEmpty()) { + title.append(excludeKillersMode ? "without" : "from").append(" ").append(listing(killers.toArray(new String[killers.size()]), ", ", " and ")).append(" "); + } + if (victims.size() > 10) { + title.append(excludeVictimsMode ? "without" : "of").append(" many victims "); + } else if (!victims.isEmpty()) { + title.append(excludeVictimsMode ? "without" : "of").append(" victim").append(victims.size() != 1 ? "s" : "").append(" ").append(listing(victims.toArray(new String[victims.size()]), ", ", " and ")).append(" "); + } + if (players.size() > 10) { + title.append(excludePlayersMode ? "without" : "from").append(" many players "); + } else if (!players.isEmpty()) { + title.append(excludePlayersMode ? "without" : "from").append(" player").append(players.size() != 1 ? "s" : "").append(" ").append(listing(players.toArray(new String[players.size()]), ", ", " and ")).append(" "); + } + if (match != null && match.length() > 0) { + title.append("matching '").append(match).append("' "); + } + if (before > 0 && since > 0) { + title.append("between ").append(since).append(" and ").append(before).append(" minutes ago "); + } else if (since > 0) { + title.append("in the last ").append(since).append(" minutes "); + } else if (before > 0) { + title.append("more than ").append(before * -1).append(" minutes ago "); + } + if (loc != null) { + if (radius > 0) { + title.append("within ").append(radius).append(" blocks of ").append(prepareToolQuery ? "clicked block" : "location").append(" "); + } else if (radius == 0) { + title.append("at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ()).append(" "); + } + } else if (sel != null) { + title.append(prepareToolQuery ? "at double chest " : "inside selection "); + } else if (prepareToolQuery) { + if (radius > 0) { + title.append("within ").append(radius).append(" blocks of clicked block "); + } else if (radius == 0) { + title.append("at clicked block "); + } + } + if (world != null && !(sel != null && prepareToolQuery)) { + title.append("in ").append(friendlyWorldname(world.getName())).append(" "); + } + if (sum != SummarizationMode.NONE) { + title.append("summed up by ").append(sum == SummarizationMode.TYPES ? "blocks" : "players").append(" "); + } + title.deleteCharAt(title.length() - 1); + title.setCharAt(0, String.valueOf(title.charAt(0)).toUpperCase().toCharArray()[0]); + return title.toString(); + } + + public String getWhere() { + return getWhere(bct); + } + + public String getWhere(BlockChangeType blockChangeType) { + final StringBuilder where = new StringBuilder("WHERE "); + if (blockChangeType == BlockChangeType.CHAT) { + if (match != null && match.length() > 0) { + final boolean unlike = match.startsWith("-"); + if (match.length() > 3 && !unlike || match.length() > 4) { + where.append("MATCH (message) AGAINST ('").append(match).append("' IN BOOLEAN MODE) AND "); + } else { + where.append("message ").append(unlike ? "NOT " : "").append("LIKE '%").append(unlike ? match.substring(1) : match).append("%' AND "); + } + } + } else if (blockChangeType == BlockChangeType.KILLS) { + if (!players.isEmpty()) { + if (!excludePlayersMode) { + where.append('('); + for (final String killerName : players) { + where.append("killers.playername = '").append(killerName).append("' OR "); + } + for (final String victimName : players) { + where.append("victims.playername = '").append(victimName).append("' OR "); + } + where.delete(where.length() - 4, where.length()); + where.append(") AND "); + } else { + for (final String killerName : players) { + where.append("killers.playername != '").append(killerName).append("' AND "); + } + for (final String victimName : players) { + where.append("victims.playername != '").append(victimName).append("' AND "); + } + } + } + + if (!killers.isEmpty()) { + if (!excludeKillersMode) { + where.append('('); + for (final String killerName : killers) { + where.append("killers.playername = '").append(killerName).append("' OR "); + } + where.delete(where.length() - 4, where.length()); + where.append(") AND "); + } else { + for (final String killerName : killers) { + where.append("killers.playername != '").append(killerName).append("' AND "); + } + } + } + + if (!victims.isEmpty()) { + if (!excludeVictimsMode) { + where.append('('); + for (final String victimName : victims) { + where.append("victims.playername = '").append(victimName).append("' OR "); + } + where.delete(where.length() - 4, where.length()); + where.append(") AND "); + } else { + for (final String victimName : victims) { + where.append("victims.playername != '").append(victimName).append("' AND "); + } + } + } + + if (loc != null) { + if (radius == 0) { + compileLocationQuery( + where, + loc.getBlockX(), loc.getBlockX(), + loc.getBlockY(), loc.getBlockY(), + loc.getBlockZ(), loc.getBlockZ() + ); + } else if (radius > 0) { + compileLocationQuery( + where, + loc.getBlockX() - radius + 1, loc.getBlockX() + radius - 1, + loc.getBlockY() - radius + 1, loc.getBlockY() + radius - 1, + loc.getBlockZ() - radius + 1, loc.getBlockZ() + radius - 1 + ); + } + + } else if (sel != null) { + compileLocationQuery( + where, + sel.getSelection().getMinimumPoint().getBlockX(), sel.getSelection().getMaximumPoint().getBlockX(), + sel.getSelection().getMinimumPoint().getBlockY(), sel.getSelection().getMaximumPoint().getBlockY(), + sel.getSelection().getMinimumPoint().getBlockZ(), sel.getSelection().getMaximumPoint().getBlockZ() + ); + } + + } else { + switch (blockChangeType) { + case ALL: + if (!typeIds.isEmpty()) { + if (excludeBlocksMode) { + where.append("NOT "); + } + where.append('('); + for (final Integer block : typeIds) { + where.append("((type = ").append(block).append(" OR replaced = ").append(block); + where.append(")"); + where.append(") OR "); + } + where.delete(where.length() - 4, where.length() - 1); + where.append(") AND "); + } + break; + case BOTH: + if (!typeIds.isEmpty()) { + if (excludeBlocksMode) { + where.append("NOT "); + } + where.append('('); + for (final Integer block : typeIds) { + where.append("((type = ").append(block).append(" OR replaced = ").append(block); + where.append(")"); + where.append(") OR "); + } + where.delete(where.length() - 4, where.length()); + where.append(") AND "); + } + where.append("type != replaced AND "); + break; + case CREATED: + if (!typeIds.isEmpty()) { + if (excludeBlocksMode) { + where.append("NOT "); + } + where.append('('); + for (final Integer block : typeIds) { + where.append("((type = ").append(block); + where.append(")"); + where.append(") OR "); + } + where.delete(where.length() - 4, where.length()); + where.append(") AND "); + } + where.append("type != 0 AND type != replaced AND "); + break; + case DESTROYED: + if (!typeIds.isEmpty()) { + if (excludeBlocksMode) { + where.append("NOT "); + } + where.append('('); + for (final Integer block : typeIds) { + where.append("((replaced = ").append(block); + where.append(")"); + where.append(") OR "); + } + where.delete(where.length() - 4, where.length()); + where.append(") AND "); + } + where.append("replaced != 0 AND type != replaced AND "); + break; + case CHESTACCESS: + if (!typeIds.isEmpty()) { + if (excludeBlocksMode) { + where.append("NOT "); + } + where.append('('); + for (final Integer block : typeIds) { + where.append("((itemtype = ").append(block); + where.append(")"); + where.append(") OR "); + } + where.delete(where.length() - 4, where.length()); + where.append(") AND "); + } + break; + default: + break; + } + if (loc != null) { + if (radius == 0) { + compileLocationQuery( + where, + loc.getBlockX(), loc.getBlockX(), + loc.getBlockY(), loc.getBlockY(), + loc.getBlockZ(), loc.getBlockZ() + ); + } else if (radius > 0) { + compileLocationQuery( + where, + loc.getBlockX() - radius + 1, loc.getBlockX() + radius - 1, + loc.getBlockY() - radius + 1, loc.getBlockY() + radius - 1, + loc.getBlockZ() - radius + 1, loc.getBlockZ() + radius - 1 + ); + } + + } else if (sel != null) { + compileLocationQuery( + where, + sel.getSelection().getMinimumPoint().getBlockX(), sel.getSelection().getMaximumPoint().getBlockX(), + sel.getSelection().getMinimumPoint().getBlockY(), sel.getSelection().getMaximumPoint().getBlockY(), + sel.getSelection().getMinimumPoint().getBlockZ(), sel.getSelection().getMaximumPoint().getBlockZ() + ); + } + + } + if (!players.isEmpty() && sum != SummarizationMode.PLAYERS && blockChangeType != BlockChangeType.KILLS) { + if (!excludePlayersMode) { + where.append('('); + for (final String playerName : players) { + where.append("playername = '").append(playerName).append("' OR "); + } + where.delete(where.length() - 4, where.length()); + where.append(") AND "); + } else { + for (final String playerName : players) { + where.append("playername != '").append(playerName).append("' AND "); + } + } + } + if (since > 0) { + where.append("date > date_sub(now(), INTERVAL ").append(since).append(" MINUTE) AND "); + } + if (before > 0) { + where.append("date < date_sub(now(), INTERVAL ").append(before).append(" MINUTE) AND "); + } + if (where.length() > 6) { + where.delete(where.length() - 4, where.length()); + } else { + where.delete(0, where.length()); + } + return where.toString(); + } + + private void compileLocationQuery(StringBuilder where, int blockX, int blockX2, int blockY, int blockY2, int blockZ, int blockZ2) { + compileLocationQueryPart(where, "x", blockX, blockX2); + where.append(" AND "); + compileLocationQueryPart(where, "y", blockY, blockY2); + where.append(" AND "); + compileLocationQueryPart(where, "z", blockZ, blockZ2); + where.append(" AND "); + } + + private void compileLocationQueryPart(StringBuilder where, String locValue, int loc, int loc2) { + int min = Math.min(loc, loc2); + int max = Math.max(loc2, loc); + + if (min == max) { + where.append(locValue).append(" = ").append(min); + } else if (max - min > 50) { + where.append(locValue).append(" >= ").append(min).append(" AND ").append(locValue).append(" <= ").append(max); + } else { + where.append(locValue).append(" in ("); + for (int c = min; c < max; c++) { + where.append(c).append(","); + } + where.append(max); + where.append(")"); + } + } + + public void parseArgs(CommandSender sender, List args) throws IllegalArgumentException { + if (args == null || args.isEmpty()) { + throw new IllegalArgumentException("No parameters specified."); + } + args = Utils.parseQuotes(args); + final Player player = sender instanceof Player ? (Player) sender : null; + final Session session = prepareToolQuery ? null : getSession(sender); + if (player != null && world == null) { + world = player.getWorld(); + } + for (int i = 0; i < args.size(); i++) { + final String param = args.get(i).toLowerCase(); + final String[] values = getValues(args, i + 1); + if (param.equals("last")) { + if (session.lastQuery == null) { + throw new IllegalArgumentException("This is your first command, you can't use last."); + } + merge(session.lastQuery); + } else if (param.equals("player")) { + if (values.length < 1) { + throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); + } + for (final String playerName : values) { + if (playerName.length() > 0) { + if (playerName.contains("!")) { + excludePlayersMode = true; + } + if (playerName.contains("\"")) { + players.add(playerName.replaceAll("[^a-zA-Z0-9_]", "")); + } else { + final List matches = logblock.getServer().matchPlayer(playerName); + if (matches.size() > 1) { + throw new IllegalArgumentException("Ambiguous playername '" + param + "'"); + } + players.add(matches.size() == 1 ? matches.get(0).getName() : playerName.replaceAll("[^a-zA-Z0-9_]", "")); + } + } + } + needPlayer = true; + } else if (param.equals("killer")) { + if (values.length < 1) { + throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); + } + for (final String killerName : values) { + if (killerName.length() > 0) { + if (killerName.contains("!")) { + excludeVictimsMode = true; + } + if (killerName.contains("\"")) { + killers.add(killerName.replaceAll("[^a-zA-Z0-9_]", "")); + } else { + final List matches = logblock.getServer().matchPlayer(killerName); + if (matches.size() > 1) { + throw new IllegalArgumentException("Ambiguous victimname '" + param + "'"); + } + killers.add(matches.size() == 1 ? matches.get(0).getName() : killerName.replaceAll("[^a-zA-Z0-9_]", "")); + } + } + } + needKiller = true; + } else if (param.equals("victim")) { + if (values.length < 1) { + throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); + } + for (final String victimName : values) { + if (victimName.length() > 0) { + if (victimName.contains("!")) { + excludeVictimsMode = true; + } + if (victimName.contains("\"")) { + victims.add(victimName.replaceAll("[^a-zA-Z0-9_]", "")); + } else { + final List matches = logblock.getServer().matchPlayer(victimName); + if (matches.size() > 1) { + throw new IllegalArgumentException("Ambiguous victimname '" + param + "'"); + } + victims.add(matches.size() == 1 ? matches.get(0).getName() : victimName.replaceAll("[^a-zA-Z0-9_]", "")); + } + } + } + needVictim = true; + } else if (param.equals("weapon")) { + if (values.length < 1) { + throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); + } + for (final String weaponName : values) { + Material mat = Material.matchMaterial(weaponName); + if (mat == null) { + throw new IllegalArgumentException("No material matching: '" + weaponName + "'"); + } + types.add(mat); + typeIds.add(MaterialConverter.getOrAddMaterialId(mat.getKey())); + } + needWeapon = true; + } else if (param.equals("block") || param.equals("type")) { + if (values.length < 1) { + throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); + } + for (String blockName : values) { + if (blockName.startsWith("!")) { + excludeBlocksMode = true; + blockName = blockName.substring(1); + } + + final Material mat = Material.matchMaterial(blockName); + if (mat == null) { + throw new IllegalArgumentException("No material matching: '" + blockName + "'"); + } + types.add(mat); + typeIds.add(MaterialConverter.getOrAddMaterialId(mat.getKey())); + } + } else if (param.equals("area")) { + if (player == null && !prepareToolQuery && loc == null) { + throw new IllegalArgumentException("You have to be a player to use area, or specify a location first"); + } + if (values.length == 0) { + radius = defaultDist; + if (!prepareToolQuery && loc == null) { + loc = player.getLocation(); + } + } else { + if (!isInt(values[0])) { + throw new IllegalArgumentException("Not a number: '" + values[0] + "'"); + } + radius = Integer.parseInt(values[0]); + if (!prepareToolQuery && loc == null) { + loc = player.getLocation(); + } + } + } else if (param.equals("selection") || param.equals("sel")) { + if (player == null) { + throw new IllegalArgumentException("You have to ba a player to use selection"); + } + final Plugin we = player.getServer().getPluginManager().getPlugin("WorldEdit"); + if (we != null) { + setSelection(RegionContainer.fromPlayerSelection(player, we)); + } else { + throw new IllegalArgumentException("WorldEdit not found!"); + } + } else if (param.equals("time") || param.equals("since")) { + since = values.length > 0 ? parseTimeSpec(values) : defaultTime; + if (since == -1) { + throw new IllegalArgumentException("Failed to parse time spec for '" + param + "'"); + } + } else if (param.equals("before")) { + before = values.length > 0 ? parseTimeSpec(values) : defaultTime; + if (before == -1) { + throw new IllegalArgumentException("Faile to parse time spec for '" + param + "'"); + } + } else if (param.equals("sum")) { + if (values.length != 1) { + throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); + } + if (values[0].startsWith("p")) { + sum = SummarizationMode.PLAYERS; + } else if (values[0].startsWith("b")) { + sum = SummarizationMode.TYPES; + } else if (values[0].startsWith("n")) { + sum = SummarizationMode.NONE; + } else { + throw new IllegalArgumentException("Wrong summarization mode"); + } + } else if (param.equals("created")) { + bct = BlockChangeType.CREATED; + } else if (param.equals("destroyed")) { + bct = BlockChangeType.DESTROYED; + } else if (param.equals("both")) { + bct = BlockChangeType.BOTH; + } else if (param.equals("chestaccess")) { + bct = BlockChangeType.CHESTACCESS; + } else if (param.equals("chat")) { + bct = BlockChangeType.CHAT; + } else if (param.equals("kills")) { + bct = BlockChangeType.KILLS; + } else if (param.equals("all")) { + bct = BlockChangeType.ALL; + } else if (param.equals("limit")) { + if (values.length != 1) { + throw new IllegalArgumentException("Wrong count of arguments for '" + param + "'"); + } + if (!isInt(values[0])) { + throw new IllegalArgumentException("Not a number: '" + values[0] + "'"); + } + limit = Integer.parseInt(values[0]); + } else if (param.equals("world")) { + if (values.length != 1) { + throw new IllegalArgumentException("Wrong count of arguments for '" + param + "'"); + } + final World w = sender.getServer().getWorld(values[0].replace("\"", "")); + if (w == null) { + throw new IllegalArgumentException("There is no world called '" + values[0] + "'"); + } + world = w; + } else if (param.equals("asc")) { + order = Order.ASC; + } else if (param.equals("desc")) { + order = Order.DESC; + } else if (param.equals("coords")) { + needCoords = true; + } else if (param.equals("silent")) { + silent = true; + } else if (param.equals("search") || param.equals("match")) { + if (values.length == 0) { + throw new IllegalArgumentException("No arguments for '" + param + "'"); + } + match = mysqlTextEscape(join(values, " ")); + } else if (param.equals("loc") || param.equals("location")) { + final String[] vectors = values.length == 1 ? values[0].split(":") : values; + if (vectors.length != 3) { + throw new IllegalArgumentException("Wrong count arguments for '" + param + "'"); + } + for (final String vec : vectors) { + if (!isInt(vec)) { + throw new IllegalArgumentException("Not a number: '" + vec + "'"); + } + } + loc = new Location(null, Integer.valueOf(vectors[0]), Integer.valueOf(vectors[1]), Integer.valueOf(vectors[2])); + radius = 0; + } else { + throw new IllegalArgumentException("Not a valid argument: '" + param + "'"); + } + i += values.length; + } + if (bct == BlockChangeType.KILLS) { + if (world == null) { + throw new IllegalArgumentException("No world specified"); + } + if (!getWorldConfig(world).isLogging(Logging.KILL)) { + throw new IllegalArgumentException("Kill logging not enabled for world '" + world.getName() + "'"); + } + } + if (!prepareToolQuery && bct != BlockChangeType.CHAT) { + if (world == null) { + throw new IllegalArgumentException("No world specified"); + } + if (!isLogged(world)) { + throw new IllegalArgumentException("This world ('" + world.getName() + "') isn't logged"); + } + } + if (session != null) { + session.lastQuery = clone(); + } + } + + public void setLocation(Location loc) { + this.loc = loc; + world = loc.getWorld(); + } + + public void setSelection(RegionContainer container) { + this.sel = container; + world = sel.getSelection().getWorld(); + } + + public void setPlayer(String playerName) { + players.clear(); + players.add(playerName); + } + + @Override + protected QueryParams clone() { + try { + final QueryParams params = (QueryParams) super.clone(); + params.players = new ArrayList(players); + params.typeIds = new ArrayList(typeIds); + params.types = new ArrayList(types); + return params; + } catch (final CloneNotSupportedException ex) { + } + return null; + } + + private static String[] getValues(List args, int offset) { + // The variable i will store the last value's index + int i; + // Iterate over the all the values from the offset up till the end + for (i = offset; i < args.size(); i++) { + // We found a keyword, break here since anything after this isn't a value. + if (isKeyWord(args.get(i))) { + break; + } + } + // If there are no values, i.e there is a keyword immediately after the offset + // return an empty string array + if (i == offset) { + return new String[0]; + } + + final String[] values = new String[i - offset]; + for (int j = offset; j < i; j++) { + String value = args.get(j); + + // If the value is encapsulated in quotes, strip them + if (value.startsWith("\"") && value.endsWith("\"")) { + value = value.substring(1, value.length() - 1); + } + values[j - offset] = value; + } + return values; + } + + public void merge(QueryParams p) { + players = p.players; + excludePlayersMode = p.excludePlayersMode; + typeIds = p.typeIds; + types = p.types; + loc = p.loc; + radius = p.radius; + sel = p.sel; + if (p.since != 0 || since != defaultTime) { + since = p.since; + } + before = p.before; + sum = p.sum; + bct = p.bct; + limit = p.limit; + world = p.world; + order = p.order; + match = p.match; + } + + public static enum BlockChangeType { + ALL, BOTH, CHESTACCESS, CREATED, DESTROYED, CHAT, KILLS + } + + public static enum Order { + ASC, DESC + } + + public static enum SummarizationMode { + NONE, PLAYERS, TYPES + } +} From ea878355950169027d20929f95db018dd09117f0 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 21 Jul 2018 15:51:16 +0200 Subject: [PATCH 014/399] Update to WorldEdit for 1.13 --- pom.xml | 12 +++- .../java/de/diddiz/LogBlock/QueryParams.java | 4 +- .../de/diddiz/worldedit/RegionContainer.java | 37 ++++++++--- .../worldedit/WorldEditLoggingHook.java | 64 ++++++++++--------- 4 files changed, 73 insertions(+), 44 deletions(-) diff --git a/pom.xml b/pom.xml index 93108f97..3ef50443 100644 --- a/pom.xml +++ b/pom.xml @@ -53,9 +53,15 @@ ${project.basedir}/LogBlockQuestioner.jar - com.sk89q - worldedit - 6.0.0-SNAPSHOT + com.sk89q.worldedit + worldedit-core + 7.0.0-SNAPSHOT + provided + + + com.sk89q.worldedit + worldedit-bukkit + 7.0.0-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index b9d51148..3d0a1517 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -9,6 +9,8 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; +import com.sk89q.worldedit.bukkit.BukkitAdapter; + import java.util.*; import static de.diddiz.LogBlock.Session.getSession; @@ -768,7 +770,7 @@ public void setLocation(Location loc) { public void setSelection(RegionContainer container) { this.sel = container; - world = sel.getSelection().getWorld(); + world = BukkitAdapter.adapt(sel.getSelection().getWorld()); } public void setPlayer(String playerName) { diff --git a/src/main/java/de/diddiz/worldedit/RegionContainer.java b/src/main/java/de/diddiz/worldedit/RegionContainer.java index 3258434d..1b86f7c4 100644 --- a/src/main/java/de/diddiz/worldedit/RegionContainer.java +++ b/src/main/java/de/diddiz/worldedit/RegionContainer.java @@ -1,8 +1,13 @@ package de.diddiz.worldedit; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.selections.CuboidSelection; -import com.sk89q.worldedit.bukkit.selections.Selection; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; + import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Player; @@ -10,32 +15,46 @@ public class RegionContainer { - private Selection selection; + private Region selection; - public RegionContainer(Selection sel) { + public RegionContainer(Region sel) { this.selection = sel; } public static RegionContainer fromPlayerSelection(Player player, Plugin plugin) { - final Selection selection = ((WorldEditPlugin) plugin).getSelection(player); + LocalSession session = ((WorldEditPlugin) plugin).getSession(player); + com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(player.getWorld()); + if (!weWorld.equals(session.getSelectionWorld())) { + throw new IllegalArgumentException("No selection defined"); + } + Region selection; + try { + selection = session.getSelection(weWorld); + } catch (IncompleteRegionException e) { + throw new IllegalArgumentException("No selection defined"); + } if (selection == null) { throw new IllegalArgumentException("No selection defined"); } - if (!(selection instanceof CuboidSelection)) { + if (!(selection instanceof CuboidRegion)) { throw new IllegalArgumentException("You have to define a cuboid selection"); } return new RegionContainer(selection); } public static RegionContainer fromCorners(World world, Location first, Location second) { - return new RegionContainer(new CuboidSelection(world, first, second)); + com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(world); + Vector firstVector = BukkitAdapter.asVector(first); + Vector secondVector = BukkitAdapter.asVector(second); + + return new RegionContainer(new CuboidRegion(weWorld, firstVector, secondVector)); } - public Selection getSelection() { + public Region getSelection() { return selection; } - public void setSelection(Selection selection) { + public void setSelection(Region selection) { this.selection = selection; } } diff --git a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java index 976f05b5..d8d01696 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java @@ -3,17 +3,26 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.event.extent.EditSessionEvent; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.extent.logging.AbstractLoggingExtent; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.util.eventbus.Subscribe; +import com.sk89q.worldedit.world.block.BlockStateHolder; + import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.Config; import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.Sign; +import org.bukkit.block.data.BlockData; import java.util.logging.Level; @@ -75,41 +84,34 @@ public void wrapForLogging(final EditSessionEvent event) { return; } - event.setExtent(new AbstractLoggingExtent(event.getExtent()) { + event.setExtent(new AbstractDelegateExtent(event.getExtent()) { @Override - protected void onBlockChange(Vector pt, BaseBlock block) { + public final boolean setBlock(Vector position, @SuppressWarnings("rawtypes") BlockStateHolder block) throws WorldEditException { + onBlockChange(position, block); + return super.setBlock(position, block); + } + + protected void onBlockChange(Vector pt, BlockStateHolder block) { if (event.getStage() != EditSession.Stage.BEFORE_CHANGE) { return; } - // FIXME wait for updated worldedit - // Location location = new Location(world, pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - // Block origin = location.getBlock(); - // Material typeBefore = origin.getType(); - // byte dataBefore = origin.getData(); - // // If we're dealing with a sign, store the block state to read the text off - // BlockState stateBefore = null; - // if (typeBefore == Material.SIGN || typeBefore == Material.WALL_SIGN) { - // stateBefore = origin.getState(); - // } - // - // // Check to see if we've broken a sign - // if (Config.isLogging(location.getWorld().getName(), Logging.SIGNTEXT) && (typeBefore == Material.SIGN || typeBefore == Material.WALL_SIGN)) { - // plugin.getConsumer().queueSignBreak(lbActor, (Sign) stateBefore); - // if (block.getType() != Material.AIR.getId()) { - // plugin.getConsumer().queueBlockPlace(lbActor, location, block.getType(), (byte) block.getData()); - // } - // } else { - // if (dataBefore != 0) { - // plugin.getConsumer().queueBlockBreak(lbActor, location, typeBefore, dataBefore); - // if (block.getType() != Material.AIR.getId()) { - // plugin.getConsumer().queueBlockPlace(lbActor, location, block.getType(), (byte) block.getData()); - // } - // } else { - // plugin.getConsumer().queueBlock(lbActor, location, typeBefore, block.getType(), (byte) block.getData()); - // } - // } + Location location = new Location(world, pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + Block origin = location.getBlock(); + Material typeBefore = origin.getType(); + + // Check to see if we've broken a sign + if (Config.isLogging(location.getWorld().getName(), Logging.SIGNTEXT) && (typeBefore == Material.SIGN || typeBefore == Material.WALL_SIGN)) { + BlockState stateBefore = origin.getState(); + plugin.getConsumer().queueSignBreak(lbActor, (Sign) stateBefore); + } else if (!origin.isEmpty()) { + plugin.getConsumer().queueBlockBreak(lbActor, location, origin.getBlockData()); + } + BlockData newBlock = BukkitAdapter.adapt(block); + if (newBlock != null && newBlock.getMaterial() != Material.AIR) { + plugin.getConsumer().queueBlockPlace(lbActor, location, newBlock); + } } }); } From 84270c59c69844a10de26e8d71aa1dd9c49dfe31 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 21 Jul 2018 16:28:37 +0200 Subject: [PATCH 015/399] Update default config --- src/main/java/de/diddiz/LogBlock/Logging.java | 54 +- .../de/diddiz/LogBlock/config/Config.java | 618 +++++++++--------- 2 files changed, 336 insertions(+), 336 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index e042265b..3c4307b2 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -1,27 +1,27 @@ -package de.diddiz.LogBlock; - -public enum Logging { - BLOCKPLACE(true), BLOCKBREAK(true), SIGNTEXT, TNTEXPLOSION(true), CREEPEREXPLOSION(true), - GHASTFIREBALLEXPLOSION(true), ENDERDRAGON(true), MISCEXPLOSION(true), FIRE(true), LEAVESDECAY, - LAVAFLOW, WATERFLOW, CHESTACCESS, KILL, CHAT, SNOWFORM, SNOWFADE, DOORINTERACT, - SWITCHINTERACT, CAKEEAT, ENDERMEN, NOTEBLOCKINTERACT, DIODEINTERACT, COMPARATORINTERACT, - PRESUREPLATEINTERACT, TRIPWIREINTERACT, CREATURECROPTRAMPLE, CROPTRAMPLE, - NATURALSTRUCTUREGROW, GRASSGROWTH, MYCELIUMSPREAD, VINEGROWTH, MUSHROOMSPREAD, - WITHER(true), WITHER_SKULL(true), BONEMEALSTRUCTUREGROW, - WORLDEDIT, TNTMINECARTEXPLOSION(true), LOCKEDCHESTDECAY, ENDERCRYSTALEXPLOSION(true); - - public static final int length = Logging.values().length; - private final boolean defaultEnabled; - - private Logging() { - this(false); - } - - private Logging(boolean defaultEnabled) { - this.defaultEnabled = defaultEnabled; - } - - public boolean isDefaultEnabled() { - return defaultEnabled; - } -} +package de.diddiz.LogBlock; + +public enum Logging { + BLOCKPLACE(true), BLOCKBREAK(true), SIGNTEXT, TNTEXPLOSION(true), CREEPEREXPLOSION(true), + GHASTFIREBALLEXPLOSION(true), ENDERDRAGON(true), MISCEXPLOSION(true), FIRE(true), LEAVESDECAY, + LAVAFLOW, WATERFLOW, CHESTACCESS, KILL, CHAT, SNOWFORM, SNOWFADE, DOORINTERACT, + SWITCHINTERACT, CAKEEAT, ENDERMEN, NOTEBLOCKINTERACT, DIODEINTERACT, COMPARATORINTERACT, + PRESUREPLATEINTERACT, TRIPWIREINTERACT, CREATURECROPTRAMPLE, CROPTRAMPLE, + NATURALSTRUCTUREGROW, GRASSGROWTH, MYCELIUMSPREAD, VINEGROWTH, MUSHROOMSPREAD, + WITHER(true), WITHER_SKULL(true), BONEMEALSTRUCTUREGROW, + WORLDEDIT, TNTMINECARTEXPLOSION(true), ENDERCRYSTALEXPLOSION(true); + + public static final int length = Logging.values().length; + private final boolean defaultEnabled; + + private Logging() { + this(false); + } + + private Logging(boolean defaultEnabled) { + this.defaultEnabled = defaultEnabled; + } + + public boolean isDefaultEnabled() { + return defaultEnabled; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index cc4e4bb4..029f0d43 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -1,309 +1,309 @@ -package de.diddiz.LogBlock.config; - -import de.diddiz.LogBlock.*; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.permissions.PermissionDefault; - -import java.io.File; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.Map.Entry; -import java.util.logging.Level; -import java.util.zip.DataFormatException; - -import static de.diddiz.util.BukkitUtils.friendlyWorldname; -import static de.diddiz.util.Utils.parseTimeSpec; -import static org.bukkit.Bukkit.*; - -public class Config { - private static LoggingEnabledMapping superWorldConfig; - private static Map worldConfigs; - public static String url, user, password; - public static int delayBetweenRuns, forceToProcessAtLeast, timePerRun; - public static boolean fireCustomEvents; - public static boolean useBukkitScheduler; - public static int queueWarningSize; - public static boolean enableAutoClearLog; - public static List autoClearLog; - public static int autoClearLogDelay; - public static boolean dumpDeletedLog; - public static boolean logCreeperExplosionsAsPlayerWhoTriggeredThese, logPlayerInfo; - public static LogKillsLevel logKillsLevel; - public static Set dontRollback, replaceAnyway; - public static int rollbackMaxTime, rollbackMaxArea; - public static Map toolsByName; - public static Map toolsByType; - public static int defaultDist, defaultTime; - public static int linesPerPage, linesLimit; - public static boolean askRollbacks, askRedos, askClearLogs, askClearLogAfterRollback, askRollbackAfterBan; - public static String banPermission; - public static Set hiddenBlocks; - public static Set hiddenPlayers; - public static Set ignoredChat; - public static SimpleDateFormat formatter; - public static boolean safetyIdCheck; - public static boolean debug; - public static boolean logEnvironmentalKills; - // Not loaded from config - checked at runtime - public static boolean mb4 = false; - - public static enum LogKillsLevel { - PLAYERS, MONSTERS, ANIMALS; - } - - public static void load(LogBlock logblock) throws DataFormatException, IOException { - final ConfigurationSection config = logblock.getConfig(); - final Map def = new HashMap(); - def.put("version", logblock.getDescription().getVersion()); - final List worldNames = new ArrayList(); - for (final World world : getWorlds()) { - worldNames.add(world.getName()); - } - if (worldNames.isEmpty()) { - worldNames.add("world"); - worldNames.add("world_nether"); - worldNames.add("world_the_end"); - } - def.put("loggedWorlds", worldNames); - def.put("mysql.host", "localhost"); - def.put("mysql.port", 3306); - def.put("mysql.database", "minecraft"); - def.put("mysql.user", "username"); - def.put("mysql.password", "pass"); - def.put("consumer.delayBetweenRuns", 2); - def.put("consumer.forceToProcessAtLeast", 200); - def.put("consumer.timePerRun", 1000); - def.put("consumer.fireCustomEvents", false); - def.put("consumer.useBukkitScheduler", true); - def.put("consumer.queueWarningSize", 1000); - def.put("clearlog.dumpDeletedLog", false); - def.put("clearlog.enableAutoClearLog", false); - def.put("clearlog.auto", Arrays.asList("world \"world\" before 365 days all", "world \"world\" player lavaflow waterflow leavesdecay before 7 days all", "world world_nether before 365 days all", "world world_nether player lavaflow before 7 days all")); - def.put("clearlog.autoClearLogDelay", "6h"); - def.put("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false); - def.put("logging.logKillsLevel", "PLAYERS"); - def.put("logging.logEnvironmentalKills", false); - def.put("logging.logPlayerInfo", false); - def.put("logging.hiddenPlayers", new ArrayList()); - def.put("logging.hiddenBlocks", Arrays.asList(0)); - def.put("logging.ignoredChat", Arrays.asList("/register", "/login")); - def.put("rollback.dontRollback", Arrays.asList(10, 11, 46, 51)); - def.put("rollback.replaceAnyway", Arrays.asList(8, 9, 10, 11, 51)); - def.put("rollback.maxTime", "2 days"); - def.put("rollback.maxArea", 50); - def.put("lookup.defaultDist", 20); - def.put("lookup.defaultTime", "30 minutes"); - def.put("lookup.linesPerPage", 15); - def.put("lookup.linesLimit", 1500); - try { - formatter = new SimpleDateFormat(config.getString("lookup.dateFormat", "MM-dd HH:mm:ss")); - } catch (IllegalArgumentException e) { - throw new DataFormatException("Invalid specification for date format, please see http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html : " + e.getMessage()); - } - def.put("lookup.dateFormat", "MM-dd HH:mm:ss"); - def.put("questioner.askRollbacks", true); - def.put("questioner.askRedos", true); - def.put("questioner.askClearLogs", true); - def.put("questioner.askClearLogAfterRollback", true); - def.put("questioner.askRollbackAfterBan", false); - def.put("questioner.banPermission", "mcbans.ban.local"); - def.put("tools.tool.aliases", Arrays.asList("t")); - def.put("tools.tool.leftClickBehavior", "NONE"); - def.put("tools.tool.rightClickBehavior", "TOOL"); - def.put("tools.tool.defaultEnabled", true); - def.put("tools.tool.item", 270); - def.put("tools.tool.canDrop", true); - def.put("tools.tool.params", "area 0 all sum none limit 15 desc silent"); - def.put("tools.tool.mode", "LOOKUP"); - def.put("tools.tool.permissionDefault", "OP"); - def.put("tools.toolblock.aliases", Arrays.asList("tb")); - def.put("tools.toolblock.leftClickBehavior", "TOOL"); - def.put("tools.toolblock.rightClickBehavior", "BLOCK"); - def.put("tools.toolblock.defaultEnabled", true); - def.put("tools.toolblock.item", 7); - def.put("tools.toolblock.canDrop", false); - def.put("tools.toolblock.params", "area 0 all sum none limit 15 desc silent"); - def.put("tools.toolblock.mode", "LOOKUP"); - def.put("tools.toolblock.permissionDefault", "OP"); - def.put("safety.id.check", true); - def.put("debug", false); - for (final Entry e : def.entrySet()) { - if (!config.contains(e.getKey())) { - config.set(e.getKey(), e.getValue()); - } - } - logblock.saveConfig(); - url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database"); - user = getStringIncludingInts(config, "mysql.user"); - password = getStringIncludingInts(config, "mysql.password"); - delayBetweenRuns = config.getInt("consumer.delayBetweenRuns", 2); - forceToProcessAtLeast = config.getInt("consumer.forceToProcessAtLeast", 0); - timePerRun = config.getInt("consumer.timePerRun", 1000); - fireCustomEvents = config.getBoolean("consumer.fireCustomEvents", false); - useBukkitScheduler = config.getBoolean("consumer.useBukkitScheduler", true); - queueWarningSize = config.getInt("consumer.queueWarningSize", 1000); - enableAutoClearLog = config.getBoolean("clearlog.enableAutoClearLog"); - autoClearLog = config.getStringList("clearlog.auto"); - dumpDeletedLog = config.getBoolean("clearlog.dumpDeletedLog", false); - autoClearLogDelay = parseTimeSpec(config.getString("clearlog.autoClearLogDelay").split(" ")); - logCreeperExplosionsAsPlayerWhoTriggeredThese = config.getBoolean("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false); - logPlayerInfo = config.getBoolean("logging.logPlayerInfo", true); - try { - logKillsLevel = LogKillsLevel.valueOf(config.getString("logging.logKillsLevel").toUpperCase()); - } catch (final IllegalArgumentException ex) { - throw new DataFormatException("logging.logKillsLevel doesn't appear to be a valid log level. Allowed are 'PLAYERS', 'MONSTERS' and 'ANIMALS'"); - } - logEnvironmentalKills = config.getBoolean("logging.logEnvironmentalKills", false); - hiddenPlayers = new HashSet(); - for (final String playerName : config.getStringList("logging.hiddenPlayers")) { - hiddenPlayers.add(playerName.toLowerCase().trim()); - } - hiddenBlocks = new HashSet(); - for (final String blocktype : config.getStringList("logging.hiddenBlocks")) { - final Material mat = Material.matchMaterial(blocktype); - if (mat != null) { - hiddenBlocks.add(mat); - } else { - throw new DataFormatException("Not a valid material in hiddenBlocks: '" + blocktype + "'"); - } - } - ignoredChat = new HashSet(); - for (String chatCommand : config.getStringList("logging.ignoredChat")) { - ignoredChat.add(chatCommand); - } - dontRollback = new HashSet(); - for (String e : config.getStringList("rollback.dontRollback")) { - Material mat = Material.matchMaterial(e); - if (mat != null) { - dontRollback.add(mat); - } else { - throw new DataFormatException("Not a valid material in dontRollback: '" + e + "'"); - } - } - replaceAnyway = new HashSet(); - for (String e : config.getStringList("rollback.replaceAnyway")) { - Material mat = Material.matchMaterial(e); - if (mat != null) { - replaceAnyway.add(mat); - } else { - throw new DataFormatException("Not a valid material in replaceAnyway: '" + e + "'"); - } - } - rollbackMaxTime = parseTimeSpec(config.getString("rollback.maxTime").split(" ")); - rollbackMaxArea = config.getInt("rollback.maxArea", 50); - defaultDist = config.getInt("lookup.defaultDist", 20); - defaultTime = parseTimeSpec(config.getString("lookup.defaultTime").split(" ")); - linesPerPage = config.getInt("lookup.linesPerPage", 15); - linesLimit = config.getInt("lookup.linesLimit", 1500); - askRollbacks = config.getBoolean("questioner.askRollbacks", true); - askRedos = config.getBoolean("questioner.askRedos", true); - askClearLogs = config.getBoolean("questioner.askClearLogs", true); - askClearLogAfterRollback = config.getBoolean("questioner.askClearLogAfterRollback", true); - askRollbackAfterBan = config.getBoolean("questioner.askRollbackAfterBan", false); - safetyIdCheck = config.getBoolean("safety.id.check", true); - debug = config.getBoolean("debug", false); - banPermission = config.getString("questioner.banPermission"); - final List tools = new ArrayList(); - final ConfigurationSection toolsSec = config.getConfigurationSection("tools"); - for (final String toolName : toolsSec.getKeys(false)) { - try { - final ConfigurationSection tSec = toolsSec.getConfigurationSection(toolName); - final List aliases = tSec.getStringList("aliases"); - final ToolBehavior leftClickBehavior = ToolBehavior.valueOf(tSec.getString("leftClickBehavior").toUpperCase()); - final ToolBehavior rightClickBehavior = ToolBehavior.valueOf(tSec.getString("rightClickBehavior").toUpperCase()); - final boolean defaultEnabled = tSec.getBoolean("defaultEnabled", false); - final Material item = Material.matchMaterial(tSec.getString("item","OAK_LOG")); - final boolean canDrop = tSec.getBoolean("canDrop", false); - final QueryParams params = new QueryParams(logblock); - params.prepareToolQuery = true; - params.parseArgs(getConsoleSender(), Arrays.asList(tSec.getString("params").split(" "))); - final ToolMode mode = ToolMode.valueOf(tSec.getString("mode").toUpperCase()); - final PermissionDefault pdef = PermissionDefault.valueOf(tSec.getString("permissionDefault").toUpperCase()); - tools.add(new Tool(toolName, aliases, leftClickBehavior, rightClickBehavior, defaultEnabled, item, canDrop, params, mode, pdef)); - } catch (final Exception ex) { - getLogger().log(Level.WARNING, "Error at parsing tool '" + toolName + "': ", ex); - } - } - toolsByName = new HashMap(); - toolsByType = new HashMap(); - for (final Tool tool : tools) { - toolsByType.put(tool.item, tool); - toolsByName.put(tool.name.toLowerCase(), tool); - for (final String alias : tool.aliases) { - toolsByName.put(alias, tool); - } - } - final List loggedWorlds = config.getStringList("loggedWorlds"); - worldConfigs = new HashMap(); - if (loggedWorlds.isEmpty()) { - throw new DataFormatException("No worlds configured"); - } - for (final String world : loggedWorlds) { - worldConfigs.put(world, new WorldConfig(new File(logblock.getDataFolder(), friendlyWorldname(world) + ".yml"))); - } - superWorldConfig = new LoggingEnabledMapping(); - for (final WorldConfig wcfg : worldConfigs.values()) { - for (final Logging l : Logging.values()) { - if (wcfg.isLogging(l)) { - superWorldConfig.setLogging(l, true); - } - } - } - } - - private static String getStringIncludingInts(ConfigurationSection cfg, String key) { - String str = cfg.getString(key); - if (str == null) { - str = String.valueOf(cfg.getInt(key)); - } - if (str == null) { - str = "No value set for '" + key + "'"; - } - return str; - } - - public static boolean isLogging(World world, Logging l) { - final WorldConfig wcfg = worldConfigs.get(world.getName()); - return wcfg != null && wcfg.isLogging(l); - } - - public static boolean isLogging(String worldName, Logging l) { - final WorldConfig wcfg = worldConfigs.get(worldName); - return wcfg != null && wcfg.isLogging(l); - } - - public static boolean isLogged(World world) { - return worldConfigs.containsKey(world.getName()); - } - - public static WorldConfig getWorldConfig(World world) { - return worldConfigs.get(world.getName()); - } - - public static WorldConfig getWorldConfig(String world) { - return worldConfigs.get(world); - } - - public static boolean isLogging(Logging l) { - return superWorldConfig.isLogging(l); - } - - public static Collection getLoggedWorlds() { - return worldConfigs.values(); - } -} - -class LoggingEnabledMapping { - private final boolean[] logging = new boolean[Logging.length]; - - public void setLogging(Logging l, boolean enabled) { - logging[l.ordinal()] = enabled; - } - - public boolean isLogging(Logging l) { - return logging[l.ordinal()]; - } -} +package de.diddiz.LogBlock.config; + +import de.diddiz.LogBlock.*; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.permissions.PermissionDefault; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.Map.Entry; +import java.util.logging.Level; +import java.util.zip.DataFormatException; + +import static de.diddiz.util.BukkitUtils.friendlyWorldname; +import static de.diddiz.util.Utils.parseTimeSpec; +import static org.bukkit.Bukkit.*; + +public class Config { + private static LoggingEnabledMapping superWorldConfig; + private static Map worldConfigs; + public static String url, user, password; + public static int delayBetweenRuns, forceToProcessAtLeast, timePerRun; + public static boolean fireCustomEvents; + public static boolean useBukkitScheduler; + public static int queueWarningSize; + public static boolean enableAutoClearLog; + public static List autoClearLog; + public static int autoClearLogDelay; + public static boolean dumpDeletedLog; + public static boolean logCreeperExplosionsAsPlayerWhoTriggeredThese, logPlayerInfo; + public static LogKillsLevel logKillsLevel; + public static Set dontRollback, replaceAnyway; + public static int rollbackMaxTime, rollbackMaxArea; + public static Map toolsByName; + public static Map toolsByType; + public static int defaultDist, defaultTime; + public static int linesPerPage, linesLimit; + public static boolean askRollbacks, askRedos, askClearLogs, askClearLogAfterRollback, askRollbackAfterBan; + public static String banPermission; + public static Set hiddenBlocks; + public static Set hiddenPlayers; + public static Set ignoredChat; + public static SimpleDateFormat formatter; + public static boolean safetyIdCheck; + public static boolean debug; + public static boolean logEnvironmentalKills; + // Not loaded from config - checked at runtime + public static boolean mb4 = false; + + public static enum LogKillsLevel { + PLAYERS, MONSTERS, ANIMALS; + } + + public static void load(LogBlock logblock) throws DataFormatException, IOException { + final ConfigurationSection config = logblock.getConfig(); + final Map def = new HashMap(); + def.put("version", logblock.getDescription().getVersion()); + final List worldNames = new ArrayList(); + for (final World world : getWorlds()) { + worldNames.add(world.getName()); + } + if (worldNames.isEmpty()) { + worldNames.add("world"); + worldNames.add("world_nether"); + worldNames.add("world_the_end"); + } + def.put("loggedWorlds", worldNames); + def.put("mysql.host", "localhost"); + def.put("mysql.port", 3306); + def.put("mysql.database", "minecraft"); + def.put("mysql.user", "username"); + def.put("mysql.password", "pass"); + def.put("consumer.delayBetweenRuns", 2); + def.put("consumer.forceToProcessAtLeast", 200); + def.put("consumer.timePerRun", 1000); + def.put("consumer.fireCustomEvents", false); + def.put("consumer.useBukkitScheduler", true); + def.put("consumer.queueWarningSize", 1000); + def.put("clearlog.dumpDeletedLog", false); + def.put("clearlog.enableAutoClearLog", false); + def.put("clearlog.auto", Arrays.asList("world \"world\" before 365 days all", "world \"world\" player lavaflow waterflow leavesdecay before 7 days all", "world world_nether before 365 days all", "world world_nether player lavaflow before 7 days all")); + def.put("clearlog.autoClearLogDelay", "6h"); + def.put("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false); + def.put("logging.logKillsLevel", "PLAYERS"); + def.put("logging.logEnvironmentalKills", false); + def.put("logging.logPlayerInfo", false); + def.put("logging.hiddenPlayers", new ArrayList()); + def.put("logging.hiddenBlocks", Arrays.asList(Material.AIR.name())); + def.put("logging.ignoredChat", Arrays.asList("/register", "/login")); + def.put("rollback.dontRollback", Arrays.asList(Material.LAVA.name(), Material.TNT.name(), Material.FIRE.name())); + def.put("rollback.replaceAnyway", Arrays.asList(Material.LAVA.name(), Material.WATER.name(), Material.FIRE.name())); + def.put("rollback.maxTime", "2 days"); + def.put("rollback.maxArea", 50); + def.put("lookup.defaultDist", 20); + def.put("lookup.defaultTime", "30 minutes"); + def.put("lookup.linesPerPage", 15); + def.put("lookup.linesLimit", 1500); + try { + formatter = new SimpleDateFormat(config.getString("lookup.dateFormat", "MM-dd HH:mm:ss")); + } catch (IllegalArgumentException e) { + throw new DataFormatException("Invalid specification for date format, please see http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html : " + e.getMessage()); + } + def.put("lookup.dateFormat", "MM-dd HH:mm:ss"); + def.put("questioner.askRollbacks", true); + def.put("questioner.askRedos", true); + def.put("questioner.askClearLogs", true); + def.put("questioner.askClearLogAfterRollback", true); + def.put("questioner.askRollbackAfterBan", false); + def.put("questioner.banPermission", "mcbans.ban.local"); + def.put("tools.tool.aliases", Arrays.asList("t")); + def.put("tools.tool.leftClickBehavior", "NONE"); + def.put("tools.tool.rightClickBehavior", "TOOL"); + def.put("tools.tool.defaultEnabled", true); + def.put("tools.tool.item", Material.WOODEN_PICKAXE.name()); + def.put("tools.tool.canDrop", true); + def.put("tools.tool.params", "area 0 all sum none limit 15 desc silent"); + def.put("tools.tool.mode", "LOOKUP"); + def.put("tools.tool.permissionDefault", "OP"); + def.put("tools.toolblock.aliases", Arrays.asList("tb")); + def.put("tools.toolblock.leftClickBehavior", "TOOL"); + def.put("tools.toolblock.rightClickBehavior", "BLOCK"); + def.put("tools.toolblock.defaultEnabled", true); + def.put("tools.toolblock.item", Material.BEDROCK.name()); + def.put("tools.toolblock.canDrop", false); + def.put("tools.toolblock.params", "area 0 all sum none limit 15 desc silent"); + def.put("tools.toolblock.mode", "LOOKUP"); + def.put("tools.toolblock.permissionDefault", "OP"); + def.put("safety.id.check", true); + def.put("debug", false); + for (final Entry e : def.entrySet()) { + if (!config.contains(e.getKey())) { + config.set(e.getKey(), e.getValue()); + } + } + logblock.saveConfig(); + url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database"); + user = getStringIncludingInts(config, "mysql.user"); + password = getStringIncludingInts(config, "mysql.password"); + delayBetweenRuns = config.getInt("consumer.delayBetweenRuns", 2); + forceToProcessAtLeast = config.getInt("consumer.forceToProcessAtLeast", 0); + timePerRun = config.getInt("consumer.timePerRun", 1000); + fireCustomEvents = config.getBoolean("consumer.fireCustomEvents", false); + useBukkitScheduler = config.getBoolean("consumer.useBukkitScheduler", true); + queueWarningSize = config.getInt("consumer.queueWarningSize", 1000); + enableAutoClearLog = config.getBoolean("clearlog.enableAutoClearLog"); + autoClearLog = config.getStringList("clearlog.auto"); + dumpDeletedLog = config.getBoolean("clearlog.dumpDeletedLog", false); + autoClearLogDelay = parseTimeSpec(config.getString("clearlog.autoClearLogDelay").split(" ")); + logCreeperExplosionsAsPlayerWhoTriggeredThese = config.getBoolean("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false); + logPlayerInfo = config.getBoolean("logging.logPlayerInfo", true); + try { + logKillsLevel = LogKillsLevel.valueOf(config.getString("logging.logKillsLevel").toUpperCase()); + } catch (final IllegalArgumentException ex) { + throw new DataFormatException("logging.logKillsLevel doesn't appear to be a valid log level. Allowed are 'PLAYERS', 'MONSTERS' and 'ANIMALS'"); + } + logEnvironmentalKills = config.getBoolean("logging.logEnvironmentalKills", false); + hiddenPlayers = new HashSet(); + for (final String playerName : config.getStringList("logging.hiddenPlayers")) { + hiddenPlayers.add(playerName.toLowerCase().trim()); + } + hiddenBlocks = new HashSet(); + for (final String blocktype : config.getStringList("logging.hiddenBlocks")) { + final Material mat = Material.matchMaterial(blocktype); + if (mat != null) { + hiddenBlocks.add(mat); + } else { + throw new DataFormatException("Not a valid material in hiddenBlocks: '" + blocktype + "'"); + } + } + ignoredChat = new HashSet(); + for (String chatCommand : config.getStringList("logging.ignoredChat")) { + ignoredChat.add(chatCommand); + } + dontRollback = new HashSet(); + for (String e : config.getStringList("rollback.dontRollback")) { + Material mat = Material.matchMaterial(e); + if (mat != null) { + dontRollback.add(mat); + } else { + throw new DataFormatException("Not a valid material in dontRollback: '" + e + "'"); + } + } + replaceAnyway = new HashSet(); + for (String e : config.getStringList("rollback.replaceAnyway")) { + Material mat = Material.matchMaterial(e); + if (mat != null) { + replaceAnyway.add(mat); + } else { + throw new DataFormatException("Not a valid material in replaceAnyway: '" + e + "'"); + } + } + rollbackMaxTime = parseTimeSpec(config.getString("rollback.maxTime").split(" ")); + rollbackMaxArea = config.getInt("rollback.maxArea", 50); + defaultDist = config.getInt("lookup.defaultDist", 20); + defaultTime = parseTimeSpec(config.getString("lookup.defaultTime").split(" ")); + linesPerPage = config.getInt("lookup.linesPerPage", 15); + linesLimit = config.getInt("lookup.linesLimit", 1500); + askRollbacks = config.getBoolean("questioner.askRollbacks", true); + askRedos = config.getBoolean("questioner.askRedos", true); + askClearLogs = config.getBoolean("questioner.askClearLogs", true); + askClearLogAfterRollback = config.getBoolean("questioner.askClearLogAfterRollback", true); + askRollbackAfterBan = config.getBoolean("questioner.askRollbackAfterBan", false); + safetyIdCheck = config.getBoolean("safety.id.check", true); + debug = config.getBoolean("debug", false); + banPermission = config.getString("questioner.banPermission"); + final List tools = new ArrayList(); + final ConfigurationSection toolsSec = config.getConfigurationSection("tools"); + for (final String toolName : toolsSec.getKeys(false)) { + try { + final ConfigurationSection tSec = toolsSec.getConfigurationSection(toolName); + final List aliases = tSec.getStringList("aliases"); + final ToolBehavior leftClickBehavior = ToolBehavior.valueOf(tSec.getString("leftClickBehavior").toUpperCase()); + final ToolBehavior rightClickBehavior = ToolBehavior.valueOf(tSec.getString("rightClickBehavior").toUpperCase()); + final boolean defaultEnabled = tSec.getBoolean("defaultEnabled", false); + final Material item = Material.matchMaterial(tSec.getString("item","OAK_LOG")); + final boolean canDrop = tSec.getBoolean("canDrop", false); + final QueryParams params = new QueryParams(logblock); + params.prepareToolQuery = true; + params.parseArgs(getConsoleSender(), Arrays.asList(tSec.getString("params").split(" "))); + final ToolMode mode = ToolMode.valueOf(tSec.getString("mode").toUpperCase()); + final PermissionDefault pdef = PermissionDefault.valueOf(tSec.getString("permissionDefault").toUpperCase()); + tools.add(new Tool(toolName, aliases, leftClickBehavior, rightClickBehavior, defaultEnabled, item, canDrop, params, mode, pdef)); + } catch (final Exception ex) { + getLogger().log(Level.WARNING, "Error at parsing tool '" + toolName + "': ", ex); + } + } + toolsByName = new HashMap(); + toolsByType = new HashMap(); + for (final Tool tool : tools) { + toolsByType.put(tool.item, tool); + toolsByName.put(tool.name.toLowerCase(), tool); + for (final String alias : tool.aliases) { + toolsByName.put(alias, tool); + } + } + final List loggedWorlds = config.getStringList("loggedWorlds"); + worldConfigs = new HashMap(); + if (loggedWorlds.isEmpty()) { + throw new DataFormatException("No worlds configured"); + } + for (final String world : loggedWorlds) { + worldConfigs.put(world, new WorldConfig(new File(logblock.getDataFolder(), friendlyWorldname(world) + ".yml"))); + } + superWorldConfig = new LoggingEnabledMapping(); + for (final WorldConfig wcfg : worldConfigs.values()) { + for (final Logging l : Logging.values()) { + if (wcfg.isLogging(l)) { + superWorldConfig.setLogging(l, true); + } + } + } + } + + private static String getStringIncludingInts(ConfigurationSection cfg, String key) { + String str = cfg.getString(key); + if (str == null) { + str = String.valueOf(cfg.getInt(key)); + } + if (str == null) { + str = "No value set for '" + key + "'"; + } + return str; + } + + public static boolean isLogging(World world, Logging l) { + final WorldConfig wcfg = worldConfigs.get(world.getName()); + return wcfg != null && wcfg.isLogging(l); + } + + public static boolean isLogging(String worldName, Logging l) { + final WorldConfig wcfg = worldConfigs.get(worldName); + return wcfg != null && wcfg.isLogging(l); + } + + public static boolean isLogged(World world) { + return worldConfigs.containsKey(world.getName()); + } + + public static WorldConfig getWorldConfig(World world) { + return worldConfigs.get(world.getName()); + } + + public static WorldConfig getWorldConfig(String world) { + return worldConfigs.get(world); + } + + public static boolean isLogging(Logging l) { + return superWorldConfig.isLogging(l); + } + + public static Collection getLoggedWorlds() { + return worldConfigs.values(); + } +} + +class LoggingEnabledMapping { + private final boolean[] logging = new boolean[Logging.length]; + + public void setLogging(Logging l, boolean enabled) { + logging[l.ordinal()] = enabled; + } + + public boolean isLogging(Logging l) { + return logging[l.ordinal()]; + } +} From d1d16a6246ffc64ca0bb99c5a18759d992f7b846 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 24 Jul 2018 13:08:52 +0200 Subject: [PATCH 016/399] Update from 1.13-pre7 to 1.13 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3ef50443..377a84b7 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ org.spigotmc spigot-api - 1.13-pre7-R0.1-SNAPSHOT + 1.13-R0.1-SNAPSHOT provided From 8f18af2252cdb67b3f357628930c5be12e11cbcf Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 24 Jul 2018 19:16:04 +0200 Subject: [PATCH 017/399] Convert old blockchange logs --- pom.xml | 4 +- .../de/diddiz/LogBlock/CommandsHandler.java | 4 +- .../java/de/diddiz/LogBlock/LogBlock.java | 14 +- src/main/java/de/diddiz/LogBlock/Updater.java | 136 + src/main/resources/blockdata.txt | 2357 +++++++++++++++++ 5 files changed, 2507 insertions(+), 8 deletions(-) create mode 100644 src/main/resources/blockdata.txt diff --git a/pom.xml b/pom.xml index 377a84b7..8c68d114 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.12-SNAPSHOT + 1.13-SNAPSHOT jar LogBlock @@ -133,7 +133,7 @@ true - ${project.basedir}/src/main/resources + src/main/resources diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 4fca25d4..6ae53cf0 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -674,7 +674,7 @@ public void run() { if (stack != null) { chestaccess = new ChestAccess(stack, rs.getBoolean("itemremove")); } - editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getInt("type"), rs.getByte("typeData"), rs.getString("signtext"), chestaccess); + editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getInt("type"), rs.getInt("typeData"), rs.getString("signtext"), chestaccess); } final int changes = editor.getSize(); if (changes > 10000) { @@ -749,7 +749,7 @@ public void run() { if (stack != null) { chestaccess = new ChestAccess(stack, !rs.getBoolean("itemremove")); } - editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getInt("replaced"), rs.getByte("replacedData"), rs.getString("signtext"), chestaccess); + editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getString("signtext"), chestaccess); } final int changes = editor.getSize(); if (!params.silent) { diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 2567c198..07e88358 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -14,6 +14,7 @@ import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; +import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.sql.Connection; @@ -56,6 +57,7 @@ Updater getUpdater() { @Override public void onLoad() { logblock = this; + consumer = new Consumer(this); try { updater = new Updater(this); Config.load(this); @@ -74,11 +76,12 @@ public void onLoad() { st.executeQuery("SET NAMES utf8mb4;"); } conn.close(); + updater.checkTables(); + MaterialConverter.initializeMaterials(getConnection()); + MaterialConverter.getOrAddMaterialId(Material.AIR.getKey()); // AIR must be the first entry if (updater.update()) { load(this); } - updater.checkTables(); - MaterialConverter.initializeMaterials(getConnection()); } catch (final NullPointerException ex) { getLogger().log(Level.SEVERE, "Error while loading: ", ex); } catch (final Exception ex) { @@ -86,12 +89,10 @@ public void onLoad() { errorAtLoading = true; return; } - consumer = new Consumer(this); } @Override public void onEnable() { - MaterialConverter.getOrAddMaterialId(Material.AIR.getKey()); // AIR must be the first entry BukkitUtils.isDoublePlant(Material.AIR); // Force static code to run final PluginManager pm = getPluginManager(); if (errorAtLoading) { @@ -333,4 +334,9 @@ public int getCount(QueryParams params) throws SQLException { conn.close(); } } + + @Override + public File getFile() { + return super.getFile(); + } } diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index b0950ffe..fe8fa3c5 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -4,13 +4,18 @@ import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.util.UUIDFetcher; import org.bukkit.Bukkit; +import org.bukkit.block.data.BlockData; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; +import java.io.BufferedInputStream; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStreamReader; import java.sql.*; import java.util.*; +import java.util.jar.JarFile; import java.util.logging.Level; import static de.diddiz.LogBlock.config.Config.getLoggedWorlds; @@ -405,6 +410,100 @@ boolean update() { } config.set("version", "1.12.0"); } + if (configVersion.compareTo(new ComparableVersion("1.13.0")) < 0) { + getLogger().info("Updating tables to 1.13.0 ..."); + try { + MaterialUpdater materialUpdater = null; + checkTables(); // we need to create the tables first + getLogger().info("Convertig BlockId to BlockData. This can take a while ..."); + final Connection conn = logblock.getConnection(); + conn.setAutoCommit(false); + final Statement st = conn.createStatement(); + for (final WorldConfig wcfg : getLoggedWorlds()) { + boolean hadRow = true; + int rowsToConvert = 0; + int done = 0; + try { + ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "`"); + if (rs.next()) { + rowsToConvert = rs.getInt(1); + getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table); + } + } catch (SQLException e) { + getLogger().info("Could not convert " + wcfg.table + ": " + e.getMessage()); + continue; + } + + PreparedStatement deleteStatement = conn.prepareStatement("DELETE FROM `" + wcfg.table + "` WHERE id = ?"); + PreparedStatement insertStatement = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-blocks` (id, date, playerid, replaced, replacedData, type, typeData, x, y, z) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); + + while (hadRow) { + hadRow = false; + ResultSet entries = st.executeQuery("SELECT id, date, playerid, replaced, type, data, x, y, z FROM `" + wcfg.table + "` ORDER BY id ASC LIMIT 10000"); + while (entries.next()) { + hadRow = true; + int id = entries.getInt("id"); + Timestamp date = entries.getTimestamp("date"); + int playerid = entries.getInt("playerid"); + int replaced = entries.getInt("replaced"); + int type = entries.getInt("type"); + int data = entries.getInt("data"); + int x = entries.getInt("x"); + int y = entries.getInt("y"); + int z = entries.getInt("z"); + if (data == 16) { + data = 0; + } + + if (materialUpdater == null) { + materialUpdater = new MaterialUpdater(logblock); + } + try { + String replacedBlockData = materialUpdater.getBlockData(replaced, data).getAsString(); + String setBlockData = materialUpdater.getBlockData(type, data).getAsString(); + + int newReplacedId = MaterialConverter.getOrAddMaterialId(replacedBlockData); + int newReplacedData = MaterialConverter.getOrAddBlockStateId(replacedBlockData); + + int newSetId = MaterialConverter.getOrAddMaterialId(setBlockData); + int newSetData = MaterialConverter.getOrAddBlockStateId(setBlockData); + + insertStatement.setInt(1, id); + insertStatement.setTimestamp(2, date); + insertStatement.setInt(3, playerid); + insertStatement.setInt(4, newReplacedId); + insertStatement.setInt(5, newReplacedData); + insertStatement.setInt(6, newSetId); + insertStatement.setInt(7, newSetData); + insertStatement.setInt(8, x); + insertStatement.setInt(9, y); + insertStatement.setInt(10, z); + insertStatement.addBatch(); + } catch (Exception e) { + getLogger().info("Exception in entry " + id + " (" + replaced + ":" + data + "->" + type + ":" + data + "): " + e.getMessage()); + } + deleteStatement.setInt(1, id); + deleteStatement.addBatch(); + + done++; + } + if (hadRow) { + insertStatement.executeBatch(); + deleteStatement.executeBatch(); + } + conn.commit(); + logblock.getConsumer().run(); // force a consumer run + getLogger().info(done + "/" + rowsToConvert); + } + } + st.close(); + conn.close(); + } catch (final SQLException | IOException ex) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.13.0"); + } logblock.saveConfig(); return true; @@ -497,4 +596,41 @@ public void run() { } } } + + public static class MaterialUpdater { + BlockData[][] blockDataMapping; + public MaterialUpdater(LogBlock plugin) throws IOException { + blockDataMapping = new BlockData[256][16]; + JarFile file = new JarFile(plugin.getFile()); + BufferedReader reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(file.getInputStream(file.getJarEntry("blockdata.txt"))), "UTF-8")); + while (true) { + String line = reader.readLine(); + if (line == null) { + break; + } + int splitter1 = line.indexOf(":"); + int splitter2 = line.indexOf(","); + if (splitter1 >= 0 && splitter2 >= 0) { + int blockid = Integer.parseInt(line.substring(0, splitter1)); + int blockdata = Integer.parseInt(line.substring(splitter1 + 1, splitter2)); + BlockData newBlockData = Bukkit.createBlockData(line.substring(splitter2 + 1)); + + if (blockdata == 0) { + for (int i = 0; i < 16; i++) { + if (blockDataMapping[blockid][i] == null) { + blockDataMapping[blockid][i] = newBlockData; + } + } + } else { + blockDataMapping[blockid][blockdata] = newBlockData; + } + } + } + file.close(); + } + + public BlockData getBlockData(int id, int data) { + return id >= 0 && id < 256 && data >= 0 && data < 16 ? blockDataMapping[id][data] : null; + } + } } diff --git a/src/main/resources/blockdata.txt b/src/main/resources/blockdata.txt new file mode 100644 index 00000000..8f943138 --- /dev/null +++ b/src/main/resources/blockdata.txt @@ -0,0 +1,2357 @@ +0:0,minecraft:air +1:0,minecraft:stone +1:1,minecraft:granite +1:2,minecraft:polished_granite +1:3,minecraft:diorite +1:4,minecraft:polished_diorite +1:5,minecraft:andesite +1:6,minecraft:polished_andesite +2:0,minecraft:grass_block[snowy=false] +3:0,minecraft:dirt +3:1,minecraft:coarse_dirt +3:2,minecraft:podzol[snowy=false] +4:0,minecraft:cobblestone +5:0,minecraft:oak_planks +5:1,minecraft:spruce_planks +5:2,minecraft:birch_planks +5:3,minecraft:jungle_planks +5:4,minecraft:acacia_planks +5:5,minecraft:dark_oak_planks +6:0,minecraft:oak_sapling[stage=0] +6:1,minecraft:spruce_sapling[stage=0] +6:2,minecraft:birch_sapling[stage=0] +6:3,minecraft:jungle_sapling[stage=0] +6:4,minecraft:acacia_sapling[stage=0] +6:5,minecraft:dark_oak_sapling[stage=0] +6:8,minecraft:oak_sapling[stage=1] +6:9,minecraft:spruce_sapling[stage=1] +6:10,minecraft:birch_sapling[stage=1] +6:11,minecraft:jungle_sapling[stage=1] +6:12,minecraft:acacia_sapling[stage=1] +6:13,minecraft:dark_oak_sapling[stage=1] +6:14,minecraft:oak_sapling[stage=1] +6:15,minecraft:oak_sapling[stage=1] +7:0,minecraft:bedrock +8:0,minecraft:water[level=0] +8:1,minecraft:water[level=1] +8:2,minecraft:water[level=2] +8:3,minecraft:water[level=3] +8:4,minecraft:water[level=4] +8:5,minecraft:water[level=5] +8:6,minecraft:water[level=6] +8:7,minecraft:water[level=7] +8:8,minecraft:water[level=8] +8:9,minecraft:water[level=9] +8:10,minecraft:water[level=10] +8:11,minecraft:water[level=11] +8:12,minecraft:water[level=12] +8:13,minecraft:water[level=13] +8:14,minecraft:water[level=14] +8:15,minecraft:water[level=15] +9:0,minecraft:water[level=0] +9:1,minecraft:water[level=1] +9:2,minecraft:water[level=2] +9:3,minecraft:water[level=3] +9:4,minecraft:water[level=4] +9:5,minecraft:water[level=5] +9:6,minecraft:water[level=6] +9:7,minecraft:water[level=7] +9:8,minecraft:water[level=8] +9:9,minecraft:water[level=9] +9:10,minecraft:water[level=10] +9:11,minecraft:water[level=11] +9:12,minecraft:water[level=12] +9:13,minecraft:water[level=13] +9:14,minecraft:water[level=14] +9:15,minecraft:water[level=15] +10:0,minecraft:lava[level=0] +10:1,minecraft:lava[level=1] +10:2,minecraft:lava[level=2] +10:3,minecraft:lava[level=3] +10:4,minecraft:lava[level=4] +10:5,minecraft:lava[level=5] +10:6,minecraft:lava[level=6] +10:7,minecraft:lava[level=7] +10:8,minecraft:lava[level=8] +10:9,minecraft:lava[level=9] +10:10,minecraft:lava[level=10] +10:11,minecraft:lava[level=11] +10:12,minecraft:lava[level=12] +10:13,minecraft:lava[level=13] +10:14,minecraft:lava[level=14] +10:15,minecraft:lava[level=15] +11:0,minecraft:lava[level=0] +11:1,minecraft:lava[level=1] +11:2,minecraft:lava[level=2] +11:3,minecraft:lava[level=3] +11:4,minecraft:lava[level=4] +11:5,minecraft:lava[level=5] +11:6,minecraft:lava[level=6] +11:7,minecraft:lava[level=7] +11:8,minecraft:lava[level=8] +11:9,minecraft:lava[level=9] +11:10,minecraft:lava[level=10] +11:11,minecraft:lava[level=11] +11:12,minecraft:lava[level=12] +11:13,minecraft:lava[level=13] +11:14,minecraft:lava[level=14] +11:15,minecraft:lava[level=15] +12:0,minecraft:sand +12:1,minecraft:red_sand +13:0,minecraft:gravel +14:0,minecraft:gold_ore +15:0,minecraft:iron_ore +16:0,minecraft:coal_ore +17:0,minecraft:oak_log[axis=y] +17:1,minecraft:spruce_log[axis=y] +17:2,minecraft:birch_log[axis=y] +17:3,minecraft:jungle_log[axis=y] +17:4,minecraft:oak_log[axis=x] +17:5,minecraft:spruce_log[axis=x] +17:6,minecraft:birch_log[axis=x] +17:7,minecraft:jungle_log[axis=x] +17:8,minecraft:oak_log[axis=z] +17:9,minecraft:spruce_log[axis=z] +17:10,minecraft:birch_log[axis=z] +17:11,minecraft:jungle_log[axis=z] +17:12,minecraft:oak_wood[axis=y] +17:13,minecraft:spruce_wood[axis=y] +17:14,minecraft:birch_wood[axis=y] +17:15,minecraft:jungle_wood[axis=y] +18:0,minecraft:oak_leaves[distance=7,persistent=false] +18:1,minecraft:spruce_leaves[distance=7,persistent=false] +18:2,minecraft:birch_leaves[distance=7,persistent=false] +18:3,minecraft:jungle_leaves[distance=7,persistent=false] +18:4,minecraft:oak_leaves[distance=7,persistent=true] +18:5,minecraft:spruce_leaves[distance=7,persistent=true] +18:6,minecraft:birch_leaves[distance=7,persistent=true] +18:7,minecraft:jungle_leaves[distance=7,persistent=true] +18:9,minecraft:spruce_leaves[distance=7,persistent=false] +18:10,minecraft:birch_leaves[distance=7,persistent=false] +18:11,minecraft:jungle_leaves[distance=7,persistent=false] +18:12,minecraft:oak_leaves[distance=7,persistent=true] +18:13,minecraft:spruce_leaves[distance=7,persistent=true] +18:14,minecraft:birch_leaves[distance=7,persistent=true] +18:15,minecraft:jungle_leaves[distance=7,persistent=true] +19:0,minecraft:sponge +19:1,minecraft:wet_sponge +19:3,minecraft:wet_sponge +19:5,minecraft:wet_sponge +19:7,minecraft:wet_sponge +19:9,minecraft:wet_sponge +19:11,minecraft:wet_sponge +19:13,minecraft:wet_sponge +19:15,minecraft:wet_sponge +20:0,minecraft:glass +21:0,minecraft:lapis_ore +22:0,minecraft:lapis_block +23:0,minecraft:dispenser[facing=down,triggered=false] +23:1,minecraft:dispenser[facing=up,triggered=false] +23:2,minecraft:dispenser[facing=north,triggered=false] +23:3,minecraft:dispenser[facing=south,triggered=false] +23:4,minecraft:dispenser[facing=west,triggered=false] +23:5,minecraft:dispenser[facing=east,triggered=false] +23:7,minecraft:dispenser[facing=up,triggered=false] +23:8,minecraft:dispenser[facing=down,triggered=true] +23:9,minecraft:dispenser[facing=up,triggered=true] +23:10,minecraft:dispenser[facing=north,triggered=true] +23:11,minecraft:dispenser[facing=south,triggered=true] +23:12,minecraft:dispenser[facing=west,triggered=true] +23:13,minecraft:dispenser[facing=east,triggered=true] +23:14,minecraft:dispenser[facing=down,triggered=true] +23:15,minecraft:dispenser[facing=up,triggered=true] +24:0,minecraft:sandstone +24:1,minecraft:chiseled_sandstone +24:2,minecraft:cut_sandstone +25:0,minecraft:note_block[instrument=harp,note=0,powered=false] +26:0,minecraft:red_bed[facing=south,occupied=false,part=foot] +26:1,minecraft:red_bed[facing=west,occupied=false,part=foot] +26:2,minecraft:red_bed[facing=north,occupied=false,part=foot] +26:3,minecraft:red_bed[facing=east,occupied=false,part=foot] +26:5,minecraft:red_bed[facing=west,occupied=false,part=foot] +26:6,minecraft:red_bed[facing=north,occupied=false,part=foot] +26:7,minecraft:red_bed[facing=east,occupied=false,part=foot] +26:8,minecraft:red_bed[facing=south,occupied=false,part=head] +26:9,minecraft:red_bed[facing=west,occupied=false,part=head] +26:10,minecraft:red_bed[facing=north,occupied=false,part=head] +26:11,minecraft:red_bed[facing=east,occupied=false,part=head] +26:12,minecraft:red_bed[facing=south,occupied=true,part=head] +26:13,minecraft:red_bed[facing=west,occupied=true,part=head] +26:14,minecraft:red_bed[facing=north,occupied=true,part=head] +26:15,minecraft:red_bed[facing=east,occupied=true,part=head] +27:0,minecraft:powered_rail[powered=false,shape=north_south] +27:6,minecraft:air +27:7,minecraft:air +27:14,minecraft:air +27:15,minecraft:air +28:0,minecraft:detector_rail[powered=false,shape=north_south] +28:6,minecraft:air +28:7,minecraft:air +28:9,minecraft:detector_rail[powered=false,shape=east_west] +28:10,minecraft:detector_rail[powered=false,shape=ascending_east] +28:11,minecraft:detector_rail[powered=false,shape=ascending_west] +28:12,minecraft:detector_rail[powered=false,shape=ascending_north] +28:13,minecraft:detector_rail[powered=false,shape=ascending_south] +28:14,minecraft:air +28:15,minecraft:air +29:0,minecraft:sticky_piston[extended=false,facing=down] +29:1,minecraft:sticky_piston[extended=false,facing=up] +29:2,minecraft:sticky_piston[extended=false,facing=north] +29:3,minecraft:sticky_piston[extended=false,facing=south] +29:4,minecraft:sticky_piston[extended=false,facing=west] +29:5,minecraft:sticky_piston[extended=false,facing=east] +29:6,minecraft:air +29:7,minecraft:air +29:8,minecraft:moving_piston[facing=down,type=sticky] +29:9,minecraft:moving_piston[facing=up,type=sticky] +29:10,minecraft:moving_piston[facing=north,type=sticky] +29:11,minecraft:moving_piston[facing=south,type=sticky] +29:12,minecraft:moving_piston[facing=west,type=sticky] +29:13,minecraft:moving_piston[facing=east,type=sticky] +29:14,minecraft:air +29:15,minecraft:air +30:0,minecraft:cobweb +31:0,minecraft:dead_bush +31:1,minecraft:grass +31:2,minecraft:fern +32:0,minecraft:dead_bush +33:0,minecraft:piston[extended=false,facing=down] +33:1,minecraft:piston[extended=false,facing=up] +33:2,minecraft:piston[extended=false,facing=north] +33:3,minecraft:piston[extended=false,facing=south] +33:4,minecraft:piston[extended=false,facing=west] +33:5,minecraft:piston[extended=false,facing=east] +33:6,minecraft:air +33:7,minecraft:air +33:8,minecraft:moving_piston[facing=down,type=normal] +33:9,minecraft:moving_piston[facing=up,type=normal] +33:10,minecraft:moving_piston[facing=north,type=normal] +33:11,minecraft:moving_piston[facing=south,type=normal] +33:12,minecraft:moving_piston[facing=west,type=normal] +33:13,minecraft:moving_piston[facing=east,type=normal] +33:14,minecraft:air +33:15,minecraft:air +34:0,minecraft:piston_head[facing=down,short=false,type=normal] +34:1,minecraft:piston_head[facing=up,short=false,type=normal] +34:2,minecraft:piston_head[facing=north,short=false,type=normal] +34:3,minecraft:piston_head[facing=south,short=false,type=normal] +34:4,minecraft:piston_head[facing=west,short=false,type=normal] +34:5,minecraft:piston_head[facing=east,short=false,type=normal] +34:6,minecraft:air +34:7,minecraft:air +34:8,minecraft:piston_head[facing=down,short=false,type=sticky] +34:9,minecraft:piston_head[facing=up,short=false,type=sticky] +34:10,minecraft:piston_head[facing=north,short=false,type=sticky] +34:11,minecraft:piston_head[facing=south,short=false,type=sticky] +34:12,minecraft:piston_head[facing=west,short=false,type=sticky] +34:13,minecraft:piston_head[facing=east,short=false,type=sticky] +34:14,minecraft:air +34:15,minecraft:air +35:0,minecraft:white_wool +35:1,minecraft:orange_wool +35:2,minecraft:magenta_wool +35:3,minecraft:light_blue_wool +35:4,minecraft:yellow_wool +35:5,minecraft:lime_wool +35:6,minecraft:pink_wool +35:7,minecraft:gray_wool +35:8,minecraft:light_gray_wool +35:9,minecraft:cyan_wool +35:10,minecraft:purple_wool +35:11,minecraft:blue_wool +35:12,minecraft:brown_wool +35:13,minecraft:green_wool +35:14,minecraft:red_wool +35:15,minecraft:black_wool +36:0,minecraft:moving_piston[facing=down,type=normal] +36:1,minecraft:moving_piston[facing=up,type=normal] +36:2,minecraft:moving_piston[facing=north,type=normal] +36:3,minecraft:moving_piston[facing=south,type=normal] +36:4,minecraft:moving_piston[facing=west,type=normal] +36:5,minecraft:moving_piston[facing=east,type=normal] +36:6,minecraft:air +36:7,minecraft:air +36:8,minecraft:moving_piston[facing=down,type=sticky] +36:9,minecraft:moving_piston[facing=up,type=sticky] +36:10,minecraft:moving_piston[facing=north,type=sticky] +36:11,minecraft:moving_piston[facing=south,type=sticky] +36:12,minecraft:moving_piston[facing=west,type=sticky] +36:13,minecraft:moving_piston[facing=east,type=sticky] +36:14,minecraft:air +36:15,minecraft:air +37:0,minecraft:dandelion +38:0,minecraft:poppy +38:1,minecraft:blue_orchid +38:2,minecraft:allium +38:3,minecraft:azure_bluet +38:4,minecraft:red_tulip +38:5,minecraft:orange_tulip +38:6,minecraft:white_tulip +38:7,minecraft:pink_tulip +38:8,minecraft:oxeye_daisy +39:0,minecraft:brown_mushroom +40:0,minecraft:red_mushroom +41:0,minecraft:gold_block +42:0,minecraft:iron_block +43:0,minecraft:stone_slab[type=double,waterlogged=false] +43:1,minecraft:sandstone_slab[type=double,waterlogged=false] +43:2,minecraft:petrified_oak_slab[type=double,waterlogged=false] +43:3,minecraft:cobblestone_slab[type=double,waterlogged=false] +43:4,minecraft:brick_slab[type=double,waterlogged=false] +43:5,minecraft:stone_brick_slab[type=double,waterlogged=false] +43:6,minecraft:nether_brick_slab[type=double,waterlogged=false] +43:7,minecraft:quartz_slab[type=double,waterlogged=false] +43:8,minecraft:smooth_stone +43:9,minecraft:smooth_sandstone +43:10,minecraft:petrified_oak_slab[type=double,waterlogged=false] +43:11,minecraft:cobblestone_slab[type=double,waterlogged=false] +43:12,minecraft:brick_slab[type=double,waterlogged=false] +43:13,minecraft:stone_brick_slab[type=double,waterlogged=false] +43:14,minecraft:nether_brick_slab[type=double,waterlogged=false] +43:15,minecraft:smooth_quartz +44:0,minecraft:stone_slab[type=bottom,waterlogged=false] +44:1,minecraft:sandstone_slab[type=bottom,waterlogged=false] +44:2,minecraft:petrified_oak_slab[type=bottom,waterlogged=false] +44:3,minecraft:cobblestone_slab[type=bottom,waterlogged=false] +44:4,minecraft:brick_slab[type=bottom,waterlogged=false] +44:5,minecraft:stone_brick_slab[type=bottom,waterlogged=false] +44:6,minecraft:nether_brick_slab[type=bottom,waterlogged=false] +44:7,minecraft:quartz_slab[type=bottom,waterlogged=false] +44:8,minecraft:stone_slab[type=top,waterlogged=false] +44:9,minecraft:sandstone_slab[type=top,waterlogged=false] +44:10,minecraft:petrified_oak_slab[type=top,waterlogged=false] +44:11,minecraft:cobblestone_slab[type=top,waterlogged=false] +44:12,minecraft:brick_slab[type=top,waterlogged=false] +44:13,minecraft:stone_brick_slab[type=top,waterlogged=false] +44:14,minecraft:nether_brick_slab[type=top,waterlogged=false] +44:15,minecraft:quartz_slab[type=top,waterlogged=false] +45:0,minecraft:bricks +46:0,minecraft:tnt +47:0,minecraft:bookshelf +48:0,minecraft:mossy_cobblestone +49:0,minecraft:obsidian +50:0,minecraft:torch +50:1,minecraft:air +50:2,minecraft:air +50:3,minecraft:air +50:4,minecraft:air +51:0,minecraft:fire[age=0,east=false,north=false,south=false,up=false,west=false] +51:1,minecraft:fire[age=1,east=false,north=false,south=false,up=false,west=false] +51:2,minecraft:fire[age=2,east=false,north=false,south=false,up=false,west=false] +51:3,minecraft:fire[age=3,east=false,north=false,south=false,up=false,west=false] +51:4,minecraft:fire[age=4,east=false,north=false,south=false,up=false,west=false] +51:5,minecraft:fire[age=5,east=false,north=false,south=false,up=false,west=false] +51:6,minecraft:fire[age=6,east=false,north=false,south=false,up=false,west=false] +51:7,minecraft:fire[age=7,east=false,north=false,south=false,up=false,west=false] +51:8,minecraft:fire[age=8,east=false,north=false,south=false,up=false,west=false] +51:9,minecraft:fire[age=9,east=false,north=false,south=false,up=false,west=false] +51:10,minecraft:fire[age=10,east=false,north=false,south=false,up=false,west=false] +51:11,minecraft:fire[age=11,east=false,north=false,south=false,up=false,west=false] +51:12,minecraft:fire[age=12,east=false,north=false,south=false,up=false,west=false] +51:13,minecraft:fire[age=13,east=false,north=false,south=false,up=false,west=false] +51:14,minecraft:fire[age=14,east=false,north=false,south=false,up=false,west=false] +51:15,minecraft:fire[age=15,east=false,north=false,south=false,up=false,west=false] +52:0,minecraft:spawner +53:0,minecraft:oak_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] +53:1,minecraft:oak_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +53:2,minecraft:oak_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +53:3,minecraft:oak_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +53:4,minecraft:oak_stairs[facing=east,half=top,shape=straight,waterlogged=false] +53:5,minecraft:oak_stairs[facing=west,half=top,shape=straight,waterlogged=false] +53:6,minecraft:oak_stairs[facing=south,half=top,shape=straight,waterlogged=false] +53:7,minecraft:oak_stairs[facing=north,half=top,shape=straight,waterlogged=false] +53:9,minecraft:oak_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +53:10,minecraft:oak_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +53:11,minecraft:oak_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +53:12,minecraft:oak_stairs[facing=east,half=top,shape=straight,waterlogged=false] +53:13,minecraft:oak_stairs[facing=west,half=top,shape=straight,waterlogged=false] +53:14,minecraft:oak_stairs[facing=south,half=top,shape=straight,waterlogged=false] +53:15,minecraft:oak_stairs[facing=north,half=top,shape=straight,waterlogged=false] +54:0,minecraft:chest[facing=north,type=single,waterlogged=false] +54:3,minecraft:chest[facing=south,type=single,waterlogged=false] +54:4,minecraft:chest[facing=west,type=single,waterlogged=false] +54:5,minecraft:chest[facing=east,type=single,waterlogged=false] +54:9,minecraft:chest[facing=south,type=single,waterlogged=false] +54:10,minecraft:chest[facing=west,type=single,waterlogged=false] +54:11,minecraft:chest[facing=east,type=single,waterlogged=false] +54:15,minecraft:chest[facing=south,type=single,waterlogged=false] +55:0,minecraft:redstone_wire[east=none,north=none,power=0,south=none,west=none] +55:2,minecraft:redstone_wire[east=none,north=none,power=1,south=none,west=none] +55:3,minecraft:redstone_wire[east=none,north=none,power=2,south=none,west=none] +55:4,minecraft:redstone_wire[east=none,north=none,power=3,south=none,west=none] +55:5,minecraft:redstone_wire[east=none,north=none,power=4,south=none,west=none] +55:6,minecraft:redstone_wire[east=none,north=none,power=5,south=none,west=none] +55:7,minecraft:redstone_wire[east=none,north=none,power=6,south=none,west=none] +55:8,minecraft:redstone_wire[east=none,north=none,power=7,south=none,west=none] +55:9,minecraft:redstone_wire[east=none,north=none,power=8,south=none,west=none] +55:10,minecraft:redstone_wire[east=none,north=none,power=9,south=none,west=none] +55:11,minecraft:redstone_wire[east=none,north=none,power=10,south=none,west=none] +55:12,minecraft:redstone_wire[east=none,north=none,power=11,south=none,west=none] +55:13,minecraft:redstone_wire[east=none,north=none,power=12,south=none,west=none] +55:14,minecraft:redstone_wire[east=none,north=none,power=13,south=none,west=none] +55:15,minecraft:redstone_wire[east=none,north=none,power=14,south=none,west=none] +56:0,minecraft:diamond_ore +57:0,minecraft:diamond_block +58:0,minecraft:crafting_table +59:0,minecraft:wheat[age=0] +59:1,minecraft:wheat[age=1] +59:2,minecraft:wheat[age=2] +59:3,minecraft:wheat[age=3] +59:4,minecraft:wheat[age=4] +59:5,minecraft:wheat[age=5] +59:6,minecraft:wheat[age=6] +59:7,minecraft:wheat[age=7] +59:8,minecraft:air +59:9,minecraft:air +59:10,minecraft:air +59:11,minecraft:air +59:12,minecraft:air +59:13,minecraft:air +59:14,minecraft:air +59:15,minecraft:air +60:0,minecraft:farmland[moisture=0] +60:1,minecraft:farmland[moisture=1] +60:2,minecraft:farmland[moisture=2] +60:3,minecraft:farmland[moisture=3] +60:4,minecraft:farmland[moisture=4] +60:5,minecraft:farmland[moisture=5] +60:6,minecraft:farmland[moisture=6] +60:7,minecraft:farmland[moisture=7] +60:9,minecraft:farmland[moisture=1] +60:10,minecraft:farmland[moisture=2] +60:11,minecraft:farmland[moisture=3] +60:12,minecraft:farmland[moisture=4] +60:13,minecraft:farmland[moisture=5] +60:14,minecraft:farmland[moisture=6] +60:15,minecraft:farmland[moisture=7] +61:0,minecraft:furnace[facing=north,lit=false] +61:3,minecraft:furnace[facing=south,lit=false] +61:4,minecraft:furnace[facing=west,lit=false] +61:5,minecraft:furnace[facing=east,lit=false] +61:9,minecraft:furnace[facing=south,lit=false] +61:10,minecraft:furnace[facing=west,lit=false] +61:11,minecraft:furnace[facing=east,lit=false] +61:15,minecraft:furnace[facing=south,lit=false] +62:0,minecraft:furnace[facing=north,lit=false] +62:3,minecraft:furnace[facing=south,lit=false] +62:4,minecraft:furnace[facing=west,lit=false] +62:5,minecraft:furnace[facing=east,lit=false] +62:9,minecraft:furnace[facing=south,lit=false] +62:10,minecraft:furnace[facing=west,lit=false] +62:11,minecraft:furnace[facing=east,lit=false] +62:15,minecraft:furnace[facing=south,lit=false] +63:0,minecraft:sign[rotation=0,waterlogged=false] +63:1,minecraft:sign[rotation=1,waterlogged=false] +63:2,minecraft:sign[rotation=2,waterlogged=false] +63:3,minecraft:sign[rotation=3,waterlogged=false] +63:4,minecraft:sign[rotation=4,waterlogged=false] +63:5,minecraft:sign[rotation=5,waterlogged=false] +63:6,minecraft:sign[rotation=6,waterlogged=false] +63:7,minecraft:sign[rotation=7,waterlogged=false] +63:8,minecraft:sign[rotation=8,waterlogged=false] +63:9,minecraft:sign[rotation=9,waterlogged=false] +63:10,minecraft:sign[rotation=10,waterlogged=false] +63:11,minecraft:sign[rotation=11,waterlogged=false] +63:12,minecraft:sign[rotation=12,waterlogged=false] +63:13,minecraft:sign[rotation=13,waterlogged=false] +63:14,minecraft:sign[rotation=14,waterlogged=false] +63:15,minecraft:sign[rotation=15,waterlogged=false] +64:0,minecraft:oak_door[facing=east,half=lower,hinge=right,open=false,powered=false] +64:1,minecraft:oak_door[facing=south,half=lower,hinge=right,open=false,powered=false] +64:2,minecraft:oak_door[facing=west,half=lower,hinge=right,open=false,powered=false] +64:3,minecraft:oak_door[facing=north,half=lower,hinge=right,open=false,powered=false] +64:4,minecraft:oak_door[facing=east,half=lower,hinge=right,open=true,powered=false] +64:5,minecraft:oak_door[facing=south,half=lower,hinge=right,open=true,powered=false] +64:6,minecraft:oak_door[facing=west,half=lower,hinge=right,open=true,powered=false] +64:7,minecraft:oak_door[facing=north,half=lower,hinge=right,open=true,powered=false] +64:8,minecraft:oak_door[facing=east,half=upper,hinge=left,open=false,powered=false] +64:9,minecraft:oak_door[facing=east,half=upper,hinge=right,open=false,powered=false] +64:10,minecraft:oak_door[facing=east,half=upper,hinge=left,open=false,powered=true] +64:11,minecraft:oak_door[facing=east,half=upper,hinge=right,open=false,powered=true] +64:12,minecraft:oak_door[facing=east,half=upper,hinge=left,open=false,powered=false] +64:13,minecraft:oak_door[facing=east,half=upper,hinge=right,open=false,powered=false] +64:14,minecraft:oak_door[facing=east,half=upper,hinge=left,open=false,powered=true] +64:15,minecraft:oak_door[facing=east,half=upper,hinge=right,open=false,powered=true] +65:0,minecraft:ladder[facing=north,waterlogged=false] +65:3,minecraft:ladder[facing=south,waterlogged=false] +65:4,minecraft:ladder[facing=west,waterlogged=false] +65:5,minecraft:ladder[facing=east,waterlogged=false] +65:9,minecraft:ladder[facing=south,waterlogged=false] +65:10,minecraft:ladder[facing=west,waterlogged=false] +65:11,minecraft:ladder[facing=east,waterlogged=false] +65:15,minecraft:ladder[facing=south,waterlogged=false] +66:0,minecraft:rail[shape=north_south] +67:0,minecraft:cobblestone_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] +67:1,minecraft:cobblestone_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +67:2,minecraft:cobblestone_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +67:3,minecraft:cobblestone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +67:4,minecraft:cobblestone_stairs[facing=east,half=top,shape=straight,waterlogged=false] +67:5,minecraft:cobblestone_stairs[facing=west,half=top,shape=straight,waterlogged=false] +67:6,minecraft:cobblestone_stairs[facing=south,half=top,shape=straight,waterlogged=false] +67:7,minecraft:cobblestone_stairs[facing=north,half=top,shape=straight,waterlogged=false] +67:9,minecraft:cobblestone_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +67:10,minecraft:cobblestone_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +67:11,minecraft:cobblestone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +67:12,minecraft:cobblestone_stairs[facing=east,half=top,shape=straight,waterlogged=false] +67:13,minecraft:cobblestone_stairs[facing=west,half=top,shape=straight,waterlogged=false] +67:14,minecraft:cobblestone_stairs[facing=south,half=top,shape=straight,waterlogged=false] +67:15,minecraft:cobblestone_stairs[facing=north,half=top,shape=straight,waterlogged=false] +68:0,minecraft:wall_sign[facing=north,waterlogged=false] +68:3,minecraft:wall_sign[facing=south,waterlogged=false] +68:4,minecraft:wall_sign[facing=west,waterlogged=false] +68:5,minecraft:wall_sign[facing=east,waterlogged=false] +68:9,minecraft:wall_sign[facing=south,waterlogged=false] +68:10,minecraft:wall_sign[facing=west,waterlogged=false] +68:11,minecraft:wall_sign[facing=east,waterlogged=false] +68:15,minecraft:wall_sign[facing=south,waterlogged=false] +69:0,minecraft:lever[face=ceiling,facing=west,powered=false] +69:1,minecraft:lever[face=wall,facing=east,powered=false] +69:2,minecraft:lever[face=wall,facing=west,powered=false] +69:3,minecraft:lever[face=wall,facing=south,powered=false] +69:4,minecraft:lever[face=wall,facing=north,powered=false] +69:5,minecraft:lever[face=floor,facing=north,powered=false] +69:6,minecraft:lever[face=floor,facing=west,powered=false] +69:7,minecraft:lever[face=ceiling,facing=north,powered=false] +69:8,minecraft:lever[face=ceiling,facing=west,powered=true] +69:9,minecraft:lever[face=wall,facing=east,powered=true] +69:10,minecraft:lever[face=wall,facing=west,powered=true] +69:11,minecraft:lever[face=wall,facing=south,powered=true] +69:12,minecraft:lever[face=wall,facing=north,powered=true] +69:13,minecraft:lever[face=floor,facing=north,powered=true] +69:14,minecraft:lever[face=floor,facing=west,powered=true] +69:15,minecraft:lever[face=ceiling,facing=north,powered=true] +70:0,minecraft:stone_pressure_plate[powered=false] +70:1,minecraft:stone_pressure_plate[powered=true] +71:0,minecraft:iron_door[facing=east,half=lower,hinge=right,open=false,powered=false] +71:1,minecraft:iron_door[facing=south,half=lower,hinge=right,open=false,powered=false] +71:2,minecraft:iron_door[facing=west,half=lower,hinge=right,open=false,powered=false] +71:3,minecraft:iron_door[facing=north,half=lower,hinge=right,open=false,powered=false] +71:4,minecraft:iron_door[facing=east,half=lower,hinge=right,open=true,powered=false] +71:5,minecraft:iron_door[facing=south,half=lower,hinge=right,open=true,powered=false] +71:6,minecraft:iron_door[facing=west,half=lower,hinge=right,open=true,powered=false] +71:7,minecraft:iron_door[facing=north,half=lower,hinge=right,open=true,powered=false] +71:8,minecraft:iron_door[facing=east,half=upper,hinge=left,open=false,powered=false] +71:9,minecraft:iron_door[facing=east,half=upper,hinge=right,open=false,powered=false] +71:10,minecraft:iron_door[facing=east,half=upper,hinge=left,open=false,powered=true] +71:11,minecraft:iron_door[facing=east,half=upper,hinge=right,open=false,powered=true] +71:12,minecraft:iron_door[facing=east,half=upper,hinge=left,open=false,powered=false] +71:13,minecraft:iron_door[facing=east,half=upper,hinge=right,open=false,powered=false] +71:14,minecraft:iron_door[facing=east,half=upper,hinge=left,open=false,powered=true] +71:15,minecraft:iron_door[facing=east,half=upper,hinge=right,open=false,powered=true] +72:0,minecraft:oak_pressure_plate[powered=false] +72:1,minecraft:oak_pressure_plate[powered=true] +73:0,minecraft:redstone_ore[lit=false] +74:0,minecraft:redstone_ore[lit=true] +75:0,minecraft:redstone_torch[lit=false] +75:1,minecraft:redstone_wall_torch[facing=east,lit=false] +75:2,minecraft:redstone_wall_torch[facing=west,lit=false] +75:3,minecraft:redstone_wall_torch[facing=south,lit=false] +75:4,minecraft:redstone_wall_torch[facing=north,lit=false] +76:0,minecraft:redstone_torch[lit=true] +76:1,minecraft:redstone_wall_torch[facing=east,lit=true] +76:2,minecraft:redstone_wall_torch[facing=west,lit=true] +76:3,minecraft:redstone_wall_torch[facing=south,lit=true] +76:4,minecraft:redstone_wall_torch[facing=north,lit=true] +77:0,minecraft:stone_button[face=ceiling,facing=north,powered=false] +77:1,minecraft:stone_button[face=wall,facing=east,powered=false] +77:2,minecraft:stone_button[face=wall,facing=west,powered=false] +77:3,minecraft:stone_button[face=wall,facing=south,powered=false] +77:4,minecraft:stone_button[face=wall,facing=north,powered=false] +77:5,minecraft:stone_button[face=floor,facing=north,powered=false] +77:6,minecraft:stone_button[face=floor,facing=north,powered=false] +77:7,minecraft:stone_button[face=floor,facing=north,powered=false] +77:8,minecraft:stone_button[face=ceiling,facing=north,powered=true] +77:9,minecraft:stone_button[face=wall,facing=east,powered=true] +77:10,minecraft:stone_button[face=wall,facing=west,powered=true] +77:11,minecraft:stone_button[face=wall,facing=south,powered=true] +77:12,minecraft:stone_button[face=wall,facing=north,powered=true] +77:13,minecraft:stone_button[face=floor,facing=north,powered=true] +77:14,minecraft:stone_button[face=floor,facing=north,powered=true] +77:15,minecraft:stone_button[face=floor,facing=north,powered=true] +78:0,minecraft:snow[layers=1] +78:1,minecraft:snow[layers=2] +78:2,minecraft:snow[layers=3] +78:3,minecraft:snow[layers=4] +78:4,minecraft:snow[layers=5] +78:5,minecraft:snow[layers=6] +78:6,minecraft:snow[layers=7] +78:7,minecraft:snow[layers=8] +78:9,minecraft:snow[layers=2] +78:10,minecraft:snow[layers=3] +78:11,minecraft:snow[layers=4] +78:12,minecraft:snow[layers=5] +78:13,minecraft:snow[layers=6] +78:14,minecraft:snow[layers=7] +78:15,minecraft:snow[layers=8] +79:0,minecraft:ice +80:0,minecraft:snow_block +81:0,minecraft:cactus[age=0] +81:1,minecraft:cactus[age=1] +81:2,minecraft:cactus[age=2] +81:3,minecraft:cactus[age=3] +81:4,minecraft:cactus[age=4] +81:5,minecraft:cactus[age=5] +81:6,minecraft:cactus[age=6] +81:7,minecraft:cactus[age=7] +81:8,minecraft:cactus[age=8] +81:9,minecraft:cactus[age=9] +81:10,minecraft:cactus[age=10] +81:11,minecraft:cactus[age=11] +81:12,minecraft:cactus[age=12] +81:13,minecraft:cactus[age=13] +81:14,minecraft:cactus[age=14] +81:15,minecraft:cactus[age=15] +82:0,minecraft:clay +83:0,minecraft:sugar_cane[age=0] +83:1,minecraft:sugar_cane[age=1] +83:2,minecraft:sugar_cane[age=2] +83:3,minecraft:sugar_cane[age=3] +83:4,minecraft:sugar_cane[age=4] +83:5,minecraft:sugar_cane[age=5] +83:6,minecraft:sugar_cane[age=6] +83:7,minecraft:sugar_cane[age=7] +83:8,minecraft:sugar_cane[age=8] +83:9,minecraft:sugar_cane[age=9] +83:10,minecraft:sugar_cane[age=10] +83:11,minecraft:sugar_cane[age=11] +83:12,minecraft:sugar_cane[age=12] +83:13,minecraft:sugar_cane[age=13] +83:14,minecraft:sugar_cane[age=14] +83:15,minecraft:sugar_cane[age=15] +84:0,minecraft:jukebox[has_record=false] +84:1,minecraft:jukebox[has_record=true] +84:2,minecraft:jukebox[has_record=true] +84:3,minecraft:jukebox[has_record=true] +84:4,minecraft:jukebox[has_record=true] +84:5,minecraft:jukebox[has_record=true] +84:6,minecraft:jukebox[has_record=true] +84:7,minecraft:jukebox[has_record=true] +84:8,minecraft:jukebox[has_record=true] +84:9,minecraft:jukebox[has_record=true] +84:10,minecraft:jukebox[has_record=true] +84:11,minecraft:jukebox[has_record=true] +84:12,minecraft:jukebox[has_record=true] +84:13,minecraft:jukebox[has_record=true] +84:14,minecraft:jukebox[has_record=true] +84:15,minecraft:jukebox[has_record=true] +85:0,minecraft:oak_fence[east=false,north=false,south=false,waterlogged=false,west=false] +86:0,minecraft:carved_pumpkin[facing=south] +86:1,minecraft:carved_pumpkin[facing=west] +86:2,minecraft:carved_pumpkin[facing=north] +86:3,minecraft:carved_pumpkin[facing=east] +86:5,minecraft:carved_pumpkin[facing=west] +86:6,minecraft:carved_pumpkin[facing=north] +86:7,minecraft:carved_pumpkin[facing=east] +86:9,minecraft:carved_pumpkin[facing=west] +86:10,minecraft:carved_pumpkin[facing=north] +86:11,minecraft:carved_pumpkin[facing=east] +86:13,minecraft:carved_pumpkin[facing=west] +86:14,minecraft:carved_pumpkin[facing=north] +86:15,minecraft:carved_pumpkin[facing=east] +87:0,minecraft:netherrack +88:0,minecraft:soul_sand +89:0,minecraft:glowstone +90:0,minecraft:nether_portal[axis=x] +90:2,minecraft:nether_portal[axis=z] +90:6,minecraft:nether_portal[axis=z] +90:10,minecraft:nether_portal[axis=z] +90:14,minecraft:nether_portal[axis=z] +91:0,minecraft:jack_o_lantern[facing=south] +91:1,minecraft:jack_o_lantern[facing=west] +91:2,minecraft:jack_o_lantern[facing=north] +91:3,minecraft:jack_o_lantern[facing=east] +91:5,minecraft:jack_o_lantern[facing=west] +91:6,minecraft:jack_o_lantern[facing=north] +91:7,minecraft:jack_o_lantern[facing=east] +91:9,minecraft:jack_o_lantern[facing=west] +91:10,minecraft:jack_o_lantern[facing=north] +91:11,minecraft:jack_o_lantern[facing=east] +91:13,minecraft:jack_o_lantern[facing=west] +91:14,minecraft:jack_o_lantern[facing=north] +91:15,minecraft:jack_o_lantern[facing=east] +92:0,minecraft:cake[bites=0] +92:1,minecraft:cake[bites=1] +92:2,minecraft:cake[bites=2] +92:3,minecraft:cake[bites=3] +92:4,minecraft:cake[bites=4] +92:5,minecraft:cake[bites=5] +92:6,minecraft:cake[bites=6] +92:7,minecraft:air +92:8,minecraft:air +92:9,minecraft:air +92:10,minecraft:air +92:11,minecraft:air +92:12,minecraft:air +92:13,minecraft:air +92:14,minecraft:air +92:15,minecraft:air +93:0,minecraft:repeater[delay=1,facing=south,locked=false,powered=false] +93:1,minecraft:repeater[delay=1,facing=west,locked=false,powered=false] +93:2,minecraft:repeater[delay=1,facing=north,locked=false,powered=false] +93:3,minecraft:repeater[delay=1,facing=east,locked=false,powered=false] +93:4,minecraft:repeater[delay=2,facing=south,locked=false,powered=false] +93:5,minecraft:repeater[delay=2,facing=west,locked=false,powered=false] +93:6,minecraft:repeater[delay=2,facing=north,locked=false,powered=false] +93:7,minecraft:repeater[delay=2,facing=east,locked=false,powered=false] +93:8,minecraft:repeater[delay=3,facing=south,locked=false,powered=false] +93:9,minecraft:repeater[delay=3,facing=west,locked=false,powered=false] +93:10,minecraft:repeater[delay=3,facing=north,locked=false,powered=false] +93:11,minecraft:repeater[delay=3,facing=east,locked=false,powered=false] +93:12,minecraft:repeater[delay=4,facing=south,locked=false,powered=false] +93:13,minecraft:repeater[delay=4,facing=west,locked=false,powered=false] +93:14,minecraft:repeater[delay=4,facing=north,locked=false,powered=false] +93:15,minecraft:repeater[delay=4,facing=east,locked=false,powered=false] +94:0,minecraft:repeater[delay=1,facing=south,locked=false,powered=true] +94:1,minecraft:repeater[delay=1,facing=west,locked=false,powered=true] +94:2,minecraft:repeater[delay=1,facing=north,locked=false,powered=true] +94:3,minecraft:repeater[delay=1,facing=east,locked=false,powered=true] +94:4,minecraft:repeater[delay=2,facing=south,locked=false,powered=true] +94:5,minecraft:repeater[delay=2,facing=west,locked=false,powered=true] +94:6,minecraft:repeater[delay=2,facing=north,locked=false,powered=true] +94:7,minecraft:repeater[delay=2,facing=east,locked=false,powered=true] +94:8,minecraft:repeater[delay=3,facing=south,locked=false,powered=true] +94:9,minecraft:repeater[delay=3,facing=west,locked=false,powered=true] +94:10,minecraft:repeater[delay=3,facing=north,locked=false,powered=true] +94:11,minecraft:repeater[delay=3,facing=east,locked=false,powered=true] +94:12,minecraft:repeater[delay=4,facing=south,locked=false,powered=true] +94:13,minecraft:repeater[delay=4,facing=west,locked=false,powered=true] +94:14,minecraft:repeater[delay=4,facing=north,locked=false,powered=true] +94:15,minecraft:repeater[delay=4,facing=east,locked=false,powered=true] +95:0,minecraft:white_stained_glass +95:1,minecraft:orange_stained_glass +95:2,minecraft:magenta_stained_glass +95:3,minecraft:light_blue_stained_glass +95:4,minecraft:yellow_stained_glass +95:5,minecraft:lime_stained_glass +95:6,minecraft:pink_stained_glass +95:7,minecraft:gray_stained_glass +95:8,minecraft:light_gray_stained_glass +95:9,minecraft:cyan_stained_glass +95:10,minecraft:purple_stained_glass +95:11,minecraft:blue_stained_glass +95:12,minecraft:brown_stained_glass +95:13,minecraft:green_stained_glass +95:14,minecraft:red_stained_glass +95:15,minecraft:black_stained_glass +96:0,minecraft:oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] +96:1,minecraft:oak_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] +96:2,minecraft:oak_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] +96:3,minecraft:oak_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] +96:4,minecraft:oak_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] +96:5,minecraft:oak_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] +96:6,minecraft:oak_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] +96:7,minecraft:oak_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] +96:8,minecraft:oak_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] +96:9,minecraft:oak_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] +96:10,minecraft:oak_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] +96:11,minecraft:oak_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] +96:12,minecraft:oak_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] +96:13,minecraft:oak_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] +96:14,minecraft:oak_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] +96:15,minecraft:oak_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] +97:0,minecraft:infested_stone +97:1,minecraft:infested_cobblestone +97:2,minecraft:infested_stone_bricks +97:3,minecraft:infested_mossy_stone_bricks +97:4,minecraft:infested_cracked_stone_bricks +97:5,minecraft:infested_chiseled_stone_bricks +98:0,minecraft:stone_bricks +98:1,minecraft:mossy_stone_bricks +98:2,minecraft:cracked_stone_bricks +98:3,minecraft:chiseled_stone_bricks +99:0,minecraft:brown_mushroom_block[down=false,east=false,north=false,south=false,up=false,west=false] +99:1,minecraft:brown_mushroom_block[down=false,east=false,north=true,south=false,up=true,west=true] +99:2,minecraft:brown_mushroom_block[down=false,east=false,north=true,south=false,up=true,west=false] +99:3,minecraft:brown_mushroom_block[down=false,east=true,north=true,south=false,up=true,west=false] +99:4,minecraft:brown_mushroom_block[down=false,east=false,north=false,south=false,up=true,west=true] +99:5,minecraft:brown_mushroom_block[down=false,east=false,north=false,south=false,up=true,west=false] +99:6,minecraft:brown_mushroom_block[down=false,east=true,north=false,south=false,up=true,west=false] +99:7,minecraft:brown_mushroom_block[down=false,east=false,north=false,south=true,up=true,west=true] +99:8,minecraft:brown_mushroom_block[down=false,east=false,north=false,south=true,up=true,west=false] +99:9,minecraft:brown_mushroom_block[down=false,east=true,north=false,south=true,up=true,west=false] +99:10,minecraft:mushroom_stem[down=false,east=true,north=true,south=true,up=false,west=true] +99:14,minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] +99:15,minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] +100:0,minecraft:red_mushroom_block[down=false,east=false,north=false,south=false,up=false,west=false] +100:1,minecraft:red_mushroom_block[down=false,east=false,north=true,south=false,up=true,west=true] +100:2,minecraft:red_mushroom_block[down=false,east=false,north=true,south=false,up=true,west=false] +100:3,minecraft:red_mushroom_block[down=false,east=true,north=true,south=false,up=true,west=false] +100:4,minecraft:red_mushroom_block[down=false,east=false,north=false,south=false,up=true,west=true] +100:5,minecraft:red_mushroom_block[down=false,east=false,north=false,south=false,up=true,west=false] +100:6,minecraft:red_mushroom_block[down=false,east=true,north=false,south=false,up=true,west=false] +100:7,minecraft:red_mushroom_block[down=false,east=false,north=false,south=true,up=true,west=true] +100:8,minecraft:red_mushroom_block[down=false,east=false,north=false,south=true,up=true,west=false] +100:9,minecraft:red_mushroom_block[down=false,east=true,north=false,south=true,up=true,west=false] +100:10,minecraft:mushroom_stem[down=false,east=true,north=true,south=true,up=false,west=true] +100:14,minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] +100:15,minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] +101:0,minecraft:iron_bars[east=false,north=false,south=false,waterlogged=false,west=false] +102:0,minecraft:glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +103:0,minecraft:melon +104:0,minecraft:pumpkin_stem[age=0] +104:1,minecraft:pumpkin_stem[age=1] +104:2,minecraft:pumpkin_stem[age=2] +104:3,minecraft:pumpkin_stem[age=3] +104:4,minecraft:pumpkin_stem[age=4] +104:5,minecraft:pumpkin_stem[age=5] +104:6,minecraft:pumpkin_stem[age=6] +104:7,minecraft:pumpkin_stem[age=7] +104:8,minecraft:air +104:9,minecraft:air +104:10,minecraft:air +104:11,minecraft:air +104:12,minecraft:air +104:13,minecraft:air +104:14,minecraft:air +104:15,minecraft:air +105:0,minecraft:melon_stem[age=0] +105:1,minecraft:melon_stem[age=1] +105:2,minecraft:melon_stem[age=2] +105:3,minecraft:melon_stem[age=3] +105:4,minecraft:melon_stem[age=4] +105:5,minecraft:melon_stem[age=5] +105:6,minecraft:melon_stem[age=6] +105:7,minecraft:melon_stem[age=7] +105:8,minecraft:air +105:9,minecraft:air +105:10,minecraft:air +105:11,minecraft:air +105:12,minecraft:air +105:13,minecraft:air +105:14,minecraft:air +105:15,minecraft:air +106:0,minecraft:vine[east=false,north=false,south=false,up=true,west=false] +106:1,minecraft:vine[east=false,north=false,south=true,up=true,west=false] +106:2,minecraft:vine[east=false,north=false,south=false,up=true,west=true] +106:3,minecraft:vine[east=false,north=false,south=true,up=true,west=true] +106:4,minecraft:vine[east=false,north=true,south=false,up=true,west=false] +106:5,minecraft:vine[east=false,north=true,south=true,up=true,west=false] +106:6,minecraft:vine[east=false,north=true,south=false,up=true,west=true] +106:7,minecraft:vine[east=false,north=true,south=true,up=true,west=true] +106:8,minecraft:vine[east=true,north=false,south=false,up=true,west=false] +106:9,minecraft:vine[east=true,north=false,south=true,up=true,west=false] +106:10,minecraft:vine[east=true,north=false,south=false,up=true,west=true] +106:11,minecraft:vine[east=true,north=false,south=true,up=true,west=true] +106:12,minecraft:vine[east=true,north=true,south=false,up=true,west=false] +106:13,minecraft:vine[east=true,north=true,south=true,up=true,west=false] +106:14,minecraft:vine[east=true,north=true,south=false,up=true,west=true] +106:15,minecraft:vine[east=true,north=true,south=true,up=true,west=true] +107:0,minecraft:oak_fence_gate[facing=south,in_wall=false,open=false,powered=false] +107:1,minecraft:oak_fence_gate[facing=west,in_wall=false,open=false,powered=false] +107:2,minecraft:oak_fence_gate[facing=north,in_wall=false,open=false,powered=false] +107:3,minecraft:oak_fence_gate[facing=east,in_wall=false,open=false,powered=false] +107:4,minecraft:oak_fence_gate[facing=south,in_wall=false,open=true,powered=false] +107:5,minecraft:oak_fence_gate[facing=west,in_wall=false,open=true,powered=false] +107:6,minecraft:oak_fence_gate[facing=north,in_wall=false,open=true,powered=false] +107:7,minecraft:oak_fence_gate[facing=east,in_wall=false,open=true,powered=false] +107:8,minecraft:oak_fence_gate[facing=south,in_wall=false,open=false,powered=true] +107:9,minecraft:oak_fence_gate[facing=west,in_wall=false,open=false,powered=true] +107:10,minecraft:oak_fence_gate[facing=north,in_wall=false,open=false,powered=true] +107:11,minecraft:oak_fence_gate[facing=east,in_wall=false,open=false,powered=true] +107:12,minecraft:oak_fence_gate[facing=south,in_wall=false,open=true,powered=true] +107:13,minecraft:oak_fence_gate[facing=west,in_wall=false,open=true,powered=true] +107:14,minecraft:oak_fence_gate[facing=north,in_wall=false,open=true,powered=true] +107:15,minecraft:oak_fence_gate[facing=east,in_wall=false,open=true,powered=true] +108:0,minecraft:brick_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] +108:1,minecraft:brick_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +108:2,minecraft:brick_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +108:3,minecraft:brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +108:4,minecraft:brick_stairs[facing=east,half=top,shape=straight,waterlogged=false] +108:5,minecraft:brick_stairs[facing=west,half=top,shape=straight,waterlogged=false] +108:6,minecraft:brick_stairs[facing=south,half=top,shape=straight,waterlogged=false] +108:7,minecraft:brick_stairs[facing=north,half=top,shape=straight,waterlogged=false] +108:9,minecraft:brick_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +108:10,minecraft:brick_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +108:11,minecraft:brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +108:12,minecraft:brick_stairs[facing=east,half=top,shape=straight,waterlogged=false] +108:13,minecraft:brick_stairs[facing=west,half=top,shape=straight,waterlogged=false] +108:14,minecraft:brick_stairs[facing=south,half=top,shape=straight,waterlogged=false] +108:15,minecraft:brick_stairs[facing=north,half=top,shape=straight,waterlogged=false] +109:0,minecraft:stone_brick_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] +109:1,minecraft:stone_brick_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +109:2,minecraft:stone_brick_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +109:3,minecraft:stone_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +109:4,minecraft:stone_brick_stairs[facing=east,half=top,shape=straight,waterlogged=false] +109:5,minecraft:stone_brick_stairs[facing=west,half=top,shape=straight,waterlogged=false] +109:6,minecraft:stone_brick_stairs[facing=south,half=top,shape=straight,waterlogged=false] +109:7,minecraft:stone_brick_stairs[facing=north,half=top,shape=straight,waterlogged=false] +109:9,minecraft:stone_brick_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +109:10,minecraft:stone_brick_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +109:11,minecraft:stone_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +109:12,minecraft:stone_brick_stairs[facing=east,half=top,shape=straight,waterlogged=false] +109:13,minecraft:stone_brick_stairs[facing=west,half=top,shape=straight,waterlogged=false] +109:14,minecraft:stone_brick_stairs[facing=south,half=top,shape=straight,waterlogged=false] +109:15,minecraft:stone_brick_stairs[facing=north,half=top,shape=straight,waterlogged=false] +110:0,minecraft:mycelium[snowy=false] +111:0,minecraft:lily_pad +112:0,minecraft:nether_bricks +113:0,minecraft:nether_brick_fence[east=false,north=false,south=false,waterlogged=false,west=false] +114:0,minecraft:nether_brick_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] +114:1,minecraft:nether_brick_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +114:2,minecraft:nether_brick_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +114:3,minecraft:nether_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +114:4,minecraft:nether_brick_stairs[facing=east,half=top,shape=straight,waterlogged=false] +114:5,minecraft:nether_brick_stairs[facing=west,half=top,shape=straight,waterlogged=false] +114:6,minecraft:nether_brick_stairs[facing=south,half=top,shape=straight,waterlogged=false] +114:7,minecraft:nether_brick_stairs[facing=north,half=top,shape=straight,waterlogged=false] +114:9,minecraft:nether_brick_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +114:10,minecraft:nether_brick_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +114:11,minecraft:nether_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +114:12,minecraft:nether_brick_stairs[facing=east,half=top,shape=straight,waterlogged=false] +114:13,minecraft:nether_brick_stairs[facing=west,half=top,shape=straight,waterlogged=false] +114:14,minecraft:nether_brick_stairs[facing=south,half=top,shape=straight,waterlogged=false] +114:15,minecraft:nether_brick_stairs[facing=north,half=top,shape=straight,waterlogged=false] +115:0,minecraft:nether_wart[age=0] +115:1,minecraft:nether_wart[age=1] +115:2,minecraft:nether_wart[age=2] +115:3,minecraft:nether_wart[age=3] +115:4,minecraft:air +115:5,minecraft:air +115:6,minecraft:air +115:7,minecraft:air +115:8,minecraft:air +115:9,minecraft:air +115:10,minecraft:air +115:11,minecraft:air +115:12,minecraft:air +115:13,minecraft:air +115:14,minecraft:air +115:15,minecraft:air +116:0,minecraft:enchanting_table +117:0,minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false] +118:0,minecraft:cauldron[level=0] +118:1,minecraft:cauldron[level=1] +118:2,minecraft:cauldron[level=2] +118:3,minecraft:cauldron[level=3] +118:4,minecraft:air +118:5,minecraft:air +118:6,minecraft:air +118:7,minecraft:air +118:8,minecraft:air +118:9,minecraft:air +118:10,minecraft:air +118:11,minecraft:air +118:12,minecraft:air +118:13,minecraft:air +118:14,minecraft:air +118:15,minecraft:air +119:0,minecraft:end_portal +120:0,minecraft:end_portal_frame[eye=false,facing=south] +120:1,minecraft:end_portal_frame[eye=false,facing=west] +120:2,minecraft:end_portal_frame[eye=false,facing=north] +120:3,minecraft:end_portal_frame[eye=false,facing=east] +120:4,minecraft:end_portal_frame[eye=true,facing=south] +120:5,minecraft:end_portal_frame[eye=true,facing=west] +120:6,minecraft:end_portal_frame[eye=true,facing=north] +120:7,minecraft:end_portal_frame[eye=true,facing=east] +120:9,minecraft:end_portal_frame[eye=false,facing=west] +120:10,minecraft:end_portal_frame[eye=false,facing=north] +120:11,minecraft:end_portal_frame[eye=false,facing=east] +120:12,minecraft:end_portal_frame[eye=true,facing=south] +120:13,minecraft:end_portal_frame[eye=true,facing=west] +120:14,minecraft:end_portal_frame[eye=true,facing=north] +120:15,minecraft:end_portal_frame[eye=true,facing=east] +121:0,minecraft:end_stone +122:0,minecraft:dragon_egg +123:0,minecraft:redstone_lamp[lit=false] +124:0,minecraft:redstone_lamp[lit=false] +125:0,minecraft:oak_slab[type=double,waterlogged=false] +125:1,minecraft:spruce_slab[type=double,waterlogged=false] +125:2,minecraft:birch_slab[type=double,waterlogged=false] +125:3,minecraft:jungle_slab[type=double,waterlogged=false] +125:4,minecraft:acacia_slab[type=double,waterlogged=false] +125:5,minecraft:dark_oak_slab[type=double,waterlogged=false] +125:9,minecraft:spruce_slab[type=double,waterlogged=false] +125:10,minecraft:birch_slab[type=double,waterlogged=false] +125:11,minecraft:jungle_slab[type=double,waterlogged=false] +125:12,minecraft:acacia_slab[type=double,waterlogged=false] +125:13,minecraft:dark_oak_slab[type=double,waterlogged=false] +126:0,minecraft:oak_slab[type=bottom,waterlogged=false] +126:1,minecraft:spruce_slab[type=bottom,waterlogged=false] +126:2,minecraft:birch_slab[type=bottom,waterlogged=false] +126:3,minecraft:jungle_slab[type=bottom,waterlogged=false] +126:4,minecraft:acacia_slab[type=bottom,waterlogged=false] +126:5,minecraft:dark_oak_slab[type=bottom,waterlogged=false] +126:8,minecraft:oak_slab[type=top,waterlogged=false] +126:9,minecraft:spruce_slab[type=top,waterlogged=false] +126:10,minecraft:birch_slab[type=top,waterlogged=false] +126:11,minecraft:jungle_slab[type=top,waterlogged=false] +126:12,minecraft:acacia_slab[type=top,waterlogged=false] +126:13,minecraft:dark_oak_slab[type=top,waterlogged=false] +126:14,minecraft:oak_slab[type=top,waterlogged=false] +126:15,minecraft:oak_slab[type=top,waterlogged=false] +127:0,minecraft:cocoa[age=0,facing=south] +127:1,minecraft:cocoa[age=0,facing=west] +127:2,minecraft:cocoa[age=0,facing=north] +127:3,minecraft:cocoa[age=0,facing=east] +127:4,minecraft:cocoa[age=1,facing=south] +127:5,minecraft:cocoa[age=1,facing=west] +127:6,minecraft:cocoa[age=1,facing=north] +127:7,minecraft:cocoa[age=1,facing=east] +127:8,minecraft:cocoa[age=2,facing=south] +127:9,minecraft:cocoa[age=2,facing=west] +127:10,minecraft:cocoa[age=2,facing=north] +127:11,minecraft:cocoa[age=2,facing=east] +127:12,minecraft:air +127:13,minecraft:air +127:14,minecraft:air +127:15,minecraft:air +128:0,minecraft:sandstone_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] +128:1,minecraft:sandstone_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +128:2,minecraft:sandstone_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +128:3,minecraft:sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +128:4,minecraft:sandstone_stairs[facing=east,half=top,shape=straight,waterlogged=false] +128:5,minecraft:sandstone_stairs[facing=west,half=top,shape=straight,waterlogged=false] +128:6,minecraft:sandstone_stairs[facing=south,half=top,shape=straight,waterlogged=false] +128:7,minecraft:sandstone_stairs[facing=north,half=top,shape=straight,waterlogged=false] +128:9,minecraft:sandstone_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +128:10,minecraft:sandstone_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +128:11,minecraft:sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +128:12,minecraft:sandstone_stairs[facing=east,half=top,shape=straight,waterlogged=false] +128:13,minecraft:sandstone_stairs[facing=west,half=top,shape=straight,waterlogged=false] +128:14,minecraft:sandstone_stairs[facing=south,half=top,shape=straight,waterlogged=false] +128:15,minecraft:sandstone_stairs[facing=north,half=top,shape=straight,waterlogged=false] +129:0,minecraft:emerald_ore +130:0,minecraft:ender_chest[facing=north,waterlogged=false] +130:3,minecraft:ender_chest[facing=south,waterlogged=false] +130:4,minecraft:ender_chest[facing=west,waterlogged=false] +130:5,minecraft:ender_chest[facing=east,waterlogged=false] +130:9,minecraft:ender_chest[facing=south,waterlogged=false] +130:10,minecraft:ender_chest[facing=west,waterlogged=false] +130:11,minecraft:ender_chest[facing=east,waterlogged=false] +130:15,minecraft:ender_chest[facing=south,waterlogged=false] +131:0,minecraft:tripwire_hook[attached=false,facing=south,powered=false] +131:1,minecraft:tripwire_hook[attached=false,facing=west,powered=false] +131:2,minecraft:tripwire_hook[attached=false,facing=north,powered=false] +131:3,minecraft:tripwire_hook[attached=false,facing=east,powered=false] +131:4,minecraft:tripwire_hook[attached=true,facing=south,powered=false] +131:5,minecraft:tripwire_hook[attached=true,facing=west,powered=false] +131:6,minecraft:tripwire_hook[attached=true,facing=north,powered=false] +131:7,minecraft:tripwire_hook[attached=true,facing=east,powered=false] +131:8,minecraft:tripwire_hook[attached=false,facing=south,powered=true] +131:9,minecraft:tripwire_hook[attached=false,facing=west,powered=true] +131:10,minecraft:tripwire_hook[attached=false,facing=north,powered=true] +131:11,minecraft:tripwire_hook[attached=false,facing=east,powered=true] +131:12,minecraft:tripwire_hook[attached=true,facing=south,powered=true] +131:13,minecraft:tripwire_hook[attached=true,facing=west,powered=true] +131:14,minecraft:tripwire_hook[attached=true,facing=north,powered=true] +131:15,minecraft:tripwire_hook[attached=true,facing=east,powered=true] +132:0,minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,powered=false,south=false,west=false] +132:1,minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,powered=true,south=false,west=false] +132:3,minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,powered=true,south=false,west=false] +132:4,minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,powered=false,south=false,west=false] +132:5,minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,powered=true,south=false,west=false] +132:6,minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,powered=false,south=false,west=false] +132:7,minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,powered=true,south=false,west=false] +132:8,minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,powered=false,south=false,west=false] +132:9,minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,powered=true,south=false,west=false] +132:10,minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,powered=false,south=false,west=false] +132:11,minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,powered=true,south=false,west=false] +132:12,minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,powered=false,south=false,west=false] +132:13,minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,powered=true,south=false,west=false] +132:14,minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,powered=false,south=false,west=false] +132:15,minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,powered=true,south=false,west=false] +133:0,minecraft:emerald_block +134:0,minecraft:spruce_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] +134:1,minecraft:spruce_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +134:2,minecraft:spruce_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +134:3,minecraft:spruce_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +134:4,minecraft:spruce_stairs[facing=east,half=top,shape=straight,waterlogged=false] +134:5,minecraft:spruce_stairs[facing=west,half=top,shape=straight,waterlogged=false] +134:6,minecraft:spruce_stairs[facing=south,half=top,shape=straight,waterlogged=false] +134:7,minecraft:spruce_stairs[facing=north,half=top,shape=straight,waterlogged=false] +134:9,minecraft:spruce_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +134:10,minecraft:spruce_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +134:11,minecraft:spruce_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +134:12,minecraft:spruce_stairs[facing=east,half=top,shape=straight,waterlogged=false] +134:13,minecraft:spruce_stairs[facing=west,half=top,shape=straight,waterlogged=false] +134:14,minecraft:spruce_stairs[facing=south,half=top,shape=straight,waterlogged=false] +134:15,minecraft:spruce_stairs[facing=north,half=top,shape=straight,waterlogged=false] +135:0,minecraft:birch_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] +135:1,minecraft:birch_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +135:2,minecraft:birch_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +135:3,minecraft:birch_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +135:4,minecraft:birch_stairs[facing=east,half=top,shape=straight,waterlogged=false] +135:5,minecraft:birch_stairs[facing=west,half=top,shape=straight,waterlogged=false] +135:6,minecraft:birch_stairs[facing=south,half=top,shape=straight,waterlogged=false] +135:7,minecraft:birch_stairs[facing=north,half=top,shape=straight,waterlogged=false] +135:9,minecraft:birch_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +135:10,minecraft:birch_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +135:11,minecraft:birch_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +135:12,minecraft:birch_stairs[facing=east,half=top,shape=straight,waterlogged=false] +135:13,minecraft:birch_stairs[facing=west,half=top,shape=straight,waterlogged=false] +135:14,minecraft:birch_stairs[facing=south,half=top,shape=straight,waterlogged=false] +135:15,minecraft:birch_stairs[facing=north,half=top,shape=straight,waterlogged=false] +136:0,minecraft:jungle_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] +136:1,minecraft:jungle_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +136:2,minecraft:jungle_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +136:3,minecraft:jungle_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +136:4,minecraft:jungle_stairs[facing=east,half=top,shape=straight,waterlogged=false] +136:5,minecraft:jungle_stairs[facing=west,half=top,shape=straight,waterlogged=false] +136:6,minecraft:jungle_stairs[facing=south,half=top,shape=straight,waterlogged=false] +136:7,minecraft:jungle_stairs[facing=north,half=top,shape=straight,waterlogged=false] +136:9,minecraft:jungle_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +136:10,minecraft:jungle_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +136:11,minecraft:jungle_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +136:12,minecraft:jungle_stairs[facing=east,half=top,shape=straight,waterlogged=false] +136:13,minecraft:jungle_stairs[facing=west,half=top,shape=straight,waterlogged=false] +136:14,minecraft:jungle_stairs[facing=south,half=top,shape=straight,waterlogged=false] +136:15,minecraft:jungle_stairs[facing=north,half=top,shape=straight,waterlogged=false] +137:0,minecraft:command_block[conditional=false,facing=down] +137:1,minecraft:command_block[conditional=false,facing=up] +137:2,minecraft:command_block[conditional=false,facing=north] +137:3,minecraft:command_block[conditional=false,facing=south] +137:4,minecraft:command_block[conditional=false,facing=west] +137:5,minecraft:command_block[conditional=false,facing=east] +137:7,minecraft:command_block[conditional=false,facing=up] +137:8,minecraft:command_block[conditional=true,facing=down] +137:9,minecraft:command_block[conditional=true,facing=up] +137:10,minecraft:command_block[conditional=true,facing=north] +137:11,minecraft:command_block[conditional=true,facing=south] +137:12,minecraft:command_block[conditional=true,facing=west] +137:13,minecraft:command_block[conditional=true,facing=east] +137:14,minecraft:command_block[conditional=true,facing=down] +137:15,minecraft:command_block[conditional=true,facing=up] +138:0,minecraft:beacon +139:0,minecraft:cobblestone_wall[east=false,north=false,south=false,up=false,waterlogged=false,west=false] +139:1,minecraft:mossy_cobblestone_wall[east=false,north=false,south=false,up=false,waterlogged=false,west=false] +140:0,minecraft:flower_pot +141:0,minecraft:carrots[age=0] +141:1,minecraft:carrots[age=1] +141:2,minecraft:carrots[age=2] +141:3,minecraft:carrots[age=3] +141:4,minecraft:carrots[age=4] +141:5,minecraft:carrots[age=5] +141:6,minecraft:carrots[age=6] +141:7,minecraft:carrots[age=7] +141:8,minecraft:air +141:9,minecraft:air +141:10,minecraft:air +141:11,minecraft:air +141:12,minecraft:air +141:13,minecraft:air +141:14,minecraft:air +141:15,minecraft:air +142:0,minecraft:potatoes[age=0] +142:1,minecraft:potatoes[age=1] +142:2,minecraft:potatoes[age=2] +142:3,minecraft:potatoes[age=3] +142:4,minecraft:potatoes[age=4] +142:5,minecraft:potatoes[age=5] +142:6,minecraft:potatoes[age=6] +142:7,minecraft:potatoes[age=7] +142:8,minecraft:air +142:9,minecraft:air +142:10,minecraft:air +142:11,minecraft:air +142:12,minecraft:air +142:13,minecraft:air +142:14,minecraft:air +142:15,minecraft:air +143:0,minecraft:oak_button[face=ceiling,facing=north,powered=false] +143:1,minecraft:oak_button[face=wall,facing=east,powered=false] +143:2,minecraft:oak_button[face=wall,facing=west,powered=false] +143:3,minecraft:oak_button[face=wall,facing=south,powered=false] +143:4,minecraft:oak_button[face=wall,facing=north,powered=false] +143:5,minecraft:oak_button[face=floor,facing=north,powered=false] +143:6,minecraft:oak_button[face=floor,facing=north,powered=false] +143:7,minecraft:oak_button[face=floor,facing=north,powered=false] +143:8,minecraft:oak_button[face=ceiling,facing=north,powered=true] +143:9,minecraft:oak_button[face=wall,facing=east,powered=true] +143:10,minecraft:oak_button[face=wall,facing=west,powered=true] +143:11,minecraft:oak_button[face=wall,facing=south,powered=true] +143:12,minecraft:oak_button[face=wall,facing=north,powered=true] +143:13,minecraft:oak_button[face=floor,facing=north,powered=true] +143:14,minecraft:oak_button[face=floor,facing=north,powered=true] +143:15,minecraft:oak_button[face=floor,facing=north,powered=true] +144:0,minecraft:skeleton_skull[rotation=0] +144:2,minecraft:skeleton_wall_skull[facing=north] +144:3,minecraft:skeleton_wall_skull[facing=south] +144:4,minecraft:skeleton_wall_skull[facing=west] +144:5,minecraft:skeleton_wall_skull[facing=east] +144:10,minecraft:skeleton_wall_skull[facing=north] +144:11,minecraft:skeleton_wall_skull[facing=south] +144:12,minecraft:skeleton_wall_skull[facing=west] +144:13,minecraft:skeleton_wall_skull[facing=east] +145:0,minecraft:anvil[facing=south] +145:1,minecraft:anvil[facing=west] +145:2,minecraft:anvil[facing=north] +145:3,minecraft:anvil[facing=east] +145:4,minecraft:chipped_anvil[facing=south] +145:5,minecraft:chipped_anvil[facing=west] +145:6,minecraft:chipped_anvil[facing=north] +145:7,minecraft:chipped_anvil[facing=east] +145:8,minecraft:damaged_anvil[facing=south] +145:9,minecraft:damaged_anvil[facing=west] +145:10,minecraft:damaged_anvil[facing=north] +145:11,minecraft:damaged_anvil[facing=east] +145:12,minecraft:air +145:13,minecraft:air +145:14,minecraft:air +145:15,minecraft:air +146:0,minecraft:trapped_chest[facing=north,type=single,waterlogged=false] +146:3,minecraft:trapped_chest[facing=south,type=single,waterlogged=false] +146:4,minecraft:trapped_chest[facing=west,type=single,waterlogged=false] +146:5,minecraft:trapped_chest[facing=east,type=single,waterlogged=false] +146:9,minecraft:trapped_chest[facing=south,type=single,waterlogged=false] +146:10,minecraft:trapped_chest[facing=west,type=single,waterlogged=false] +146:11,minecraft:trapped_chest[facing=east,type=single,waterlogged=false] +146:15,minecraft:trapped_chest[facing=south,type=single,waterlogged=false] +147:0,minecraft:light_weighted_pressure_plate[power=0] +147:1,minecraft:light_weighted_pressure_plate[power=1] +147:2,minecraft:light_weighted_pressure_plate[power=2] +147:3,minecraft:light_weighted_pressure_plate[power=3] +147:4,minecraft:light_weighted_pressure_plate[power=4] +147:5,minecraft:light_weighted_pressure_plate[power=5] +147:6,minecraft:light_weighted_pressure_plate[power=6] +147:7,minecraft:light_weighted_pressure_plate[power=7] +147:8,minecraft:light_weighted_pressure_plate[power=8] +147:9,minecraft:light_weighted_pressure_plate[power=9] +147:10,minecraft:light_weighted_pressure_plate[power=10] +147:11,minecraft:light_weighted_pressure_plate[power=11] +147:12,minecraft:light_weighted_pressure_plate[power=12] +147:13,minecraft:light_weighted_pressure_plate[power=13] +147:14,minecraft:light_weighted_pressure_plate[power=14] +147:15,minecraft:light_weighted_pressure_plate[power=15] +148:0,minecraft:heavy_weighted_pressure_plate[power=0] +148:1,minecraft:heavy_weighted_pressure_plate[power=1] +148:2,minecraft:heavy_weighted_pressure_plate[power=2] +148:3,minecraft:heavy_weighted_pressure_plate[power=3] +148:4,minecraft:heavy_weighted_pressure_plate[power=4] +148:5,minecraft:heavy_weighted_pressure_plate[power=5] +148:6,minecraft:heavy_weighted_pressure_plate[power=6] +148:7,minecraft:heavy_weighted_pressure_plate[power=7] +148:8,minecraft:heavy_weighted_pressure_plate[power=8] +148:9,minecraft:heavy_weighted_pressure_plate[power=9] +148:10,minecraft:heavy_weighted_pressure_plate[power=10] +148:11,minecraft:heavy_weighted_pressure_plate[power=11] +148:12,minecraft:heavy_weighted_pressure_plate[power=12] +148:13,minecraft:heavy_weighted_pressure_plate[power=13] +148:14,minecraft:heavy_weighted_pressure_plate[power=14] +148:15,minecraft:heavy_weighted_pressure_plate[power=15] +149:0,minecraft:comparator[facing=south,mode=compare,powered=false] +149:1,minecraft:comparator[facing=west,mode=compare,powered=false] +149:2,minecraft:comparator[facing=north,mode=compare,powered=false] +149:3,minecraft:comparator[facing=east,mode=compare,powered=false] +149:4,minecraft:comparator[facing=south,mode=subtract,powered=false] +149:5,minecraft:comparator[facing=west,mode=subtract,powered=false] +149:6,minecraft:comparator[facing=north,mode=subtract,powered=false] +149:7,minecraft:comparator[facing=east,mode=subtract,powered=false] +149:8,minecraft:comparator[facing=south,mode=compare,powered=true] +149:9,minecraft:comparator[facing=west,mode=compare,powered=true] +149:10,minecraft:comparator[facing=north,mode=compare,powered=true] +149:11,minecraft:comparator[facing=east,mode=compare,powered=true] +149:12,minecraft:comparator[facing=south,mode=subtract,powered=true] +149:13,minecraft:comparator[facing=west,mode=subtract,powered=true] +149:14,minecraft:comparator[facing=north,mode=subtract,powered=true] +149:15,minecraft:comparator[facing=east,mode=subtract,powered=true] +150:0,minecraft:comparator[facing=south,mode=compare,powered=false] +150:1,minecraft:comparator[facing=west,mode=compare,powered=false] +150:2,minecraft:comparator[facing=north,mode=compare,powered=false] +150:3,minecraft:comparator[facing=east,mode=compare,powered=false] +150:4,minecraft:comparator[facing=south,mode=subtract,powered=false] +150:5,minecraft:comparator[facing=west,mode=subtract,powered=false] +150:6,minecraft:comparator[facing=north,mode=subtract,powered=false] +150:7,minecraft:comparator[facing=east,mode=subtract,powered=false] +150:8,minecraft:comparator[facing=south,mode=compare,powered=true] +150:9,minecraft:comparator[facing=west,mode=compare,powered=true] +150:10,minecraft:comparator[facing=north,mode=compare,powered=true] +150:11,minecraft:comparator[facing=east,mode=compare,powered=true] +150:12,minecraft:comparator[facing=south,mode=subtract,powered=true] +150:13,minecraft:comparator[facing=west,mode=subtract,powered=true] +150:14,minecraft:comparator[facing=north,mode=subtract,powered=true] +150:15,minecraft:comparator[facing=east,mode=subtract,powered=true] +151:0,minecraft:daylight_detector[inverted=false,power=0] +151:1,minecraft:daylight_detector[inverted=false,power=1] +151:2,minecraft:daylight_detector[inverted=false,power=2] +151:3,minecraft:daylight_detector[inverted=false,power=3] +151:4,minecraft:daylight_detector[inverted=false,power=4] +151:5,minecraft:daylight_detector[inverted=false,power=5] +151:6,minecraft:daylight_detector[inverted=false,power=6] +151:7,minecraft:daylight_detector[inverted=false,power=7] +151:8,minecraft:daylight_detector[inverted=false,power=8] +151:9,minecraft:daylight_detector[inverted=false,power=9] +151:10,minecraft:daylight_detector[inverted=false,power=10] +151:11,minecraft:daylight_detector[inverted=false,power=11] +151:12,minecraft:daylight_detector[inverted=false,power=12] +151:13,minecraft:daylight_detector[inverted=false,power=13] +151:14,minecraft:daylight_detector[inverted=false,power=14] +151:15,minecraft:daylight_detector[inverted=false,power=15] +152:0,minecraft:redstone_block +153:0,minecraft:nether_quartz_ore +154:0,minecraft:hopper[enabled=true,facing=down] +154:1,minecraft:air +154:2,minecraft:hopper[enabled=true,facing=north] +154:3,minecraft:hopper[enabled=true,facing=south] +154:4,minecraft:hopper[enabled=true,facing=west] +154:5,minecraft:hopper[enabled=true,facing=east] +154:7,minecraft:air +154:9,minecraft:air +154:10,minecraft:hopper[enabled=true,facing=north] +154:11,minecraft:hopper[enabled=true,facing=south] +154:12,minecraft:hopper[enabled=true,facing=west] +154:13,minecraft:hopper[enabled=true,facing=east] +154:15,minecraft:air +155:0,minecraft:quartz_block +155:1,minecraft:chiseled_quartz_block +155:2,minecraft:quartz_pillar[axis=y] +155:3,minecraft:quartz_pillar[axis=x] +155:4,minecraft:quartz_pillar[axis=z] +156:0,minecraft:quartz_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] +156:1,minecraft:quartz_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +156:2,minecraft:quartz_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +156:3,minecraft:quartz_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +156:4,minecraft:quartz_stairs[facing=east,half=top,shape=straight,waterlogged=false] +156:5,minecraft:quartz_stairs[facing=west,half=top,shape=straight,waterlogged=false] +156:6,minecraft:quartz_stairs[facing=south,half=top,shape=straight,waterlogged=false] +156:7,minecraft:quartz_stairs[facing=north,half=top,shape=straight,waterlogged=false] +156:9,minecraft:quartz_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +156:10,minecraft:quartz_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +156:11,minecraft:quartz_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +156:12,minecraft:quartz_stairs[facing=east,half=top,shape=straight,waterlogged=false] +156:13,minecraft:quartz_stairs[facing=west,half=top,shape=straight,waterlogged=false] +156:14,minecraft:quartz_stairs[facing=south,half=top,shape=straight,waterlogged=false] +156:15,minecraft:quartz_stairs[facing=north,half=top,shape=straight,waterlogged=false] +157:0,minecraft:activator_rail[powered=false,shape=north_south] +157:6,minecraft:air +157:7,minecraft:air +157:14,minecraft:air +157:15,minecraft:air +158:0,minecraft:dropper[facing=down,triggered=false] +158:1,minecraft:dropper[facing=up,triggered=false] +158:2,minecraft:dropper[facing=north,triggered=false] +158:3,minecraft:dropper[facing=south,triggered=false] +158:4,minecraft:dropper[facing=west,triggered=false] +158:5,minecraft:dropper[facing=east,triggered=false] +158:7,minecraft:dropper[facing=up,triggered=false] +158:8,minecraft:dropper[facing=down,triggered=true] +158:9,minecraft:dropper[facing=up,triggered=true] +158:10,minecraft:dropper[facing=north,triggered=true] +158:11,minecraft:dropper[facing=south,triggered=true] +158:12,minecraft:dropper[facing=west,triggered=true] +158:13,minecraft:dropper[facing=east,triggered=true] +158:14,minecraft:dropper[facing=down,triggered=true] +158:15,minecraft:dropper[facing=up,triggered=true] +159:0,minecraft:white_terracotta +159:1,minecraft:orange_terracotta +159:2,minecraft:magenta_terracotta +159:3,minecraft:light_blue_terracotta +159:4,minecraft:yellow_terracotta +159:5,minecraft:lime_terracotta +159:6,minecraft:pink_terracotta +159:7,minecraft:gray_terracotta +159:8,minecraft:light_gray_terracotta +159:9,minecraft:cyan_terracotta +159:10,minecraft:purple_terracotta +159:11,minecraft:blue_terracotta +159:12,minecraft:brown_terracotta +159:13,minecraft:green_terracotta +159:14,minecraft:red_terracotta +159:15,minecraft:black_terracotta +160:0,minecraft:white_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:1,minecraft:orange_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:2,minecraft:magenta_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:3,minecraft:light_blue_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:4,minecraft:yellow_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:5,minecraft:lime_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:6,minecraft:pink_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:7,minecraft:gray_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:8,minecraft:light_gray_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:9,minecraft:cyan_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:10,minecraft:purple_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:11,minecraft:blue_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:12,minecraft:brown_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:13,minecraft:green_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:14,minecraft:red_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +160:15,minecraft:black_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false] +161:0,minecraft:acacia_leaves[distance=7,persistent=false] +161:1,minecraft:dark_oak_leaves[distance=7,persistent=false] +161:2,minecraft:air +161:3,minecraft:air +161:4,minecraft:acacia_leaves[distance=7,persistent=true] +161:5,minecraft:dark_oak_leaves[distance=7,persistent=true] +161:6,minecraft:air +161:7,minecraft:air +161:9,minecraft:dark_oak_leaves[distance=7,persistent=false] +161:10,minecraft:air +161:11,minecraft:air +161:12,minecraft:acacia_leaves[distance=7,persistent=true] +161:13,minecraft:dark_oak_leaves[distance=7,persistent=true] +161:14,minecraft:air +161:15,minecraft:air +162:0,minecraft:acacia_log[axis=y] +162:1,minecraft:dark_oak_log[axis=y] +162:2,minecraft:air +162:3,minecraft:air +162:4,minecraft:acacia_log[axis=x] +162:5,minecraft:dark_oak_log[axis=x] +162:6,minecraft:air +162:7,minecraft:air +162:8,minecraft:acacia_log[axis=z] +162:9,minecraft:dark_oak_log[axis=z] +162:10,minecraft:air +162:11,minecraft:air +162:12,minecraft:acacia_wood[axis=y] +162:13,minecraft:dark_oak_wood[axis=y] +162:14,minecraft:air +162:15,minecraft:air +163:0,minecraft:acacia_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] +163:1,minecraft:acacia_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +163:2,minecraft:acacia_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +163:3,minecraft:acacia_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +163:4,minecraft:acacia_stairs[facing=east,half=top,shape=straight,waterlogged=false] +163:5,minecraft:acacia_stairs[facing=west,half=top,shape=straight,waterlogged=false] +163:6,minecraft:acacia_stairs[facing=south,half=top,shape=straight,waterlogged=false] +163:7,minecraft:acacia_stairs[facing=north,half=top,shape=straight,waterlogged=false] +163:9,minecraft:acacia_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +163:10,minecraft:acacia_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +163:11,minecraft:acacia_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +163:12,minecraft:acacia_stairs[facing=east,half=top,shape=straight,waterlogged=false] +163:13,minecraft:acacia_stairs[facing=west,half=top,shape=straight,waterlogged=false] +163:14,minecraft:acacia_stairs[facing=south,half=top,shape=straight,waterlogged=false] +163:15,minecraft:acacia_stairs[facing=north,half=top,shape=straight,waterlogged=false] +164:0,minecraft:dark_oak_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] +164:1,minecraft:dark_oak_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +164:2,minecraft:dark_oak_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +164:3,minecraft:dark_oak_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +164:4,minecraft:dark_oak_stairs[facing=east,half=top,shape=straight,waterlogged=false] +164:5,minecraft:dark_oak_stairs[facing=west,half=top,shape=straight,waterlogged=false] +164:6,minecraft:dark_oak_stairs[facing=south,half=top,shape=straight,waterlogged=false] +164:7,minecraft:dark_oak_stairs[facing=north,half=top,shape=straight,waterlogged=false] +164:9,minecraft:dark_oak_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +164:10,minecraft:dark_oak_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +164:11,minecraft:dark_oak_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +164:12,minecraft:dark_oak_stairs[facing=east,half=top,shape=straight,waterlogged=false] +164:13,minecraft:dark_oak_stairs[facing=west,half=top,shape=straight,waterlogged=false] +164:14,minecraft:dark_oak_stairs[facing=south,half=top,shape=straight,waterlogged=false] +164:15,minecraft:dark_oak_stairs[facing=north,half=top,shape=straight,waterlogged=false] +165:0,minecraft:slime_block +166:0,minecraft:barrier +167:0,minecraft:iron_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] +167:1,minecraft:iron_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] +167:2,minecraft:iron_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] +167:3,minecraft:iron_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] +167:4,minecraft:iron_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] +167:5,minecraft:iron_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] +167:6,minecraft:iron_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] +167:7,minecraft:iron_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] +167:8,minecraft:iron_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] +167:9,minecraft:iron_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] +167:10,minecraft:iron_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] +167:11,minecraft:iron_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] +167:12,minecraft:iron_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] +167:13,minecraft:iron_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] +167:14,minecraft:iron_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] +167:15,minecraft:iron_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] +168:0,minecraft:prismarine +168:1,minecraft:prismarine_bricks +168:2,minecraft:dark_prismarine +169:0,minecraft:sea_lantern +170:0,minecraft:hay_block[axis=y] +170:4,minecraft:hay_block[axis=x] +170:5,minecraft:hay_block[axis=x] +170:6,minecraft:hay_block[axis=x] +170:7,minecraft:hay_block[axis=x] +170:8,minecraft:hay_block[axis=z] +170:9,minecraft:hay_block[axis=z] +170:10,minecraft:hay_block[axis=z] +170:11,minecraft:hay_block[axis=z] +171:0,minecraft:white_carpet +171:1,minecraft:orange_carpet +171:2,minecraft:magenta_carpet +171:3,minecraft:light_blue_carpet +171:4,minecraft:yellow_carpet +171:5,minecraft:lime_carpet +171:6,minecraft:pink_carpet +171:7,minecraft:gray_carpet +171:8,minecraft:light_gray_carpet +171:9,minecraft:cyan_carpet +171:10,minecraft:purple_carpet +171:11,minecraft:blue_carpet +171:12,minecraft:brown_carpet +171:13,minecraft:green_carpet +171:14,minecraft:red_carpet +171:15,minecraft:black_carpet +172:0,minecraft:terracotta +173:0,minecraft:coal_block +174:0,minecraft:packed_ice +175:0,minecraft:sunflower[half=lower] +175:1,minecraft:lilac[half=lower] +175:2,minecraft:tall_grass[half=lower] +175:3,minecraft:large_fern[half=lower] +175:4,minecraft:rose_bush[half=lower] +175:5,minecraft:peony[half=lower] +175:8,minecraft:peony[half=upper] +175:9,minecraft:peony[half=upper] +175:10,minecraft:peony[half=upper] +175:11,minecraft:peony[half=upper] +175:12,minecraft:peony[half=upper] +175:13,minecraft:peony[half=upper] +175:14,minecraft:peony[half=upper] +175:15,minecraft:peony[half=upper] +176:0,minecraft:black_banner[rotation=0] +176:1,minecraft:black_banner[rotation=1] +176:2,minecraft:black_banner[rotation=2] +176:3,minecraft:black_banner[rotation=3] +176:4,minecraft:black_banner[rotation=4] +176:5,minecraft:black_banner[rotation=5] +176:6,minecraft:black_banner[rotation=6] +176:7,minecraft:black_banner[rotation=7] +176:8,minecraft:black_banner[rotation=8] +176:9,minecraft:black_banner[rotation=9] +176:10,minecraft:black_banner[rotation=10] +176:11,minecraft:black_banner[rotation=11] +176:12,minecraft:black_banner[rotation=12] +176:13,minecraft:black_banner[rotation=13] +176:14,minecraft:black_banner[rotation=14] +176:15,minecraft:black_banner[rotation=15] +177:0,minecraft:black_wall_banner[facing=north] +177:3,minecraft:black_wall_banner[facing=south] +177:4,minecraft:black_wall_banner[facing=west] +177:5,minecraft:black_wall_banner[facing=east] +177:9,minecraft:black_wall_banner[facing=south] +177:10,minecraft:black_wall_banner[facing=west] +177:11,minecraft:black_wall_banner[facing=east] +177:15,minecraft:black_wall_banner[facing=south] +178:0,minecraft:daylight_detector[inverted=true,power=0] +178:1,minecraft:daylight_detector[inverted=true,power=1] +178:2,minecraft:daylight_detector[inverted=true,power=2] +178:3,minecraft:daylight_detector[inverted=true,power=3] +178:4,minecraft:daylight_detector[inverted=true,power=4] +178:5,minecraft:daylight_detector[inverted=true,power=5] +178:6,minecraft:daylight_detector[inverted=true,power=6] +178:7,minecraft:daylight_detector[inverted=true,power=7] +178:8,minecraft:daylight_detector[inverted=true,power=8] +178:9,minecraft:daylight_detector[inverted=true,power=9] +178:10,minecraft:daylight_detector[inverted=true,power=10] +178:11,minecraft:daylight_detector[inverted=true,power=11] +178:12,minecraft:daylight_detector[inverted=true,power=12] +178:13,minecraft:daylight_detector[inverted=true,power=13] +178:14,minecraft:daylight_detector[inverted=true,power=14] +178:15,minecraft:daylight_detector[inverted=true,power=15] +179:0,minecraft:red_sandstone +179:1,minecraft:chiseled_red_sandstone +179:2,minecraft:cut_red_sandstone +180:0,minecraft:red_sandstone_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] +180:1,minecraft:red_sandstone_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +180:2,minecraft:red_sandstone_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +180:3,minecraft:red_sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +180:4,minecraft:red_sandstone_stairs[facing=east,half=top,shape=straight,waterlogged=false] +180:5,minecraft:red_sandstone_stairs[facing=west,half=top,shape=straight,waterlogged=false] +180:6,minecraft:red_sandstone_stairs[facing=south,half=top,shape=straight,waterlogged=false] +180:7,minecraft:red_sandstone_stairs[facing=north,half=top,shape=straight,waterlogged=false] +180:9,minecraft:red_sandstone_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +180:10,minecraft:red_sandstone_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +180:11,minecraft:red_sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +180:12,minecraft:red_sandstone_stairs[facing=east,half=top,shape=straight,waterlogged=false] +180:13,minecraft:red_sandstone_stairs[facing=west,half=top,shape=straight,waterlogged=false] +180:14,minecraft:red_sandstone_stairs[facing=south,half=top,shape=straight,waterlogged=false] +180:15,minecraft:red_sandstone_stairs[facing=north,half=top,shape=straight,waterlogged=false] +181:0,minecraft:red_sandstone_slab[type=double,waterlogged=false] +181:8,minecraft:smooth_red_sandstone +181:9,minecraft:smooth_red_sandstone +181:10,minecraft:smooth_red_sandstone +181:11,minecraft:smooth_red_sandstone +181:12,minecraft:smooth_red_sandstone +181:13,minecraft:smooth_red_sandstone +181:14,minecraft:smooth_red_sandstone +181:15,minecraft:smooth_red_sandstone +182:0,minecraft:red_sandstone_slab[type=bottom,waterlogged=false] +182:8,minecraft:red_sandstone_slab[type=top,waterlogged=false] +182:9,minecraft:red_sandstone_slab[type=top,waterlogged=false] +182:10,minecraft:red_sandstone_slab[type=top,waterlogged=false] +182:11,minecraft:red_sandstone_slab[type=top,waterlogged=false] +182:12,minecraft:red_sandstone_slab[type=top,waterlogged=false] +182:13,minecraft:red_sandstone_slab[type=top,waterlogged=false] +182:14,minecraft:red_sandstone_slab[type=top,waterlogged=false] +182:15,minecraft:red_sandstone_slab[type=top,waterlogged=false] +183:0,minecraft:spruce_fence_gate[facing=south,in_wall=false,open=false,powered=false] +183:1,minecraft:spruce_fence_gate[facing=west,in_wall=false,open=false,powered=false] +183:2,minecraft:spruce_fence_gate[facing=north,in_wall=false,open=false,powered=false] +183:3,minecraft:spruce_fence_gate[facing=east,in_wall=false,open=false,powered=false] +183:4,minecraft:spruce_fence_gate[facing=south,in_wall=false,open=true,powered=false] +183:5,minecraft:spruce_fence_gate[facing=west,in_wall=false,open=true,powered=false] +183:6,minecraft:spruce_fence_gate[facing=north,in_wall=false,open=true,powered=false] +183:7,minecraft:spruce_fence_gate[facing=east,in_wall=false,open=true,powered=false] +183:8,minecraft:spruce_fence_gate[facing=south,in_wall=false,open=false,powered=true] +183:9,minecraft:spruce_fence_gate[facing=west,in_wall=false,open=false,powered=true] +183:10,minecraft:spruce_fence_gate[facing=north,in_wall=false,open=false,powered=true] +183:11,minecraft:spruce_fence_gate[facing=east,in_wall=false,open=false,powered=true] +183:12,minecraft:spruce_fence_gate[facing=south,in_wall=false,open=true,powered=true] +183:13,minecraft:spruce_fence_gate[facing=west,in_wall=false,open=true,powered=true] +183:14,minecraft:spruce_fence_gate[facing=north,in_wall=false,open=true,powered=true] +183:15,minecraft:spruce_fence_gate[facing=east,in_wall=false,open=true,powered=true] +184:0,minecraft:birch_fence_gate[facing=south,in_wall=false,open=false,powered=false] +184:1,minecraft:birch_fence_gate[facing=west,in_wall=false,open=false,powered=false] +184:2,minecraft:birch_fence_gate[facing=north,in_wall=false,open=false,powered=false] +184:3,minecraft:birch_fence_gate[facing=east,in_wall=false,open=false,powered=false] +184:4,minecraft:birch_fence_gate[facing=south,in_wall=false,open=true,powered=false] +184:5,minecraft:birch_fence_gate[facing=west,in_wall=false,open=true,powered=false] +184:6,minecraft:birch_fence_gate[facing=north,in_wall=false,open=true,powered=false] +184:7,minecraft:birch_fence_gate[facing=east,in_wall=false,open=true,powered=false] +184:8,minecraft:birch_fence_gate[facing=south,in_wall=false,open=false,powered=true] +184:9,minecraft:birch_fence_gate[facing=west,in_wall=false,open=false,powered=true] +184:10,minecraft:birch_fence_gate[facing=north,in_wall=false,open=false,powered=true] +184:11,minecraft:birch_fence_gate[facing=east,in_wall=false,open=false,powered=true] +184:12,minecraft:birch_fence_gate[facing=south,in_wall=false,open=true,powered=true] +184:13,minecraft:birch_fence_gate[facing=west,in_wall=false,open=true,powered=true] +184:14,minecraft:birch_fence_gate[facing=north,in_wall=false,open=true,powered=true] +184:15,minecraft:birch_fence_gate[facing=east,in_wall=false,open=true,powered=true] +185:0,minecraft:jungle_fence_gate[facing=south,in_wall=false,open=false,powered=false] +185:1,minecraft:jungle_fence_gate[facing=west,in_wall=false,open=false,powered=false] +185:2,minecraft:jungle_fence_gate[facing=north,in_wall=false,open=false,powered=false] +185:3,minecraft:jungle_fence_gate[facing=east,in_wall=false,open=false,powered=false] +185:4,minecraft:jungle_fence_gate[facing=south,in_wall=false,open=true,powered=false] +185:5,minecraft:jungle_fence_gate[facing=west,in_wall=false,open=true,powered=false] +185:6,minecraft:jungle_fence_gate[facing=north,in_wall=false,open=true,powered=false] +185:7,minecraft:jungle_fence_gate[facing=east,in_wall=false,open=true,powered=false] +185:8,minecraft:jungle_fence_gate[facing=south,in_wall=false,open=false,powered=true] +185:9,minecraft:jungle_fence_gate[facing=west,in_wall=false,open=false,powered=true] +185:10,minecraft:jungle_fence_gate[facing=north,in_wall=false,open=false,powered=true] +185:11,minecraft:jungle_fence_gate[facing=east,in_wall=false,open=false,powered=true] +185:12,minecraft:jungle_fence_gate[facing=south,in_wall=false,open=true,powered=true] +185:13,minecraft:jungle_fence_gate[facing=west,in_wall=false,open=true,powered=true] +185:14,minecraft:jungle_fence_gate[facing=north,in_wall=false,open=true,powered=true] +185:15,minecraft:jungle_fence_gate[facing=east,in_wall=false,open=true,powered=true] +186:0,minecraft:dark_oak_fence_gate[facing=south,in_wall=false,open=false,powered=false] +186:1,minecraft:dark_oak_fence_gate[facing=west,in_wall=false,open=false,powered=false] +186:2,minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=false,powered=false] +186:3,minecraft:dark_oak_fence_gate[facing=east,in_wall=false,open=false,powered=false] +186:4,minecraft:dark_oak_fence_gate[facing=south,in_wall=false,open=true,powered=false] +186:5,minecraft:dark_oak_fence_gate[facing=west,in_wall=false,open=true,powered=false] +186:6,minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=true,powered=false] +186:7,minecraft:dark_oak_fence_gate[facing=east,in_wall=false,open=true,powered=false] +186:8,minecraft:dark_oak_fence_gate[facing=south,in_wall=false,open=false,powered=true] +186:9,minecraft:dark_oak_fence_gate[facing=west,in_wall=false,open=false,powered=true] +186:10,minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=false,powered=true] +186:11,minecraft:dark_oak_fence_gate[facing=east,in_wall=false,open=false,powered=true] +186:12,minecraft:dark_oak_fence_gate[facing=south,in_wall=false,open=true,powered=true] +186:13,minecraft:dark_oak_fence_gate[facing=west,in_wall=false,open=true,powered=true] +186:14,minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=true,powered=true] +186:15,minecraft:dark_oak_fence_gate[facing=east,in_wall=false,open=true,powered=true] +187:0,minecraft:acacia_fence_gate[facing=south,in_wall=false,open=false,powered=false] +187:1,minecraft:acacia_fence_gate[facing=west,in_wall=false,open=false,powered=false] +187:2,minecraft:acacia_fence_gate[facing=north,in_wall=false,open=false,powered=false] +187:3,minecraft:acacia_fence_gate[facing=east,in_wall=false,open=false,powered=false] +187:4,minecraft:acacia_fence_gate[facing=south,in_wall=false,open=true,powered=false] +187:5,minecraft:acacia_fence_gate[facing=west,in_wall=false,open=true,powered=false] +187:6,minecraft:acacia_fence_gate[facing=north,in_wall=false,open=true,powered=false] +187:7,minecraft:acacia_fence_gate[facing=east,in_wall=false,open=true,powered=false] +187:8,minecraft:acacia_fence_gate[facing=south,in_wall=false,open=false,powered=true] +187:9,minecraft:acacia_fence_gate[facing=west,in_wall=false,open=false,powered=true] +187:10,minecraft:acacia_fence_gate[facing=north,in_wall=false,open=false,powered=true] +187:11,minecraft:acacia_fence_gate[facing=east,in_wall=false,open=false,powered=true] +187:12,minecraft:acacia_fence_gate[facing=south,in_wall=false,open=true,powered=true] +187:13,minecraft:acacia_fence_gate[facing=west,in_wall=false,open=true,powered=true] +187:14,minecraft:acacia_fence_gate[facing=north,in_wall=false,open=true,powered=true] +187:15,minecraft:acacia_fence_gate[facing=east,in_wall=false,open=true,powered=true] +188:0,minecraft:spruce_fence[east=false,north=false,south=false,waterlogged=false,west=false] +189:0,minecraft:birch_fence[east=false,north=false,south=false,waterlogged=false,west=false] +190:0,minecraft:jungle_fence[east=false,north=false,south=false,waterlogged=false,west=false] +191:0,minecraft:dark_oak_fence[east=false,north=false,south=false,waterlogged=false,west=false] +192:0,minecraft:acacia_fence[east=false,north=false,south=false,waterlogged=false,west=false] +193:0,minecraft:spruce_door[facing=east,half=lower,hinge=right,open=false,powered=false] +193:1,minecraft:spruce_door[facing=south,half=lower,hinge=right,open=false,powered=false] +193:2,minecraft:spruce_door[facing=west,half=lower,hinge=right,open=false,powered=false] +193:3,minecraft:spruce_door[facing=north,half=lower,hinge=right,open=false,powered=false] +193:4,minecraft:spruce_door[facing=east,half=lower,hinge=right,open=true,powered=false] +193:5,minecraft:spruce_door[facing=south,half=lower,hinge=right,open=true,powered=false] +193:6,minecraft:spruce_door[facing=west,half=lower,hinge=right,open=true,powered=false] +193:7,minecraft:spruce_door[facing=north,half=lower,hinge=right,open=true,powered=false] +193:8,minecraft:spruce_door[facing=east,half=upper,hinge=left,open=false,powered=false] +193:9,minecraft:spruce_door[facing=east,half=upper,hinge=right,open=false,powered=false] +193:10,minecraft:spruce_door[facing=east,half=upper,hinge=left,open=false,powered=true] +193:11,minecraft:spruce_door[facing=east,half=upper,hinge=right,open=false,powered=true] +193:12,minecraft:spruce_door[facing=east,half=upper,hinge=left,open=false,powered=false] +193:13,minecraft:spruce_door[facing=east,half=upper,hinge=right,open=false,powered=false] +193:14,minecraft:spruce_door[facing=east,half=upper,hinge=left,open=false,powered=true] +193:15,minecraft:spruce_door[facing=east,half=upper,hinge=right,open=false,powered=true] +194:0,minecraft:birch_door[facing=east,half=lower,hinge=right,open=false,powered=false] +194:1,minecraft:birch_door[facing=south,half=lower,hinge=right,open=false,powered=false] +194:2,minecraft:birch_door[facing=west,half=lower,hinge=right,open=false,powered=false] +194:3,minecraft:birch_door[facing=north,half=lower,hinge=right,open=false,powered=false] +194:4,minecraft:birch_door[facing=east,half=lower,hinge=right,open=true,powered=false] +194:5,minecraft:birch_door[facing=south,half=lower,hinge=right,open=true,powered=false] +194:6,minecraft:birch_door[facing=west,half=lower,hinge=right,open=true,powered=false] +194:7,minecraft:birch_door[facing=north,half=lower,hinge=right,open=true,powered=false] +194:8,minecraft:birch_door[facing=east,half=upper,hinge=left,open=false,powered=false] +194:9,minecraft:birch_door[facing=east,half=upper,hinge=right,open=false,powered=false] +194:10,minecraft:birch_door[facing=east,half=upper,hinge=left,open=false,powered=true] +194:11,minecraft:birch_door[facing=east,half=upper,hinge=right,open=false,powered=true] +194:12,minecraft:birch_door[facing=east,half=upper,hinge=left,open=false,powered=false] +194:13,minecraft:birch_door[facing=east,half=upper,hinge=right,open=false,powered=false] +194:14,minecraft:birch_door[facing=east,half=upper,hinge=left,open=false,powered=true] +194:15,minecraft:birch_door[facing=east,half=upper,hinge=right,open=false,powered=true] +195:0,minecraft:jungle_door[facing=east,half=lower,hinge=right,open=false,powered=false] +195:1,minecraft:jungle_door[facing=south,half=lower,hinge=right,open=false,powered=false] +195:2,minecraft:jungle_door[facing=west,half=lower,hinge=right,open=false,powered=false] +195:3,minecraft:jungle_door[facing=north,half=lower,hinge=right,open=false,powered=false] +195:4,minecraft:jungle_door[facing=east,half=lower,hinge=right,open=true,powered=false] +195:5,minecraft:jungle_door[facing=south,half=lower,hinge=right,open=true,powered=false] +195:6,minecraft:jungle_door[facing=west,half=lower,hinge=right,open=true,powered=false] +195:7,minecraft:jungle_door[facing=north,half=lower,hinge=right,open=true,powered=false] +195:8,minecraft:jungle_door[facing=east,half=upper,hinge=left,open=false,powered=false] +195:9,minecraft:jungle_door[facing=east,half=upper,hinge=right,open=false,powered=false] +195:10,minecraft:jungle_door[facing=east,half=upper,hinge=left,open=false,powered=true] +195:11,minecraft:jungle_door[facing=east,half=upper,hinge=right,open=false,powered=true] +195:12,minecraft:jungle_door[facing=east,half=upper,hinge=left,open=false,powered=false] +195:13,minecraft:jungle_door[facing=east,half=upper,hinge=right,open=false,powered=false] +195:14,minecraft:jungle_door[facing=east,half=upper,hinge=left,open=false,powered=true] +195:15,minecraft:jungle_door[facing=east,half=upper,hinge=right,open=false,powered=true] +196:0,minecraft:acacia_door[facing=east,half=lower,hinge=right,open=false,powered=false] +196:1,minecraft:acacia_door[facing=south,half=lower,hinge=right,open=false,powered=false] +196:2,minecraft:acacia_door[facing=west,half=lower,hinge=right,open=false,powered=false] +196:3,minecraft:acacia_door[facing=north,half=lower,hinge=right,open=false,powered=false] +196:4,minecraft:acacia_door[facing=east,half=lower,hinge=right,open=true,powered=false] +196:5,minecraft:acacia_door[facing=south,half=lower,hinge=right,open=true,powered=false] +196:6,minecraft:acacia_door[facing=west,half=lower,hinge=right,open=true,powered=false] +196:7,minecraft:acacia_door[facing=north,half=lower,hinge=right,open=true,powered=false] +196:8,minecraft:acacia_door[facing=east,half=upper,hinge=left,open=false,powered=false] +196:9,minecraft:acacia_door[facing=east,half=upper,hinge=right,open=false,powered=false] +196:10,minecraft:acacia_door[facing=east,half=upper,hinge=left,open=false,powered=true] +196:11,minecraft:acacia_door[facing=east,half=upper,hinge=right,open=false,powered=true] +196:12,minecraft:acacia_door[facing=east,half=upper,hinge=left,open=false,powered=false] +196:13,minecraft:acacia_door[facing=east,half=upper,hinge=right,open=false,powered=false] +196:14,minecraft:acacia_door[facing=east,half=upper,hinge=left,open=false,powered=true] +196:15,minecraft:acacia_door[facing=east,half=upper,hinge=right,open=false,powered=true] +197:0,minecraft:dark_oak_door[facing=east,half=lower,hinge=right,open=false,powered=false] +197:1,minecraft:dark_oak_door[facing=south,half=lower,hinge=right,open=false,powered=false] +197:2,minecraft:dark_oak_door[facing=west,half=lower,hinge=right,open=false,powered=false] +197:3,minecraft:dark_oak_door[facing=north,half=lower,hinge=right,open=false,powered=false] +197:4,minecraft:dark_oak_door[facing=east,half=lower,hinge=right,open=true,powered=false] +197:5,minecraft:dark_oak_door[facing=south,half=lower,hinge=right,open=true,powered=false] +197:6,minecraft:dark_oak_door[facing=west,half=lower,hinge=right,open=true,powered=false] +197:7,minecraft:dark_oak_door[facing=north,half=lower,hinge=right,open=true,powered=false] +197:8,minecraft:dark_oak_door[facing=east,half=upper,hinge=left,open=false,powered=false] +197:9,minecraft:dark_oak_door[facing=east,half=upper,hinge=right,open=false,powered=false] +197:10,minecraft:dark_oak_door[facing=east,half=upper,hinge=left,open=false,powered=true] +197:11,minecraft:dark_oak_door[facing=east,half=upper,hinge=right,open=false,powered=true] +197:12,minecraft:dark_oak_door[facing=east,half=upper,hinge=left,open=false,powered=false] +197:13,minecraft:dark_oak_door[facing=east,half=upper,hinge=right,open=false,powered=false] +197:14,minecraft:dark_oak_door[facing=east,half=upper,hinge=left,open=false,powered=true] +197:15,minecraft:dark_oak_door[facing=east,half=upper,hinge=right,open=false,powered=true] +198:0,minecraft:end_rod[facing=down] +198:1,minecraft:end_rod[facing=up] +198:2,minecraft:end_rod[facing=north] +198:3,minecraft:end_rod[facing=south] +198:4,minecraft:end_rod[facing=west] +198:5,minecraft:end_rod[facing=east] +198:7,minecraft:end_rod[facing=up] +198:8,minecraft:end_rod[facing=north] +198:9,minecraft:end_rod[facing=south] +198:10,minecraft:end_rod[facing=west] +198:11,minecraft:end_rod[facing=east] +198:13,minecraft:end_rod[facing=up] +198:14,minecraft:end_rod[facing=north] +198:15,minecraft:end_rod[facing=south] +199:0,minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=false] +200:0,minecraft:chorus_flower[age=0] +200:1,minecraft:chorus_flower[age=1] +200:2,minecraft:chorus_flower[age=2] +200:3,minecraft:chorus_flower[age=3] +200:4,minecraft:chorus_flower[age=4] +200:5,minecraft:chorus_flower[age=5] +200:6,minecraft:air +200:7,minecraft:air +200:8,minecraft:air +200:9,minecraft:air +200:10,minecraft:air +200:11,minecraft:air +200:12,minecraft:air +200:13,minecraft:air +200:14,minecraft:air +200:15,minecraft:air +201:0,minecraft:purpur_block +202:0,minecraft:purpur_pillar[axis=y] +202:4,minecraft:purpur_pillar[axis=x] +202:5,minecraft:purpur_pillar[axis=x] +202:6,minecraft:purpur_pillar[axis=x] +202:7,minecraft:purpur_pillar[axis=x] +202:8,minecraft:purpur_pillar[axis=z] +202:9,minecraft:purpur_pillar[axis=z] +202:10,minecraft:purpur_pillar[axis=z] +202:11,minecraft:purpur_pillar[axis=z] +203:0,minecraft:purpur_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] +203:1,minecraft:purpur_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +203:2,minecraft:purpur_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +203:3,minecraft:purpur_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +203:4,minecraft:purpur_stairs[facing=east,half=top,shape=straight,waterlogged=false] +203:5,minecraft:purpur_stairs[facing=west,half=top,shape=straight,waterlogged=false] +203:6,minecraft:purpur_stairs[facing=south,half=top,shape=straight,waterlogged=false] +203:7,minecraft:purpur_stairs[facing=north,half=top,shape=straight,waterlogged=false] +203:9,minecraft:purpur_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] +203:10,minecraft:purpur_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] +203:11,minecraft:purpur_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] +203:12,minecraft:purpur_stairs[facing=east,half=top,shape=straight,waterlogged=false] +203:13,minecraft:purpur_stairs[facing=west,half=top,shape=straight,waterlogged=false] +203:14,minecraft:purpur_stairs[facing=south,half=top,shape=straight,waterlogged=false] +203:15,minecraft:purpur_stairs[facing=north,half=top,shape=straight,waterlogged=false] +204:0,minecraft:purpur_slab[type=double,waterlogged=false] +205:0,minecraft:purpur_slab[type=bottom,waterlogged=false] +205:8,minecraft:purpur_slab[type=top,waterlogged=false] +205:9,minecraft:purpur_slab[type=top,waterlogged=false] +205:10,minecraft:purpur_slab[type=top,waterlogged=false] +205:11,minecraft:purpur_slab[type=top,waterlogged=false] +205:12,minecraft:purpur_slab[type=top,waterlogged=false] +205:13,minecraft:purpur_slab[type=top,waterlogged=false] +205:14,minecraft:purpur_slab[type=top,waterlogged=false] +205:15,minecraft:purpur_slab[type=top,waterlogged=false] +206:0,minecraft:end_stone_bricks +207:0,minecraft:beetroots[age=0] +207:1,minecraft:beetroots[age=1] +207:2,minecraft:beetroots[age=2] +207:3,minecraft:beetroots[age=3] +207:4,minecraft:air +207:5,minecraft:air +207:6,minecraft:air +207:7,minecraft:air +207:8,minecraft:air +207:9,minecraft:air +207:10,minecraft:air +207:11,minecraft:air +207:12,minecraft:air +207:13,minecraft:air +207:14,minecraft:air +207:15,minecraft:air +208:0,minecraft:grass_path +209:0,minecraft:end_gateway +210:0,minecraft:repeating_command_block[conditional=false,facing=down] +210:1,minecraft:repeating_command_block[conditional=false,facing=up] +210:2,minecraft:repeating_command_block[conditional=false,facing=north] +210:3,minecraft:repeating_command_block[conditional=false,facing=south] +210:4,minecraft:repeating_command_block[conditional=false,facing=west] +210:5,minecraft:repeating_command_block[conditional=false,facing=east] +210:7,minecraft:repeating_command_block[conditional=false,facing=up] +210:8,minecraft:repeating_command_block[conditional=true,facing=down] +210:9,minecraft:repeating_command_block[conditional=true,facing=up] +210:10,minecraft:repeating_command_block[conditional=true,facing=north] +210:11,minecraft:repeating_command_block[conditional=true,facing=south] +210:12,minecraft:repeating_command_block[conditional=true,facing=west] +210:13,minecraft:repeating_command_block[conditional=true,facing=east] +210:14,minecraft:repeating_command_block[conditional=true,facing=down] +210:15,minecraft:repeating_command_block[conditional=true,facing=up] +211:0,minecraft:chain_command_block[conditional=false,facing=down] +211:1,minecraft:chain_command_block[conditional=false,facing=up] +211:2,minecraft:chain_command_block[conditional=false,facing=north] +211:3,minecraft:chain_command_block[conditional=false,facing=south] +211:4,minecraft:chain_command_block[conditional=false,facing=west] +211:5,minecraft:chain_command_block[conditional=false,facing=east] +211:7,minecraft:chain_command_block[conditional=false,facing=up] +211:8,minecraft:chain_command_block[conditional=true,facing=down] +211:9,minecraft:chain_command_block[conditional=true,facing=up] +211:10,minecraft:chain_command_block[conditional=true,facing=north] +211:11,minecraft:chain_command_block[conditional=true,facing=south] +211:12,minecraft:chain_command_block[conditional=true,facing=west] +211:13,minecraft:chain_command_block[conditional=true,facing=east] +211:14,minecraft:chain_command_block[conditional=true,facing=down] +211:15,minecraft:chain_command_block[conditional=true,facing=up] +212:0,minecraft:frosted_ice[age=0] +212:1,minecraft:frosted_ice[age=1] +212:2,minecraft:frosted_ice[age=2] +212:3,minecraft:frosted_ice[age=3] +212:4,minecraft:frosted_ice[age=3] +212:5,minecraft:frosted_ice[age=3] +212:6,minecraft:frosted_ice[age=3] +212:7,minecraft:frosted_ice[age=3] +212:8,minecraft:frosted_ice[age=3] +212:9,minecraft:frosted_ice[age=3] +212:10,minecraft:frosted_ice[age=3] +212:11,minecraft:frosted_ice[age=3] +212:12,minecraft:frosted_ice[age=3] +212:13,minecraft:frosted_ice[age=3] +212:14,minecraft:frosted_ice[age=3] +212:15,minecraft:frosted_ice[age=3] +213:0,minecraft:magma_block +214:0,minecraft:nether_wart_block +215:0,minecraft:red_nether_bricks +216:0,minecraft:bone_block[axis=y] +216:4,minecraft:bone_block[axis=x] +216:5,minecraft:bone_block[axis=x] +216:6,minecraft:bone_block[axis=x] +216:7,minecraft:bone_block[axis=x] +216:8,minecraft:bone_block[axis=z] +216:9,minecraft:bone_block[axis=z] +216:10,minecraft:bone_block[axis=z] +216:11,minecraft:bone_block[axis=z] +217:0,minecraft:structure_void +218:0,minecraft:observer[facing=down,powered=false] +218:1,minecraft:observer[facing=up,powered=false] +218:2,minecraft:observer[facing=north,powered=false] +218:3,minecraft:observer[facing=south,powered=false] +218:4,minecraft:observer[facing=west,powered=false] +218:5,minecraft:observer[facing=east,powered=false] +218:7,minecraft:observer[facing=up,powered=false] +218:9,minecraft:observer[facing=up,powered=false] +218:10,minecraft:observer[facing=north,powered=false] +218:11,minecraft:observer[facing=south,powered=false] +218:12,minecraft:observer[facing=west,powered=false] +218:13,minecraft:observer[facing=east,powered=false] +218:15,minecraft:observer[facing=up,powered=false] +219:0,minecraft:white_shulker_box[facing=down] +219:1,minecraft:white_shulker_box[facing=up] +219:2,minecraft:white_shulker_box[facing=north] +219:3,minecraft:white_shulker_box[facing=south] +219:4,minecraft:white_shulker_box[facing=west] +219:5,minecraft:white_shulker_box[facing=east] +219:7,minecraft:white_shulker_box[facing=up] +219:8,minecraft:white_shulker_box[facing=north] +219:9,minecraft:white_shulker_box[facing=south] +219:10,minecraft:white_shulker_box[facing=west] +219:11,minecraft:white_shulker_box[facing=east] +219:13,minecraft:white_shulker_box[facing=up] +219:14,minecraft:white_shulker_box[facing=north] +219:15,minecraft:white_shulker_box[facing=south] +220:0,minecraft:orange_shulker_box[facing=down] +220:1,minecraft:orange_shulker_box[facing=up] +220:2,minecraft:orange_shulker_box[facing=north] +220:3,minecraft:orange_shulker_box[facing=south] +220:4,minecraft:orange_shulker_box[facing=west] +220:5,minecraft:orange_shulker_box[facing=east] +220:7,minecraft:orange_shulker_box[facing=up] +220:8,minecraft:orange_shulker_box[facing=north] +220:9,minecraft:orange_shulker_box[facing=south] +220:10,minecraft:orange_shulker_box[facing=west] +220:11,minecraft:orange_shulker_box[facing=east] +220:13,minecraft:orange_shulker_box[facing=up] +220:14,minecraft:orange_shulker_box[facing=north] +220:15,minecraft:orange_shulker_box[facing=south] +221:0,minecraft:magenta_shulker_box[facing=down] +221:1,minecraft:magenta_shulker_box[facing=up] +221:2,minecraft:magenta_shulker_box[facing=north] +221:3,minecraft:magenta_shulker_box[facing=south] +221:4,minecraft:magenta_shulker_box[facing=west] +221:5,minecraft:magenta_shulker_box[facing=east] +221:7,minecraft:magenta_shulker_box[facing=up] +221:8,minecraft:magenta_shulker_box[facing=north] +221:9,minecraft:magenta_shulker_box[facing=south] +221:10,minecraft:magenta_shulker_box[facing=west] +221:11,minecraft:magenta_shulker_box[facing=east] +221:13,minecraft:magenta_shulker_box[facing=up] +221:14,minecraft:magenta_shulker_box[facing=north] +221:15,minecraft:magenta_shulker_box[facing=south] +222:0,minecraft:light_blue_shulker_box[facing=down] +222:1,minecraft:light_blue_shulker_box[facing=up] +222:2,minecraft:light_blue_shulker_box[facing=north] +222:3,minecraft:light_blue_shulker_box[facing=south] +222:4,minecraft:light_blue_shulker_box[facing=west] +222:5,minecraft:light_blue_shulker_box[facing=east] +222:7,minecraft:light_blue_shulker_box[facing=up] +222:8,minecraft:light_blue_shulker_box[facing=north] +222:9,minecraft:light_blue_shulker_box[facing=south] +222:10,minecraft:light_blue_shulker_box[facing=west] +222:11,minecraft:light_blue_shulker_box[facing=east] +222:13,minecraft:light_blue_shulker_box[facing=up] +222:14,minecraft:light_blue_shulker_box[facing=north] +222:15,minecraft:light_blue_shulker_box[facing=south] +223:0,minecraft:yellow_shulker_box[facing=down] +223:1,minecraft:yellow_shulker_box[facing=up] +223:2,minecraft:yellow_shulker_box[facing=north] +223:3,minecraft:yellow_shulker_box[facing=south] +223:4,minecraft:yellow_shulker_box[facing=west] +223:5,minecraft:yellow_shulker_box[facing=east] +223:7,minecraft:yellow_shulker_box[facing=up] +223:8,minecraft:yellow_shulker_box[facing=north] +223:9,minecraft:yellow_shulker_box[facing=south] +223:10,minecraft:yellow_shulker_box[facing=west] +223:11,minecraft:yellow_shulker_box[facing=east] +223:13,minecraft:yellow_shulker_box[facing=up] +223:14,minecraft:yellow_shulker_box[facing=north] +223:15,minecraft:yellow_shulker_box[facing=south] +224:0,minecraft:lime_shulker_box[facing=down] +224:1,minecraft:lime_shulker_box[facing=up] +224:2,minecraft:lime_shulker_box[facing=north] +224:3,minecraft:lime_shulker_box[facing=south] +224:4,minecraft:lime_shulker_box[facing=west] +224:5,minecraft:lime_shulker_box[facing=east] +224:7,minecraft:lime_shulker_box[facing=up] +224:8,minecraft:lime_shulker_box[facing=north] +224:9,minecraft:lime_shulker_box[facing=south] +224:10,minecraft:lime_shulker_box[facing=west] +224:11,minecraft:lime_shulker_box[facing=east] +224:13,minecraft:lime_shulker_box[facing=up] +224:14,minecraft:lime_shulker_box[facing=north] +224:15,minecraft:lime_shulker_box[facing=south] +225:0,minecraft:pink_shulker_box[facing=down] +225:1,minecraft:pink_shulker_box[facing=up] +225:2,minecraft:pink_shulker_box[facing=north] +225:3,minecraft:pink_shulker_box[facing=south] +225:4,minecraft:pink_shulker_box[facing=west] +225:5,minecraft:pink_shulker_box[facing=east] +225:7,minecraft:pink_shulker_box[facing=up] +225:8,minecraft:pink_shulker_box[facing=north] +225:9,minecraft:pink_shulker_box[facing=south] +225:10,minecraft:pink_shulker_box[facing=west] +225:11,minecraft:pink_shulker_box[facing=east] +225:13,minecraft:pink_shulker_box[facing=up] +225:14,minecraft:pink_shulker_box[facing=north] +225:15,minecraft:pink_shulker_box[facing=south] +226:0,minecraft:gray_shulker_box[facing=down] +226:1,minecraft:gray_shulker_box[facing=up] +226:2,minecraft:gray_shulker_box[facing=north] +226:3,minecraft:gray_shulker_box[facing=south] +226:4,minecraft:gray_shulker_box[facing=west] +226:5,minecraft:gray_shulker_box[facing=east] +226:7,minecraft:gray_shulker_box[facing=up] +226:8,minecraft:gray_shulker_box[facing=north] +226:9,minecraft:gray_shulker_box[facing=south] +226:10,minecraft:gray_shulker_box[facing=west] +226:11,minecraft:gray_shulker_box[facing=east] +226:13,minecraft:gray_shulker_box[facing=up] +226:14,minecraft:gray_shulker_box[facing=north] +226:15,minecraft:gray_shulker_box[facing=south] +227:0,minecraft:light_gray_shulker_box[facing=down] +227:1,minecraft:light_gray_shulker_box[facing=up] +227:2,minecraft:light_gray_shulker_box[facing=north] +227:3,minecraft:light_gray_shulker_box[facing=south] +227:4,minecraft:light_gray_shulker_box[facing=west] +227:5,minecraft:light_gray_shulker_box[facing=east] +227:7,minecraft:light_gray_shulker_box[facing=up] +227:8,minecraft:light_gray_shulker_box[facing=north] +227:9,minecraft:light_gray_shulker_box[facing=south] +227:10,minecraft:light_gray_shulker_box[facing=west] +227:11,minecraft:light_gray_shulker_box[facing=east] +227:13,minecraft:light_gray_shulker_box[facing=up] +227:14,minecraft:light_gray_shulker_box[facing=north] +227:15,minecraft:light_gray_shulker_box[facing=south] +228:0,minecraft:cyan_shulker_box[facing=down] +228:1,minecraft:cyan_shulker_box[facing=up] +228:2,minecraft:cyan_shulker_box[facing=north] +228:3,minecraft:cyan_shulker_box[facing=south] +228:4,minecraft:cyan_shulker_box[facing=west] +228:5,minecraft:cyan_shulker_box[facing=east] +228:7,minecraft:cyan_shulker_box[facing=up] +228:8,minecraft:cyan_shulker_box[facing=north] +228:9,minecraft:cyan_shulker_box[facing=south] +228:10,minecraft:cyan_shulker_box[facing=west] +228:11,minecraft:cyan_shulker_box[facing=east] +228:13,minecraft:cyan_shulker_box[facing=up] +228:14,minecraft:cyan_shulker_box[facing=north] +228:15,minecraft:cyan_shulker_box[facing=south] +229:0,minecraft:shulker_box[facing=down] +229:1,minecraft:shulker_box[facing=up] +229:2,minecraft:shulker_box[facing=north] +229:3,minecraft:shulker_box[facing=south] +229:4,minecraft:shulker_box[facing=west] +229:5,minecraft:shulker_box[facing=east] +229:7,minecraft:shulker_box[facing=up] +229:8,minecraft:shulker_box[facing=north] +229:9,minecraft:shulker_box[facing=south] +229:10,minecraft:shulker_box[facing=west] +229:11,minecraft:shulker_box[facing=east] +229:13,minecraft:shulker_box[facing=up] +229:14,minecraft:shulker_box[facing=north] +229:15,minecraft:shulker_box[facing=south] +230:0,minecraft:blue_shulker_box[facing=down] +230:1,minecraft:blue_shulker_box[facing=up] +230:2,minecraft:blue_shulker_box[facing=north] +230:3,minecraft:blue_shulker_box[facing=south] +230:4,minecraft:blue_shulker_box[facing=west] +230:5,minecraft:blue_shulker_box[facing=east] +230:7,minecraft:blue_shulker_box[facing=up] +230:8,minecraft:blue_shulker_box[facing=north] +230:9,minecraft:blue_shulker_box[facing=south] +230:10,minecraft:blue_shulker_box[facing=west] +230:11,minecraft:blue_shulker_box[facing=east] +230:13,minecraft:blue_shulker_box[facing=up] +230:14,minecraft:blue_shulker_box[facing=north] +230:15,minecraft:blue_shulker_box[facing=south] +231:0,minecraft:brown_shulker_box[facing=down] +231:1,minecraft:brown_shulker_box[facing=up] +231:2,minecraft:brown_shulker_box[facing=north] +231:3,minecraft:brown_shulker_box[facing=south] +231:4,minecraft:brown_shulker_box[facing=west] +231:5,minecraft:brown_shulker_box[facing=east] +231:7,minecraft:brown_shulker_box[facing=up] +231:8,minecraft:brown_shulker_box[facing=north] +231:9,minecraft:brown_shulker_box[facing=south] +231:10,minecraft:brown_shulker_box[facing=west] +231:11,minecraft:brown_shulker_box[facing=east] +231:13,minecraft:brown_shulker_box[facing=up] +231:14,minecraft:brown_shulker_box[facing=north] +231:15,minecraft:brown_shulker_box[facing=south] +232:0,minecraft:green_shulker_box[facing=down] +232:1,minecraft:green_shulker_box[facing=up] +232:2,minecraft:green_shulker_box[facing=north] +232:3,minecraft:green_shulker_box[facing=south] +232:4,minecraft:green_shulker_box[facing=west] +232:5,minecraft:green_shulker_box[facing=east] +232:7,minecraft:green_shulker_box[facing=up] +232:8,minecraft:green_shulker_box[facing=north] +232:9,minecraft:green_shulker_box[facing=south] +232:10,minecraft:green_shulker_box[facing=west] +232:11,minecraft:green_shulker_box[facing=east] +232:13,minecraft:green_shulker_box[facing=up] +232:14,minecraft:green_shulker_box[facing=north] +232:15,minecraft:green_shulker_box[facing=south] +233:0,minecraft:red_shulker_box[facing=down] +233:1,minecraft:red_shulker_box[facing=up] +233:2,minecraft:red_shulker_box[facing=north] +233:3,minecraft:red_shulker_box[facing=south] +233:4,minecraft:red_shulker_box[facing=west] +233:5,minecraft:red_shulker_box[facing=east] +233:7,minecraft:red_shulker_box[facing=up] +233:8,minecraft:red_shulker_box[facing=north] +233:9,minecraft:red_shulker_box[facing=south] +233:10,minecraft:red_shulker_box[facing=west] +233:11,minecraft:red_shulker_box[facing=east] +233:13,minecraft:red_shulker_box[facing=up] +233:14,minecraft:red_shulker_box[facing=north] +233:15,minecraft:red_shulker_box[facing=south] +234:0,minecraft:black_shulker_box[facing=down] +234:1,minecraft:black_shulker_box[facing=up] +234:2,minecraft:black_shulker_box[facing=north] +234:3,minecraft:black_shulker_box[facing=south] +234:4,minecraft:black_shulker_box[facing=west] +234:5,minecraft:black_shulker_box[facing=east] +234:7,minecraft:black_shulker_box[facing=up] +234:8,minecraft:black_shulker_box[facing=north] +234:9,minecraft:black_shulker_box[facing=south] +234:10,minecraft:black_shulker_box[facing=west] +234:11,minecraft:black_shulker_box[facing=east] +234:13,minecraft:black_shulker_box[facing=up] +234:14,minecraft:black_shulker_box[facing=north] +234:15,minecraft:black_shulker_box[facing=south] +235:0,minecraft:white_glazed_terracotta[facing=south] +235:1,minecraft:white_glazed_terracotta[facing=west] +235:2,minecraft:white_glazed_terracotta[facing=north] +235:3,minecraft:white_glazed_terracotta[facing=east] +235:5,minecraft:white_glazed_terracotta[facing=west] +235:6,minecraft:white_glazed_terracotta[facing=north] +235:7,minecraft:white_glazed_terracotta[facing=east] +235:9,minecraft:white_glazed_terracotta[facing=west] +235:10,minecraft:white_glazed_terracotta[facing=north] +235:11,minecraft:white_glazed_terracotta[facing=east] +235:13,minecraft:white_glazed_terracotta[facing=west] +235:14,minecraft:white_glazed_terracotta[facing=north] +235:15,minecraft:white_glazed_terracotta[facing=east] +236:0,minecraft:orange_glazed_terracotta[facing=south] +236:1,minecraft:orange_glazed_terracotta[facing=west] +236:2,minecraft:orange_glazed_terracotta[facing=north] +236:3,minecraft:orange_glazed_terracotta[facing=east] +236:5,minecraft:orange_glazed_terracotta[facing=west] +236:6,minecraft:orange_glazed_terracotta[facing=north] +236:7,minecraft:orange_glazed_terracotta[facing=east] +236:9,minecraft:orange_glazed_terracotta[facing=west] +236:10,minecraft:orange_glazed_terracotta[facing=north] +236:11,minecraft:orange_glazed_terracotta[facing=east] +236:13,minecraft:orange_glazed_terracotta[facing=west] +236:14,minecraft:orange_glazed_terracotta[facing=north] +236:15,minecraft:orange_glazed_terracotta[facing=east] +237:0,minecraft:magenta_glazed_terracotta[facing=south] +237:1,minecraft:magenta_glazed_terracotta[facing=west] +237:2,minecraft:magenta_glazed_terracotta[facing=north] +237:3,minecraft:magenta_glazed_terracotta[facing=east] +237:5,minecraft:magenta_glazed_terracotta[facing=west] +237:6,minecraft:magenta_glazed_terracotta[facing=north] +237:7,minecraft:magenta_glazed_terracotta[facing=east] +237:9,minecraft:magenta_glazed_terracotta[facing=west] +237:10,minecraft:magenta_glazed_terracotta[facing=north] +237:11,minecraft:magenta_glazed_terracotta[facing=east] +237:13,minecraft:magenta_glazed_terracotta[facing=west] +237:14,minecraft:magenta_glazed_terracotta[facing=north] +237:15,minecraft:magenta_glazed_terracotta[facing=east] +238:0,minecraft:light_blue_glazed_terracotta[facing=south] +238:1,minecraft:light_blue_glazed_terracotta[facing=west] +238:2,minecraft:light_blue_glazed_terracotta[facing=north] +238:3,minecraft:light_blue_glazed_terracotta[facing=east] +238:5,minecraft:light_blue_glazed_terracotta[facing=west] +238:6,minecraft:light_blue_glazed_terracotta[facing=north] +238:7,minecraft:light_blue_glazed_terracotta[facing=east] +238:9,minecraft:light_blue_glazed_terracotta[facing=west] +238:10,minecraft:light_blue_glazed_terracotta[facing=north] +238:11,minecraft:light_blue_glazed_terracotta[facing=east] +238:13,minecraft:light_blue_glazed_terracotta[facing=west] +238:14,minecraft:light_blue_glazed_terracotta[facing=north] +238:15,minecraft:light_blue_glazed_terracotta[facing=east] +239:0,minecraft:yellow_glazed_terracotta[facing=south] +239:1,minecraft:yellow_glazed_terracotta[facing=west] +239:2,minecraft:yellow_glazed_terracotta[facing=north] +239:3,minecraft:yellow_glazed_terracotta[facing=east] +239:5,minecraft:yellow_glazed_terracotta[facing=west] +239:6,minecraft:yellow_glazed_terracotta[facing=north] +239:7,minecraft:yellow_glazed_terracotta[facing=east] +239:9,minecraft:yellow_glazed_terracotta[facing=west] +239:10,minecraft:yellow_glazed_terracotta[facing=north] +239:11,minecraft:yellow_glazed_terracotta[facing=east] +239:13,minecraft:yellow_glazed_terracotta[facing=west] +239:14,minecraft:yellow_glazed_terracotta[facing=north] +239:15,minecraft:yellow_glazed_terracotta[facing=east] +240:0,minecraft:lime_glazed_terracotta[facing=south] +240:1,minecraft:lime_glazed_terracotta[facing=west] +240:2,minecraft:lime_glazed_terracotta[facing=north] +240:3,minecraft:lime_glazed_terracotta[facing=east] +240:5,minecraft:lime_glazed_terracotta[facing=west] +240:6,minecraft:lime_glazed_terracotta[facing=north] +240:7,minecraft:lime_glazed_terracotta[facing=east] +240:9,minecraft:lime_glazed_terracotta[facing=west] +240:10,minecraft:lime_glazed_terracotta[facing=north] +240:11,minecraft:lime_glazed_terracotta[facing=east] +240:13,minecraft:lime_glazed_terracotta[facing=west] +240:14,minecraft:lime_glazed_terracotta[facing=north] +240:15,minecraft:lime_glazed_terracotta[facing=east] +241:0,minecraft:pink_glazed_terracotta[facing=south] +241:1,minecraft:pink_glazed_terracotta[facing=west] +241:2,minecraft:pink_glazed_terracotta[facing=north] +241:3,minecraft:pink_glazed_terracotta[facing=east] +241:5,minecraft:pink_glazed_terracotta[facing=west] +241:6,minecraft:pink_glazed_terracotta[facing=north] +241:7,minecraft:pink_glazed_terracotta[facing=east] +241:9,minecraft:pink_glazed_terracotta[facing=west] +241:10,minecraft:pink_glazed_terracotta[facing=north] +241:11,minecraft:pink_glazed_terracotta[facing=east] +241:13,minecraft:pink_glazed_terracotta[facing=west] +241:14,minecraft:pink_glazed_terracotta[facing=north] +241:15,minecraft:pink_glazed_terracotta[facing=east] +242:0,minecraft:gray_glazed_terracotta[facing=south] +242:1,minecraft:gray_glazed_terracotta[facing=west] +242:2,minecraft:gray_glazed_terracotta[facing=north] +242:3,minecraft:gray_glazed_terracotta[facing=east] +242:5,minecraft:gray_glazed_terracotta[facing=west] +242:6,minecraft:gray_glazed_terracotta[facing=north] +242:7,minecraft:gray_glazed_terracotta[facing=east] +242:9,minecraft:gray_glazed_terracotta[facing=west] +242:10,minecraft:gray_glazed_terracotta[facing=north] +242:11,minecraft:gray_glazed_terracotta[facing=east] +242:13,minecraft:gray_glazed_terracotta[facing=west] +242:14,minecraft:gray_glazed_terracotta[facing=north] +242:15,minecraft:gray_glazed_terracotta[facing=east] +243:0,minecraft:light_gray_glazed_terracotta[facing=south] +243:1,minecraft:light_gray_glazed_terracotta[facing=west] +243:2,minecraft:light_gray_glazed_terracotta[facing=north] +243:3,minecraft:light_gray_glazed_terracotta[facing=east] +243:5,minecraft:light_gray_glazed_terracotta[facing=west] +243:6,minecraft:light_gray_glazed_terracotta[facing=north] +243:7,minecraft:light_gray_glazed_terracotta[facing=east] +243:9,minecraft:light_gray_glazed_terracotta[facing=west] +243:10,minecraft:light_gray_glazed_terracotta[facing=north] +243:11,minecraft:light_gray_glazed_terracotta[facing=east] +243:13,minecraft:light_gray_glazed_terracotta[facing=west] +243:14,minecraft:light_gray_glazed_terracotta[facing=north] +243:15,minecraft:light_gray_glazed_terracotta[facing=east] +244:0,minecraft:cyan_glazed_terracotta[facing=south] +244:1,minecraft:cyan_glazed_terracotta[facing=west] +244:2,minecraft:cyan_glazed_terracotta[facing=north] +244:3,minecraft:cyan_glazed_terracotta[facing=east] +244:5,minecraft:cyan_glazed_terracotta[facing=west] +244:6,minecraft:cyan_glazed_terracotta[facing=north] +244:7,minecraft:cyan_glazed_terracotta[facing=east] +244:9,minecraft:cyan_glazed_terracotta[facing=west] +244:10,minecraft:cyan_glazed_terracotta[facing=north] +244:11,minecraft:cyan_glazed_terracotta[facing=east] +244:13,minecraft:cyan_glazed_terracotta[facing=west] +244:14,minecraft:cyan_glazed_terracotta[facing=north] +244:15,minecraft:cyan_glazed_terracotta[facing=east] +245:0,minecraft:purple_glazed_terracotta[facing=south] +245:1,minecraft:purple_glazed_terracotta[facing=west] +245:2,minecraft:purple_glazed_terracotta[facing=north] +245:3,minecraft:purple_glazed_terracotta[facing=east] +245:5,minecraft:purple_glazed_terracotta[facing=west] +245:6,minecraft:purple_glazed_terracotta[facing=north] +245:7,minecraft:purple_glazed_terracotta[facing=east] +245:9,minecraft:purple_glazed_terracotta[facing=west] +245:10,minecraft:purple_glazed_terracotta[facing=north] +245:11,minecraft:purple_glazed_terracotta[facing=east] +245:13,minecraft:purple_glazed_terracotta[facing=west] +245:14,minecraft:purple_glazed_terracotta[facing=north] +245:15,minecraft:purple_glazed_terracotta[facing=east] +246:0,minecraft:blue_glazed_terracotta[facing=south] +246:1,minecraft:blue_glazed_terracotta[facing=west] +246:2,minecraft:blue_glazed_terracotta[facing=north] +246:3,minecraft:blue_glazed_terracotta[facing=east] +246:5,minecraft:blue_glazed_terracotta[facing=west] +246:6,minecraft:blue_glazed_terracotta[facing=north] +246:7,minecraft:blue_glazed_terracotta[facing=east] +246:9,minecraft:blue_glazed_terracotta[facing=west] +246:10,minecraft:blue_glazed_terracotta[facing=north] +246:11,minecraft:blue_glazed_terracotta[facing=east] +246:13,minecraft:blue_glazed_terracotta[facing=west] +246:14,minecraft:blue_glazed_terracotta[facing=north] +246:15,minecraft:blue_glazed_terracotta[facing=east] +247:0,minecraft:brown_glazed_terracotta[facing=south] +247:1,minecraft:brown_glazed_terracotta[facing=west] +247:2,minecraft:brown_glazed_terracotta[facing=north] +247:3,minecraft:brown_glazed_terracotta[facing=east] +247:5,minecraft:brown_glazed_terracotta[facing=west] +247:6,minecraft:brown_glazed_terracotta[facing=north] +247:7,minecraft:brown_glazed_terracotta[facing=east] +247:9,minecraft:brown_glazed_terracotta[facing=west] +247:10,minecraft:brown_glazed_terracotta[facing=north] +247:11,minecraft:brown_glazed_terracotta[facing=east] +247:13,minecraft:brown_glazed_terracotta[facing=west] +247:14,minecraft:brown_glazed_terracotta[facing=north] +247:15,minecraft:brown_glazed_terracotta[facing=east] +248:0,minecraft:green_glazed_terracotta[facing=south] +248:1,minecraft:green_glazed_terracotta[facing=west] +248:2,minecraft:green_glazed_terracotta[facing=north] +248:3,minecraft:green_glazed_terracotta[facing=east] +248:5,minecraft:green_glazed_terracotta[facing=west] +248:6,minecraft:green_glazed_terracotta[facing=north] +248:7,minecraft:green_glazed_terracotta[facing=east] +248:9,minecraft:green_glazed_terracotta[facing=west] +248:10,minecraft:green_glazed_terracotta[facing=north] +248:11,minecraft:green_glazed_terracotta[facing=east] +248:13,minecraft:green_glazed_terracotta[facing=west] +248:14,minecraft:green_glazed_terracotta[facing=north] +248:15,minecraft:green_glazed_terracotta[facing=east] +249:0,minecraft:red_glazed_terracotta[facing=south] +249:1,minecraft:red_glazed_terracotta[facing=west] +249:2,minecraft:red_glazed_terracotta[facing=north] +249:3,minecraft:red_glazed_terracotta[facing=east] +249:5,minecraft:red_glazed_terracotta[facing=west] +249:6,minecraft:red_glazed_terracotta[facing=north] +249:7,minecraft:red_glazed_terracotta[facing=east] +249:9,minecraft:red_glazed_terracotta[facing=west] +249:10,minecraft:red_glazed_terracotta[facing=north] +249:11,minecraft:red_glazed_terracotta[facing=east] +249:13,minecraft:red_glazed_terracotta[facing=west] +249:14,minecraft:red_glazed_terracotta[facing=north] +249:15,minecraft:red_glazed_terracotta[facing=east] +250:0,minecraft:black_glazed_terracotta[facing=south] +250:1,minecraft:black_glazed_terracotta[facing=west] +250:2,minecraft:black_glazed_terracotta[facing=north] +250:3,minecraft:black_glazed_terracotta[facing=east] +250:5,minecraft:black_glazed_terracotta[facing=west] +250:6,minecraft:black_glazed_terracotta[facing=north] +250:7,minecraft:black_glazed_terracotta[facing=east] +250:9,minecraft:black_glazed_terracotta[facing=west] +250:10,minecraft:black_glazed_terracotta[facing=north] +250:11,minecraft:black_glazed_terracotta[facing=east] +250:13,minecraft:black_glazed_terracotta[facing=west] +250:14,minecraft:black_glazed_terracotta[facing=north] +250:15,minecraft:black_glazed_terracotta[facing=east] +251:0,minecraft:white_concrete +251:1,minecraft:orange_concrete +251:2,minecraft:magenta_concrete +251:3,minecraft:light_blue_concrete +251:4,minecraft:yellow_concrete +251:5,minecraft:lime_concrete +251:6,minecraft:pink_concrete +251:7,minecraft:gray_concrete +251:8,minecraft:light_gray_concrete +251:9,minecraft:cyan_concrete +251:10,minecraft:purple_concrete +251:11,minecraft:blue_concrete +251:12,minecraft:brown_concrete +251:13,minecraft:green_concrete +251:14,minecraft:red_concrete +251:15,minecraft:black_concrete +252:0,minecraft:white_concrete_powder +252:1,minecraft:orange_concrete_powder +252:2,minecraft:magenta_concrete_powder +252:3,minecraft:light_blue_concrete_powder +252:4,minecraft:yellow_concrete_powder +252:5,minecraft:lime_concrete_powder +252:6,minecraft:pink_concrete_powder +252:7,minecraft:gray_concrete_powder +252:8,minecraft:light_gray_concrete_powder +252:9,minecraft:cyan_concrete_powder +252:10,minecraft:purple_concrete_powder +252:11,minecraft:blue_concrete_powder +252:12,minecraft:brown_concrete_powder +252:13,minecraft:green_concrete_powder +252:14,minecraft:red_concrete_powder +252:15,minecraft:black_concrete_powder +255:0,minecraft:structure_block[mode=save] +255:1,minecraft:structure_block[mode=load] +255:2,minecraft:structure_block[mode=corner] +255:3,minecraft:structure_block[mode=data] From bdf18fac1e382f5a55f4a6864b9aa4212c0157f2 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 24 Jul 2018 21:50:59 +0200 Subject: [PATCH 018/399] Fix MaterialConverter query --- src/main/java/de/diddiz/LogBlock/MaterialConverter.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java index 62010d20..ba38d220 100644 --- a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java +++ b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java @@ -90,11 +90,7 @@ public static BlockData getBlockData(int materialId, int blockStateId) { } public static Material getMaterial(int materialId) { - String material = idToMaterial[materialId]; - if (materialId >= 0) { - material = material + idToBlockState[materialId]; - } - return materialKeyToMaterial.get(material); + return materialKeyToMaterial.get(idToMaterial[materialId]); } public static void initializeMaterials(Connection connection) throws SQLException { From 5cb9dfda503acb076caf9d082bb29e7e4e564718 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 25 Jul 2018 16:48:48 +0200 Subject: [PATCH 019/399] Update dependencies & maven plugins, add relocations --- pom.xml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 8c68d114..876c4b97 100644 --- a/pom.xml +++ b/pom.xml @@ -73,7 +73,7 @@ com.zaxxer HikariCP - 2.7.4 + 3.2.0 compile @@ -140,7 +140,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.2 + 3.7.0 1.8 1.8 @@ -149,7 +149,7 @@ org.codehaus.mojo build-helper-maven-plugin - 1.9.1 + 3.0.0 regex-property @@ -169,7 +169,7 @@ org.apache.maven.plugins maven-shade-plugin - 2.3 + 3.1.1 @@ -178,6 +178,18 @@ shade + + + + com.zaxxer.hikari + de.diddiz.lib.com.zaxxer.hikari + + + org.slf4j + de.diddiz.lib.org.slf4j + + + From 6e2325d346c2d9f85fce646a8a634196ccd26829 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 25 Jul 2018 17:17:29 +0200 Subject: [PATCH 020/399] The weapon might be null --- src/main/java/de/diddiz/LogBlock/Consumer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 7f8afbf8..683e9cdf 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -309,7 +309,7 @@ public void queueKill(Location location, Actor killer, Actor victim, ItemStack w if (victim == null || !isLogged(location.getWorld())) { return; } - queue.add(new KillRow(location, killer == null ? null : killer, victim, MaterialConverter.getOrAddMaterialId(weapon.getType().getKey().toString()))); + queue.add(new KillRow(location, killer == null ? null : killer, victim, weapon == null ? 0 : MaterialConverter.getOrAddMaterialId(weapon.getType().getKey().toString()))); } /** From 905c25a943039902383396faba07cd2bf47ddead Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 25 Jul 2018 17:18:32 +0200 Subject: [PATCH 021/399] Set the maximum size for the connection pool --- src/main/java/de/diddiz/util/MySQLConnectionPool.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/diddiz/util/MySQLConnectionPool.java b/src/main/java/de/diddiz/util/MySQLConnectionPool.java index b7e944c4..7db615a3 100644 --- a/src/main/java/de/diddiz/util/MySQLConnectionPool.java +++ b/src/main/java/de/diddiz/util/MySQLConnectionPool.java @@ -18,6 +18,7 @@ public MySQLConnectionPool(String url, String user, String password) { ds.setPassword(password); ds.setMinimumIdle(2); + ds.setMaximumPoolSize(15); ds.setPoolName("LogBlock-Connection-Pool"); ds.addDataSourceProperty("useUnicode", "true"); From 0a7ea8e747e75bccffacbc4deb6c35a5cddb2d17 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 27 Jul 2018 17:19:15 +0200 Subject: [PATCH 022/399] Treat CAVE_AIR and VOID_AIR the same as AIR --- src/main/java/de/diddiz/LogBlock/BlockChange.java | 10 +++++----- src/main/java/de/diddiz/LogBlock/Consumer.java | 12 ++++++------ src/main/java/de/diddiz/LogBlock/Kill.java | 4 +++- src/main/java/de/diddiz/LogBlock/WorldEditor.java | 6 ++++-- .../LogBlock/events/BlockChangePreLogEvent.java | 6 ++++-- .../diddiz/LogBlock/listeners/BlockPlaceLogging.java | 8 ++++---- .../diddiz/LogBlock/listeners/FluidFlowLogging.java | 8 ++++---- src/main/java/de/diddiz/util/BukkitUtils.java | 4 ++++ src/main/java/de/diddiz/util/LoggingUtil.java | 2 +- src/main/java/de/diddiz/util/Utils.java | 3 +-- .../de/diddiz/worldedit/WorldEditLoggingHook.java | 4 +++- 11 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index caa282e3..30af6f7c 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -74,14 +74,14 @@ public String toString() { msg.append(actor.getName()).append(" "); } if (signtext != null) { - final String action = type.getMaterial() == Material.AIR ? "destroyed " : "created "; + final String action = BukkitUtils.isEmpty(type.getMaterial()) ? "destroyed " : "created "; if (!signtext.contains("\0")) { msg.append(action).append(signtext); } else { - msg.append(action).append((type.getMaterial() != Material.AIR ? type : replaced).getMaterial().name()).append(" [").append(signtext.replace("\0", "] [")).append("]"); + msg.append(action).append((!BukkitUtils.isEmpty(type.getMaterial()) ? type : replaced).getMaterial().name()).append(" [").append(signtext.replace("\0", "] [")).append("]"); } } else if (type.equals(replaced)) { - if (type.getMaterial() == Material.AIR) { + if (BukkitUtils.isEmpty(type.getMaterial())) { msg.append("did an unspecified action"); } else if (ca != null) { if (ca.itemStack == null) { @@ -109,9 +109,9 @@ public String toString() { } else if (type.getMaterial() == Material.TRIPWIRE) { msg.append("ran into ").append(type.getMaterial().name()); } - } else if (type.getMaterial() == Material.AIR) { + } else if (BukkitUtils.isEmpty(type.getMaterial())) { msg.append("destroyed ").append(replaced.getMaterial().name()); - } else if (replaced.getMaterial() == Material.AIR) { + } else if (BukkitUtils.isEmpty(replaced.getMaterial())) { msg.append("created ").append(type.getMaterial().name()); } else { msg.append("replaced ").append(replaced.getMaterial().name()).append(" with ").append(type.getMaterial().name()); diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 683e9cdf..20bdb125 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -67,7 +67,7 @@ public void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDat } /** - * Logs a block break. The type afterwards is assumed to be 0 (air). + * Logs a block break. The type afterwards is assumed to be air. * * @param actor * Actor responsible for breaking the block @@ -79,7 +79,7 @@ public void queueBlockBreak(Actor actor, BlockState before) { } /** - * Logs a block break. The block type afterwards is assumed to be 0 (air). + * Logs a block break. The block type afterwards is assumed to be air. * * @param actor * Actor responsible for the block break @@ -95,7 +95,7 @@ public void queueBlockBreak(Actor actor, Location loc, BlockData typeBefore) { } /** - * Logs a block place. The block type before is assumed to be 0 (air). + * Logs a block place. The block type before is assumed to be air. * * @param actor * Actor responsible for placing the block @@ -107,7 +107,7 @@ public void queueBlockPlace(Actor actor, BlockState after) { } /** - * Logs a block place. The block type before is assumed to be 0 (air). + * Logs a block place. The block type before is assumed to be air. * * @param actor * Actor responsible for placing the block @@ -215,7 +215,7 @@ public void queueChestAccess(Actor actor, Location loc, BlockData type, ItemStac } /** - * Logs a container block break. The block type before is assumed to be o (air). All content is assumed to be taken. + * Logs a container block break. The block type before is assumed to be air. All content is assumed to be taken. * * @param actor * The actor breaking the container @@ -230,7 +230,7 @@ public void queueContainerBreak(Actor actor, BlockState container) { } /** - * Logs a container block break. The block type before is assumed to be o (air). All content is assumed to be taken. + * Logs a container block break. The block type before is assumed to be air. All content is assumed to be taken. * * @param actor * The actor responsible for breaking the container diff --git a/src/main/java/de/diddiz/LogBlock/Kill.java b/src/main/java/de/diddiz/LogBlock/Kill.java index 11ea97f8..819d32bc 100755 --- a/src/main/java/de/diddiz/LogBlock/Kill.java +++ b/src/main/java/de/diddiz/LogBlock/Kill.java @@ -1,6 +1,8 @@ package de.diddiz.LogBlock; import de.diddiz.LogBlock.config.Config; +import de.diddiz.util.BukkitUtils; + import org.bukkit.Location; import org.bukkit.Material; @@ -57,7 +59,7 @@ public String getMessage() { } public String prettyItemName(Material t) { - if (t == null || t == Material.AIR) { + if (t == null || BukkitUtils.isEmpty(t)) { return "fist"; } return t.toString().replace('_', ' ').toLowerCase(); diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 5cd9c033..813493a1 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -20,6 +20,8 @@ import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import de.diddiz.util.BukkitUtils; + import java.io.File; import java.io.PrintWriter; import java.text.SimpleDateFormat; @@ -167,7 +169,7 @@ PerformResult perform() throws WorldEditorException { return PerformResult.BLACKLISTED; } final Block block = loc.getBlock(); - if (replacedBlock.getMaterial() == Material.AIR && block.getType() == Material.AIR) { + if (BukkitUtils.isEmpty(replacedBlock.getMaterial()) && BukkitUtils.isEmpty(block.getType())) { return PerformResult.NO_ACTION; } final BlockState state = block.getState(); @@ -175,7 +177,7 @@ PerformResult perform() throws WorldEditorException { world.loadChunk(block.getChunk()); } if (setBlock.equals(replacedBlock)) { - if (setBlock.getMaterial() == Material.AIR) { + if (BukkitUtils.isEmpty(setBlock.getMaterial())) { block.setType(Material.AIR); } else if (ca != null) { if (state instanceof InventoryHolder) { diff --git a/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java b/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java index ade7807b..9d7bf62e 100644 --- a/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java +++ b/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java @@ -2,6 +2,8 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.ChestAccess; +import de.diddiz.util.BukkitUtils; + import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -85,10 +87,10 @@ public void setSignText(String[] signText) { private boolean isValidSign() { - if ((typeAfter.getMaterial() == Material.SIGN || typeAfter.getMaterial() == Material.WALL_SIGN) && typeBefore.getMaterial() == Material.AIR) { + if ((typeAfter.getMaterial() == Material.SIGN || typeAfter.getMaterial() == Material.WALL_SIGN) && BukkitUtils.isEmpty(typeBefore.getMaterial())) { return true; } - if ((typeBefore.getMaterial() == Material.SIGN || typeBefore.getMaterial() == Material.WALL_SIGN) && typeAfter.getMaterial() == Material.AIR) { + if ((typeBefore.getMaterial() == Material.SIGN || typeBefore.getMaterial() == Material.WALL_SIGN) && BukkitUtils.isEmpty(typeAfter.getMaterial())) { return true; } if ((typeAfter.getMaterial() == Material.SIGN || typeAfter.getMaterial() == Material.WALL_SIGN) && typeBefore.equals(typeAfter)) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java index 1324319b..f48aff8d 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java @@ -37,7 +37,7 @@ public void onBlockPlace(BlockPlaceEvent event) { if (type.hasGravity()) { // Catch placed blocks overwriting something - if (before.getType() != Material.AIR) { + if (!BukkitUtils.isEmpty(before.getType())) { consumer.queueBlockBreak(actor, before); } @@ -46,7 +46,7 @@ public void onBlockPlace(BlockPlaceEvent event) { int y = loc.getBlockY(); int z = loc.getBlockZ(); // Blocks only fall if they have a chance to start a velocity - if (event.getBlock().getRelative(BlockFace.DOWN).getType() == Material.AIR) { + if (BukkitUtils.isEmpty(event.getBlock().getRelative(BlockFace.DOWN).getType())) { while (y > 0 && BukkitUtils.canFall(loc.getWorld(), x, (y - 1), z)) { y--; } @@ -56,7 +56,7 @@ public void onBlockPlace(BlockPlaceEvent event) { Location finalLoc = new Location(loc.getWorld(), x, y, z); // Run this check to avoid false positives if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) { - if (finalLoc.getBlock().getType() == Material.AIR || finalLoc.equals(event.getBlock().getLocation())) { + if (BukkitUtils.isEmpty(finalLoc.getBlock().getType()) || finalLoc.equals(event.getBlock().getLocation())) { consumer.queueBlockPlace(actor, finalLoc, event.getBlock().getBlockData()); } else { consumer.queueBlockReplace(actor, finalLoc, finalLoc.getBlock().getBlockData(), event.getBlock().getBlockData()); @@ -75,7 +75,7 @@ public void onBlockPlace(BlockPlaceEvent event) { LogBlock.getInstance().getServer().getScheduler().scheduleSyncDelayedTask(LogBlock.getInstance(), new Runnable() { @Override public void run() { - if (before.getType() == Material.AIR) { + if (BukkitUtils.isEmpty(before.getType())) { consumer.queueBlockPlace(actor, after); } else { consumer.queueBlockReplace(actor, before, after); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index 750b73dc..c1ebe5e2 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -32,7 +32,7 @@ public void onBlockFromTo(BlockFromToEvent event) { final Block to = event.getToBlock(); final Material typeTo = to.getType(); - final boolean canFlow = typeTo == Material.AIR || BukkitUtils.getNonFluidProofBlocks().contains(typeTo); + final boolean canFlow = BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo); if (typeFrom == Material.LAVA) { Levelled levelledFrom = (Levelled)blockDataFrom; if (canFlow && wcfg.isLogging(Logging.LAVAFLOW)) { @@ -41,7 +41,7 @@ public void onBlockFromTo(BlockFromToEvent event) { } else { Levelled newBlock = (Levelled) blockDataFrom.clone(); newBlock.setLevel(levelledFrom.getLevel() + 1); - if (typeTo == Material.AIR) { + if (BukkitUtils.isEmpty(typeTo)) { consumer.queueBlockPlace(new Actor("LavaFlow"), to.getLocation(), newBlock); } else { consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), newBlock); @@ -58,7 +58,7 @@ public void onBlockFromTo(BlockFromToEvent event) { Levelled levelledFrom = (Levelled)blockDataFrom; Levelled newBlock = (Levelled) blockDataFrom.clone(); newBlock.setLevel(levelledFrom.getLevel() + 1); - if (typeTo == Material.AIR) { + if (BukkitUtils.isEmpty(typeTo)) { consumer.queueBlockPlace(new Actor("WaterFlow"), to.getLocation(), newBlock); } else if (BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), newBlock); @@ -70,7 +70,7 @@ public void onBlockFromTo(BlockFromToEvent event) { consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), Material.STONE.createBlockData()); } } - if (typeTo == Material.AIR || BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { + if (BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { for (final BlockFace face : new BlockFace[]{BlockFace.DOWN, BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH}) { final Block lower = to.getRelative(face); if (lower.getType() == Material.LAVA) { diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 6a43c9a8..516b83dc 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -487,4 +487,8 @@ public static Material itemIDfromProjectileEntity(Entity e) { public static boolean isDoublePlant(Material m) { return doublePlants.contains(m); } + + public static boolean isEmpty(Material m) { + return m == Material.AIR || m == Material.CAVE_AIR || m == Material.VOID_AIR; + } } diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index 6a58d92d..10e03c12 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -50,7 +50,7 @@ public static void smartLogFallables(Consumer consumer, Actor actor, Block origi // Run this check to avoid false positives if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) { finalLoc.add(0, up, 0); // Add this here after checking for block breakers - if (finalLoc.getBlock().getType() == Material.AIR) { + if (BukkitUtils.isEmpty(finalLoc.getBlock().getType())) { consumer.queueBlockPlace(actor, finalLoc, checkBlock.getBlockData()); } else { consumer.queueBlockReplace(actor, finalLoc, finalLoc.getBlock().getBlockData(), checkBlock.getBlockData()); diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index 849d56f7..c52a6768 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -16,7 +16,6 @@ import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; -import org.bukkit.Material; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.inventory.ItemStack; @@ -239,7 +238,7 @@ public static ItemStack loadItemStack(byte[] data) { } public static byte[] saveItemStack(ItemStack stack) { - if (stack == null || stack.getType() == Material.AIR) { + if (stack == null || BukkitUtils.isEmpty(stack.getType())) { return null; } try { diff --git a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java index d8d01696..64b2a8f7 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java @@ -15,6 +15,8 @@ import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.Config; +import de.diddiz.util.BukkitUtils; + import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -109,7 +111,7 @@ protected void onBlockChange(Vector pt, BlockStateHolder block) { plugin.getConsumer().queueBlockBreak(lbActor, location, origin.getBlockData()); } BlockData newBlock = BukkitAdapter.adapt(block); - if (newBlock != null && newBlock.getMaterial() != Material.AIR) { + if (newBlock != null && !BukkitUtils.isEmpty(newBlock.getMaterial())) { plugin.getConsumer().queueBlockPlace(lbActor, location, newBlock); } } From f41a2f0b45d4831c8a7c400fafe195e10a502dd6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 28 Jul 2018 05:42:31 +0200 Subject: [PATCH 023/399] Update repositorys/Remove dead repos --- pom.xml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 876c4b97..6207091a 100644 --- a/pom.xml +++ b/pom.xml @@ -84,17 +84,9 @@ - - repobo-snap - http://repo.bukkit.org/content/groups/public - sk89q-repo - http://maven.sk89q.com/repo/ - - - kitteh-repo - http://repo.kitteh.org/content/groups/public + https://maven.sk89q.com/repo/ spigot-repo From 71a950a48bf5ed2971ce4012407d10d78d8910db Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 28 Jul 2018 05:45:07 +0200 Subject: [PATCH 024/399] Add the new airs to the config --- src/main/java/de/diddiz/LogBlock/config/Config.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 029f0d43..0573c3e6 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -88,7 +88,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("logging.logEnvironmentalKills", false); def.put("logging.logPlayerInfo", false); def.put("logging.hiddenPlayers", new ArrayList()); - def.put("logging.hiddenBlocks", Arrays.asList(Material.AIR.name())); + def.put("logging.hiddenBlocks", Arrays.asList(Material.AIR.name(),Material.CAVE_AIR.name(),Material.VOID_AIR.name())); def.put("logging.ignoredChat", Arrays.asList("/register", "/login")); def.put("rollback.dontRollback", Arrays.asList(Material.LAVA.name(), Material.TNT.name(), Material.FIRE.name())); def.put("rollback.replaceAnyway", Arrays.asList(Material.LAVA.name(), Material.WATER.name(), Material.FIRE.name())); From 88faff82308dee7692924582890b3754455c770e Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 28 Jul 2018 05:46:06 +0200 Subject: [PATCH 025/399] Formating --- src/main/java/de/diddiz/LogBlock/config/Config.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 0573c3e6..b7db375b 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -88,7 +88,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("logging.logEnvironmentalKills", false); def.put("logging.logPlayerInfo", false); def.put("logging.hiddenPlayers", new ArrayList()); - def.put("logging.hiddenBlocks", Arrays.asList(Material.AIR.name(),Material.CAVE_AIR.name(),Material.VOID_AIR.name())); + def.put("logging.hiddenBlocks", Arrays.asList(Material.AIR.name(), Material.CAVE_AIR.name(), Material.VOID_AIR.name())); def.put("logging.ignoredChat", Arrays.asList("/register", "/login")); def.put("rollback.dontRollback", Arrays.asList(Material.LAVA.name(), Material.TNT.name(), Material.FIRE.name())); def.put("rollback.replaceAnyway", Arrays.asList(Material.LAVA.name(), Material.WATER.name(), Material.FIRE.name())); From 0bdbce59b8cc5d30f4470aecf08e9734e0996eeb Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 29 Jul 2018 15:30:57 +0200 Subject: [PATCH 026/399] Legacy materials are not iterated, so don't have to check for that --- src/main/java/de/diddiz/LogBlock/MaterialConverter.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java index ba38d220..2f48d864 100644 --- a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java +++ b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java @@ -25,9 +25,7 @@ public class MaterialConverter { static { for (Material m : Material.values()) { - if (!m.name().startsWith("LEGACY_") && m.getKey() != null) { - materialKeyToMaterial.put(m.getKey().toString(), m); - } + materialKeyToMaterial.put(m.getKey().toString(), m); } } From 9f1fc3fe7b68eb948b6b687b19730c84d48008bf Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 29 Jul 2018 15:31:59 +0200 Subject: [PATCH 027/399] Do not check for invalid materials in the config before upgrading them --- .../java/de/diddiz/LogBlock/config/Config.java | 14 ++++++++++---- .../de/diddiz/LogBlock/config/WorldConfig.java | 4 +++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index b7db375b..d271ab7d 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -1,6 +1,8 @@ package de.diddiz.LogBlock.config; import de.diddiz.LogBlock.*; +import de.diddiz.util.ComparableVersion; + import org.bukkit.Material; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; @@ -136,6 +138,10 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti } } logblock.saveConfig(); + + ComparableVersion configVersion = new ComparableVersion(config.getString("version")); + boolean oldConfig = configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion().replace(" (manually compiled)", ""))) < 0; + url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database"); user = getStringIncludingInts(config, "mysql.user"); password = getStringIncludingInts(config, "mysql.password"); @@ -166,7 +172,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti final Material mat = Material.matchMaterial(blocktype); if (mat != null) { hiddenBlocks.add(mat); - } else { + } else if (!oldConfig) { throw new DataFormatException("Not a valid material in hiddenBlocks: '" + blocktype + "'"); } } @@ -179,7 +185,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti Material mat = Material.matchMaterial(e); if (mat != null) { dontRollback.add(mat); - } else { + } else if (!oldConfig) { throw new DataFormatException("Not a valid material in dontRollback: '" + e + "'"); } } @@ -188,7 +194,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti Material mat = Material.matchMaterial(e); if (mat != null) { replaceAnyway.add(mat); - } else { + } else if (!oldConfig) { throw new DataFormatException("Not a valid material in replaceAnyway: '" + e + "'"); } } @@ -242,7 +248,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti throw new DataFormatException("No worlds configured"); } for (final String world : loggedWorlds) { - worldConfigs.put(world, new WorldConfig(new File(logblock.getDataFolder(), friendlyWorldname(world) + ".yml"))); + worldConfigs.put(world, new WorldConfig(world, new File(logblock.getDataFolder(), friendlyWorldname(world) + ".yml"))); } superWorldConfig = new LoggingEnabledMapping(); for (final WorldConfig wcfg : worldConfigs.values()) { diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index 4a1878be..7b705187 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -10,9 +10,11 @@ import java.util.Map.Entry; public class WorldConfig extends LoggingEnabledMapping { + public final String world; public final String table; - public WorldConfig(File file) throws IOException { + public WorldConfig(String world, File file) throws IOException { + this.world = world; final Map def = new HashMap(); // "Before MySQL 5.1.6, database and table names cannot contain "/", "\", ".", or characters that are not permitted in file names" - MySQL manual // They _can_ contain spaces, but replace them as well From dc5c8a82c3bd42951e950742f4a56f2223492e5b Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 29 Jul 2018 15:32:38 +0200 Subject: [PATCH 028/399] Log stack traces for some more exceptions --- src/main/java/de/diddiz/LogBlock/LogBlock.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 07e88358..324d33c5 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -85,7 +85,7 @@ public void onLoad() { } catch (final NullPointerException ex) { getLogger().log(Level.SEVERE, "Error while loading: ", ex); } catch (final Exception ex) { - getLogger().severe("Error while loading: " + ex.getMessage()); + getLogger().log(Level.SEVERE, "Error while loading: " + ex.getMessage(), ex); errorAtLoading = true; return; } @@ -272,7 +272,7 @@ public Connection getConnection() { getLogger().log(Level.SEVERE, "Error while fetching connection: ", ex); connected = false; } else { - getLogger().severe("MySQL connection lost"); + getLogger().log(Level.SEVERE, "MySQL connection lost", ex); } return null; } From 166548da18c03527f9056d42329ee9cd1ed92707 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 29 Jul 2018 15:34:43 +0200 Subject: [PATCH 029/399] Upgrade config, chestaccess and kills too --- src/main/java/de/diddiz/LogBlock/Updater.java | 381 ++++++-- src/main/resources/itemdata.txt | 839 ++++++++++++++++++ 2 files changed, 1139 insertions(+), 81 deletions(-) create mode 100644 src/main/resources/itemdata.txt diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index fe8fa3c5..c2f9fe9d 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -3,10 +3,14 @@ import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.util.UUIDFetcher; +import de.diddiz.util.Utils; + import org.bukkit.Bukkit; +import org.bukkit.Material; import org.bukkit.block.data.BlockData; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemStack; import java.io.BufferedInputStream; import java.io.BufferedReader; @@ -23,6 +27,7 @@ import static de.diddiz.util.BukkitUtils.friendlyWorldname; import de.diddiz.util.ComparableVersion; import java.util.regex.Pattern; + import static org.bukkit.Bukkit.getLogger; class Updater { @@ -413,13 +418,14 @@ boolean update() { if (configVersion.compareTo(new ComparableVersion("1.13.0")) < 0) { getLogger().info("Updating tables to 1.13.0 ..."); try { - MaterialUpdater materialUpdater = null; - checkTables(); // we need to create the tables first + MaterialUpdater1_13 materialUpdater = new MaterialUpdater1_13(logblock); getLogger().info("Convertig BlockId to BlockData. This can take a while ..."); final Connection conn = logblock.getConnection(); conn.setAutoCommit(false); final Statement st = conn.createStatement(); for (final WorldConfig wcfg : getLoggedWorlds()) { + getLogger().info("Processing world " + wcfg.world + "..."); + getLogger().info("Processing block changes..."); boolean hadRow = true; int rowsToConvert = 0; int done = 0; @@ -429,75 +435,187 @@ boolean update() { rowsToConvert = rs.getInt(1); getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table); } + rs.close(); + + PreparedStatement deleteStatement = conn.prepareStatement("DELETE FROM `" + wcfg.table + "` WHERE id = ?"); + PreparedStatement insertStatement = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-blocks` (id, date, playerid, replaced, replacedData, type, typeData, x, y, z) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); + + while (hadRow) { + hadRow = false; + ResultSet entries = st.executeQuery("SELECT id, date, playerid, replaced, type, data, x, y, z FROM `" + wcfg.table + "` ORDER BY id ASC LIMIT 10000"); + while (entries.next()) { + hadRow = true; + int id = entries.getInt("id"); + Timestamp date = entries.getTimestamp("date"); + int playerid = entries.getInt("playerid"); + int replaced = entries.getInt("replaced"); + int type = entries.getInt("type"); + int data = entries.getInt("data"); + int x = entries.getInt("x"); + int y = entries.getInt("y"); + int z = entries.getInt("z"); + if (data == 16) { + data = 0; + } + + try { + String replacedBlockData = materialUpdater.getBlockData(replaced, data).getAsString(); + String setBlockData = materialUpdater.getBlockData(type, data).getAsString(); + + int newReplacedId = MaterialConverter.getOrAddMaterialId(replacedBlockData); + int newReplacedData = MaterialConverter.getOrAddBlockStateId(replacedBlockData); + + int newSetId = MaterialConverter.getOrAddMaterialId(setBlockData); + int newSetData = MaterialConverter.getOrAddBlockStateId(setBlockData); + + insertStatement.setInt(1, id); + insertStatement.setTimestamp(2, date); + insertStatement.setInt(3, playerid); + insertStatement.setInt(4, newReplacedId); + insertStatement.setInt(5, newReplacedData); + insertStatement.setInt(6, newSetId); + insertStatement.setInt(7, newSetData); + insertStatement.setInt(8, x); + insertStatement.setInt(9, y); + insertStatement.setInt(10, z); + insertStatement.addBatch(); + } catch (Exception e) { + getLogger().info("Exception in entry " + id + " (" + replaced + ":" + data + "->" + type + ":" + data + "): " + e.getMessage()); + } + deleteStatement.setInt(1, id); + deleteStatement.addBatch(); + + done++; + } + entries.close(); + if (hadRow) { + insertStatement.executeBatch(); + deleteStatement.executeBatch(); + } + conn.commit(); + logblock.getConsumer().run(); // force a consumer run to save new material mappings + getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + } + insertStatement.close(); + deleteStatement.close(); } catch (SQLException e) { getLogger().info("Could not convert " + wcfg.table + ": " + e.getMessage()); - continue; } - PreparedStatement deleteStatement = conn.prepareStatement("DELETE FROM `" + wcfg.table + "` WHERE id = ?"); - PreparedStatement insertStatement = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-blocks` (id, date, playerid, replaced, replacedData, type, typeData, x, y, z) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); - - while (hadRow) { - hadRow = false; - ResultSet entries = st.executeQuery("SELECT id, date, playerid, replaced, type, data, x, y, z FROM `" + wcfg.table + "` ORDER BY id ASC LIMIT 10000"); - while (entries.next()) { - hadRow = true; - int id = entries.getInt("id"); - Timestamp date = entries.getTimestamp("date"); - int playerid = entries.getInt("playerid"); - int replaced = entries.getInt("replaced"); - int type = entries.getInt("type"); - int data = entries.getInt("data"); - int x = entries.getInt("x"); - int y = entries.getInt("y"); - int z = entries.getInt("z"); - if (data == 16) { - data = 0; + getLogger().info("Processing chests..."); + rowsToConvert = 0; + done = 0; + try { + ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-chest`"); + if (rs.next()) { + rowsToConvert = rs.getInt(1); + getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-chest"); + } + rs.close(); + + PreparedStatement insertChestData = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-chestdata` (id, item, itemremove) VALUES (?, ?, ?)"); + PreparedStatement deleteChest = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-chest` WHERE id = ?"); + while (true) { + rs = st.executeQuery("SELECT id, itemtype, itemamount, itemdata FROM `" + wcfg.table + "-chest` ORDER BY id ASC LIMIT 10000"); + boolean anyRow = false; + while (rs.next()) { + anyRow = true; + int id = rs.getInt("id"); + int itemtype = rs.getInt("itemtype"); + int itemdata = rs.getInt("itemdata"); + int amount = rs.getInt("itemamount"); + Material weaponMaterial = materialUpdater.getMaterial(itemtype, itemdata); + if (weaponMaterial == null) { + weaponMaterial = Material.AIR; + } + ItemStack stack = weaponMaterial.getMaxDurability() > 0 ? new ItemStack(weaponMaterial, Math.abs(amount), (short)itemdata) : new ItemStack(weaponMaterial, Math.abs(amount)); + insertChestData.setInt(1, id); + insertChestData.setBytes(2, Utils.saveItemStack(stack)); + insertChestData.setInt(3, amount >= 0 ? 0 : 1); + insertChestData.addBatch(); + + deleteChest.setInt(1, id); + deleteChest.addBatch(); + done++; } + rs.close(); + if (!anyRow) { + break; + } + insertChestData.executeBatch(); + deleteChest.executeBatch(); + conn.commit(); + getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + } + insertChestData.close(); + deleteChest.close(); + } catch (SQLException e) { + getLogger().info("Could not convert " + wcfg.table + "-chest: " + e.getMessage()); + } - if (materialUpdater == null) { - materialUpdater = new MaterialUpdater(logblock); + if (wcfg.isLogging(Logging.KILL)) { + getLogger().info("Processing kills..."); + rowsToConvert = 0; + done = 0; + try { + ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-kills`"); + if (rs.next()) { + rowsToConvert = rs.getInt(1); + getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-kills"); } - try { - String replacedBlockData = materialUpdater.getBlockData(replaced, data).getAsString(); - String setBlockData = materialUpdater.getBlockData(type, data).getAsString(); - - int newReplacedId = MaterialConverter.getOrAddMaterialId(replacedBlockData); - int newReplacedData = MaterialConverter.getOrAddBlockStateId(replacedBlockData); - - int newSetId = MaterialConverter.getOrAddMaterialId(setBlockData); - int newSetData = MaterialConverter.getOrAddBlockStateId(setBlockData); - - insertStatement.setInt(1, id); - insertStatement.setTimestamp(2, date); - insertStatement.setInt(3, playerid); - insertStatement.setInt(4, newReplacedId); - insertStatement.setInt(5, newReplacedData); - insertStatement.setInt(6, newSetId); - insertStatement.setInt(7, newSetData); - insertStatement.setInt(8, x); - insertStatement.setInt(9, y); - insertStatement.setInt(10, z); - insertStatement.addBatch(); - } catch (Exception e) { - getLogger().info("Exception in entry " + id + " (" + replaced + ":" + data + "->" + type + ":" + data + "): " + e.getMessage()); + rs.close(); + + PreparedStatement updateWeaponStatement = conn.prepareStatement("UPDATE `" + wcfg.table + "`-kills SET weapon = ? WHERE id = ?"); + for (int start = 0;; start += 10000) { + rs = st.executeQuery("SELECT id, weapon FROM `" + wcfg.table + "-kills` ORDER BY id ASC LIMIT " + start + ",10000"); + boolean anyUpdate = false; + boolean anyRow = false; + while (rs.next()) { + anyRow = true; + int id = rs.getInt("id"); + int weapon = rs.getInt("weapon"); + Material weaponMaterial = materialUpdater.getMaterial(weapon, 0); + if (weaponMaterial == null) { + weaponMaterial = Material.AIR; + } + int newWeapon = MaterialConverter.getOrAddMaterialId(weaponMaterial.getKey()); + if (newWeapon != weapon) { + anyUpdate = true; + updateWeaponStatement.setInt(1, newWeapon); + updateWeaponStatement.setInt(2, id); + updateWeaponStatement.addBatch(); + } + done++; + } + rs.close(); + if (anyUpdate) { + updateWeaponStatement.executeBatch(); + conn.commit(); + logblock.getConsumer().run(); // force a consumer run to save new material mappings + } + getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + if (!anyRow) { + break; + } } - deleteStatement.setInt(1, id); - deleteStatement.addBatch(); - - done++; - } - if (hadRow) { - insertStatement.executeBatch(); - deleteStatement.executeBatch(); + updateWeaponStatement.close(); + } catch (SQLException e) { + getLogger().info("Could not convert " + wcfg.table + "-kills: " + e.getMessage()); } - conn.commit(); - logblock.getConsumer().run(); // force a consumer run - getLogger().info(done + "/" + rowsToConvert); } } st.close(); conn.close(); + + getLogger().info("Updating config to 1.13.0 ..."); + config.set("logging.hiddenBlocks", materialUpdater.convertMaterials(config.getStringList("logging.hiddenBlocks"))); + config.set("rollback.dontRollback", materialUpdater.convertMaterials(config.getStringList("rollback.dontRollback"))); + config.set("rollback.replaceAnyway", materialUpdater.convertMaterials(config.getStringList("rollback.replaceAnyway"))); + final ConfigurationSection toolsSec = config.getConfigurationSection("tools"); + for (final String toolName : toolsSec.getKeys(false)) { + final ConfigurationSection tSec = toolsSec.getConfigurationSection(toolName); + tSec.set("item", materialUpdater.convertMaterial(tSec.getString("item", "OAK_LOG"))); + } } catch (final SQLException | IOException ex) { Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; @@ -597,40 +715,141 @@ public void run() { } } - public static class MaterialUpdater { + public static class MaterialUpdater1_13 { BlockData[][] blockDataMapping; - public MaterialUpdater(LogBlock plugin) throws IOException { + Material[][] itemMapping = new Material[10][]; + public MaterialUpdater1_13(LogBlock plugin) throws IOException { blockDataMapping = new BlockData[256][16]; - JarFile file = new JarFile(plugin.getFile()); - BufferedReader reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(file.getInputStream(file.getJarEntry("blockdata.txt"))), "UTF-8")); - while (true) { - String line = reader.readLine(); - if (line == null) { - break; - } - int splitter1 = line.indexOf(":"); - int splitter2 = line.indexOf(","); - if (splitter1 >= 0 && splitter2 >= 0) { - int blockid = Integer.parseInt(line.substring(0, splitter1)); - int blockdata = Integer.parseInt(line.substring(splitter1 + 1, splitter2)); - BlockData newBlockData = Bukkit.createBlockData(line.substring(splitter2 + 1)); - - if (blockdata == 0) { - for (int i = 0; i < 16; i++) { - if (blockDataMapping[blockid][i] == null) { - blockDataMapping[blockid][i] = newBlockData; + try (JarFile file = new JarFile(plugin.getFile())) { + BufferedReader reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(file.getInputStream(file.getJarEntry("blockdata.txt"))), "UTF-8")); + while (true) { + String line = reader.readLine(); + if (line == null) { + break; + } + int splitter1 = line.indexOf(":"); + int splitter2 = line.indexOf(","); + if (splitter1 >= 0 && splitter2 >= 0) { + int blockid = Integer.parseInt(line.substring(0, splitter1)); + int blockdata = Integer.parseInt(line.substring(splitter1 + 1, splitter2)); + BlockData newBlockData = Bukkit.createBlockData(line.substring(splitter2 + 1)); + + if (blockdata == 0) { + for (int i = 0; i < 16; i++) { + if (blockDataMapping[blockid][i] == null) { + blockDataMapping[blockid][i] = newBlockData; + } } + } else { + blockDataMapping[blockid][blockdata] = newBlockData; } - } else { - blockDataMapping[blockid][blockdata] = newBlockData; } } + reader.close(); + + HashMap materialKeysToMaterial = new HashMap<>(); + for (Material material : Material.values()) { + materialKeysToMaterial.put(material.getKey().toString(), material); + } + + reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(file.getInputStream(file.getJarEntry("itemdata.txt"))), "UTF-8")); + while (true) { + String line = reader.readLine(); + if (line == null) { + break; + } + int splitter1 = line.indexOf(":"); + int splitter2 = line.indexOf(","); + if (splitter1 >= 0 && splitter2 >= 0) { + int itemid = Integer.parseInt(line.substring(0, splitter1)); + int itemdata = Integer.parseInt(line.substring(splitter1 + 1, splitter2)); + Material newMaterial = materialKeysToMaterial.get(line.substring(splitter2 + 1)); + if (newMaterial == null) { + throw new IOException("Unknown item: " + line.substring(splitter2 + 1)); + } + if (itemid >= itemMapping.length) { + itemMapping = Arrays.copyOf(itemMapping, Math.max(itemMapping.length * 3 / 2, itemid + 1)); + } + + Material[] itemValues = itemMapping[itemid]; + if (itemValues == null) { + itemValues = new Material[itemdata + 1]; + itemMapping[itemid] = itemValues; + } else if (itemValues.length <= itemdata) { + itemValues = Arrays.copyOf(itemValues, itemdata + 1); + itemMapping[itemid] = itemValues; + } + itemValues[itemdata] = newMaterial; + } + } + reader.close(); } - file.close(); } public BlockData getBlockData(int id, int data) { return id >= 0 && id < 256 && data >= 0 && data < 16 ? blockDataMapping[id][data] : null; } + + public Material getMaterial(int id, int data) { + Material[] materials = id >= 0 && id < itemMapping.length ? itemMapping[id] : null; + if (materials != null && materials.length > 0) { + if (materials[0] != null && materials[0].getMaxDurability() == 0 && data >= 0 && data < materials.length && materials[data] != null) { + return materials[data]; + } + return materials[0]; + } + return null; + } + + public Material getMaterial(String id) { + int item = 0; + int data = 0; + int seperator = id.indexOf(':'); + if (seperator < 0) { + item = Integer.parseInt(id); + } else { + item = Integer.parseInt(id.substring(0, seperator)); + data = Integer.parseInt(id.substring(seperator + 1)); + } + return getMaterial(item, data); + } + + public String convertMaterial(String oldEntry) { + if (oldEntry == null) { + return null; + } + try { + Material newMaterial = getMaterial(oldEntry); + if (newMaterial != null) { + return newMaterial.name(); + } + } catch (Exception e) { + Material newMaterial = Material.matchMaterial(oldEntry, true); + if (newMaterial != null) { + return newMaterial.name(); + } else { + newMaterial = Material.matchMaterial(oldEntry); + if (newMaterial != null) { + return newMaterial.name(); + } + } + } + return null; + } + + public List convertMaterials(Collection oldEntries) { + Set newEntries = new LinkedHashSet<>(); + for (String oldEntry : oldEntries) { + String newEntry = convertMaterial(oldEntry); + if (newEntry != null) { + newEntries.add(newEntry); + if (newEntry.equals(Material.AIR.name())) { + newEntries.add(Material.CAVE_AIR.name()); + newEntries.add(Material.VOID_AIR.name()); + } + } + } + return new ArrayList<>(newEntries); + } } } diff --git a/src/main/resources/itemdata.txt b/src/main/resources/itemdata.txt new file mode 100644 index 00000000..44f83afd --- /dev/null +++ b/src/main/resources/itemdata.txt @@ -0,0 +1,839 @@ +0:0,minecraft:air +1:0,minecraft:stone +1:1,minecraft:granite +1:2,minecraft:polished_granite +1:3,minecraft:diorite +1:4,minecraft:polished_diorite +1:5,minecraft:andesite +1:6,minecraft:polished_andesite +2:0,minecraft:grass_block +3:0,minecraft:dirt +3:1,minecraft:coarse_dirt +3:2,minecraft:podzol +4:0,minecraft:cobblestone +5:0,minecraft:oak_planks +5:1,minecraft:spruce_planks +5:2,minecraft:birch_planks +5:3,minecraft:jungle_planks +5:4,minecraft:acacia_planks +5:5,minecraft:dark_oak_planks +6:0,minecraft:oak_sapling +6:1,minecraft:spruce_sapling +6:2,minecraft:birch_sapling +6:3,minecraft:jungle_sapling +6:4,minecraft:acacia_sapling +6:5,minecraft:dark_oak_sapling +6:9,minecraft:spruce_sapling +6:10,minecraft:birch_sapling +6:11,minecraft:jungle_sapling +6:12,minecraft:acacia_sapling +6:13,minecraft:dark_oak_sapling +7:0,minecraft:bedrock +8:0,minecraft:water +9:0,minecraft:water +10:0,minecraft:lava +11:0,minecraft:lava +12:0,minecraft:sand +12:1,minecraft:red_sand +13:0,minecraft:gravel +14:0,minecraft:gold_ore +15:0,minecraft:iron_ore +16:0,minecraft:coal_ore +17:0,minecraft:oak_log +17:1,minecraft:spruce_log +17:2,minecraft:birch_log +17:3,minecraft:jungle_log +17:5,minecraft:spruce_log +17:6,minecraft:birch_log +17:7,minecraft:jungle_log +17:9,minecraft:spruce_log +17:10,minecraft:birch_log +17:11,minecraft:jungle_log +18:0,minecraft:oak_leaves +18:1,minecraft:spruce_leaves +18:2,minecraft:birch_leaves +18:3,minecraft:jungle_leaves +18:5,minecraft:spruce_leaves +18:6,minecraft:birch_leaves +18:7,minecraft:jungle_leaves +18:9,minecraft:spruce_leaves +18:10,minecraft:birch_leaves +18:11,minecraft:jungle_leaves +18:13,minecraft:spruce_leaves +18:14,minecraft:birch_leaves +18:15,minecraft:jungle_leaves +19:0,minecraft:sponge +19:1,minecraft:wet_sponge +20:0,minecraft:glass +21:0,minecraft:lapis_ore +22:0,minecraft:lapis_block +23:0,minecraft:dispenser +24:0,minecraft:sandstone +24:1,minecraft:chiseled_sandstone +24:2,minecraft:cut_sandstone +25:0,minecraft:note_block +26:0,minecraft:red_bed +27:0,minecraft:powered_rail +28:0,minecraft:detector_rail +29:0,minecraft:sticky_piston +30:0,minecraft:cobweb +31:0,minecraft:dead_bush +31:1,minecraft:grass +31:2,minecraft:fern +32:0,minecraft:dead_bush +33:0,minecraft:piston +34:0,minecraft:piston_head +35:0,minecraft:white_wool +35:1,minecraft:orange_wool +35:2,minecraft:magenta_wool +35:3,minecraft:light_blue_wool +35:4,minecraft:yellow_wool +35:5,minecraft:lime_wool +35:6,minecraft:pink_wool +35:7,minecraft:gray_wool +35:8,minecraft:light_gray_wool +35:9,minecraft:cyan_wool +35:10,minecraft:purple_wool +35:11,minecraft:blue_wool +35:12,minecraft:brown_wool +35:13,minecraft:green_wool +35:14,minecraft:red_wool +35:15,minecraft:black_wool +36:0,minecraft:moving_piston +37:0,minecraft:dandelion +38:0,minecraft:poppy +38:1,minecraft:blue_orchid +38:2,minecraft:allium +38:3,minecraft:azure_bluet +38:4,minecraft:red_tulip +38:5,minecraft:orange_tulip +38:6,minecraft:white_tulip +38:7,minecraft:pink_tulip +38:8,minecraft:oxeye_daisy +39:0,minecraft:brown_mushroom +40:0,minecraft:red_mushroom +41:0,minecraft:gold_block +42:0,minecraft:iron_block +43:0,minecraft:stone_slab +43:1,minecraft:sandstone_slab +43:2,minecraft:petrified_oak_slab +43:3,minecraft:cobblestone_slab +43:4,minecraft:brick_slab +43:5,minecraft:stone_brick_slab +43:6,minecraft:nether_brick_slab +43:7,minecraft:quartz_slab +43:8,minecraft:smooth_stone +43:9,minecraft:smooth_sandstone +43:10,minecraft:petrified_oak_slab +43:11,minecraft:cobblestone_slab +43:12,minecraft:brick_slab +43:13,minecraft:stone_brick_slab +43:14,minecraft:nether_brick_slab +43:15,minecraft:smooth_quartz +44:0,minecraft:stone_slab +44:1,minecraft:sandstone_slab +44:2,minecraft:petrified_oak_slab +44:3,minecraft:cobblestone_slab +44:4,minecraft:brick_slab +44:5,minecraft:stone_brick_slab +44:6,minecraft:nether_brick_slab +44:7,minecraft:quartz_slab +44:9,minecraft:sandstone_slab +44:10,minecraft:petrified_oak_slab +44:11,minecraft:cobblestone_slab +44:12,minecraft:brick_slab +44:13,minecraft:stone_brick_slab +44:14,minecraft:nether_brick_slab +44:15,minecraft:quartz_slab +45:0,minecraft:bricks +46:0,minecraft:tnt +47:0,minecraft:bookshelf +48:0,minecraft:mossy_cobblestone +49:0,minecraft:obsidian +50:0,minecraft:torch +50:1,minecraft:wall_torch +50:2,minecraft:wall_torch +50:3,minecraft:wall_torch +50:4,minecraft:wall_torch +51:0,minecraft:fire +52:0,minecraft:spawner +53:0,minecraft:oak_stairs +54:0,minecraft:chest +55:0,minecraft:redstone_wire +56:0,minecraft:diamond_ore +57:0,minecraft:diamond_block +58:0,minecraft:crafting_table +59:0,minecraft:wheat +60:0,minecraft:farmland +61:0,minecraft:furnace +62:0,minecraft:air +62:2,minecraft:furnace +62:3,minecraft:furnace +62:4,minecraft:furnace +62:5,minecraft:furnace +63:0,minecraft:sign +64:0,minecraft:oak_door +65:0,minecraft:ladder +66:0,minecraft:rail +67:0,minecraft:cobblestone_stairs +68:0,minecraft:air +68:2,minecraft:wall_sign +68:3,minecraft:wall_sign +68:4,minecraft:wall_sign +68:5,minecraft:wall_sign +69:0,minecraft:lever +70:0,minecraft:stone_pressure_plate +71:0,minecraft:iron_door +72:0,minecraft:oak_pressure_plate +73:0,minecraft:redstone_ore +74:0,minecraft:redstone_ore +75:0,minecraft:air +75:1,minecraft:redstone_wall_torch +75:2,minecraft:redstone_wall_torch +75:3,minecraft:redstone_wall_torch +75:4,minecraft:redstone_wall_torch +75:5,minecraft:redstone_torch +76:0,minecraft:redstone_torch +76:1,minecraft:redstone_wall_torch +76:2,minecraft:redstone_wall_torch +76:3,minecraft:redstone_wall_torch +76:4,minecraft:redstone_wall_torch +77:0,minecraft:stone_button +78:0,minecraft:snow +79:0,minecraft:ice +80:0,minecraft:snow_block +81:0,minecraft:cactus +82:0,minecraft:clay +83:0,minecraft:sugar_cane +84:0,minecraft:jukebox +85:0,minecraft:oak_fence +86:0,minecraft:carved_pumpkin +87:0,minecraft:netherrack +88:0,minecraft:soul_sand +89:0,minecraft:glowstone +90:0,minecraft:nether_portal +91:0,minecraft:jack_o_lantern +92:0,minecraft:cake +93:0,minecraft:repeater +94:0,minecraft:repeater +95:0,minecraft:white_stained_glass +95:1,minecraft:orange_stained_glass +95:2,minecraft:magenta_stained_glass +95:3,minecraft:light_blue_stained_glass +95:4,minecraft:yellow_stained_glass +95:5,minecraft:lime_stained_glass +95:6,minecraft:pink_stained_glass +95:7,minecraft:gray_stained_glass +95:8,minecraft:light_gray_stained_glass +95:9,minecraft:cyan_stained_glass +95:10,minecraft:purple_stained_glass +95:11,minecraft:blue_stained_glass +95:12,minecraft:brown_stained_glass +95:13,minecraft:green_stained_glass +95:14,minecraft:red_stained_glass +95:15,minecraft:black_stained_glass +96:0,minecraft:oak_trapdoor +97:0,minecraft:infested_stone +97:1,minecraft:infested_cobblestone +97:2,minecraft:infested_stone_bricks +97:3,minecraft:infested_mossy_stone_bricks +97:4,minecraft:infested_cracked_stone_bricks +97:5,minecraft:infested_chiseled_stone_bricks +98:0,minecraft:stone_bricks +98:1,minecraft:mossy_stone_bricks +98:2,minecraft:cracked_stone_bricks +98:3,minecraft:chiseled_stone_bricks +99:0,minecraft:brown_mushroom_block +99:10,minecraft:mushroom_stem +99:15,minecraft:mushroom_stem +100:0,minecraft:red_mushroom_block +100:10,minecraft:mushroom_stem +100:15,minecraft:mushroom_stem +101:0,minecraft:iron_bars +102:0,minecraft:glass_pane +103:0,minecraft:melon +104:0,minecraft:pumpkin_stem +105:0,minecraft:melon_stem +106:0,minecraft:vine +107:0,minecraft:oak_fence_gate +108:0,minecraft:brick_stairs +109:0,minecraft:stone_brick_stairs +110:0,minecraft:mycelium +111:0,minecraft:lily_pad +112:0,minecraft:nether_bricks +113:0,minecraft:nether_brick_fence +114:0,minecraft:nether_brick_stairs +115:0,minecraft:nether_wart +116:0,minecraft:enchanting_table +117:0,minecraft:brewing_stand +118:0,minecraft:cauldron +119:0,minecraft:end_portal +120:0,minecraft:end_portal_frame +121:0,minecraft:end_stone +122:0,minecraft:dragon_egg +123:0,minecraft:redstone_lamp +124:0,minecraft:redstone_lamp +125:0,minecraft:oak_slab +125:1,minecraft:spruce_slab +125:2,minecraft:birch_slab +125:3,minecraft:jungle_slab +125:4,minecraft:acacia_slab +125:5,minecraft:dark_oak_slab +126:0,minecraft:oak_slab +126:1,minecraft:spruce_slab +126:2,minecraft:birch_slab +126:3,minecraft:jungle_slab +126:4,minecraft:acacia_slab +126:5,minecraft:dark_oak_slab +126:9,minecraft:spruce_slab +126:10,minecraft:birch_slab +126:11,minecraft:jungle_slab +126:12,minecraft:acacia_slab +126:13,minecraft:dark_oak_slab +127:0,minecraft:cocoa +128:0,minecraft:sandstone_stairs +129:0,minecraft:emerald_ore +130:0,minecraft:ender_chest +131:0,minecraft:tripwire_hook +132:0,minecraft:tripwire +133:0,minecraft:emerald_block +134:0,minecraft:spruce_stairs +135:0,minecraft:birch_stairs +136:0,minecraft:jungle_stairs +137:0,minecraft:command_block +138:0,minecraft:beacon +139:0,minecraft:cobblestone_wall +139:1,minecraft:mossy_cobblestone_wall +140:0,minecraft:potted_cactus +141:0,minecraft:carrots +142:0,minecraft:potatoes +143:0,minecraft:oak_button +144:0,minecraft:air +145:0,minecraft:anvil +145:4,minecraft:chipped_anvil +145:5,minecraft:chipped_anvil +145:6,minecraft:chipped_anvil +145:7,minecraft:chipped_anvil +145:8,minecraft:damaged_anvil +145:9,minecraft:damaged_anvil +145:10,minecraft:damaged_anvil +145:11,minecraft:damaged_anvil +146:0,minecraft:trapped_chest +147:0,minecraft:light_weighted_pressure_plate +148:0,minecraft:heavy_weighted_pressure_plate +149:0,minecraft:comparator +150:0,minecraft:comparator +151:0,minecraft:daylight_detector +152:0,minecraft:redstone_block +153:0,minecraft:nether_quartz_ore +154:0,minecraft:hopper +155:0,minecraft:quartz_block +155:1,minecraft:chiseled_quartz_block +155:2,minecraft:quartz_pillar +155:3,minecraft:quartz_pillar +155:4,minecraft:quartz_pillar +156:0,minecraft:quartz_stairs +157:0,minecraft:activator_rail +158:0,minecraft:dropper +159:0,minecraft:white_terracotta +159:1,minecraft:orange_terracotta +159:2,minecraft:magenta_terracotta +159:3,minecraft:light_blue_terracotta +159:4,minecraft:yellow_terracotta +159:5,minecraft:lime_terracotta +159:6,minecraft:pink_terracotta +159:7,minecraft:gray_terracotta +159:8,minecraft:light_gray_terracotta +159:9,minecraft:cyan_terracotta +159:10,minecraft:purple_terracotta +159:11,minecraft:blue_terracotta +159:12,minecraft:brown_terracotta +159:13,minecraft:green_terracotta +159:14,minecraft:red_terracotta +159:15,minecraft:black_terracotta +160:0,minecraft:white_stained_glass_pane +160:1,minecraft:orange_stained_glass_pane +160:2,minecraft:magenta_stained_glass_pane +160:3,minecraft:light_blue_stained_glass_pane +160:4,minecraft:yellow_stained_glass_pane +160:5,minecraft:lime_stained_glass_pane +160:6,minecraft:pink_stained_glass_pane +160:7,minecraft:gray_stained_glass_pane +160:8,minecraft:light_gray_stained_glass_pane +160:9,minecraft:cyan_stained_glass_pane +160:10,minecraft:purple_stained_glass_pane +160:11,minecraft:blue_stained_glass_pane +160:12,minecraft:brown_stained_glass_pane +160:13,minecraft:green_stained_glass_pane +160:14,minecraft:red_stained_glass_pane +160:15,minecraft:black_stained_glass_pane +161:0,minecraft:acacia_leaves +161:1,minecraft:dark_oak_leaves +161:5,minecraft:dark_oak_leaves +161:9,minecraft:dark_oak_leaves +161:13,minecraft:dark_oak_leaves +162:0,minecraft:acacia_log +162:1,minecraft:dark_oak_log +162:5,minecraft:dark_oak_log +162:9,minecraft:dark_oak_log +163:0,minecraft:acacia_stairs +164:0,minecraft:dark_oak_stairs +165:0,minecraft:slime_block +166:0,minecraft:barrier +167:0,minecraft:iron_trapdoor +168:0,minecraft:prismarine +168:1,minecraft:prismarine_bricks +168:2,minecraft:dark_prismarine +169:0,minecraft:sea_lantern +170:0,minecraft:hay_block +171:0,minecraft:white_carpet +171:1,minecraft:orange_carpet +171:2,minecraft:magenta_carpet +171:3,minecraft:light_blue_carpet +171:4,minecraft:yellow_carpet +171:5,minecraft:lime_carpet +171:6,minecraft:pink_carpet +171:7,minecraft:gray_carpet +171:8,minecraft:light_gray_carpet +171:9,minecraft:cyan_carpet +171:10,minecraft:purple_carpet +171:11,minecraft:blue_carpet +171:12,minecraft:brown_carpet +171:13,minecraft:green_carpet +171:14,minecraft:red_carpet +171:15,minecraft:black_carpet +172:0,minecraft:terracotta +173:0,minecraft:coal_block +174:0,minecraft:packed_ice +175:0,minecraft:sunflower +175:1,minecraft:lilac +175:2,minecraft:tall_grass +175:3,minecraft:large_fern +175:4,minecraft:rose_bush +175:5,minecraft:peony +175:8,minecraft:peony +175:9,minecraft:peony +175:10,minecraft:peony +175:11,minecraft:peony +176:0,minecraft:white_banner +177:0,minecraft:air +177:2,minecraft:white_wall_banner +177:3,minecraft:white_wall_banner +177:4,minecraft:white_wall_banner +177:5,minecraft:white_wall_banner +178:0,minecraft:daylight_detector +179:0,minecraft:red_sandstone +179:1,minecraft:chiseled_red_sandstone +179:2,minecraft:cut_red_sandstone +180:0,minecraft:red_sandstone_stairs +181:0,minecraft:red_sandstone_slab +181:8,minecraft:smooth_red_sandstone +182:0,minecraft:red_sandstone_slab +183:0,minecraft:spruce_fence_gate +184:0,minecraft:birch_fence_gate +185:0,minecraft:jungle_fence_gate +186:0,minecraft:dark_oak_fence_gate +187:0,minecraft:acacia_fence_gate +188:0,minecraft:spruce_fence +189:0,minecraft:birch_fence +190:0,minecraft:jungle_fence +191:0,minecraft:dark_oak_fence +192:0,minecraft:acacia_fence +193:0,minecraft:spruce_door +194:0,minecraft:birch_door +195:0,minecraft:jungle_door +196:0,minecraft:acacia_door +197:0,minecraft:dark_oak_door +198:0,minecraft:end_rod +199:0,minecraft:chorus_plant +200:0,minecraft:chorus_flower +201:0,minecraft:purpur_block +202:0,minecraft:purpur_pillar +203:0,minecraft:purpur_stairs +204:0,minecraft:purpur_slab +205:0,minecraft:purpur_slab +206:0,minecraft:end_stone_bricks +207:0,minecraft:beetroots +208:0,minecraft:grass_path +209:0,minecraft:end_gateway +210:0,minecraft:repeating_command_block +211:0,minecraft:chain_command_block +212:0,minecraft:frosted_ice +213:0,minecraft:magma_block +214:0,minecraft:nether_wart_block +215:0,minecraft:red_nether_bricks +216:0,minecraft:bone_block +217:0,minecraft:structure_void +218:0,minecraft:observer +219:0,minecraft:white_shulker_box +220:0,minecraft:orange_shulker_box +221:0,minecraft:magenta_shulker_box +222:0,minecraft:light_blue_shulker_box +223:0,minecraft:yellow_shulker_box +224:0,minecraft:lime_shulker_box +225:0,minecraft:pink_shulker_box +226:0,minecraft:gray_shulker_box +227:0,minecraft:light_gray_shulker_box +228:0,minecraft:cyan_shulker_box +229:0,minecraft:purple_shulker_box +230:0,minecraft:blue_shulker_box +231:0,minecraft:brown_shulker_box +232:0,minecraft:green_shulker_box +233:0,minecraft:red_shulker_box +234:0,minecraft:black_shulker_box +235:0,minecraft:white_glazed_terracotta +236:0,minecraft:orange_glazed_terracotta +237:0,minecraft:magenta_glazed_terracotta +238:0,minecraft:light_blue_glazed_terracotta +239:0,minecraft:yellow_glazed_terracotta +240:0,minecraft:lime_glazed_terracotta +241:0,minecraft:pink_glazed_terracotta +242:0,minecraft:gray_glazed_terracotta +243:0,minecraft:light_gray_glazed_terracotta +244:0,minecraft:cyan_glazed_terracotta +245:0,minecraft:purple_glazed_terracotta +246:0,minecraft:blue_glazed_terracotta +247:0,minecraft:brown_glazed_terracotta +248:0,minecraft:green_glazed_terracotta +249:0,minecraft:red_glazed_terracotta +250:0,minecraft:black_glazed_terracotta +251:0,minecraft:white_concrete +251:1,minecraft:orange_concrete +251:2,minecraft:magenta_concrete +251:3,minecraft:light_blue_concrete +251:4,minecraft:yellow_concrete +251:5,minecraft:lime_concrete +251:6,minecraft:pink_concrete +251:7,minecraft:gray_concrete +251:8,minecraft:light_gray_concrete +251:9,minecraft:cyan_concrete +251:10,minecraft:purple_concrete +251:11,minecraft:blue_concrete +251:12,minecraft:brown_concrete +251:13,minecraft:green_concrete +251:14,minecraft:red_concrete +251:15,minecraft:black_concrete +252:0,minecraft:white_concrete_powder +252:1,minecraft:orange_concrete_powder +252:2,minecraft:magenta_concrete_powder +252:3,minecraft:light_blue_concrete_powder +252:4,minecraft:yellow_concrete_powder +252:5,minecraft:lime_concrete_powder +252:6,minecraft:pink_concrete_powder +252:7,minecraft:gray_concrete_powder +252:8,minecraft:light_gray_concrete_powder +252:9,minecraft:cyan_concrete_powder +252:10,minecraft:purple_concrete_powder +252:11,minecraft:blue_concrete_powder +252:12,minecraft:brown_concrete_powder +252:13,minecraft:green_concrete_powder +252:14,minecraft:red_concrete_powder +252:15,minecraft:black_concrete_powder +255:0,minecraft:structure_block +256:0,minecraft:iron_shovel +257:0,minecraft:iron_pickaxe +258:0,minecraft:iron_axe +259:0,minecraft:flint_and_steel +260:0,minecraft:apple +261:0,minecraft:bow +262:0,minecraft:arrow +263:0,minecraft:coal +263:1,minecraft:charcoal +264:0,minecraft:diamond +265:0,minecraft:iron_ingot +266:0,minecraft:gold_ingot +267:0,minecraft:iron_sword +268:0,minecraft:wooden_sword +269:0,minecraft:wooden_shovel +270:0,minecraft:wooden_pickaxe +271:0,minecraft:wooden_axe +272:0,minecraft:stone_sword +273:0,minecraft:stone_shovel +274:0,minecraft:stone_pickaxe +275:0,minecraft:stone_axe +276:0,minecraft:diamond_sword +277:0,minecraft:diamond_shovel +278:0,minecraft:diamond_pickaxe +279:0,minecraft:diamond_axe +280:0,minecraft:stick +281:0,minecraft:bowl +282:0,minecraft:mushroom_stew +283:0,minecraft:golden_sword +284:0,minecraft:golden_shovel +285:0,minecraft:golden_pickaxe +286:0,minecraft:golden_axe +287:0,minecraft:string +288:0,minecraft:feather +289:0,minecraft:gunpowder +290:0,minecraft:wooden_hoe +291:0,minecraft:stone_hoe +292:0,minecraft:iron_hoe +293:0,minecraft:diamond_hoe +294:0,minecraft:golden_hoe +295:0,minecraft:wheat_seeds +296:0,minecraft:wheat +297:0,minecraft:bread +298:0,minecraft:leather_helmet +299:0,minecraft:leather_chestplate +300:0,minecraft:leather_leggings +301:0,minecraft:leather_boots +302:0,minecraft:chainmail_helmet +303:0,minecraft:chainmail_chestplate +304:0,minecraft:chainmail_leggings +305:0,minecraft:chainmail_boots +306:0,minecraft:iron_helmet +307:0,minecraft:iron_chestplate +308:0,minecraft:iron_leggings +309:0,minecraft:iron_boots +310:0,minecraft:diamond_helmet +311:0,minecraft:diamond_chestplate +312:0,minecraft:diamond_leggings +313:0,minecraft:diamond_boots +314:0,minecraft:golden_helmet +315:0,minecraft:golden_chestplate +316:0,minecraft:golden_leggings +317:0,minecraft:golden_boots +318:0,minecraft:flint +319:0,minecraft:porkchop +320:0,minecraft:cooked_porkchop +321:0,minecraft:painting +322:0,minecraft:golden_apple +322:1,minecraft:enchanted_golden_apple +323:0,minecraft:sign +324:0,minecraft:oak_door +325:0,minecraft:bucket +326:0,minecraft:water_bucket +327:0,minecraft:lava_bucket +328:0,minecraft:minecart +329:0,minecraft:saddle +330:0,minecraft:iron_door +331:0,minecraft:redstone +332:0,minecraft:snowball +333:0,minecraft:oak_boat +334:0,minecraft:leather +335:0,minecraft:milk_bucket +336:0,minecraft:brick +337:0,minecraft:clay_ball +338:0,minecraft:sugar_cane +339:0,minecraft:paper +340:0,minecraft:book +341:0,minecraft:slime_ball +342:0,minecraft:chest_minecart +343:0,minecraft:furnace_minecart +344:0,minecraft:egg +345:0,minecraft:compass +346:0,minecraft:fishing_rod +347:0,minecraft:clock +348:0,minecraft:glowstone_dust +349:0,minecraft:cod +349:1,minecraft:salmon +349:2,minecraft:tropical_fish +349:3,minecraft:pufferfish +350:0,minecraft:cooked_cod +350:1,minecraft:cooked_salmon +351:0,minecraft:ink_sac +351:1,minecraft:rose_red +351:2,minecraft:cactus_green +351:3,minecraft:cocoa_beans +351:4,minecraft:lapis_lazuli +351:5,minecraft:purple_dye +351:6,minecraft:cyan_dye +351:7,minecraft:light_gray_dye +351:8,minecraft:gray_dye +351:9,minecraft:pink_dye +351:10,minecraft:lime_dye +351:11,minecraft:dandelion_yellow +351:12,minecraft:light_blue_dye +351:13,minecraft:magenta_dye +351:14,minecraft:orange_dye +351:15,minecraft:bone_meal +352:0,minecraft:bone +353:0,minecraft:sugar +354:0,minecraft:cake +355:0,minecraft:red_bed +355:1,minecraft:orange_bed +355:2,minecraft:magenta_bed +355:3,minecraft:light_blue_bed +355:4,minecraft:yellow_bed +355:5,minecraft:lime_bed +355:6,minecraft:pink_bed +355:7,minecraft:gray_bed +355:8,minecraft:light_gray_bed +355:9,minecraft:cyan_bed +355:10,minecraft:purple_bed +355:11,minecraft:blue_bed +355:12,minecraft:brown_bed +355:13,minecraft:green_bed +355:15,minecraft:black_bed +356:0,minecraft:repeater +357:0,minecraft:cookie +358:0,minecraft:filled_map +359:0,minecraft:shears +360:0,minecraft:melon_slice +361:0,minecraft:pumpkin_seeds +362:0,minecraft:melon_seeds +363:0,minecraft:beef +364:0,minecraft:cooked_beef +365:0,minecraft:chicken +366:0,minecraft:cooked_chicken +367:0,minecraft:rotten_flesh +368:0,minecraft:ender_pearl +369:0,minecraft:blaze_rod +370:0,minecraft:ghast_tear +371:0,minecraft:gold_nugget +372:0,minecraft:nether_wart +373:0,minecraft:potion +374:0,minecraft:glass_bottle +375:0,minecraft:spider_eye +376:0,minecraft:fermented_spider_eye +377:0,minecraft:blaze_powder +378:0,minecraft:magma_cream +379:0,minecraft:brewing_stand +380:0,minecraft:cauldron +381:0,minecraft:ender_eye +382:0,minecraft:glistering_melon_slice +383:0,minecraft:pig_spawn_egg +383:4,minecraft:elder_guardian_spawn_egg +383:5,minecraft:wither_skeleton_spawn_egg +383:6,minecraft:stray_spawn_egg +383:23,minecraft:husk_spawn_egg +383:27,minecraft:zombie_villager_spawn_egg +383:28,minecraft:skeleton_horse_spawn_egg +383:29,minecraft:zombie_horse_spawn_egg +383:31,minecraft:donkey_spawn_egg +383:32,minecraft:mule_spawn_egg +383:34,minecraft:evoker_spawn_egg +383:35,minecraft:vex_spawn_egg +383:36,minecraft:vindicator_spawn_egg +383:50,minecraft:creeper_spawn_egg +383:51,minecraft:skeleton_spawn_egg +383:52,minecraft:spider_spawn_egg +383:54,minecraft:zombie_spawn_egg +383:55,minecraft:slime_spawn_egg +383:56,minecraft:ghast_spawn_egg +383:57,minecraft:zombie_pigman_spawn_egg +383:58,minecraft:enderman_spawn_egg +383:59,minecraft:cave_spider_spawn_egg +383:60,minecraft:silverfish_spawn_egg +383:61,minecraft:blaze_spawn_egg +383:62,minecraft:magma_cube_spawn_egg +383:65,minecraft:bat_spawn_egg +383:66,minecraft:witch_spawn_egg +383:67,minecraft:endermite_spawn_egg +383:68,minecraft:guardian_spawn_egg +383:69,minecraft:shulker_spawn_egg +383:91,minecraft:sheep_spawn_egg +383:92,minecraft:cow_spawn_egg +383:93,minecraft:chicken_spawn_egg +383:94,minecraft:squid_spawn_egg +383:95,minecraft:wolf_spawn_egg +383:96,minecraft:mooshroom_spawn_egg +383:98,minecraft:ocelot_spawn_egg +383:100,minecraft:horse_spawn_egg +383:101,minecraft:rabbit_spawn_egg +383:102,minecraft:polar_bear_spawn_egg +383:103,minecraft:llama_spawn_egg +383:105,minecraft:parrot_spawn_egg +383:120,minecraft:villager_spawn_egg +383:255,minecraft:turtle_spawn_egg +384:0,minecraft:experience_bottle +385:0,minecraft:fire_charge +386:0,minecraft:writable_book +387:0,minecraft:written_book +388:0,minecraft:emerald +389:0,minecraft:item_frame +390:0,minecraft:flower_pot +391:0,minecraft:carrot +392:0,minecraft:potato +393:0,minecraft:baked_potato +394:0,minecraft:poisonous_potato +395:0,minecraft:map +396:0,minecraft:golden_carrot +397:0,minecraft:skeleton_skull +397:1,minecraft:wither_skeleton_skull +397:2,minecraft:zombie_head +397:3,minecraft:player_head +397:4,minecraft:creeper_head +397:5,minecraft:dragon_head +398:0,minecraft:carrot_on_a_stick +399:0,minecraft:nether_star +400:0,minecraft:pumpkin_pie +401:0,minecraft:firework_rocket +402:0,minecraft:firework_star +403:0,minecraft:enchanted_book +404:0,minecraft:comparator +405:0,minecraft:nether_brick +406:0,minecraft:quartz +407:0,minecraft:tnt_minecart +408:0,minecraft:hopper_minecart +409:0,minecraft:prismarine_shard +410:0,minecraft:prismarine_crystals +411:0,minecraft:rabbit +412:0,minecraft:cooked_rabbit +413:0,minecraft:rabbit_stew +414:0,minecraft:rabbit_foot +415:0,minecraft:rabbit_hide +416:0,minecraft:armor_stand +417:0,minecraft:iron_horse_armor +418:0,minecraft:golden_horse_armor +419:0,minecraft:diamond_horse_armor +420:0,minecraft:lead +421:0,minecraft:name_tag +422:0,minecraft:command_block_minecart +423:0,minecraft:mutton +424:0,minecraft:cooked_mutton +425:0,minecraft:black_banner +425:1,minecraft:red_banner +425:2,minecraft:green_banner +425:3,minecraft:brown_banner +425:4,minecraft:blue_banner +425:5,minecraft:purple_banner +425:6,minecraft:cyan_banner +425:7,minecraft:light_gray_banner +425:8,minecraft:gray_banner +425:9,minecraft:pink_banner +425:10,minecraft:lime_banner +425:11,minecraft:yellow_banner +425:12,minecraft:light_blue_banner +425:13,minecraft:magenta_banner +425:14,minecraft:orange_banner +425:15,minecraft:white_banner +426:0,minecraft:end_crystal +427:0,minecraft:spruce_door +428:0,minecraft:birch_door +429:0,minecraft:jungle_door +430:0,minecraft:acacia_door +431:0,minecraft:dark_oak_door +432:0,minecraft:chorus_fruit +433:0,minecraft:popped_chorus_fruit +434:0,minecraft:beetroot +435:0,minecraft:beetroot_seeds +436:0,minecraft:beetroot_soup +437:0,minecraft:dragon_breath +438:0,minecraft:splash_potion +439:0,minecraft:spectral_arrow +440:0,minecraft:tipped_arrow +441:0,minecraft:lingering_potion +442:0,minecraft:shield +443:0,minecraft:elytra +444:0,minecraft:spruce_boat +445:0,minecraft:birch_boat +446:0,minecraft:jungle_boat +447:0,minecraft:acacia_boat +448:0,minecraft:dark_oak_boat +449:0,minecraft:totem_of_undying +450:0,minecraft:shulker_shell +452:0,minecraft:iron_nugget +453:0,minecraft:knowledge_book +2256:0,minecraft:music_disc_13 +2257:0,minecraft:music_disc_cat +2258:0,minecraft:music_disc_blocks +2259:0,minecraft:music_disc_chirp +2260:0,minecraft:music_disc_far +2261:0,minecraft:music_disc_mall +2262:0,minecraft:music_disc_mellohi +2263:0,minecraft:music_disc_stal +2264:0,minecraft:music_disc_strad +2265:0,minecraft:music_disc_ward +2266:0,minecraft:music_disc_11 +2267:0,minecraft:music_disc_wait From afb81f850dd77467b0fd25f41e735c782b9aba82 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 30 Jul 2018 16:41:12 +0200 Subject: [PATCH 030/399] The uncolored skulker box is also a block --- src/main/java/de/diddiz/util/BukkitUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 516b83dc..2e1fa1bd 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -167,6 +167,7 @@ public class BukkitUtils { containerBlocks.add(Material.BREWING_STAND); containerBlocks.add(Material.FURNACE); containerBlocks.add(Material.BEACON); + containerBlocks.add(Material.SHULKER_BOX); containerBlocks.add(Material.BLACK_SHULKER_BOX); containerBlocks.add(Material.BLUE_SHULKER_BOX); containerBlocks.add(Material.LIGHT_GRAY_SHULKER_BOX); From f6e440c1df1456c350333d1b77d22da26337618a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 30 Jul 2018 16:41:55 +0200 Subject: [PATCH 031/399] cleanup (de)serializing of ItemStacks --- src/main/java/de/diddiz/util/Utils.java | 36 +++++++++++++++++-------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index c52a6768..6b7b19f2 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -11,6 +11,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; @@ -20,6 +21,8 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.inventory.ItemStack; +import de.diddiz.LogBlock.LogBlock; + public class Utils { public static String newline = System.getProperty("line.separator"); @@ -225,14 +228,10 @@ public static ItemStack loadItemStack(byte[] data) { if (data == null || data.length == 0) { return null; } - YamlConfiguration conf = new YamlConfiguration(); try { - InputStreamReader reader = new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(data)), "UTF-8"); - conf.load(reader); - reader.close(); - return conf.getItemStack("stack"); - } catch (IOException | InvalidConfigurationException e) { - e.printStackTrace(); + return deserializeYamlConfiguration(data).getItemStack("stack"); + } catch (InvalidConfigurationException e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Exception while deserializing ItemStack", e); } return null; } @@ -241,17 +240,32 @@ public static byte[] saveItemStack(ItemStack stack) { if (stack == null || BukkitUtils.isEmpty(stack.getType())) { return null; } + YamlConfiguration conf = new YamlConfiguration(); + conf.set("stack", stack); + return serializeYamlConfiguration(conf); + } + + public static YamlConfiguration deserializeYamlConfiguration(byte[] data) throws InvalidConfigurationException { + YamlConfiguration conf = new YamlConfiguration(); + try { + InputStreamReader reader = new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(data)), "UTF-8"); + conf.load(reader); + reader.close(); + return conf; + } catch (IOException e) { + throw new RuntimeException("IOException should be impossible for ByteArrayInputStream", e); + } + } + + public static byte[] serializeYamlConfiguration(YamlConfiguration conf) { try { - YamlConfiguration conf = new YamlConfiguration(); - conf.set("stack", stack); ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(new GZIPOutputStream(baos), "UTF-8"); writer.write(conf.saveToString()); writer.close(); return baos.toByteArray(); } catch (IOException e) { - e.printStackTrace(); + throw new RuntimeException("IOException should be impossible for ByteArrayOutputStream", e); } - return null; } } From fca9c90032fc26bc6fa668b9720b18e9b4cfb0e6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 30 Jul 2018 16:48:09 +0200 Subject: [PATCH 032/399] Improve version parsing for update check --- src/main/java/de/diddiz/LogBlock/Updater.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index c2f9fe9d..dde3cc34 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -47,7 +47,7 @@ boolean update() { logblock.saveConfig(); } ComparableVersion configVersion = new ComparableVersion(versionString); - if (configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion())) >= 0) { + if (configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion().replace(" (manually compiled)", ""))) >= 0) { return false; } if (configVersion.compareTo(new ComparableVersion("1.2.7")) < 0) { From 58e5cdf890301951b401394bd92a82b02cd26ef1 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 02:19:40 +0200 Subject: [PATCH 033/399] Serialize BlockStates Banner, spawner and player heads can now be rolled back --- pom.xml | 2 +- .../java/de/diddiz/LogBlock/BlockChange.java | 56 ++++++++---- .../de/diddiz/LogBlock/CommandsHandler.java | 27 ++---- .../java/de/diddiz/LogBlock/Consumer.java | 59 +++++++------ .../java/de/diddiz/LogBlock/QueryParams.java | 10 +-- src/main/java/de/diddiz/LogBlock/Updater.java | 86 ++++++++++++++++++- .../java/de/diddiz/LogBlock/WorldEditor.java | 35 ++++---- .../LogBlock/blockstate/BlockStateCodec.java | 15 ++++ .../blockstate/BlockStateCodecBanner.java | 70 +++++++++++++++ .../blockstate/BlockStateCodecSign.java | 76 ++++++++++++++++ .../blockstate/BlockStateCodecSkull.java | 54 ++++++++++++ .../blockstate/BlockStateCodecSpawner.java | 60 +++++++++++++ .../LogBlock/blockstate/BlockStateCodecs.java | 80 +++++++++++++++++ .../worldedit/WorldEditLoggingHook.java | 8 +- 14 files changed, 539 insertions(+), 99 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java create mode 100644 src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java create mode 100644 src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java create mode 100644 src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java create mode 100644 src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java create mode 100644 src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java diff --git a/pom.xml b/pom.xml index 6207091a..31ddf18d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.13-SNAPSHOT + 1.13.1-SNAPSHOT jar LogBlock diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 30af6f7c..75351ab4 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock; +import de.diddiz.LogBlock.blockstate.BlockStateCodecs; import de.diddiz.LogBlock.config.Config; import de.diddiz.util.BukkitUtils; import de.diddiz.util.Utils; @@ -14,29 +15,28 @@ import java.sql.ResultSet; import java.sql.SQLException; - -import static de.diddiz.util.LoggingUtil.checkText; +import java.util.logging.Level; public class BlockChange implements LookupCacheElement { public final long id, date; public final Location loc; public final Actor actor; public final String playerName; - // public final BlockData replaced, type; public final int replacedMaterial, replacedData, typeMaterial, typeData; - public final String signtext; + public final byte[] replacedState, typeState; public final ChestAccess ca; - public BlockChange(long date, Location loc, Actor actor, int replaced, int replacedData, int type, int typeData, String signtext, ChestAccess ca) { + public BlockChange(long date, Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { id = 0; this.date = date; this.loc = loc; this.actor = actor; this.replacedMaterial = replaced; this.replacedData = replacedData; + this.replacedState = replacedState; this.typeMaterial = type; this.typeData = typeData; - this.signtext = checkText(signtext); + this.typeState = typeState; this.ca = ca; this.playerName = actor == null ? null : actor.getName(); } @@ -51,7 +51,8 @@ public BlockChange(ResultSet rs, QueryParams p) throws SQLException { replacedData = p.needType ? rs.getInt("replacedData") : -1; typeMaterial = p.needType ? rs.getInt("type") : 0; typeData = p.needType ? rs.getInt("typeData") : -1; - signtext = p.needSignText ? rs.getString("signtext") : null; + replacedState = p.needType ? rs.getBytes("replacedState") : null; + typeState = p.needType ? rs.getBytes("typeState") : null; ChestAccess catemp = null; if (p.needChestAccess) { ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); @@ -66,6 +67,32 @@ public BlockChange(ResultSet rs, QueryParams p) throws SQLException { public String toString() { BlockData type = MaterialConverter.getBlockData(typeMaterial, typeData); BlockData replaced = MaterialConverter.getBlockData(replacedMaterial, replacedData); + String typeDetails = null; + if (BlockStateCodecs.hasCodec(type.getMaterial())) { + try { + typeDetails = BlockStateCodecs.toString(type.getMaterial(), typeState); + } catch (Exception e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + type.getMaterial(), e); + } + } + if (typeDetails == null) { + typeDetails = ""; + } else { + typeDetails = " " + typeDetails; + } + String replacedDetails = null; + if (BlockStateCodecs.hasCodec(replaced.getMaterial())) { + try { + replacedDetails = BlockStateCodecs.toString(replaced.getMaterial(), replacedState); + } catch (Exception e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + replaced.getMaterial(), e); + } + } + if (replacedDetails == null) { + replacedDetails = ""; + } else { + replacedDetails = " " + replacedDetails; + } final StringBuilder msg = new StringBuilder(); if (date > 0) { msg.append(Config.formatter.format(date)).append(" "); @@ -73,14 +100,7 @@ public String toString() { if (actor != null) { msg.append(actor.getName()).append(" "); } - if (signtext != null) { - final String action = BukkitUtils.isEmpty(type.getMaterial()) ? "destroyed " : "created "; - if (!signtext.contains("\0")) { - msg.append(action).append(signtext); - } else { - msg.append(action).append((!BukkitUtils.isEmpty(type.getMaterial()) ? type : replaced).getMaterial().name()).append(" [").append(signtext.replace("\0", "] [")).append("]"); - } - } else if (type.equals(replaced)) { + if (type.equals(replaced)) { if (BukkitUtils.isEmpty(type.getMaterial())) { msg.append("did an unspecified action"); } else if (ca != null) { @@ -110,11 +130,11 @@ public String toString() { msg.append("ran into ").append(type.getMaterial().name()); } } else if (BukkitUtils.isEmpty(type.getMaterial())) { - msg.append("destroyed ").append(replaced.getMaterial().name()); + msg.append("destroyed ").append(replaced.getMaterial().name()).append(replacedDetails); } else if (BukkitUtils.isEmpty(replaced.getMaterial())) { - msg.append("created ").append(type.getMaterial().name()); + msg.append("created ").append(type.getMaterial().name()).append(typeDetails); } else { - msg.append("replaced ").append(replaced.getMaterial().name()).append(" with ").append(type.getMaterial().name()); + msg.append("replaced ").append(replaced.getMaterial().name()).append(replacedDetails).append(" with ").append(type.getMaterial().name()).append(typeDetails); } if (loc != null) { msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ()); diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 6ae53cf0..fe74da18 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -10,7 +10,6 @@ import org.bukkit.ChatColor; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -456,9 +455,6 @@ public void run() { params.needType = true; params.needData = true; params.needPlayer = true; - if (params.types.isEmpty() || params.types.contains(Material.SIGN) || params.types.contains(Material.WALL_SIGN)) { - params.needSignText = true; - } if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) { params.needChestAccess = true; } @@ -521,9 +517,6 @@ public void run() { params.needType = true; params.needData = true; params.needPlayer = true; - if (params.types.isEmpty() || params.types.contains(Material.SIGN) || params.types.contains(Material.WALL_SIGN)) { - params.needSignText = true; - } if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) { params.needChestAccess = true; } @@ -646,7 +639,6 @@ public void run() { params.needCoords = true; params.needType = true; params.needData = true; - params.needSignText = true; params.needChestAccess = true; params.order = Order.DESC; params.sum = SummarizationMode.NONE; @@ -674,7 +666,7 @@ public void run() { if (stack != null) { chestaccess = new ChestAccess(stack, rs.getBoolean("itemremove")); } - editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getInt("type"), rs.getInt("typeData"), rs.getString("signtext"), chestaccess); + editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), chestaccess); } final int changes = editor.getSize(); if (changes > 10000) { @@ -725,7 +717,6 @@ public void run() { params.needCoords = true; params.needType = true; params.needData = true; - params.needSignText = true; params.needChestAccess = true; params.order = Order.ASC; params.sum = SummarizationMode.NONE; @@ -749,7 +740,7 @@ public void run() { if (stack != null) { chestaccess = new ChestAccess(stack, !rs.getBoolean("itemremove")); } - editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getString("signtext"), chestaccess); + editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), chestaccess); } final int changes = editor.getSize(); if (!params.silent) { @@ -824,23 +815,23 @@ public void run() { state.execute("DELETE `" + table + "` FROM `" + table + "-blocks` " + join + params.getWhere()); sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + ". Deleted " + deleted + " entries."); } - rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-sign` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL"); + rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-state` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL"); rs.next(); if ((deleted = rs.getInt(1)) > 0) { if (dumpDeletedLog) { - state.execute("SELECT id, signtext FROM `" + table + "-sign` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-sign " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); + state.execute("SELECT id, replacedState, typeState FROM `" + table + "-state` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-state " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); } - state.execute("DELETE `" + table + "-sign` FROM `" + table + "-sign` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL;"); - sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-sign. Deleted " + deleted + " entries."); + state.execute("DELETE `" + table + "-state` FROM `" + table + "-state` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL;"); + sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-state. Deleted " + deleted + " entries."); } rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-chestdata` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL"); rs.next(); if ((deleted = rs.getInt(1)) > 0) { if (dumpDeletedLog) { - state.execute("SELECT id, item, itemremove FROM `" + table + "-chest` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-chest " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); + state.execute("SELECT id, item, itemremove FROM `" + table + "-chestdata` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-chest " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); } - state.execute("DELETE `" + table + "-chest` FROM `" + table + "-chest` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL;"); - sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-chest. Deleted " + deleted + " entries."); + state.execute("DELETE `" + table + "-chestdata` FROM `" + table + "-chestdata` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL;"); + sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-chestdata. Deleted " + deleted + " entries."); } } catch (final Exception ex) { sender.sendMessage(ChatColor.RED + "Exception, check error log"); diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 20bdb125..c01371cc 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -1,5 +1,7 @@ package de.diddiz.LogBlock; +import de.diddiz.LogBlock.blockstate.BlockStateCodecSign; +import de.diddiz.LogBlock.blockstate.BlockStateCodecs; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.events.BlockChangePreLogEvent; import de.diddiz.util.Utils; @@ -63,7 +65,7 @@ public class Consumer extends TimerTask { * Data of the block after the change */ public void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter) { - queueBlock(actor, loc, typeBefore, typeAfter, null, null); + queueBlock(actor, loc, typeBefore, typeAfter, null, null, null); } /** @@ -75,7 +77,7 @@ public void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDat * Blockstate of the block before actually being destroyed. */ public void queueBlockBreak(Actor actor, BlockState before) { - queueBlockBreak(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData()); + queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), null, BlockStateCodecs.serialize(before), null, null); } /** @@ -103,7 +105,7 @@ public void queueBlockBreak(Actor actor, Location loc, BlockData typeBefore) { * Blockstate of the block after actually being placed. */ public void queueBlockPlace(Actor actor, BlockState after) { - queueBlockPlace(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), after.getBlockData()); + queueBlock(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), null, after.getBlockData(), null, BlockStateCodecs.serialize(after), null); } /** @@ -133,7 +135,7 @@ public void queueBlockPlace(Actor actor, Location loc, BlockData type) { * Blockstate of the block after actually being placed. */ public void queueBlockReplace(Actor actor, BlockState before, BlockState after) { - queueBlockReplace(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), after.getBlockData()); + queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), after.getBlockData(), BlockStateCodecs.serialize(before), BlockStateCodecs.serialize(after), null); } /** @@ -149,7 +151,7 @@ public void queueBlockReplace(Actor actor, BlockState before, BlockState after) * Data of the block after being replaced */ public void queueBlockReplace(Actor actor, BlockState before, BlockData typeAfter) { - queueBlockReplace(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), typeAfter); + queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), typeAfter, BlockStateCodecs.serialize(before), null, null); } /** @@ -165,12 +167,11 @@ public void queueBlockReplace(Actor actor, BlockState before, BlockData typeAfte * Blockstate of the block after actually being placed. */ public void queueBlockReplace(Actor actor, BlockData typeBefore, BlockState after) { - queueBlockReplace(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), typeBefore, after.getBlockData()); + queueBlock(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), typeBefore, after.getBlockData(), null, BlockStateCodecs.serialize(after), null); } public void queueBlockReplace(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter) { - queueBlockBreak(actor, loc, typeBefore); - queueBlockPlace(actor, loc, typeAfter); + queueBlock(actor, loc, typeBefore, typeAfter, null, null, null); } /** @@ -211,7 +212,7 @@ public void queueChestAccess(Actor actor, BlockState container, ItemStack itemSt * Data of the item taken/stored */ public void queueChestAccess(Actor actor, Location loc, BlockData type, ItemStack itemStack, boolean remove) { - queueBlock(actor, loc, type, type, null, new ChestAccess(itemStack, remove)); + queueBlock(actor, loc, type, type, null, null, new ChestAccess(itemStack, remove)); } /** @@ -326,11 +327,8 @@ public void queueKill(Location location, Actor killer, Actor victim, ItemStack w * @param lines * The four lines on the sign. */ - public void queueSignBreak(Actor actor, Location loc, BlockData type, String[] lines) { - if ((type.getMaterial() != Material.SIGN && type.getMaterial() != Material.WALL_SIGN) || lines == null || lines.length != 4) { - return; - } - queueBlock(actor, loc, type, null, lines[0] + "\0" + lines[1] + "\0" + lines[2] + "\0" + lines[3], null); + public void queueSignBreak(Actor actor, Location loc, BlockData type, byte[] typeState) { + queueBlock(actor, loc, type, null, typeState, null, null); } /** @@ -342,7 +340,7 @@ public void queueSignBreak(Actor actor, Location loc, BlockData type, String[] l * The sign being broken */ public void queueSignBreak(Actor actor, Sign sign) { - queueSignBreak(actor, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getBlockData(), sign.getLines()); + queueSignBreak(actor, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getBlockData(), BlockStateCodecs.serialize(sign)); } /** @@ -363,7 +361,7 @@ public void queueSignPlace(Actor actor, Location loc, BlockData type, String[] l if ((type.getMaterial() != Material.SIGN && type.getMaterial() != Material.WALL_SIGN) || lines == null || lines.length != 4) { return; } - queueBlock(actor, loc, null, type, lines[0] + "\0" + lines[1] + "\0" + lines[2] + "\0" + lines[3], null); + queueBlock(actor, loc, null, type, null, Utils.serializeYamlConfiguration(BlockStateCodecSign.serialize(lines)), null); } /** @@ -585,7 +583,7 @@ private boolean addPlayer(Statement state, Actor actor) throws SQLException { return playerIds.containsKey(actor); } - private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter, String signtext, ChestAccess ca) { + private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter, byte[] stateBefore, byte[] stateAfter, ChestAccess ca) { if (typeBefore == null) { typeBefore = Bukkit.createBlockData(Material.AIR); } @@ -594,7 +592,7 @@ private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDa } if (Config.fireCustomEvents) { // Create and call the event - BlockChangePreLogEvent event = new BlockChangePreLogEvent(actor, loc, typeBefore, typeAfter, signtext, ca); + BlockChangePreLogEvent event = new BlockChangePreLogEvent(actor, loc, typeBefore, typeAfter, null, ca); logblock.getServer().getPluginManager().callEvent(event); if (event.isCancelled()) { return; @@ -605,7 +603,7 @@ private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDa loc = event.getLocation(); typeBefore = event.getTypeBefore(); typeAfter = event.getTypeAfter(); - signtext = event.getSignText(); + // signtext = event.getSignText(); ca = event.getChestAccess(); } // Do this last so LogBlock still has final say in what is being added @@ -620,7 +618,7 @@ private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDa int typeMaterialId = MaterialConverter.getOrAddMaterialId(typeString); int typeStateId = MaterialConverter.getOrAddBlockStateId(typeString); - queue.add(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, typeMaterialId, typeStateId, signtext, ca)); + queue.add(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, stateBefore, typeMaterialId, typeStateId, stateAfter, ca)); } private String playerID(Actor actor) { @@ -670,19 +668,19 @@ private interface MergeableRow extends PreparedStatementRow { private class BlockRow extends BlockChange implements MergeableRow { private Connection connection; - public BlockRow(Location loc, Actor actor, int replaced, int replacedData, int type, int typeData, String signtext, ChestAccess ca) { - super(System.currentTimeMillis() / 1000, loc, actor, replaced, replacedData, type, typeData, signtext, ca); + public BlockRow(Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { + super(System.currentTimeMillis() / 1000, loc, actor, replaced, replacedData, replacedState, type, typeData, typeState, ca); } @Override public String[] getInserts() { final String table = getWorldConfig(loc.getWorld()).table; - final String[] inserts = new String[ca != null || signtext != null ? 2 : 1]; + final String[] inserts = new String[ca != null || replacedState != null || typeState != null ? 2 : 1]; inserts[0] = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(actor) + ", " + replacedMaterial + ", " + replacedData + ", " + typeMaterial + ", " + typeData + ", '" + loc.getBlockX() + "', " + safeY(loc) + ", '" + loc.getBlockZ() + "');"; - if (signtext != null) { - inserts[1] = "INSERT INTO `" + table + "-sign` (id, signtext) values (LAST_INSERT_ID(), '" + mysqlTextEscape(signtext) + "');"; + if (replacedState != null || typeState != null) { + inserts[1] = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES('" + Utils.mysqlEscapeBytes(replacedState) + "', '" + Utils.mysqlEscapeBytes(typeState) + "', LAST_INSERT_ID());"; } else if (ca != null) { inserts[1] = "INSERT INTO `" + table + "-chestdata` (id, item, itemremoved) values (LAST_INSERT_ID(), '" + Utils.mysqlEscapeBytes(Utils.saveItemStack(ca.itemStack)) + "', " + (ca.remove ? 1 : 0) + ");"; } @@ -727,10 +725,11 @@ public void executeStatements() throws SQLException { rs.next(); id = rs.getInt(1); - if (signtext != null) { - ps = connection.prepareStatement("INSERT INTO `" + table + "-sign` (signtext, id) VALUES(?, ?)"); - ps.setString(1, signtext); - ps.setInt(2, id); + if (typeState != null || replacedState != null) { + ps = connection.prepareStatement("INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(?, ?, ?)"); + ps.setBytes(1, replacedState); + ps.setBytes(2, typeState); + ps.setInt(3, id); ps.executeUpdate(); } else if (ca != null) { ps = connection.prepareStatement("INSERT INTO `" + table + "-chestdata` (item, itemremove, id) values (?, ?, ?)"); @@ -772,7 +771,7 @@ public void executeStatements() throws SQLException { @Override public boolean isUnique() { - return !(signtext == null && ca == null && playerIds.containsKey(actor)); + return !(typeState == null && replacedState == null && ca == null && playerIds.containsKey(actor)); } @Override diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 3d0a1517..b97ee031 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -34,7 +34,7 @@ public final class QueryParams implements Cloneable { public List typeIds = new ArrayList(); public World world = null; public String match = null; - public boolean needCount = false, needId = false, needDate = false, needType = false, needData = false, needPlayer = false, needCoords = false, needSignText = false, needChestAccess = false, needMessage = false, needKiller = false, needVictim = false, needWeapon = false; + public boolean needCount = false, needId = false, needDate = false, needType = false, needData = false, needPlayer = false, needCoords = false, needChestAccess = false, needMessage = false, needKiller = false, needVictim = false, needWeapon = false; private final LogBlock logblock; public QueryParams(LogBlock logblock) { @@ -145,8 +145,8 @@ public String getQuery() { if (needCoords) { select += "x, y, z, "; } - if (needSignText) { - select += "signtext, "; + if (needData) { + select += "replacedState, typeState, "; } if (needChestAccess) { select += "item, itemremove, "; @@ -157,8 +157,8 @@ public String getQuery() { if (needPlayer || players.size() > 0) { from += "INNER JOIN `lb-players` USING (playerid) "; } - if (needSignText) { - from += "LEFT JOIN `" + getTable() + "-sign` USING (id) "; + if (!needCount && needData) { + from += "LEFT JOIN `" + getTable() + "-state` USING (id) "; } if (needChestAccess) // If BlockChangeType is CHESTACCESS, we can use more efficient query diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index dde3cc34..123be336 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock; +import de.diddiz.LogBlock.blockstate.BlockStateCodecSign; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.util.UUIDFetcher; @@ -386,7 +387,7 @@ boolean update() { } for (final WorldConfig wcfg : getLoggedWorlds()) { if (wcfg.isLogging(Logging.SIGNTEXT)) { - checkCharset(wcfg.table + "-sign","signtext",st); + // checkCharset(wcfg.table + "-sign","signtext",st); } } st.close(); @@ -565,7 +566,7 @@ boolean update() { } rs.close(); - PreparedStatement updateWeaponStatement = conn.prepareStatement("UPDATE `" + wcfg.table + "`-kills SET weapon = ? WHERE id = ?"); + PreparedStatement updateWeaponStatement = conn.prepareStatement("UPDATE `" + wcfg.table + "-kills` SET weapon = ? WHERE id = ?"); for (int start = 0;; start += 10000) { rs = st.executeQuery("SELECT id, weapon FROM `" + wcfg.table + "-kills` ORDER BY id ASC LIMIT " + start + ",10000"); boolean anyUpdate = false; @@ -622,7 +623,85 @@ boolean update() { } config.set("version", "1.13.0"); } + + if (configVersion.compareTo(new ComparableVersion("1.13.1")) < 0) { + getLogger().info("Updating tables to 1.13.1 ..."); + try { + final Connection conn = logblock.getConnection(); + conn.setAutoCommit(false); + final Statement st = conn.createStatement(); + for (final WorldConfig wcfg : getLoggedWorlds()) { + getLogger().info("Processing world " + wcfg.world + "..."); + if (wcfg.isLogging(Logging.SIGNTEXT)) { + int rowsToConvert = 0; + int done = 0; + try { + ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-sign`"); + if (rs.next()) { + rowsToConvert = rs.getInt(1); + getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-sign"); + } + rs.close(); + + PreparedStatement insertSignState = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-state` (id, replacedState, typeState) VALUES (?, ?, ?)"); + PreparedStatement deleteSign = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-sign` WHERE id = ?"); + while (true) { + rs = st.executeQuery("SELECT id, signtext, replaced, type FROM `" + wcfg.table + "-sign` LEFT JOIN `" + wcfg.table + "-blocks` USING (id) ORDER BY id ASC LIMIT 10000"); + boolean anyRow = false; + while (rs.next()) { + anyRow = true; + int id = rs.getInt("id"); + String signText = rs.getString("signtext"); + int replaced = rs.getInt("replaced"); + boolean nullBlock = rs.wasNull(); + int type = rs.getInt("type"); + + if (!nullBlock && signText != null) { + String[] lines = signText.split("\0", 4); + byte[] bytes = Utils.serializeYamlConfiguration(BlockStateCodecSign.serialize(lines)); + + Material replacedMaterial = MaterialConverter.getBlockData(replaced, -1).getMaterial(); + Material typeMaterial = MaterialConverter.getBlockData(type, -1).getMaterial(); + boolean wasSign = replacedMaterial == Material.SIGN || replacedMaterial == Material.WALL_SIGN; + boolean isSign = typeMaterial == Material.SIGN || typeMaterial == Material.WALL_SIGN; + + insertSignState.setInt(1, id); + insertSignState.setBytes(2, wasSign ? bytes : null); + insertSignState.setBytes(3, isSign ? bytes : null); + insertSignState.addBatch(); + } + + deleteSign.setInt(1, id); + deleteSign.addBatch(); + done++; + } + rs.close(); + if (!anyRow) { + break; + } + insertSignState.executeBatch(); + deleteSign.executeBatch(); + conn.commit(); + getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + } + insertSignState.close(); + deleteSign.close(); + } catch (SQLException e) { + getLogger().info("Could not convert " + wcfg.table + "-sign: " + e.getMessage()); + } + } + } + st.close(); + conn.close(); + } catch (final SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + + config.set("version", "1.13.1"); + } + logblock.saveConfig(); return true; } @@ -667,8 +746,9 @@ void checkTables() throws SQLException { for (final WorldConfig wcfg : getLoggedWorlds()) { createTable(dbm, state, wcfg.table + "-blocks", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced SMALLINT UNSIGNED NOT NULL, replacedData SMALLINT NOT NULL, type SMALLINT UNSIGNED NOT NULL, typeData SMALLINT NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))"); - createTable(dbm, state, wcfg.table + "-sign", "(id INT UNSIGNED NOT NULL, signtext VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); + // createTable(dbm, state, wcfg.table + "-sign", "(id INT UNSIGNED NOT NULL, signtext VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); createTable(dbm, state, wcfg.table + "-chestdata", "(id INT UNSIGNED NOT NULL, item MEDIUMBLOB, itemremove TINYINT, PRIMARY KEY (id))"); + createTable(dbm, state, wcfg.table + "-state", "(id INT UNSIGNED NOT NULL, replacedState MEDIUMBLOB NULL, typeState MEDIUMBLOB NULL, PRIMARY KEY (id))"); if (wcfg.isLogging(Logging.KILL)) { createTable(dbm, state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id))"); } diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 813493a1..a83cf7b8 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -7,7 +7,6 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; -import org.bukkit.block.Sign; import org.bukkit.block.data.Bisected.Half; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.Bed; @@ -20,6 +19,7 @@ import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import de.diddiz.LogBlock.blockstate.BlockStateCodecs; import de.diddiz.util.BukkitUtils; import java.io.File; @@ -76,8 +76,8 @@ public void setSender(CommandSender sender) { this.sender = sender; } - public void queueEdit(int x, int y, int z, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess item) { - edits.add(new Edit(0, new Location(world, x, y, z), null, replaced, replaceData, type, typeData, signtext, item)); + public void queueEdit(int x, int y, int z, int replaced, int replaceData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess item) { + edits.add(new Edit(0, new Location(world, x, y, z), null, replaced, replaceData, replacedState, type, typeData, typeState, item)); } public long getElapsedTime() { @@ -153,8 +153,8 @@ private static enum PerformResult { } private class Edit extends BlockChange { - public Edit(long time, Location loc, Actor actor, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess ca) { - super(time, loc, actor, replaced, replaceData, type, typeData, signtext, ca); + public Edit(long time, Location loc, Actor actor, int replaced, int replaceData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { + super(time, loc, actor, replaced, replaceData,replacedState , type, typeData, typeState, ca); } PerformResult perform() throws WorldEditorException { @@ -172,7 +172,7 @@ PerformResult perform() throws WorldEditorException { if (BukkitUtils.isEmpty(replacedBlock.getMaterial()) && BukkitUtils.isEmpty(block.getType())) { return PerformResult.NO_ACTION; } - final BlockState state = block.getState(); + BlockState state = block.getState(); if (!world.isChunkLoaded(block.getChunk())) { world.loadChunk(block.getChunk()); } @@ -217,21 +217,18 @@ PerformResult perform() throws WorldEditorException { } block.setBlockData(replacedBlock); BlockData newData = block.getBlockData(); + if (BlockStateCodecs.hasCodec(replacedBlock.getMaterial())) { + state = block.getState(); + try { + BlockStateCodecs.deserialize(state, replacedState); + state.update(); + } catch (Exception e) { + throw new WorldEditorException("Failed to restore blockstate of " + block.getType() + ": " + e, block.getLocation()); + } + } final Material curtype = block.getType(); - if (signtext != null && (curtype == Material.SIGN || curtype == Material.WALL_SIGN)) { - final Sign sign = (Sign) block.getState(); - final String[] lines = signtext.split("\0", 4); - if (lines.length < 4) { - return PerformResult.NO_ACTION; - } - for (int i = 0; i < 4; i++) { - sign.setLine(i, lines[i]); - } - if (!sign.update()) { - throw new WorldEditorException("Failed to update signtext of " + block.getType(), block.getLocation()); - } - } else if (newData instanceof Bed) { + if (newData instanceof Bed) { final Bed bed = (Bed) newData; final Block secBlock = bed.getPart() == Part.HEAD ? block.getRelative(bed.getFacing().getOppositeFace()) : block.getRelative(bed.getFacing()); if (secBlock.isEmpty()) { diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java new file mode 100644 index 00000000..a3e5b0b1 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java @@ -0,0 +1,15 @@ +package de.diddiz.LogBlock.blockstate; + +import org.bukkit.Material; +import org.bukkit.block.BlockState; +import org.bukkit.configuration.file.YamlConfiguration; + +public interface BlockStateCodec { + Material[] getApplicableMaterials(); + + YamlConfiguration serialize(BlockState state); + + void deserialize(BlockState state, YamlConfiguration conf); + + String toString(YamlConfiguration conf); +} diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java new file mode 100644 index 00000000..65359ebd --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java @@ -0,0 +1,70 @@ +package de.diddiz.LogBlock.blockstate; + +import java.util.List; + +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.block.Banner; +import org.bukkit.block.BlockState; +import org.bukkit.block.banner.Pattern; +import org.bukkit.block.banner.PatternType; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; + +public class BlockStateCodecBanner implements BlockStateCodec { + @Override + public Material[] getApplicableMaterials() { + return new Material[] { Material.WHITE_BANNER, Material.ORANGE_BANNER, Material.MAGENTA_BANNER, Material.LIGHT_BLUE_BANNER, Material.YELLOW_BANNER, Material.LIME_BANNER, Material.PINK_BANNER, Material.GRAY_BANNER, Material.LIGHT_GRAY_BANNER, Material.CYAN_BANNER, Material.PURPLE_BANNER, + Material.BLUE_BANNER, Material.BROWN_BANNER, Material.GREEN_BANNER, Material.RED_BANNER, Material.BLACK_BANNER, Material.WHITE_WALL_BANNER, Material.ORANGE_WALL_BANNER, Material.MAGENTA_WALL_BANNER, Material.LIGHT_BLUE_WALL_BANNER, Material.YELLOW_WALL_BANNER, + Material.LIME_WALL_BANNER, Material.PINK_WALL_BANNER, Material.GRAY_WALL_BANNER, Material.LIGHT_GRAY_WALL_BANNER, Material.CYAN_WALL_BANNER, Material.PURPLE_WALL_BANNER, Material.BLUE_WALL_BANNER, Material.BROWN_WALL_BANNER, Material.GREEN_WALL_BANNER, Material.RED_WALL_BANNER, + Material.BLACK_WALL_BANNER }; + } + + @Override + public YamlConfiguration serialize(BlockState state) { + if (state instanceof Banner) { + Banner banner = (Banner) state; + int nr = 0; + List patterns = banner.getPatterns(); + if (!patterns.isEmpty()) { + YamlConfiguration conf = new YamlConfiguration(); + ConfigurationSection patternsSection = conf.createSection("patterns"); + for (Pattern pattern : patterns) { + ConfigurationSection section = patternsSection.createSection(Integer.toString(nr)); + section.set("color", pattern.getColor().name()); + section.set("pattern", pattern.getPattern().name()); + nr++; + } + return conf; + } + } + return null; + } + + @Override + public void deserialize(BlockState state, YamlConfiguration conf) { + if (state instanceof Banner) { + Banner banner = (Banner) state; + int oldPatterns = banner.getPatterns().size(); + for (int i = 0; i < oldPatterns; i++) { + banner.removePattern(0); + } + ConfigurationSection patternsSection = conf == null ? null : conf.getConfigurationSection("patterns"); + if (patternsSection != null) { + for (String key : patternsSection.getKeys(false)) { + ConfigurationSection section = patternsSection.getConfigurationSection(key); + if (section != null) { + DyeColor color = DyeColor.valueOf(section.getString("color")); + PatternType type = PatternType.valueOf(section.getString("pattern")); + banner.addPattern(new Pattern(color, type)); + } + } + } + } + } + + @Override + public String toString(YamlConfiguration conf) { + return null; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java new file mode 100644 index 00000000..04e6e9de --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -0,0 +1,76 @@ +package de.diddiz.LogBlock.blockstate; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.block.BlockState; +import org.bukkit.block.Sign; +import org.bukkit.configuration.file.YamlConfiguration; + +public class BlockStateCodecSign implements BlockStateCodec { + @Override + public Material[] getApplicableMaterials() { + return new Material[] { Material.WALL_SIGN, Material.SIGN }; + } + + @Override + public YamlConfiguration serialize(BlockState state) { + if (state instanceof Sign) { + Sign sign = (Sign) state; + String[] lines = sign.getLines(); + boolean hasText = false; + for (int i = 0; i < lines.length; i++) { + if (lines[i] != null && lines[i].length() > 0) { + hasText = true; + break; + } + } + if (hasText) { + YamlConfiguration conf = new YamlConfiguration(); + conf.set("lines", Arrays.asList(lines)); + return conf; + } + } + return null; + } + + /** + * This is required for the SignChangeEvent, because we have no BlockState there. + */ + public static YamlConfiguration serialize(String[] lines) { + YamlConfiguration conf = new YamlConfiguration(); + conf.set("lines", Arrays.asList(lines)); + return conf; + } + + @Override + public void deserialize(BlockState state, YamlConfiguration conf) { + if (state instanceof Sign) { + Sign sign = (Sign) state; + List lines = Collections.emptyList(); + if (conf != null) { + lines = conf.getStringList("lines"); + } + for (int i = 0; i < 4; i++) { + String line = lines.size() > i && lines.get(i) != null ? lines.get(i) : ""; + sign.setLine(i, line); + } + } + } + + @Override + public String toString(YamlConfiguration conf) { + if (conf != null) { + StringBuilder sb = new StringBuilder(); + for (String line : conf.getStringList("lines")) { + if (sb.length() > 0) + sb.append(" "); + sb.append("[").append(line).append("]"); + } + return sb.toString(); + } + return null; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java new file mode 100644 index 00000000..dbeeaf85 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java @@ -0,0 +1,54 @@ +package de.diddiz.LogBlock.blockstate; + +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.block.BlockState; +import org.bukkit.block.Skull; +import org.bukkit.configuration.file.YamlConfiguration; + +public class BlockStateCodecSkull implements BlockStateCodec { + @Override + public Material[] getApplicableMaterials() { + return new Material[] { Material.PLAYER_WALL_HEAD, Material.PLAYER_HEAD }; + } + + @Override + public YamlConfiguration serialize(BlockState state) { + if (state instanceof Skull) { + Skull skull = (Skull) state; + OfflinePlayer owner = skull.hasOwner() ? skull.getOwningPlayer() : null; + if (owner != null) { + YamlConfiguration conf = new YamlConfiguration(); + conf.set("owner", owner.getUniqueId().toString()); + return conf; + } + } + return null; + } + + @Override + public void deserialize(BlockState state, YamlConfiguration conf) { + if (state instanceof Skull) { + Skull skull = (Skull) state; + UUID ownerId = conf == null ? null : UUID.fromString(conf.getString("owner")); + if (ownerId == null) { + skull.setOwningPlayer(null); + } else { + skull.setOwningPlayer(Bukkit.getOfflinePlayer(ownerId)); + } + } + } + + @Override + public String toString(YamlConfiguration conf) { + UUID ownerId = conf == null ? null : UUID.fromString(conf.getString("owner")); + if (ownerId != null) { + OfflinePlayer owner = Bukkit.getOfflinePlayer(ownerId); + return "[" + (owner.getName() != null ? owner.getName() : owner.getUniqueId().toString()) + "]"; + } + return null; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java new file mode 100644 index 00000000..32696844 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java @@ -0,0 +1,60 @@ +package de.diddiz.LogBlock.blockstate; + +import org.bukkit.Material; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.EntityType; + +public class BlockStateCodecSpawner implements BlockStateCodec { + @Override + public Material[] getApplicableMaterials() { + return new Material[] { Material.SPAWNER }; + } + + @Override + public YamlConfiguration serialize(BlockState state) { + if (state instanceof CreatureSpawner) { + CreatureSpawner spawner = (CreatureSpawner) state; + YamlConfiguration conf = new YamlConfiguration(); + conf.set("delay", spawner.getDelay()); + conf.set("maxNearbyEntities", spawner.getMaxNearbyEntities()); + conf.set("maxSpawnDelay", spawner.getMaxSpawnDelay()); + conf.set("minSpawnDelay", spawner.getMinSpawnDelay()); + conf.set("requiredPlayerRange", spawner.getRequiredPlayerRange()); + conf.set("spawnCount", spawner.getSpawnCount()); + conf.set("spawnedType", spawner.getSpawnedType().name()); + conf.set("spawnRange", spawner.getSpawnRange()); + return conf; + } + return null; + } + + @Override + public void deserialize(BlockState state, YamlConfiguration conf) { + if (state instanceof CreatureSpawner) { + CreatureSpawner spawner = (CreatureSpawner) state; + if (conf != null) { + spawner.setDelay(conf.getInt("delay")); + spawner.setMaxNearbyEntities(conf.getInt("maxNearbyEntities")); + spawner.setMaxSpawnDelay(conf.getInt("maxSpawnDelay")); + spawner.setMinSpawnDelay(conf.getInt("minSpawnDelay")); + spawner.setRequiredPlayerRange(conf.getInt("requiredPlayerRange")); + spawner.setSpawnCount(conf.getInt("spawnCount")); + spawner.setSpawnedType(EntityType.valueOf(conf.getString("spawnedType"))); + spawner.setSpawnRange(conf.getInt("spawnRange")); + } + } + } + + @Override + public String toString(YamlConfiguration conf) { + if (conf != null) { + EntityType entity = EntityType.valueOf(conf.getString("spawnedType")); + if (entity != null) { + return "[" + entity + "]"; + } + } + return null; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java new file mode 100644 index 00000000..8cac08ac --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java @@ -0,0 +1,80 @@ +package de.diddiz.LogBlock.blockstate; + +import java.util.EnumMap; +import java.util.Map; +import java.util.logging.Level; + +import org.bukkit.Material; +import org.bukkit.block.BlockState; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; + +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.util.Utils; + +public class BlockStateCodecs { + private static Map codecs = new EnumMap<>(Material.class); + + public static void registerCodec(BlockStateCodec codec) { + Material[] materials = codec.getApplicableMaterials(); + for (Material material : materials) { + if (codecs.containsKey(material)) { + throw new IllegalArgumentException("BlockStateCodec for " + material + " already registered!"); + } + codecs.put(material, codec); + } + } + + static { + registerCodec(new BlockStateCodecSign()); + registerCodec(new BlockStateCodecSkull()); + registerCodec(new BlockStateCodecBanner()); + registerCodec(new BlockStateCodecSpawner()); + } + + public static boolean hasCodec(Material material) { + return codecs.containsKey(material); + } + + public static byte[] serialize(BlockState state) { + BlockStateCodec codec = codecs.get(state.getType()); + if (codec != null) { + YamlConfiguration serialized = codec.serialize(state); + if (serialized != null && !serialized.getKeys(false).isEmpty()) { + return Utils.serializeYamlConfiguration(serialized); + } + } + return null; + } + + public static void deserialize(BlockState block, byte[] state) { + BlockStateCodec codec = codecs.get(block.getType()); + if (codec != null) { + YamlConfiguration conf = null; + try { + if (state != null) { + conf = Utils.deserializeYamlConfiguration(state); + } + } catch (InvalidConfigurationException e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Exception while deserializing BlockState", e); + } + codec.deserialize(block, conf); + } + } + + public static String toString(Material material, byte[] state) { + BlockStateCodec codec = codecs.get(material); + if (codec != null) { + YamlConfiguration conf = null; + try { + if (state != null) { + conf = Utils.deserializeYamlConfiguration(state); + } + } catch (InvalidConfigurationException e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Exception while deserializing BlockState", e); + } + return codec.toString(conf); + } + return null; + } +} diff --git a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java index 64b2a8f7..783c9ddc 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java @@ -14,6 +14,7 @@ import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.blockstate.BlockStateCodecs; import de.diddiz.LogBlock.config.Config; import de.diddiz.util.BukkitUtils; @@ -22,8 +23,6 @@ import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.block.Sign; import org.bukkit.block.data.BlockData; import java.util.logging.Level; @@ -104,9 +103,8 @@ protected void onBlockChange(Vector pt, BlockStateHolder block) { Material typeBefore = origin.getType(); // Check to see if we've broken a sign - if (Config.isLogging(location.getWorld().getName(), Logging.SIGNTEXT) && (typeBefore == Material.SIGN || typeBefore == Material.WALL_SIGN)) { - BlockState stateBefore = origin.getState(); - plugin.getConsumer().queueSignBreak(lbActor, (Sign) stateBefore); + if (BlockStateCodecs.hasCodec(typeBefore)) { + plugin.getConsumer().queueBlockBreak(lbActor, origin.getState()); } else if (!origin.isEmpty()) { plugin.getConsumer().queueBlockBreak(lbActor, location, origin.getBlockData()); } From 6680e9e3eb16a05e582b700348ed1d1a2c7462f5 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 03:01:26 +0200 Subject: [PATCH 034/399] Allow querying for item types in chestaccess --- src/main/java/de/diddiz/LogBlock/BlockChange.java | 2 +- src/main/java/de/diddiz/LogBlock/ChestAccess.java | 4 +++- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 4 ++-- src/main/java/de/diddiz/LogBlock/Consumer.java | 7 ++++--- src/main/java/de/diddiz/LogBlock/QueryParams.java | 4 ++-- src/main/java/de/diddiz/LogBlock/Updater.java | 11 +++++++++-- 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 75351ab4..c2872a84 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -57,7 +57,7 @@ public BlockChange(ResultSet rs, QueryParams p) throws SQLException { if (p.needChestAccess) { ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); if (stack != null) { - catemp = new ChestAccess(stack, rs.getBoolean("itemremove")); + catemp = new ChestAccess(stack, rs.getBoolean("itemremove"), rs.getInt("itemtype")); } } ca = catemp; diff --git a/src/main/java/de/diddiz/LogBlock/ChestAccess.java b/src/main/java/de/diddiz/LogBlock/ChestAccess.java index f4926627..312dc05f 100644 --- a/src/main/java/de/diddiz/LogBlock/ChestAccess.java +++ b/src/main/java/de/diddiz/LogBlock/ChestAccess.java @@ -5,9 +5,11 @@ public class ChestAccess { final ItemStack itemStack; final boolean remove; + final int itemType; - public ChestAccess(ItemStack itemStack, boolean remove) { + public ChestAccess(ItemStack itemStack, boolean remove, int itemType) { this.itemStack = itemStack; this.remove = remove; + this.itemType = itemType; } } diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index fe74da18..4e25e63d 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -664,7 +664,7 @@ public void run() { ChestAccess chestaccess = null; ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); if (stack != null) { - chestaccess = new ChestAccess(stack, rs.getBoolean("itemremove")); + chestaccess = new ChestAccess(stack, rs.getBoolean("itemremove"), rs.getInt("itemtype")); } editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), chestaccess); } @@ -738,7 +738,7 @@ public void run() { ChestAccess chestaccess = null; ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); if (stack != null) { - chestaccess = new ChestAccess(stack, !rs.getBoolean("itemremove")); + chestaccess = new ChestAccess(stack, !rs.getBoolean("itemremove"), rs.getInt("itemtype")); } editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), chestaccess); } diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index c01371cc..7a34ce31 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -212,7 +212,7 @@ public void queueChestAccess(Actor actor, BlockState container, ItemStack itemSt * Data of the item taken/stored */ public void queueChestAccess(Actor actor, Location loc, BlockData type, ItemStack itemStack, boolean remove) { - queueBlock(actor, loc, type, type, null, null, new ChestAccess(itemStack, remove)); + queueBlock(actor, loc, type, type, null, null, new ChestAccess(itemStack, remove, MaterialConverter.getOrAddMaterialId(itemStack.getType().getKey()))); } /** @@ -682,7 +682,7 @@ public String[] getInserts() { if (replacedState != null || typeState != null) { inserts[1] = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES('" + Utils.mysqlEscapeBytes(replacedState) + "', '" + Utils.mysqlEscapeBytes(typeState) + "', LAST_INSERT_ID());"; } else if (ca != null) { - inserts[1] = "INSERT INTO `" + table + "-chestdata` (id, item, itemremoved) values (LAST_INSERT_ID(), '" + Utils.mysqlEscapeBytes(Utils.saveItemStack(ca.itemStack)) + "', " + (ca.remove ? 1 : 0) + ");"; + inserts[1] = "INSERT INTO `" + table + "-chestdata` (id, item, itemremoved, itemtype) values (LAST_INSERT_ID(), '" + Utils.mysqlEscapeBytes(Utils.saveItemStack(ca.itemStack)) + "', " + (ca.remove ? 1 : 0) + ", " + ca.itemType + ");"; } return inserts; } @@ -732,10 +732,11 @@ public void executeStatements() throws SQLException { ps.setInt(3, id); ps.executeUpdate(); } else if (ca != null) { - ps = connection.prepareStatement("INSERT INTO `" + table + "-chestdata` (item, itemremove, id) values (?, ?, ?)"); + ps = connection.prepareStatement("INSERT INTO `" + table + "-chestdata` (item, itemremove, id, itemtype) values (?, ?, ?, ?)"); ps.setBytes(1, Utils.saveItemStack(ca.itemStack)); ps.setInt(2, ca.remove ? 1 : 0); ps.setInt(3, id); + ps.setInt(4, ca.itemType); ps.executeUpdate(); } } catch (final SQLException ex) { diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index b97ee031..b4a4dfcf 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -149,7 +149,7 @@ public String getQuery() { select += "replacedState, typeState, "; } if (needChestAccess) { - select += "item, itemremove, "; + select += "item, itemremove, itemtype, "; } select = select.substring(0, select.length() - 2); } @@ -605,7 +605,7 @@ public void parseArgs(CommandSender sender, List args) throws IllegalArg throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); } for (final String weaponName : values) { - Material mat = Material.matchMaterial(weaponName); + Material mat = weaponName.equalsIgnoreCase("fist") ? Material.AIR : Material.matchMaterial(weaponName); if (mat == null) { throw new IllegalArgumentException("No material matching: '" + weaponName + "'"); } diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 123be336..205b490e 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -514,7 +514,7 @@ boolean update() { } rs.close(); - PreparedStatement insertChestData = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-chestdata` (id, item, itemremove) VALUES (?, ?, ?)"); + PreparedStatement insertChestData = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-chestdata` (id, item, itemremove, itemtype) VALUES (?, ?, ?, ?)"); PreparedStatement deleteChest = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-chest` WHERE id = ?"); while (true) { rs = st.executeQuery("SELECT id, itemtype, itemamount, itemdata FROM `" + wcfg.table + "-chest` ORDER BY id ASC LIMIT 10000"); @@ -533,6 +533,7 @@ boolean update() { insertChestData.setInt(1, id); insertChestData.setBytes(2, Utils.saveItemStack(stack)); insertChestData.setInt(3, amount >= 0 ? 0 : 1); + insertChestData.setInt(4, MaterialConverter.getOrAddMaterialId(weaponMaterial.getKey())); insertChestData.addBatch(); deleteChest.setInt(1, id); @@ -632,6 +633,12 @@ boolean update() { final Statement st = conn.createStatement(); for (final WorldConfig wcfg : getLoggedWorlds()) { getLogger().info("Processing world " + wcfg.world + "..."); + ResultSet rsCol = st.executeQuery("SHOW COLUMNS FROM `" + wcfg.table + "-chestdata` LIKE 'itemtype'"); + if (!rsCol.next()) { + st.execute("ALTER TABLE `" + wcfg.table + "-chestdata` ADD COLUMN `itemtype` SMALLINT NOT NULL DEFAULT '0'"); + } + rsCol.close(); + conn.commit(); if (wcfg.isLogging(Logging.SIGNTEXT)) { int rowsToConvert = 0; int done = 0; @@ -747,7 +754,7 @@ void checkTables() throws SQLException { for (final WorldConfig wcfg : getLoggedWorlds()) { createTable(dbm, state, wcfg.table + "-blocks", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced SMALLINT UNSIGNED NOT NULL, replacedData SMALLINT NOT NULL, type SMALLINT UNSIGNED NOT NULL, typeData SMALLINT NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))"); // createTable(dbm, state, wcfg.table + "-sign", "(id INT UNSIGNED NOT NULL, signtext VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); - createTable(dbm, state, wcfg.table + "-chestdata", "(id INT UNSIGNED NOT NULL, item MEDIUMBLOB, itemremove TINYINT, PRIMARY KEY (id))"); + createTable(dbm, state, wcfg.table + "-chestdata", "(id INT UNSIGNED NOT NULL, item MEDIUMBLOB, itemremove TINYINT, itemtype SMALLINT NOT NULL DEFAULT '0', PRIMARY KEY (id))"); createTable(dbm, state, wcfg.table + "-state", "(id INT UNSIGNED NOT NULL, replacedState MEDIUMBLOB NULL, typeState MEDIUMBLOB NULL, PRIMARY KEY (id))"); if (wcfg.isLogging(Logging.KILL)) { createTable(dbm, state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id))"); From f83fc7cee22e08c06dcbecddcb71344aa6076264 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 13:23:45 +0200 Subject: [PATCH 035/399] Typo --- src/main/java/de/diddiz/LogBlock/QueryParams.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index b4a4dfcf..7f8fd2d5 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -650,7 +650,7 @@ public void parseArgs(CommandSender sender, List args) throws IllegalArg } } else if (param.equals("selection") || param.equals("sel")) { if (player == null) { - throw new IllegalArgumentException("You have to ba a player to use selection"); + throw new IllegalArgumentException("You have to be a player to use selection"); } final Plugin we = player.getServer().getPluginManager().getPlugin("WorldEdit"); if (we != null) { From d403af42d95aaf335a708902ffd64523e382f361 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 13:33:33 +0200 Subject: [PATCH 036/399] Cancel early when trying to lookup chat while chat is not logged Fixes #683 --- src/main/java/de/diddiz/LogBlock/QueryParams.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 7f8fd2d5..4c3be43b 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock; +import de.diddiz.LogBlock.config.Config; import de.diddiz.util.Utils; import de.diddiz.worldedit.RegionContainer; import org.bukkit.Location; @@ -758,6 +759,9 @@ public void parseArgs(CommandSender sender, List args) throws IllegalArg throw new IllegalArgumentException("This world ('" + world.getName() + "') isn't logged"); } } + if (bct == BlockChangeType.CHAT && !Config.isLogging(Logging.CHAT)) { + throw new IllegalArgumentException("Chat is not logged"); + } if (session != null) { session.lastQuery = clone(); } From 76500f2e5179763764ee4afeb9f33cf2b1139ec9 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 14:08:50 +0200 Subject: [PATCH 037/399] Always check collation when upgrading tables --- src/main/java/de/diddiz/LogBlock/Updater.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 205b490e..f393e19f 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -381,9 +381,9 @@ boolean update() { try { conn.setAutoCommit(true); final Statement st = conn.createStatement(); - checkCharset("lb-players","name",st); + checkCharset("lb-players", "name", st, false); if (isLogging(Logging.CHAT)) { - checkCharset("lb-chat","message", st); + checkCharset("lb-chat", "message", st, false); } for (final WorldConfig wcfg : getLoggedWorlds()) { if (wcfg.isLogging(Logging.SIGNTEXT)) { @@ -708,12 +708,29 @@ boolean update() { config.set("version", "1.13.1"); } + + // this can always be checked + try { + final Connection conn = logblock.getConnection(); + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + checkCharset("lb-players", "name", st, true); + if (isLogging(Logging.CHAT)) { + checkCharset("lb-chat", "message", st, true); + } + + st.close(); + conn.close(); + } catch (final SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } logblock.saveConfig(); return true; } - void checkCharset(String table, String column, Statement st) throws SQLException { + void checkCharset(String table, String column, Statement st, boolean silent) throws SQLException { final ResultSet rs = st.executeQuery("SHOW FULL COLUMNS FROM `" + table + "` WHERE field = '" + column + "'"); String charset = "utf8"; if (Config.mb4) { @@ -722,7 +739,7 @@ void checkCharset(String table, String column, Statement st) throws SQLException if (rs.next() && !rs.getString("Collation").substring(0, charset.length()).equalsIgnoreCase(charset)) { st.execute("ALTER TABLE `" + table + "` CONVERT TO CHARSET " + charset); getLogger().info("Table " + table + " modified"); - } else { + } else if (!silent) { getLogger().info("Table " + table + " already fine, skipping it"); } } From a1d622ebbdecc931b40555790f2ffa3b6e512690 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 14:16:34 +0200 Subject: [PATCH 038/399] Use the plugin logger instead of the global logger --- .../de/diddiz/LogBlock/CommandsHandler.java | 26 ++-- .../java/de/diddiz/LogBlock/Consumer.java | 23 ++-- .../de/diddiz/LogBlock/DumpedLogImporter.java | 13 +- src/main/java/de/diddiz/LogBlock/Updater.java | 128 +++++++++--------- .../java/de/diddiz/LogBlock/WorldEditor.java | 3 +- 5 files changed, 93 insertions(+), 100 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 4e25e63d..5871c8a6 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -36,8 +36,6 @@ import static de.diddiz.util.BukkitUtils.saveSpawnHeight; import static de.diddiz.util.Utils.isInt; import static de.diddiz.util.Utils.listing; -import static org.bukkit.Bukkit.getLogger; -import static org.bukkit.Bukkit.getServer; public class CommandsHandler implements CommandExecutor { private final LogBlock logblock; @@ -114,7 +112,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, if (logblock.hasPermission(sender, "logblock.lookup")) { World world = null; if (args.length > 1) { - world = getServer().getWorld(args[1]); + world = logblock.getServer().getWorld(args[1]); } else if (sender instanceof Player) { world = ((Player) sender).getWorld(); } @@ -356,7 +354,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, sender.sendMessage(ChatColor.RED + "Not enough arguments given"); } catch (final Exception ex) { sender.sendMessage(ChatColor.RED + "Error, check server.log"); - getLogger().log(Level.WARNING, "Exception in commands handler: ", ex); + logblock.getLogger().log(Level.WARNING, "Exception in commands handler: ", ex); } return true; } @@ -427,7 +425,7 @@ public final void close() { rs.close(); } } catch (final SQLException ex) { - getLogger().log(Level.SEVERE, "[CommandsHandler] SQL exception on close", ex); + logblock.getLogger().log(Level.SEVERE, "[CommandsHandler] SQL exception on close", ex); } } } @@ -492,7 +490,7 @@ public void run() { } } catch (final Exception ex) { sender.sendMessage(ChatColor.RED + "Exception, check error log"); - getLogger().log(Level.SEVERE, "[Lookup] " + params.getQuery() + ": ", ex); + logblock.getLogger().log(Level.SEVERE, "[Lookup] " + params.getQuery() + ": ", ex); } finally { close(); } @@ -548,7 +546,7 @@ public void run() { sender.sendMessage(ChatColor.GREEN + "Wrote " + counter + " lines."); } catch (final Exception ex) { sender.sendMessage(ChatColor.RED + "Exception, check error log"); - getLogger().log(Level.SEVERE, "[WriteLogFile] " + params.getQuery() + " (file was " + file.getAbsolutePath() + "): ", ex); + logblock.getLogger().log(Level.SEVERE, "[WriteLogFile] " + params.getQuery() + " (file was " + file.getAbsolutePath() + "): ", ex); } finally { close(); } @@ -621,7 +619,7 @@ public void run() { } } catch (final Exception ex) { sender.sendMessage(ChatColor.RED + "Exception, check error log"); - getLogger().log(Level.SEVERE, "[Teleport] " + params.getQuery() + ": ", ex); + logblock.getLogger().log(Level.SEVERE, "[Teleport] " + params.getQuery() + ": ", ex); } finally { close(); } @@ -699,7 +697,7 @@ public void run() { } } catch (final Exception ex) { sender.sendMessage(ChatColor.RED + "Exception, check error log"); - getLogger().log(Level.SEVERE, "[Rollback] " + params.getQuery() + ": ", ex); + logblock.getLogger().log(Level.SEVERE, "[Rollback] " + params.getQuery() + ": ", ex); } finally { close(); } @@ -760,7 +758,7 @@ public void run() { sender.sendMessage(ChatColor.GREEN + "Redo finished successfully (" + editor.getElapsedTime() + " ms, " + editor.getSuccesses() + "/" + changes + " blocks" + (editor.getErrors() > 0 ? ", " + ChatColor.RED + editor.getErrors() + " errors" + ChatColor.GREEN : "") + (editor.getBlacklistCollisions() > 0 ? ", " + editor.getBlacklistCollisions() + " blacklist collisions" : "") + ")"); } catch (final Exception ex) { sender.sendMessage(ChatColor.RED + "Exception, check error log"); - getLogger().log(Level.SEVERE, "[Redo] " + params.getQuery() + ": ", ex); + logblock.getLogger().log(Level.SEVERE, "[Redo] " + params.getQuery() + ": ", ex); } finally { close(); } @@ -808,7 +806,7 @@ public void run() { state.execute("SELECT * FROM `" + table + "-blocks` " + join + params.getWhere() + "INTO OUTFILE '" + new File(dumpFolder, time + " " + table + " " + params.getTitle().replace(":", ".") + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); } catch (final SQLException ex) { sender.sendMessage(ChatColor.RED + "Error while dumping log. Make sure your MySQL user has access to the LogBlock folder, or disable clearlog.dumpDeletedLog"); - getLogger().log(Level.SEVERE, "[ClearLog] Exception while dumping log: ", ex); + logblock.getLogger().log(Level.SEVERE, "[ClearLog] Exception while dumping log: ", ex); return; } } @@ -835,18 +833,18 @@ public void run() { } } catch (final Exception ex) { sender.sendMessage(ChatColor.RED + "Exception, check error log"); - getLogger().log(Level.SEVERE, "[ClearLog] Exception: ", ex); + logblock.getLogger().log(Level.SEVERE, "[ClearLog] Exception: ", ex); } finally { close(); } } } - private static ResultSet executeQuery(Statement state, String query) throws SQLException { + private ResultSet executeQuery(Statement state, String query) throws SQLException { if (Config.debug) { long startTime = System.currentTimeMillis(); ResultSet rs = state.executeQuery(query); - getLogger().log(Level.INFO, "[LogBlock Debug] Time Taken: " + (System.currentTimeMillis() - startTime) + " milliseconds. Query: " + query); + logblock.getLogger().log(Level.INFO, "[LogBlock Debug] Time Taken: " + (System.currentTimeMillis() - startTime) + " milliseconds. Query: " + query); return rs; } else { return state.executeQuery(query); diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 7a34ce31..cc900b2c 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -33,7 +33,6 @@ import static de.diddiz.LogBlock.config.Config.*; import static de.diddiz.util.Utils.mysqlTextEscape; import static de.diddiz.util.BukkitUtils.*; -import static org.bukkit.Bukkit.getLogger; public class Consumer extends TimerTask { private final Queue queue = new LinkedBlockingQueue(); @@ -418,7 +417,7 @@ public synchronized void run() { conn = logblock.getConnection(); if (Config.queueWarningSize > 0 && queue.size() >= Config.queueWarningSize) { - getLogger().info("[Consumer] Queue overloaded. Size: " + getQueueSize()); + logblock.getLogger().info("[Consumer] Queue overloaded. Size: " + getQueueSize()); } if (conn == null) { @@ -437,7 +436,7 @@ public synchronized void run() { if (!addPlayer(state, actor)) { if (!failedPlayers.contains(actor)) { failedPlayers.add(actor); - getLogger().warning("[Consumer] Failed to add player " + actor.getName()); + logblock.getLogger().warning("[Consumer] Failed to add player " + actor.getName()); } continue process; } @@ -477,7 +476,7 @@ public synchronized void run() { try { PSRow.executeStatements(); } catch (final SQLException ex) { - getLogger().log(Level.SEVERE, "[Consumer] SQL exception on insertion: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Consumer] SQL exception on insertion: ", ex); break; } } else { @@ -485,7 +484,7 @@ public synchronized void run() { try { state.execute(insert); } catch (final SQLException ex) { - getLogger().log(Level.SEVERE, "[Consumer] SQL exception on " + insert + ": ", ex); + logblock.getLogger().log(Level.SEVERE, "[Consumer] SQL exception on " + insert + ": ", ex); break process; } } @@ -495,7 +494,7 @@ public synchronized void run() { } conn.commit(); } catch (final SQLException ex) { - getLogger().log(Level.SEVERE, "[Consumer] SQL exception", ex); + logblock.getLogger().log(Level.SEVERE, "[Consumer] SQL exception", ex); } finally { try { if (state != null) { @@ -505,15 +504,15 @@ public synchronized void run() { conn.close(); } } catch (final SQLException ex) { - getLogger().log(Level.SEVERE, "[Consumer] SQL exception on close", ex); + logblock.getLogger().log(Level.SEVERE, "[Consumer] SQL exception on close", ex); } lock.unlock(); if (debug) { long timeElapsed = System.currentTimeMillis() - startTime; float rowPerTime = count / timeElapsed; - getLogger().log(Level.INFO, "[Consumer] Finished consumer cycle in " + timeElapsed + " milliseconds."); - getLogger().log(Level.INFO, "[Consumer] Total rows processed: " + count + ". row/time: " + String.format("%.4f", rowPerTime)); + logblock.getLogger().log(Level.INFO, "[Consumer] Finished consumer cycle in " + timeElapsed + " milliseconds."); + logblock.getLogger().log(Level.INFO, "[Consumer] Total rows processed: " + count + ". row/time: " + String.format("%.4f", rowPerTime)); } } } @@ -741,10 +740,10 @@ public void executeStatements() throws SQLException { } } catch (final SQLException ex) { if (ps1 != null) { - getLogger().log(Level.SEVERE, "[Consumer] Troublesome query: " + ps1.toString()); + logblock.getLogger().log(Level.SEVERE, "[Consumer] Troublesome query: " + ps1.toString()); } if (ps != null) { - getLogger().log(Level.SEVERE, "[Consumer] Troublesome query: " + ps.toString()); + logblock.getLogger().log(Level.SEVERE, "[Consumer] Troublesome query: " + ps.toString()); } throw ex; } finally { @@ -831,7 +830,7 @@ public void executeStatements() throws SQLException { ps.executeBatch(); } catch (final SQLException ex) { if (ps != null) { - getLogger().log(Level.SEVERE, "[Consumer] Troublesome query: " + ps.toString()); + logblock.getLogger().log(Level.SEVERE, "[Consumer] Troublesome query: " + ps.toString()); } throw ex; } finally { diff --git a/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java b/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java index 85bc6a73..42af3ed9 100644 --- a/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java +++ b/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java @@ -9,7 +9,6 @@ import java.util.logging.Level; import static de.diddiz.util.Utils.newline; -import static org.bukkit.Bukkit.getLogger; public class DumpedLogImporter implements Runnable { private final LogBlock logblock; @@ -22,7 +21,7 @@ public class DumpedLogImporter implements Runnable { public void run() { final File[] imports = new File("plugins/LogBlock/import/").listFiles(new ExtensionFilenameFilter("sql")); if (imports != null && imports.length > 0) { - getLogger().info("Found " + imports.length + " imports."); + logblock.getLogger().info("Found " + imports.length + " imports."); Connection conn = null; try { conn = logblock.getConnection(); @@ -34,7 +33,7 @@ public void run() { final BufferedWriter writer = new BufferedWriter(new FileWriter(new File(logblock.getDataFolder(), "import/failed.txt"))); int successes = 0, errors = 0; for (final File sqlFile : imports) { - getLogger().info("Trying to import " + sqlFile.getName() + " ..."); + logblock.getLogger().info("Trying to import " + sqlFile.getName() + " ..."); final BufferedReader reader = new BufferedReader(new FileReader(sqlFile)); String line; while ((line = reader.readLine()) != null) { @@ -42,7 +41,7 @@ public void run() { st.execute(line); successes++; } catch (final Exception ex) { - getLogger().warning("Error while importing: '" + line + "': " + ex.getMessage()); + logblock.getLogger().warning("Error while importing: '" + line + "': " + ex.getMessage()); writer.write(line + newline); errors++; } @@ -50,13 +49,13 @@ public void run() { conn.commit(); reader.close(); sqlFile.delete(); - getLogger().info("Successfully imported " + sqlFile.getName() + "."); + logblock.getLogger().info("Successfully imported " + sqlFile.getName() + "."); } writer.close(); st.close(); - getLogger().info("Successfully imported stored queue. (" + successes + " rows imported, " + errors + " errors)"); + logblock.getLogger().info("Successfully imported stored queue. (" + successes + " rows imported, " + errors + " errors)"); } catch (final Exception ex) { - getLogger().log(Level.WARNING, "Error while importing: ", ex); + logblock.getLogger().log(Level.WARNING, "Error while importing: ", ex); } finally { if (conn != null) { try { diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index f393e19f..4a7371c6 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -29,8 +29,6 @@ import de.diddiz.util.ComparableVersion; import java.util.regex.Pattern; -import static org.bukkit.Bukkit.getLogger; - class Updater { private final LogBlock logblock; final int UUID_CONVERT_BATCH_SIZE = 100; @@ -52,7 +50,7 @@ boolean update() { return false; } if (configVersion.compareTo(new ComparableVersion("1.2.7")) < 0) { - getLogger().info("Updating tables to 1.2.7 ..."); + logblock.getLogger().info("Updating tables to 1.2.7 ..."); if (isLogging(Logging.CHAT)) { final Connection conn = logblock.getConnection(); try { @@ -62,14 +60,14 @@ boolean update() { st.close(); conn.close(); } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } } config.set("version", "1.2.7"); } if (configVersion.compareTo(new ComparableVersion("1.3")) < 0) { - getLogger().info("Updating config to 1.3.0 ..."); + logblock.getLogger().info("Updating config to 1.3.0 ..."); for (final String tool : config.getConfigurationSection("tools").getKeys(false)) { if (config.get("tools." + tool + ".permissionDefault") == null) { config.set("tools." + tool + ".permissionDefault", "OP"); @@ -78,7 +76,7 @@ boolean update() { config.set("version", "1.3.0"); } if (configVersion.compareTo(new ComparableVersion("1.3.1")) < 0) { - getLogger().info("Updating tables to 1.3.1 ..."); + logblock.getLogger().info("Updating tables to 1.3.1 ..."); final Connection conn = logblock.getConnection(); try { conn.setAutoCommit(true); @@ -87,13 +85,13 @@ boolean update() { st.close(); conn.close(); } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } config.set("version", "1.3.1"); } if (configVersion.compareTo(new ComparableVersion("1.3.2")) < 0) { - getLogger().info("Updating tables to 1.3.2 ..."); + logblock.getLogger().info("Updating tables to 1.3.2 ..."); final Connection conn = logblock.getConnection(); try { conn.setAutoCommit(true); @@ -102,18 +100,18 @@ boolean update() { st.close(); conn.close(); } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } config.set("version", "1.3.2"); } if (configVersion.compareTo(new ComparableVersion("1.4")) < 0) { - getLogger().info("Updating config to 1.4.0 ..."); + logblock.getLogger().info("Updating config to 1.4.0 ..."); config.set("clearlog.keepLogDays", null); config.set("version", "1.4.0"); } if (configVersion.compareTo(new ComparableVersion("1.4.2")) < 0) { - getLogger().info("Updating config to 1.4.2 ..."); + logblock.getLogger().info("Updating config to 1.4.2 ..."); for (final String world : config.getStringList("loggedWorlds")) { final File file = new File(logblock.getDataFolder(), friendlyWorldname(world) + ".yml"); final YamlConfiguration wcfg = YamlConfiguration.loadConfiguration(file); @@ -192,14 +190,14 @@ boolean update() { try { wcfg.save(file); } catch (final IOException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); } } config.set("clearlog.keepLogDays", null); config.set("version", "1.4.2"); } if (configVersion.compareTo(new ComparableVersion("1.5.1")) < 0) { - getLogger().info("Updating tables to 1.5.1 ..."); + logblock.getLogger().info("Updating tables to 1.5.1 ..."); final Connection conn = logblock.getConnection(); try { conn.setAutoCommit(true); @@ -212,13 +210,13 @@ boolean update() { st.close(); conn.close(); } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } config.set("version", "1.5.1"); } if (configVersion.compareTo(new ComparableVersion("1.5.2")) < 0) { - getLogger().info("Updating tables to 1.5.2 ..."); + logblock.getLogger().info("Updating tables to 1.5.2 ..."); final Connection conn = logblock.getConnection(); try { conn.setAutoCommit(true); @@ -230,18 +228,18 @@ boolean update() { st.execute("ALTER TABLE `lb-players` DROP onlinetime"); st.execute("ALTER TABLE `lb-players` CHANGE onlinetime2 onlinetime INT UNSIGNED NOT NULL"); } else { - getLogger().info("Column lb-players was already modified, skipping it."); + logblock.getLogger().info("Column lb-players was already modified, skipping it."); } st.close(); conn.close(); } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } config.set("version", "1.5.2"); } if (configVersion.compareTo(new ComparableVersion("1.8.1")) < 0) { - getLogger().info("Updating tables to 1.8.1 ..."); + logblock.getLogger().info("Updating tables to 1.8.1 ..."); final Connection conn = logblock.getConnection(); try { conn.setAutoCommit(true); @@ -249,21 +247,21 @@ boolean update() { for (final WorldConfig wcfg : getLoggedWorlds()) { if (wcfg.isLogging(Logging.CHESTACCESS)) { st.execute("ALTER TABLE `" + wcfg.table + "-chest` CHANGE itemdata itemdata SMALLINT NOT NULL"); - getLogger().info("Table " + wcfg.table + "-chest modified"); + logblock.getLogger().info("Table " + wcfg.table + "-chest modified"); } } st.close(); conn.close(); } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } config.set("version", "1.8.1"); } if (configVersion.compareTo(new ComparableVersion("1.9")) < 0) { - getLogger().info("Updating tables to 1.9.0 ..."); - getLogger().info("Importing UUIDs for large databases may take some time"); + logblock.getLogger().info("Updating tables to 1.9.0 ..."); + logblock.getLogger().info("Importing UUIDs for large databases may take some time"); final Connection conn = logblock.getConnection(); try { conn.setAutoCommit(true); @@ -272,7 +270,7 @@ boolean update() { } catch (final SQLException ex) { // Error 1060 is MySQL error "column already exists". We want to continue with import if we get that error if (ex.getErrorCode() != 1060) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } } @@ -292,7 +290,7 @@ boolean update() { rs = st.executeQuery("SELECT COUNT(playername) FROM `lb-players` WHERE LENGTH(UUID)=0"); rs.next(); String total = Integer.toString(rs.getInt(1)); - getLogger().info(total + " players to convert"); + logblock.getLogger().info(total + " players to convert"); int done = 0; conn.setAutoCommit(false); @@ -311,7 +309,7 @@ boolean update() { for (Map.Entry entry : players.entrySet()) { if (response.get(entry.getKey()) == null) { theUUID = unimportedPrefix + entry.getKey(); - getLogger().warning(entry.getKey() + " not found - giving UUID of " + theUUID); + logblock.getLogger().warning(entry.getKey() + " not found - giving UUID of " + theUUID); } else { theUUID = response.get(entry.getKey()).toString(); } @@ -322,7 +320,7 @@ boolean update() { conn.commit(); players.clear(); names.clear(); - getLogger().info("Processed " + Integer.toString(done) + " out of " + total); + logblock.getLogger().info("Processed " + Integer.toString(done) + " out of " + total); rs.close(); rs = st.executeQuery("SELECT playerid,playername FROM `lb-players` WHERE LENGTH(UUID)=0 LIMIT " + Integer.toString(UUID_CONVERT_BATCH_SIZE)); } @@ -332,16 +330,16 @@ boolean update() { conn.close(); } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } catch (Exception ex) { - Bukkit.getLogger().log(Level.SEVERE, "[UUID importer]", ex); + logblock.getLogger().log(Level.SEVERE, "[UUID importer]", ex); return false; } config.set("version", "1.9.0"); } if (configVersion.compareTo(new ComparableVersion("1.9.4")) < 0) { - getLogger().info("Updating tables to 1.9.4 ..."); + logblock.getLogger().info("Updating tables to 1.9.4 ..."); final Connection conn = logblock.getConnection(); try { conn.setAutoCommit(true); @@ -351,7 +349,7 @@ boolean update() { st.execute("DROP INDEX UUID ON `lb-players`"); } catch (final SQLException ex) { if (ex.getErrorCode() != 1091) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } } @@ -359,7 +357,7 @@ boolean update() { st.execute("DROP INDEX playername ON `lb-players`"); } catch (final SQLException ex) { if (ex.getErrorCode() != 1091) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } } @@ -368,7 +366,7 @@ boolean update() { st.close(); conn.close(); } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } config.set("version", "1.9.4"); @@ -376,7 +374,7 @@ boolean update() { // Ensure charset for free-text fields is UTF-8, or UTF8-mb4 if possible // As this may be an expensive operation and the database default may already be this, check on a table-by-table basis before converting if (configVersion.compareTo(new ComparableVersion("1.10.0")) < 0) { - getLogger().info("Updating tables to 1.10.0 ..."); + logblock.getLogger().info("Updating tables to 1.10.0 ..."); final Connection conn = logblock.getConnection(); try { conn.setAutoCommit(true); @@ -393,14 +391,14 @@ boolean update() { st.close(); conn.close(); } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } config.set("version", "1.10.0"); } if (configVersion.compareTo(new ComparableVersion("1.12.0")) < 0) { - getLogger().info("Updating tables to 1.12.0 ..."); + logblock.getLogger().info("Updating tables to 1.12.0 ..."); if (isLogging(Logging.CHAT)) { final Connection conn = logblock.getConnection(); try { @@ -410,23 +408,23 @@ boolean update() { st.close(); conn.close(); } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } } config.set("version", "1.12.0"); } if (configVersion.compareTo(new ComparableVersion("1.13.0")) < 0) { - getLogger().info("Updating tables to 1.13.0 ..."); + logblock.getLogger().info("Updating tables to 1.13.0 ..."); try { MaterialUpdater1_13 materialUpdater = new MaterialUpdater1_13(logblock); - getLogger().info("Convertig BlockId to BlockData. This can take a while ..."); + logblock.getLogger().info("Convertig BlockId to BlockData. This can take a while ..."); final Connection conn = logblock.getConnection(); conn.setAutoCommit(false); final Statement st = conn.createStatement(); for (final WorldConfig wcfg : getLoggedWorlds()) { - getLogger().info("Processing world " + wcfg.world + "..."); - getLogger().info("Processing block changes..."); + logblock.getLogger().info("Processing world " + wcfg.world + "..."); + logblock.getLogger().info("Processing block changes..."); boolean hadRow = true; int rowsToConvert = 0; int done = 0; @@ -434,7 +432,7 @@ boolean update() { ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "`"); if (rs.next()) { rowsToConvert = rs.getInt(1); - getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table); + logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table); } rs.close(); @@ -481,7 +479,7 @@ boolean update() { insertStatement.setInt(10, z); insertStatement.addBatch(); } catch (Exception e) { - getLogger().info("Exception in entry " + id + " (" + replaced + ":" + data + "->" + type + ":" + data + "): " + e.getMessage()); + logblock.getLogger().info("Exception in entry " + id + " (" + replaced + ":" + data + "->" + type + ":" + data + "): " + e.getMessage()); } deleteStatement.setInt(1, id); deleteStatement.addBatch(); @@ -495,22 +493,22 @@ boolean update() { } conn.commit(); logblock.getConsumer().run(); // force a consumer run to save new material mappings - getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); } insertStatement.close(); deleteStatement.close(); } catch (SQLException e) { - getLogger().info("Could not convert " + wcfg.table + ": " + e.getMessage()); + logblock.getLogger().info("Could not convert " + wcfg.table + ": " + e.getMessage()); } - getLogger().info("Processing chests..."); + logblock.getLogger().info("Processing chests..."); rowsToConvert = 0; done = 0; try { ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-chest`"); if (rs.next()) { rowsToConvert = rs.getInt(1); - getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-chest"); + logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-chest"); } rs.close(); @@ -547,23 +545,23 @@ boolean update() { insertChestData.executeBatch(); deleteChest.executeBatch(); conn.commit(); - getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); } insertChestData.close(); deleteChest.close(); } catch (SQLException e) { - getLogger().info("Could not convert " + wcfg.table + "-chest: " + e.getMessage()); + logblock.getLogger().info("Could not convert " + wcfg.table + "-chest: " + e.getMessage()); } if (wcfg.isLogging(Logging.KILL)) { - getLogger().info("Processing kills..."); + logblock.getLogger().info("Processing kills..."); rowsToConvert = 0; done = 0; try { ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-kills`"); if (rs.next()) { rowsToConvert = rs.getInt(1); - getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-kills"); + logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-kills"); } rs.close(); @@ -595,21 +593,21 @@ boolean update() { conn.commit(); logblock.getConsumer().run(); // force a consumer run to save new material mappings } - getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); if (!anyRow) { break; } } updateWeaponStatement.close(); } catch (SQLException e) { - getLogger().info("Could not convert " + wcfg.table + "-kills: " + e.getMessage()); + logblock.getLogger().info("Could not convert " + wcfg.table + "-kills: " + e.getMessage()); } } } st.close(); conn.close(); - getLogger().info("Updating config to 1.13.0 ..."); + logblock.getLogger().info("Updating config to 1.13.0 ..."); config.set("logging.hiddenBlocks", materialUpdater.convertMaterials(config.getStringList("logging.hiddenBlocks"))); config.set("rollback.dontRollback", materialUpdater.convertMaterials(config.getStringList("rollback.dontRollback"))); config.set("rollback.replaceAnyway", materialUpdater.convertMaterials(config.getStringList("rollback.replaceAnyway"))); @@ -619,20 +617,20 @@ boolean update() { tSec.set("item", materialUpdater.convertMaterial(tSec.getString("item", "OAK_LOG"))); } } catch (final SQLException | IOException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } config.set("version", "1.13.0"); } if (configVersion.compareTo(new ComparableVersion("1.13.1")) < 0) { - getLogger().info("Updating tables to 1.13.1 ..."); + logblock.getLogger().info("Updating tables to 1.13.1 ..."); try { final Connection conn = logblock.getConnection(); conn.setAutoCommit(false); final Statement st = conn.createStatement(); for (final WorldConfig wcfg : getLoggedWorlds()) { - getLogger().info("Processing world " + wcfg.world + "..."); + logblock.getLogger().info("Processing world " + wcfg.world + "..."); ResultSet rsCol = st.executeQuery("SHOW COLUMNS FROM `" + wcfg.table + "-chestdata` LIKE 'itemtype'"); if (!rsCol.next()) { st.execute("ALTER TABLE `" + wcfg.table + "-chestdata` ADD COLUMN `itemtype` SMALLINT NOT NULL DEFAULT '0'"); @@ -646,7 +644,7 @@ boolean update() { ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-sign`"); if (rs.next()) { rowsToConvert = rs.getInt(1); - getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-sign"); + logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-sign"); } rs.close(); @@ -689,12 +687,12 @@ boolean update() { insertSignState.executeBatch(); deleteSign.executeBatch(); conn.commit(); - getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); } insertSignState.close(); deleteSign.close(); } catch (SQLException e) { - getLogger().info("Could not convert " + wcfg.table + "-sign: " + e.getMessage()); + logblock.getLogger().info("Could not convert " + wcfg.table + "-sign: " + e.getMessage()); } } } @@ -702,7 +700,7 @@ boolean update() { st.close(); conn.close(); } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } @@ -722,7 +720,7 @@ boolean update() { st.close(); conn.close(); } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } @@ -738,9 +736,9 @@ void checkCharset(String table, String column, Statement st, boolean silent) thr } if (rs.next() && !rs.getString("Collation").substring(0, charset.length()).equalsIgnoreCase(charset)) { st.execute("ALTER TABLE `" + table + "` CONVERT TO CHARSET " + charset); - getLogger().info("Table " + table + " modified"); + logblock.getLogger().info("Table " + table + " modified"); } else if (!silent) { - getLogger().info("Table " + table + " already fine, skipping it"); + logblock.getLogger().info("Table " + table + " already fine, skipping it"); } } @@ -781,9 +779,9 @@ void checkTables() throws SQLException { conn.close(); } - private static void createTable(DatabaseMetaData dbm, Statement state, String table, String query) throws SQLException { + private void createTable(DatabaseMetaData dbm, Statement state, String table, String query) throws SQLException { if (!dbm.getTables(null, null, table, null).next()) { - getLogger().log(Level.INFO, "Creating table " + table + "."); + logblock.getLogger().log(Level.INFO, "Creating table " + table + "."); state.execute("CREATE TABLE `" + table + "` " + query); if (!dbm.getTables(null, null, table, null).next()) { throw new SQLException("Table " + table + " not found and failed to create"); diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index a83cf7b8..e4963fd0 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -34,7 +34,6 @@ import static de.diddiz.LogBlock.config.Config.dontRollback; import static de.diddiz.LogBlock.config.Config.replaceAnyway; import static de.diddiz.util.BukkitUtils.*; -import static org.bukkit.Bukkit.getLogger; public class WorldEditor implements Runnable { private final LogBlock logblock; @@ -118,7 +117,7 @@ public synchronized void run() { } catch (final WorldEditorException ex) { errorList.add(ex); } catch (final Exception ex) { - getLogger().log(Level.WARNING, "[WorldEditor] Exeption: ", ex); + logblock.getLogger().log(Level.WARNING, "[WorldEditor] Exeption: ", ex); } counter++; if (sender != null) { From 1e8779cb9afb88ad6473803d04e3f9e5e9dd3b5c Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 15:18:06 +0200 Subject: [PATCH 039/399] Add null check for inventory logging Maybe fix #681 --- .../diddiz/LogBlock/listeners/ChestAccessLogging.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index 50527add..dba45d62 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -42,10 +42,12 @@ public void onInventoryClose(InventoryCloseEvent event) { final ItemStack[] after = compressInventory(event.getInventory().getContents()); final ItemStack[] diff = compareInventories(before, after); final Location loc = getInventoryHolderLocation(holder); - for (final ItemStack item : diff) { - ItemStack item2 = item.clone(); - item2.setAmount(Math.abs(item.getAmount())); - consumer.queueChestAccess(Actor.actorFromEntity(player), loc, loc.getWorld().getBlockAt(loc).getBlockData(), item2, item.getAmount() < 0); + if (loc != null) { + for (final ItemStack item : diff) { + ItemStack item2 = item.clone(); + item2.setAmount(Math.abs(item.getAmount())); + consumer.queueChestAccess(Actor.actorFromEntity(player), loc, loc.getWorld().getBlockAt(loc).getBlockData(), item2, item.getAmount() < 0); + } } containers.remove(player); } From 19762691d038189fbf1866f4bde03e55d73bac3a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 15:35:11 +0200 Subject: [PATCH 040/399] Fix chest access logging (incorrect field name) --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 2 +- src/main/java/de/diddiz/LogBlock/Consumer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 5871c8a6..aaf4a72b 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -826,7 +826,7 @@ public void run() { rs.next(); if ((deleted = rs.getInt(1)) > 0) { if (dumpDeletedLog) { - state.execute("SELECT id, item, itemremove FROM `" + table + "-chestdata` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-chest " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); + state.execute("SELECT id, item, itemremove, itemtype FROM `" + table + "-chestdata` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-chest " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); } state.execute("DELETE `" + table + "-chestdata` FROM `" + table + "-chestdata` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL;"); sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-chestdata. Deleted " + deleted + " entries."); diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index cc900b2c..9639a0c9 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -681,7 +681,7 @@ public String[] getInserts() { if (replacedState != null || typeState != null) { inserts[1] = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES('" + Utils.mysqlEscapeBytes(replacedState) + "', '" + Utils.mysqlEscapeBytes(typeState) + "', LAST_INSERT_ID());"; } else if (ca != null) { - inserts[1] = "INSERT INTO `" + table + "-chestdata` (id, item, itemremoved, itemtype) values (LAST_INSERT_ID(), '" + Utils.mysqlEscapeBytes(Utils.saveItemStack(ca.itemStack)) + "', " + (ca.remove ? 1 : 0) + ", " + ca.itemType + ");"; + inserts[1] = "INSERT INTO `" + table + "-chestdata` (id, item, itemremove, itemtype) values (LAST_INSERT_ID(), '" + Utils.mysqlEscapeBytes(Utils.saveItemStack(ca.itemStack)) + "', " + (ca.remove ? 1 : 0) + ", " + ca.itemType + ");"; } return inserts; } From 759cd230a1f82cf29a2b5ff3d7305e5bebc0a951 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 15:54:21 +0200 Subject: [PATCH 041/399] sanity checks for some command params rollback/redo of chat or kills is not possible --- .../de/diddiz/LogBlock/CommandsHandler.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index aaf4a72b..400920f3 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -634,6 +634,18 @@ public CommandRollback(CommandSender sender, QueryParams params, boolean async) @Override public void run() { try { + if(params.bct == BlockChangeType.CHAT) { + sender.sendMessage(ChatColor.RED + "Chat cannot be rolled back"); + return; + } + if(params.bct == BlockChangeType.KILLS) { + sender.sendMessage(ChatColor.RED + "Kills cannot be rolled back"); + return; + } + if(params.sum != SummarizationMode.NONE) { + sender.sendMessage(ChatColor.RED + "Cannot rollback summarized changes"); + return; + } params.needCoords = true; params.needType = true; params.needData = true; @@ -712,6 +724,18 @@ public CommandRedo(CommandSender sender, QueryParams params, boolean async) thro @Override public void run() { try { + if(params.bct == BlockChangeType.CHAT) { + sender.sendMessage(ChatColor.RED + "Chat cannot be redone"); + return; + } + if(params.bct == BlockChangeType.KILLS) { + sender.sendMessage(ChatColor.RED + "Kills cannot be redone"); + return; + } + if(params.sum != SummarizationMode.NONE) { + sender.sendMessage(ChatColor.RED + "Cannot redo summarized changes"); + return; + } params.needCoords = true; params.needType = true; params.needData = true; From 354c9078b19239f3c5e5b1830c47959bdd458398 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 16:16:02 +0200 Subject: [PATCH 042/399] Case insensitive check for ignored chat commands Fixes #651 --- src/main/java/de/diddiz/LogBlock/Consumer.java | 9 ++++++--- src/main/java/de/diddiz/LogBlock/config/Config.java | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 9639a0c9..913b713c 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -376,9 +376,12 @@ public void queueSignPlace(Actor actor, Sign sign) { } public void queueChat(Actor player, String message) { - for (String ignored : Config.ignoredChat) { - if (message.startsWith(ignored)) { - return; + if (!Config.ignoredChat.isEmpty()) { + String lowerCaseMessage = message.toLowerCase(); + for (String ignored : Config.ignoredChat) { + if (lowerCaseMessage.startsWith(ignored)) { + return; + } } } if (hiddenPlayers.contains(player.getName().toLowerCase())) { diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index d271ab7d..b6df65a0 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -44,7 +44,7 @@ public class Config { public static String banPermission; public static Set hiddenBlocks; public static Set hiddenPlayers; - public static Set ignoredChat; + public static List ignoredChat; public static SimpleDateFormat formatter; public static boolean safetyIdCheck; public static boolean debug; @@ -176,9 +176,9 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti throw new DataFormatException("Not a valid material in hiddenBlocks: '" + blocktype + "'"); } } - ignoredChat = new HashSet(); + ignoredChat = new ArrayList(); for (String chatCommand : config.getStringList("logging.ignoredChat")) { - ignoredChat.add(chatCommand); + ignoredChat.add(chatCommand.toLowerCase()); } dontRollback = new HashSet(); for (String e : config.getStringList("rollback.dontRollback")) { From c73b29e43b5eec165b615716742c5cf092fa0678 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 17:40:14 +0200 Subject: [PATCH 043/399] Fix cloning of QueryParams and using them async --- .../de/diddiz/LogBlock/CommandsHandler.java | 2 +- .../java/de/diddiz/LogBlock/QueryParams.java | 20 ++++++++++++------- .../de/diddiz/worldedit/RegionContainer.java | 12 ++++++++++- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 400920f3..ee8762a2 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -405,7 +405,7 @@ public abstract class AbstractCommand implements Runnable { protected AbstractCommand(CommandSender sender, QueryParams params, boolean async) throws Exception { this.sender = sender; - this.params = params; + this.params = params == null ? null : params.clone(); if (async) { scheduler.runTaskAsynchronously(logblock, this); } else { diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 4c3be43b..ef87d619 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -534,7 +534,7 @@ public void parseArgs(CommandSender sender, List args) throws IllegalArg final String param = args.get(i).toLowerCase(); final String[] values = getValues(args, i + 1); if (param.equals("last")) { - if (session.lastQuery == null) { + if (session == null || session.lastQuery == null) { throw new IllegalArgumentException("This is your first command, you can't use last."); } merge(session.lastQuery); @@ -787,12 +787,16 @@ protected QueryParams clone() { try { final QueryParams params = (QueryParams) super.clone(); params.players = new ArrayList(players); + params.killers = new ArrayList(killers); + params.victims = new ArrayList(victims); params.typeIds = new ArrayList(typeIds); params.types = new ArrayList(types); + params.loc = loc == null ? null : loc.clone(); + params.sel = sel == null ? null : sel.clone(); return params; } catch (final CloneNotSupportedException ex) { + throw new Error("QueryParams should be cloneable", ex); } - return null; } private static String[] getValues(List args, int offset) { @@ -825,13 +829,15 @@ private static String[] getValues(List args, int offset) { } public void merge(QueryParams p) { - players = p.players; + players.addAll(p.players); + killers.addAll(p.killers); + victims.addAll(p.victims); excludePlayersMode = p.excludePlayersMode; - typeIds = p.typeIds; - types = p.types; - loc = p.loc; + typeIds.addAll(p.typeIds); + types.addAll(p.types); + loc = p.loc == null ? null : p.loc.clone(); radius = p.radius; - sel = p.sel; + sel = p.sel == null ? null : p.sel.clone(); if (p.since != 0 || since != defaultTime) { since = p.since; } diff --git a/src/main/java/de/diddiz/worldedit/RegionContainer.java b/src/main/java/de/diddiz/worldedit/RegionContainer.java index 1b86f7c4..f699eb39 100644 --- a/src/main/java/de/diddiz/worldedit/RegionContainer.java +++ b/src/main/java/de/diddiz/worldedit/RegionContainer.java @@ -13,7 +13,7 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -public class RegionContainer { +public class RegionContainer implements Cloneable { private Region selection; @@ -57,4 +57,14 @@ public Region getSelection() { public void setSelection(Region selection) { this.selection = selection; } + + @Override + public RegionContainer clone() { + try { + RegionContainer clone = (RegionContainer) super.clone(); + return clone; + } catch (final CloneNotSupportedException ex) { + throw new Error("RegionContainer should be cloneable", ex); + } + } } From b80777a9a0f2b8a409405065e1b1dce1e17249a5 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 17:58:31 +0200 Subject: [PATCH 044/399] Improve WorldEdit encapsulation --- .../de/diddiz/LogBlock/CommandsHandler.java | 2 +- .../java/de/diddiz/LogBlock/QueryParams.java | 16 +++-- .../de/diddiz/worldedit/RegionContainer.java | 58 +++++++++++++------ 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index ee8762a2..9ffc1244 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -389,7 +389,7 @@ private boolean checkRestrictions(CommandSender sender, QueryParams params) { sender.sendMessage(ChatColor.RED + "You are not allowed to rollback more than " + rollbackMaxTime + " minutes"); return false; } - if (rollbackMaxArea > 0 && (params.sel == null && params.loc == null || params.radius > rollbackMaxArea || params.sel != null && (params.sel.getSelection().getLength() > rollbackMaxArea || params.sel.getSelection().getWidth() > rollbackMaxArea))) { + if (rollbackMaxArea > 0 && (params.sel == null && params.loc == null || params.radius > rollbackMaxArea || params.sel != null && (params.sel.getSizeX() > rollbackMaxArea || params.sel.getSizeZ() > rollbackMaxArea))) { sender.sendMessage(ChatColor.RED + "You are not allowed to rollback an area larger than " + rollbackMaxArea + " blocks"); return false; } diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index ef87d619..a5447964 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -10,8 +10,6 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import com.sk89q.worldedit.bukkit.BukkitAdapter; - import java.util.*; import static de.diddiz.LogBlock.Session.getSession; @@ -349,9 +347,9 @@ public String getWhere(BlockChangeType blockChangeType) { } else if (sel != null) { compileLocationQuery( where, - sel.getSelection().getMinimumPoint().getBlockX(), sel.getSelection().getMaximumPoint().getBlockX(), - sel.getSelection().getMinimumPoint().getBlockY(), sel.getSelection().getMaximumPoint().getBlockY(), - sel.getSelection().getMinimumPoint().getBlockZ(), sel.getSelection().getMaximumPoint().getBlockZ() + sel.getMinimumPoint().getBlockX(), sel.getMaximumPoint().getBlockX(), + sel.getMinimumPoint().getBlockY(), sel.getMaximumPoint().getBlockY(), + sel.getMinimumPoint().getBlockZ(), sel.getMaximumPoint().getBlockZ() ); } @@ -458,9 +456,9 @@ public String getWhere(BlockChangeType blockChangeType) { } else if (sel != null) { compileLocationQuery( where, - sel.getSelection().getMinimumPoint().getBlockX(), sel.getSelection().getMaximumPoint().getBlockX(), - sel.getSelection().getMinimumPoint().getBlockY(), sel.getSelection().getMaximumPoint().getBlockY(), - sel.getSelection().getMinimumPoint().getBlockZ(), sel.getSelection().getMaximumPoint().getBlockZ() + sel.getMinimumPoint().getBlockX(), sel.getMaximumPoint().getBlockX(), + sel.getMinimumPoint().getBlockY(), sel.getMaximumPoint().getBlockY(), + sel.getMinimumPoint().getBlockZ(), sel.getMaximumPoint().getBlockZ() ); } @@ -774,7 +772,7 @@ public void setLocation(Location loc) { public void setSelection(RegionContainer container) { this.sel = container; - world = BukkitAdapter.adapt(sel.getSelection().getWorld()); + world = sel.getWorld(); } public void setPlayer(String playerName) { diff --git a/src/main/java/de/diddiz/worldedit/RegionContainer.java b/src/main/java/de/diddiz/worldedit/RegionContainer.java index f699eb39..658a3bf4 100644 --- a/src/main/java/de/diddiz/worldedit/RegionContainer.java +++ b/src/main/java/de/diddiz/worldedit/RegionContainer.java @@ -2,7 +2,6 @@ import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.regions.CuboidRegion; @@ -12,18 +11,29 @@ import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; +import org.bukkit.util.BlockVector; +import org.bukkit.util.Vector; public class RegionContainer implements Cloneable { - private Region selection; + private World world; + private BlockVector min = new BlockVector(); + private BlockVector max = new BlockVector(); - public RegionContainer(Region sel) { - this.selection = sel; + public RegionContainer(World world, Vector first, Vector second) { + this.world = world; + this.min.setX(Math.min(first.getBlockX(),second.getBlockX())); + this.min.setY(Math.min(first.getBlockY(),second.getBlockY())); + this.min.setZ(Math.min(first.getBlockZ(),second.getBlockZ())); + this.max.setX(Math.max(first.getBlockX(),second.getBlockX())); + this.max.setY(Math.max(first.getBlockY(),second.getBlockY())); + this.max.setZ(Math.max(first.getBlockZ(),second.getBlockZ())); } - public static RegionContainer fromPlayerSelection(Player player, Plugin plugin) { - LocalSession session = ((WorldEditPlugin) plugin).getSession(player); - com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(player.getWorld()); + public static RegionContainer fromPlayerSelection(Player player, Plugin worldEditPlugin) { + LocalSession session = ((WorldEditPlugin) worldEditPlugin).getSession(player); + World world = player.getWorld(); + com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(world); if (!weWorld.equals(session.getSelectionWorld())) { throw new IllegalArgumentException("No selection defined"); } @@ -39,29 +49,43 @@ public static RegionContainer fromPlayerSelection(Player player, Plugin plugin) if (!(selection instanceof CuboidRegion)) { throw new IllegalArgumentException("You have to define a cuboid selection"); } - return new RegionContainer(selection); + com.sk89q.worldedit.Vector weMin = selection.getMinimumPoint(); + com.sk89q.worldedit.Vector weMax = selection.getMaximumPoint(); + Vector min = new Vector(weMin.getBlockX(), weMin.getBlockY(), weMin.getBlockZ()); + Vector max = new Vector(weMax.getBlockX(), weMax.getBlockY(), weMax.getBlockZ()); + return new RegionContainer(world, min, max); } public static RegionContainer fromCorners(World world, Location first, Location second) { - com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(world); - Vector firstVector = BukkitAdapter.asVector(first); - Vector secondVector = BukkitAdapter.asVector(second); - - return new RegionContainer(new CuboidRegion(weWorld, firstVector, secondVector)); + return new RegionContainer(world, first.toVector(), second.toVector()); + } + + public World getWorld() { + return world; + } + + public BlockVector getMinimumPoint() { + return min; + } + + public BlockVector getMaximumPoint() { + return max; } - public Region getSelection() { - return selection; + public int getSizeX() { + return max.getBlockX() - min.getBlockX() + 1; } - public void setSelection(Region selection) { - this.selection = selection; + public int getSizeZ() { + return max.getBlockZ() - min.getBlockZ() + 1; } @Override public RegionContainer clone() { try { RegionContainer clone = (RegionContainer) super.clone(); + clone.min = min.clone(); + clone.max = max.clone(); return clone; } catch (final CloneNotSupportedException ex) { throw new Error("RegionContainer should be cloneable", ex); From 28aabd09c76471d0a6cd45eb4bb75631c665b198 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 18:00:28 +0200 Subject: [PATCH 045/399] Rename RegionContainer to CuboidRegion --- .../java/de/diddiz/LogBlock/QueryParams.java | 8 ++++---- .../LogBlock/listeners/ToolListener.java | 4 ++-- ...RegionContainer.java => CuboidRegion.java} | 19 +++++++++---------- 3 files changed, 15 insertions(+), 16 deletions(-) rename src/main/java/de/diddiz/worldedit/{RegionContainer.java => CuboidRegion.java} (81%) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index a5447964..0aa45659 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -2,7 +2,7 @@ import de.diddiz.LogBlock.config.Config; import de.diddiz.util.Utils; -import de.diddiz.worldedit.RegionContainer; +import de.diddiz.worldedit.CuboidRegion; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -27,7 +27,7 @@ public final class QueryParams implements Cloneable { public List killers = new ArrayList(); public List victims = new ArrayList(); public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, excludeBlocksMode = false, prepareToolQuery = false, silent = false; - public RegionContainer sel = null; + public CuboidRegion sel = null; public SummarizationMode sum = SummarizationMode.NONE; public List types = new ArrayList(); public List typeIds = new ArrayList(); @@ -653,7 +653,7 @@ public void parseArgs(CommandSender sender, List args) throws IllegalArg } final Plugin we = player.getServer().getPluginManager().getPlugin("WorldEdit"); if (we != null) { - setSelection(RegionContainer.fromPlayerSelection(player, we)); + setSelection(CuboidRegion.fromPlayerSelection(player, we)); } else { throw new IllegalArgumentException("WorldEdit not found!"); } @@ -770,7 +770,7 @@ public void setLocation(Location loc) { world = loc.getWorld(); } - public void setSelection(RegionContainer container) { + public void setSelection(CuboidRegion container) { this.sel = container; world = sel.getWorld(); } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java index af4073f1..d10cc766 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java @@ -1,7 +1,7 @@ package de.diddiz.LogBlock.listeners; import de.diddiz.LogBlock.*; -import de.diddiz.worldedit.RegionContainer; +import de.diddiz.worldedit.CuboidRegion; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.block.Block; @@ -59,7 +59,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { if (logblock.getServer().getPluginManager().isPluginEnabled("WorldEdit")) { for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) { if (block.getRelative(face).getType() == block.getType()) { - params.setSelection(RegionContainer.fromCorners(event.getPlayer().getWorld(), + params.setSelection(CuboidRegion.fromCorners(event.getPlayer().getWorld(), block.getLocation(), block.getRelative(face).getLocation())); } } diff --git a/src/main/java/de/diddiz/worldedit/RegionContainer.java b/src/main/java/de/diddiz/worldedit/CuboidRegion.java similarity index 81% rename from src/main/java/de/diddiz/worldedit/RegionContainer.java rename to src/main/java/de/diddiz/worldedit/CuboidRegion.java index 658a3bf4..8bb02098 100644 --- a/src/main/java/de/diddiz/worldedit/RegionContainer.java +++ b/src/main/java/de/diddiz/worldedit/CuboidRegion.java @@ -4,7 +4,6 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import org.bukkit.Location; @@ -14,13 +13,13 @@ import org.bukkit.util.BlockVector; import org.bukkit.util.Vector; -public class RegionContainer implements Cloneable { +public class CuboidRegion implements Cloneable { private World world; private BlockVector min = new BlockVector(); private BlockVector max = new BlockVector(); - public RegionContainer(World world, Vector first, Vector second) { + public CuboidRegion(World world, Vector first, Vector second) { this.world = world; this.min.setX(Math.min(first.getBlockX(),second.getBlockX())); this.min.setY(Math.min(first.getBlockY(),second.getBlockY())); @@ -30,7 +29,7 @@ public RegionContainer(World world, Vector first, Vector second) { this.max.setZ(Math.max(first.getBlockZ(),second.getBlockZ())); } - public static RegionContainer fromPlayerSelection(Player player, Plugin worldEditPlugin) { + public static CuboidRegion fromPlayerSelection(Player player, Plugin worldEditPlugin) { LocalSession session = ((WorldEditPlugin) worldEditPlugin).getSession(player); World world = player.getWorld(); com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(world); @@ -46,18 +45,18 @@ public static RegionContainer fromPlayerSelection(Player player, Plugin worldEdi if (selection == null) { throw new IllegalArgumentException("No selection defined"); } - if (!(selection instanceof CuboidRegion)) { + if (!(selection instanceof com.sk89q.worldedit.regions.CuboidRegion)) { throw new IllegalArgumentException("You have to define a cuboid selection"); } com.sk89q.worldedit.Vector weMin = selection.getMinimumPoint(); com.sk89q.worldedit.Vector weMax = selection.getMaximumPoint(); Vector min = new Vector(weMin.getBlockX(), weMin.getBlockY(), weMin.getBlockZ()); Vector max = new Vector(weMax.getBlockX(), weMax.getBlockY(), weMax.getBlockZ()); - return new RegionContainer(world, min, max); + return new CuboidRegion(world, min, max); } - public static RegionContainer fromCorners(World world, Location first, Location second) { - return new RegionContainer(world, first.toVector(), second.toVector()); + public static CuboidRegion fromCorners(World world, Location first, Location second) { + return new CuboidRegion(world, first.toVector(), second.toVector()); } public World getWorld() { @@ -81,9 +80,9 @@ public int getSizeZ() { } @Override - public RegionContainer clone() { + public CuboidRegion clone() { try { - RegionContainer clone = (RegionContainer) super.clone(); + CuboidRegion clone = (CuboidRegion) super.clone(); clone.min = min.clone(); clone.max = max.clone(); return clone; From 2fe886205b675a3ee7c4d4233200b027f3097879 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 18:58:48 +0200 Subject: [PATCH 046/399] Calculate online time locally Fixes #645 --- .../java/de/diddiz/LogBlock/Consumer.java | 14 ++++++------ .../java/de/diddiz/LogBlock/LogBlock.java | 7 +++--- .../LogBlock/listeners/PlayerInfoLogging.java | 22 ++++++++++++++++++- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 913b713c..0d37b217 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -394,8 +394,8 @@ public void queueJoin(Player player) { queue.add(new PlayerJoinRow(player)); } - public void queueLeave(Player player) { - queue.add(new PlayerLeaveRow(player)); + public void queueLeave(Player player, long onlineTime) { + queue.add(new PlayerLeaveRow(player, onlineTime)); } public void queueAddMaterialMapping(int key, String material) { @@ -1019,20 +1019,20 @@ public Actor[] getActors() { } private class PlayerLeaveRow implements Row { - private final long leaveTime; + private final long onlineTime; private final Actor actor; - PlayerLeaveRow(Player player) { - leaveTime = System.currentTimeMillis() / 1000; + PlayerLeaveRow(Player player, long onlineTime) { + this.onlineTime = onlineTime; actor = Actor.actorFromEntity(player); } @Override public String[] getInserts() { if (logPlayerInfo) { - return new String[] { "UPDATE `lb-players` SET onlinetime = onlinetime + TIMESTAMPDIFF(SECOND, lastlogin, FROM_UNIXTIME('" + leaveTime + "')), playername = '" + mysqlTextEscape(actor.getName()) + "' WHERE lastlogin > 0 && UUID = '" + actor.getUUID() + "';" }; + return new String[] { "UPDATE `lb-players` SET onlinetime = onlinetime + " + onlineTime + " WHERE lastlogin > 0 && UUID = '" + actor.getUUID() + "';" }; } - return new String[] { "UPDATE `lb-players` SET playername = '" + mysqlTextEscape(actor.getName()) + "' WHERE UUID = '" + actor.getUUID() + "';" }; + return new String[0]; } @Override diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 324d33c5..3e1e9090 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -37,6 +37,7 @@ public class LogBlock extends JavaPlugin { private Updater updater = null; private Timer timer = null; private boolean errorAtLoading = false, noDb = false, connected = true; + private PlayerInfoLogging playerInfoLogging; public static LogBlock getInstance() { return logblock; @@ -147,7 +148,7 @@ public void onEnable() { private void registerEvents() { final PluginManager pm = getPluginManager(); pm.registerEvents(new ToolListener(this), this); - pm.registerEvents(new PlayerInfoLogging(this), this); + pm.registerEvents(playerInfoLogging = new PlayerInfoLogging(this), this); if (askRollbackAfterBan) { pm.registerEvents(new BanListener(this), this); } @@ -214,9 +215,9 @@ public void onDisable() { } getServer().getScheduler().cancelTasks(this); if (consumer != null) { - if (logPlayerInfo && getServer().getOnlinePlayers() != null) { + if (logPlayerInfo && playerInfoLogging != null) { for (final Player player : getServer().getOnlinePlayers()) { - consumer.queueLeave(player); + playerInfoLogging.onPlayerQuit(player); } } getLogger().info("Waiting for consumer ..."); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/PlayerInfoLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/PlayerInfoLogging.java index dad35039..fbdf9c4a 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/PlayerInfoLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/PlayerInfoLogging.java @@ -1,23 +1,43 @@ package de.diddiz.LogBlock.listeners; import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.config.Config; + +import java.util.HashMap; +import java.util.UUID; + +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; public class PlayerInfoLogging extends LoggingListener { + + private final HashMap playerLogins = new HashMap<>(); + public PlayerInfoLogging(LogBlock lb) { super(lb); } @EventHandler(priority = EventPriority.MONITOR) public void onPlayerJoin(PlayerJoinEvent event) { + playerLogins.put(event.getPlayer().getUniqueId(), System.currentTimeMillis()); consumer.queueJoin(event.getPlayer()); } @EventHandler(priority = EventPriority.MONITOR) public void onPlayerQuit(PlayerQuitEvent event) { - consumer.queueLeave(event.getPlayer()); + onPlayerQuit(event.getPlayer()); + } + + public void onPlayerQuit(Player player) { + Long joinTime = playerLogins.remove(player.getUniqueId()); + if (Config.logPlayerInfo && joinTime != null) { + long onlineTime = (System.currentTimeMillis() - joinTime) / 1000; + if (onlineTime > 0) { + consumer.queueLeave(player, onlineTime); + } + } } } From c541847225127c537ba88d89c32e9ff38a58b487 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 21:00:50 +0200 Subject: [PATCH 047/399] Lets keywords have a min amount of arguments So querys like */lb world world* (Find logs in the world named "world") or */lb player destroyed* (Find logs for a player named "destroyed") are possible --- .../java/de/diddiz/LogBlock/QueryParams.java | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 0aa45659..adb7692b 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -18,7 +18,39 @@ import static de.diddiz.util.Utils.*; public final class QueryParams implements Cloneable { - private static final Set keywords = new HashSet(Arrays.asList("player".hashCode(), "area".hashCode(), "selection".hashCode(), "sel".hashCode(), "block".hashCode(), "type".hashCode(), "sum".hashCode(), "destroyed".hashCode(), "created".hashCode(), "chestaccess".hashCode(), "all".hashCode(), "time".hashCode(), "since".hashCode(), "before".hashCode(), "limit".hashCode(), "world".hashCode(), "asc".hashCode(), "desc".hashCode(), "last".hashCode(), "coords".hashCode(), "silent".hashCode(), "chat".hashCode(), "search".hashCode(), "match".hashCode(), "loc".hashCode(), "location".hashCode(), "kills".hashCode(), "killer".hashCode(), "victim".hashCode(), "both".hashCode())); + private static final HashMap keywords = new HashMap<>(); + static { + keywords.put("player", 1); + keywords.put("area", 0); + keywords.put("selection", 0); + keywords.put("sel", 0); + keywords.put("block", 1); + keywords.put("type", 1); + keywords.put("sum", 1); + keywords.put("destroyed", 0); + keywords.put("created", 0); + keywords.put("chestaccess", 0); + keywords.put("all", 0); + keywords.put("time", 0); + keywords.put("since", 0); + keywords.put("before", 0); + keywords.put("limit", 1); + keywords.put("world", 1); + keywords.put("asc", 0); + keywords.put("desc", 0); + keywords.put("last", 0); + keywords.put("coords", 0); + keywords.put("silent", 0); + keywords.put("chat", 0); + keywords.put("search", 1); + keywords.put("match", 1); + keywords.put("loc", 1); + keywords.put("location", 1); + keywords.put("kills", 0); + keywords.put("killer", 1); + keywords.put("victim", 1); + keywords.put("both", 0); + } public BlockChangeType bct = BlockChangeType.BOTH; public int limit = -1, before = 0, since = 0, radius = -1; public Location loc = null; @@ -46,7 +78,12 @@ public QueryParams(LogBlock logblock, CommandSender sender, List args) t } public static boolean isKeyWord(String param) { - return keywords.contains(param.toLowerCase().hashCode()); + return keywords.containsKey(param.toLowerCase()); + } + + public static int getKeyWordMinArguments(String param) { + Integer minArgs = keywords.get(param.toLowerCase()); + return minArgs == null ? 0 : minArgs; } public String getLimit() { @@ -530,7 +567,7 @@ public void parseArgs(CommandSender sender, List args) throws IllegalArg } for (int i = 0; i < args.size(); i++) { final String param = args.get(i).toLowerCase(); - final String[] values = getValues(args, i + 1); + final String[] values = getValues(args, i + 1, getKeyWordMinArguments(param)); if (param.equals("last")) { if (session == null || session.lastQuery == null) { throw new IllegalArgumentException("This is your first command, you can't use last."); @@ -797,13 +834,13 @@ protected QueryParams clone() { } } - private static String[] getValues(List args, int offset) { + private static String[] getValues(List args, int offset, int minParams) { // The variable i will store the last value's index int i; // Iterate over the all the values from the offset up till the end for (i = offset; i < args.size(); i++) { // We found a keyword, break here since anything after this isn't a value. - if (isKeyWord(args.get(i))) { + if (i >= offset + minParams && isKeyWord(args.get(i))) { break; } } From e5097a1577e0050dd50d5cf82557d0ec14e05131 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 22:00:17 +0200 Subject: [PATCH 048/399] Compare all aspects if ItemStacks, not only Material --- .../java/de/diddiz/LogBlock/BlockChange.java | 4 +- src/main/java/de/diddiz/util/BukkitUtils.java | 153 ++++++++++++------ 2 files changed, 108 insertions(+), 49 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index c2872a84..af3be972 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -107,9 +107,9 @@ public String toString() { if (ca.itemStack == null) { msg.append("looked inside ").append(type.getMaterial().name()); } else if (ca.remove) { - msg.append("took ").append(ca.itemStack.getAmount()).append("x ").append(ca.itemStack.getType().name()).append(" from ").append(type.getMaterial().name()); + msg.append("took ").append(BukkitUtils.toString(ca.itemStack)).append(" from ").append(type.getMaterial().name()); } else { - msg.append("put ").append(ca.itemStack.getAmount()).append("x ").append(ca.itemStack.getType().name()).append(" into ").append(type.getMaterial().name()); + msg.append("put ").append(BukkitUtils.toString(ca.itemStack)).append(" into ").append(type.getMaterial().name()); } } else if (BukkitUtils.getContainerBlocks().contains(type.getMaterial())) { msg.append("opened ").append(type.getMaterial().name()); diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 2e1fa1bd..180ad815 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -8,6 +8,7 @@ import org.bukkit.block.data.Bisected.Half; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.Stairs; +import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -15,9 +16,12 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; +import org.bukkit.inventory.meta.ItemMeta; import java.io.File; import java.util.*; +import java.util.Map.Entry; public class BukkitUtils { private static final Set> blockEquivalents; @@ -283,48 +287,28 @@ public static Location getInventoryHolderLocation(InventoryHolder holder) { } public static ItemStack[] compareInventories(ItemStack[] items1, ItemStack[] items2) { - final ItemStackComparator comperator = new ItemStackComparator(); final ArrayList diff = new ArrayList(); - final int l1 = items1.length, l2 = items2.length; - for (int i = 0; i < l1; i++) { - if (items1[i] != null) { - items1[i] = new ItemStack(items1[i]); - } - } - for (int i = 0; i < l2; i++) { - if (items2[i] != null) { - items2[i] = new ItemStack(items2[i]); - } + for (ItemStack current : items2) { + diff.add(new ItemStack(current)); } - int c1 = 0, c2 = 0; - while (c1 < l1 || c2 < l2) { - if (c1 >= l1) { - diff.add(items2[c2]); - c2++; - continue; - } - if (c2 >= l2) { - items1[c1].setAmount(items1[c1].getAmount() * -1); - diff.add(items1[c1]); - c1++; - continue; - } - final int comp = comperator.compare(items1[c1], items2[c2]); - if (comp < 0) { - items1[c1].setAmount(items1[c1].getAmount() * -1); - diff.add(items1[c1]); - c1++; - } else if (comp > 0) { - diff.add(items2[c2]); - c2++; - } else { - final int amount = items2[c2].getAmount() - items1[c1].getAmount(); - if (amount != 0) { - items1[c1].setAmount(amount); - diff.add(items1[c1]); + for (ItemStack previous : items1) { + boolean found = false; + for (ItemStack current : diff) { + if (current.isSimilar(previous)) { + int newAmount = current.getAmount() - previous.getAmount(); + if (newAmount == 0) { + diff.remove(current); + } else { + current.setAmount(newAmount); + } + found = true; + break; } - c1++; - c2++; + } + if (!found) { + ItemStack subtracted = new ItemStack(previous); + subtracted.setAmount(-subtracted.getAmount()); + diff.add(subtracted); } } return diff.toArray(new ItemStack[diff.size()]); @@ -347,7 +331,6 @@ public static ItemStack[] compressInventory(ItemStack[] items) { } } } - Collections.sort(compressed, new ItemStackComparator()); return compressed.toArray(new ItemStack[compressed.size()]); } @@ -474,13 +457,6 @@ public static boolean canFall(World world, int x, int y, int z) { return false; } - public static class ItemStackComparator implements Comparator { - @Override - public int compare(ItemStack a, ItemStack b) { - return a.getType().name().compareTo(b.getType().name()); - } - } - public static Material itemIDfromProjectileEntity(Entity e) { return projectileItems.get(e.getType()); } @@ -492,4 +468,87 @@ public static boolean isDoublePlant(Material m) { public static boolean isEmpty(Material m) { return m == Material.AIR || m == Material.CAVE_AIR || m == Material.VOID_AIR; } + + public static String toString(ItemStack stack) { + if (stack == null || stack.getAmount() == 0 || isEmpty(stack.getType())) { + return "nothing"; + } + StringBuilder sb = new StringBuilder(); + sb.append(stack.getAmount()).append("x ").append(stack.getType().name()); + ItemMeta meta = stack.getItemMeta(); + boolean metaStarted = false; + if (meta.hasEnchants()) { + Map enchants = meta.getEnchants(); + if (!enchants.isEmpty()) { + for (Entry e : enchants.entrySet()) { + if (!metaStarted) { + sb.append(" ["); + metaStarted = true; + } else { + sb.append(", "); + } + sb.append(formatMinecraftKey(e.getKey().getKey().getKey())); + if (e.getValue().intValue() > 1) { + sb.append(" ").append(maybeToRoman(e.getValue().intValue() - 1)); + } + } + } + } + if (meta instanceof EnchantmentStorageMeta) { + EnchantmentStorageMeta emeta = (EnchantmentStorageMeta) meta; + if (emeta.hasStoredEnchants()) { + Map enchants = emeta.getStoredEnchants(); + if (!enchants.isEmpty()) { + for (Entry e : enchants.entrySet()) { + if (!metaStarted) { + sb.append(" ["); + metaStarted = true; + } else { + sb.append(", "); + } + sb.append(formatMinecraftKey(e.getKey().getKey().getKey())); + if (e.getValue().intValue() > 1) { + sb.append(" ").append(maybeToRoman(e.getValue().intValue() - 1)); + } + } + } + } + } + if (metaStarted) { + sb.append("]"); + } + return sb.toString(); + } + + private static final String[] romanNumbers = new String[] { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "XI", "X" }; + + private static String maybeToRoman(int value) { + if (value > 0 && value <= 10) { + return romanNumbers[value]; + } + return Integer.toString(value); + } + + public static String formatMinecraftKey(String s) { + char[] cap = s.toCharArray(); + boolean lastSpace = true; + for (int i = 0; i < cap.length; i++) { + char c = cap[i]; + if (c == '_') { + c = ' '; + lastSpace = true; + } else if (c >= '0' && c <= '9' || c == '(' || c == ')') { + lastSpace = true; + } else { + if (lastSpace) { + c = Character.toUpperCase(c); + } else { + c = Character.toLowerCase(c); + } + lastSpace = false; + } + cap[i] = c; + } + return new String(cap); + } } From fd450aee80a5be30b9143818cefd1ee621af2897 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 31 Jul 2018 23:17:26 +0200 Subject: [PATCH 049/399] Check if world is logged in LogBlock.getCount --- src/main/java/de/diddiz/LogBlock/LogBlock.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 3e1e9090..7d816fba 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -314,6 +314,9 @@ public List getBlockChanges(QueryParams params) throws SQLException } public int getCount(QueryParams params) throws SQLException { + if (params == null || params.world == null || !Config.isLogged(params.world)) { + throw new IllegalArgumentException("World is not logged: " + ((params == null || params.world == null) ? "null" : params.world.getName())); + } final Connection conn = getConnection(); Statement state = null; if (conn == null) { From cd2dbc081395ec39bda43ca56741bf1e2ac44ccb Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 1 Aug 2018 00:28:13 +0200 Subject: [PATCH 050/399] Integrate Questioner into Logblock You do not need the extra plugin any more. If you want no questions asked, just disable it in the config. --- LogBlockQuestioner.jar | Bin 5575 -> 0 bytes pom.xml | 7 -- .../de/diddiz/LogBlock/CommandsHandler.java | 15 ++-- .../java/de/diddiz/LogBlock/LogBlock.java | 7 ++ .../diddiz/LogBlock/questioner/Question.java | 73 +++++++++++++++++ .../LogBlock/questioner/Questioner.java | 75 ++++++++++++++++++ 6 files changed, 161 insertions(+), 16 deletions(-) delete mode 100644 LogBlockQuestioner.jar create mode 100644 src/main/java/de/diddiz/LogBlock/questioner/Question.java create mode 100644 src/main/java/de/diddiz/LogBlock/questioner/Questioner.java diff --git a/LogBlockQuestioner.jar b/LogBlockQuestioner.jar deleted file mode 100644 index aa16a489761db39aeb3caf470aaf7decfb4761ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5575 zcmb7I2T)U6yA7StOdwQgN)+k6NbfE5UV;!LbV4uE5eQ0^CenNFQUyc^O%SP}caf%m zq7(tar|-`HuK&I7{de9vvuF01GxL3W=B!z3e@hpJhYtY|6B7f1+ic_jzX1Zk2WTl9 z%JZmetMF;bYpbg$8yNCxsay>M0AIC6-e|&jcqhnVJe;E=V~zU!SfRDecbm8XT^JGZ z^HAJ_>px4;|6IEN)4=&J4FrFFwMFvTI@;Pg2JmUR*(!e6lZA`Dv-6E9dqBG0IEc!$Qlqi5 z(&!k&eb>UzSsQtp#Fv%p>9U)dv;a>rR%~aW#Ep=g$wkg^2fhhvd%?z)i)Ic#D)4*T z>gwEhn;?0tFo-bK9NbmrWS3!V2*3vGXISZzM< zX=L4+19Y?SU_LvDX=NXy7`(y{TzLf8sCD}&9?wCZGV#^h+tHfA9zOu7HB++RaHMp5 zQ6RQ(f40QASwagzvn`yxNtZ~@@6POn%VBX4*bmaNhCci_2jrc7*bO(~`S472MvfvD zPCU(hAePEiRda^I54Plg5RCLO#}7No(WQn4*#&D#2ndAGIc9o>3sUb2`PKi|-Zp80)* z@TU0qB!-i{;(BUa+~SPCQ|dyWMS6{{oZQaUq=a@aG%7Bo!@wQ6Wd+a6Xy`G-55+q6l* zL!S=_o3oCf;ERM*^gK`k)okZ=LHmo@q3{cl09*iol;A%xTjZaZ{dcneLGBWxkNS%$ zkSkH~Brpc9z`$A@4i#<*FNbD`D$5xVc^2Hh@hmg>=(fdmHeIMHt^RqP+eDYLI86n{ZZE0rpK;G4}QKa9G^NU1ToTZ+wNH4O=9;04ivaduUA5#UN8Y~5a z-N(e3vO3rwLHp=#Gqx7fJY2S%GI?XHE9mN@x;iyY9Z((Rj6P@;VM#>rU$4YlZNf_N zohMW!$&Yf+x3jcm%R37_8_QL%zN+A%oQ!%fC3>lhuC?VH0|oBT!BuDjsJ#`Rjt`E9 zGFqwNzFcNSk&JHODq77noi(m$g?C&J=y~_B*#KM9d5~#iNj31@HAOH}I_qA?BZmQ| zzBI*{4rdHQIw}%OUoO)y(PAsi~93w)yHd`wd($Ph*kO6$$E#z20B!_qn&# z?zT`uzPyNR%aW4bF2{L_O2-~|Q$%Z7n5j!sr4zx>3#gr#K z)&CK2n_?ULJUvG$b4^eCU5!nM0Ibha^>+qJYRjFq$nX(g|1EafS#dw1<@ z3bvA?Gg2lUsirxL`{kqcg0iDs`SI7%Nm`V?wS7`56}-3Z473s;%bOu2Sbd~1pn1`( z_||Lh))ZBk#}1i^wnG?r_c6*uobN@^;^2u^s8zgg!%XgIm9}8jYt zy`qX+p$0>-UV*ATyxd872*#|2?IL*fU`r>RgKLR<40BEk zWX@5Kuc}JJk0@STkz`;&$Fe^uzM4Te@Jn_MK0=NHmu}J;Xe`z)pR^E10v9ALy`O`G zJlrNM3a9V(fs5SQ4|e7ilgZ2k0#3`SbSIYu^h#VlGUh zJX@n&A-xYrtzBx;D41xP@CStnpcUb(8b8qCoT$=k?p35ocIa@-+ZjW@X!pb`qHk&# zJ6nD}IExFpU8U*Gp$!t5y0!i_+M{yo#)s)zF%e1>J0)3yIPq#UkIYl-8sxt&622w) z0%`A3sqXodAUAwO7!G~?0yu3Fah{|Aan=nqwDO2cWWvm4X69DBJBDl8icnT{FG0q{ zUNKf}@vp~&CLJCH^L?p9#PShs@~_aXV8}D#dLneXNJ?mQH7EN0ZhScX@!#%CLxFQc z9v=Xx1pX(D;`%3z`j`9up-k~c7Y0-&kSkv3JctH+hYuWYiciV<^rlh1Oup$v*iA^x z%!g!nN?QGOKQWRMghfq@@x{1|t8+8oLV_%o9;k1heYGT;|H`K{RDJhF)@QONBzif^ zYwU8=ugmLTe)Y%Iu|Sy0ckUa}1)P`&un48z7?EN?lXPvgYCy_TlcD8?in}jIPfz`M zlczCofSQLvN;oJpnujpGFk`!|XN~-=+ld*vQrUvO_^5WMUi4*76V~7TmCZnV8vg$F zafO~%Lo%Vg!_bL?Mc90anbdIn%pQLSvBPu**%%6ysgb%SMJPtqPP5L?0B4zucW@WK zD_CeQ|Ga$0|Fb)so?Qx!d7uMM5BCue*MbS`Kqckwwp3&~?b|rinbEUn%{I6g>;oc- z6cgRAdFpZZ#!{k}G8e+7_)~}6F`M#tIiW75#lEX;j)!{m*Bc%qw8S0hAe~lBo6Am8 zwV9#=IN=Ru15VZ8Djq>w$onFaY04JC)Y?9{3b|8-p&sh^PEqkvd**`67BjvsUja&h zCs0QP?;+U%-D7so#(8fbh0gGuKF)>!4HX$UWee41wP4_QWLXrQq*_j9Z4(2JAhb<+ zPLzI(7=8AXd9or)0+MpH82^&;WCX+G0;b>J$&Vc6JcP=6#}qu{Pv3=tTMPzdq*UXm z)HzQQGRG$=+}^fe?Xt>o6e|Y;lZ$$nc1+M4a5%AabsrH#k@}U8N;EaqW+laC9Za>& zIeqtLA?!4!Ab(6B!v@VK=e+?H9RUMX=`^0^I_Xp%5{pUgC^x+R{(v5ju6U~jd9!J9 z{`q3b?)Zksu;!E3gP;U;agCgYrLH(ykL=+(^CeyGWl#X0(ud(W;5I%4$gZBbXGz~n zoFc=(()hH+TE$jOO^yaaucX{MuEkSnc8~x}oDx(4(SGGfS~HI<2)R4UZJ=^1rbOU9 z_6*-pVSs)j6a~|fe5|BNPm_#AVvnUo?VZkxFqheJ0v;@Ik6PuLXZ$(ohl2NR7(@=f zP&PBfdi&Hc!r=?Ewr~*rR#u;k5O&EwLT!4nm^bD-FORx&2BBr<3^Lih^_h&@8-GD?h&fO d#zVZjd#$@VoXLJ#KN1v?U z-Ota=xeuIP1GD$#ZERVgf)spX2`&4|*m-&`gy{1~S9rBru?8Dh&B_dBTQAx>$;@on z`Y2$a>PYjE1E20&HYZ`b{pMG&cg#UN8x#lnCkV?%h>_5>FNe3{MYyuP>D8@sd{4|ph z<>y-y5=6}BIe86Jovo|FUi)Ifz`Yckmru2;@t)yPNRan^H@NeqQ9bpX#pV(kbkz;z zybO1g>Ur`olydRAPm05ltiqJ;OHn_Uk>PuA0ZD6Ym@ELkhB7D2|@^;Cb5B)1rWy3TcsHk&4!u zQoCFqdJ$MV$UH>>(0v0O5M4S>OG#fcE*nov7jRqGQZ_!FE<`b3k`>;W#F1SIlRr+F zWFyGQjd-sZ@o8p+C0vfgJ_mfLi3oa9&$;``gQ0Fq?t4A>9y|UQ|EUXOh8r)lFlj*l z_RE#3Le6Wt=cEFiVX7m;vv@#Pk@$<7&$OmUiSElC1>Dh9zd3wxIfXc+++Y7ZzRI`bxfCQNn& zdL%16Dm2vP0(-DnMQ5=r4{*LZy`Q8(k|%MnxsvrU(x#)b8A}>cX$C-+7fCU=w0JVy z>1`R5=^ftnA+@qC1XFc<_PpD_;7c^ByvBPye}a%p`{HeLVjLgGovf(i@sCw^=cF6! z3$He@!yHRp_NxsK=C-Jp}A?HND?$O~rpG#nb06;J4fAT2BfAXlm-=lS15D$=^nvP!H$e$zR zAKsN?OE0Uu!0oM1p&>u;x_QKD7Vt}BI4!aLg)3V2 z%abo-EbhowbI6X@7Ippr^O)>0Z6cdl?s(F?!?hRPca^kk$k9KS4>6#|C1t`@pXDm~ z+U#jYocvn@+zgtip*>g%DmlY3 z;KMU)0!1kSZ?QQZ`6hm;#U}fy8)KjSa-jw*T8MI4oC^da-)v`f*TyK6b?;XDV)bh> zO;*?>t@KLmTCGhyTgu2+K?4!wT2cpHQs1g1Fv)z($6bxnaZkK+)E>;#7`v9W?N#uM z@!ZKn3>wToMY~1~@7{OWiqn21=UK9a-(KmtFiR%9A&#;ZTL>(fc6AWfv7#=`>IT%B zx83AFkvP1yf?32}UdU_Cd01&^DB#i^fIEAb5Y@Bg&+Js!M}GglV`yzV_1-fwG!!j> zdBIh|O2R&#&LEL22_y4m7_x2mpmHQF!c9+@O7g$O*y<}ZZQ*jI~?rE{S19dr8b@P5w9p8RTqVZ+j*)(#Kiiyhn zWo{!;l)bOkk3PSy+qukulWm^`#;}*uvQI}%waFdW6u3UT14qc7Y|7!4gmLaWPqiS#QA*PfPuIv-I=Kadrt`Rg7okjs z;u=a}Ug9uR*zvNhrB}5}{IL|`>XxxCf`E5ZvVf3Z#XIAY6yH}b(k2)$d-jv#gbJUT z%afRiS$<*B$JQB{v!KO6aS3i>QoM(FL+gF}!4DT{hRUII<4tAfe7_{eq$)ue_vf|v zI`My!9Fm`s{_lgxuSn!iNaFoN{l5$Q zA5#9;7Qg$*uZiYQtP=f0i+`VQ{#y8Vw*0c8KM_Ik4~74J_W#Y4{@U>O-~Ee(f8vDl ZcS`EQ2!8q|06_TjA^n*|l~VnB`!8h}oJ#-z diff --git a/pom.xml b/pom.xml index 31ddf18d..4d59272c 100644 --- a/pom.xml +++ b/pom.xml @@ -45,13 +45,6 @@ 1.13-R0.1-SNAPSHOT provided - - ${project.groupId} - questioner - ${project.version} - system - ${project.basedir}/LogBlockQuestioner.jar - com.sk89q.worldedit worldedit-core diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 9ffc1244..fa37d8b5 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -5,7 +5,6 @@ import de.diddiz.LogBlock.QueryParams.SummarizationMode; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.LogBlockQuestioner.LogBlockQuestioner; import de.diddiz.util.Utils; import org.bukkit.ChatColor; @@ -40,12 +39,10 @@ public class CommandsHandler implements CommandExecutor { private final LogBlock logblock; private final BukkitScheduler scheduler; - private final LogBlockQuestioner questioner; CommandsHandler(LogBlock logblock) { this.logblock = logblock; scheduler = logblock.getServer().getScheduler(); - questioner = (LogBlockQuestioner) logblock.getServer().getPluginManager().getPlugin("LogBlockQuestioner"); } @Override @@ -691,16 +688,16 @@ public void run() { } return; } - if (!params.silent && askRollbacks && questioner != null && sender instanceof Player && !questioner.ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { + if (!params.silent && askRollbacks && sender instanceof Player && !logblock.getQuestioner().ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { sender.sendMessage(ChatColor.RED + "Rollback aborted"); return; } editor.start(); getSession(sender).lookupCache = editor.errors; sender.sendMessage(ChatColor.GREEN + "Rollback finished successfully (" + editor.getElapsedTime() + " ms, " + editor.getSuccesses() + "/" + changes + " blocks" + (editor.getErrors() > 0 ? ", " + ChatColor.RED + editor.getErrors() + " errors" + ChatColor.GREEN : "") + (editor.getBlacklistCollisions() > 0 ? ", " + editor.getBlacklistCollisions() + " blacklist collisions" : "") + ")"); - if (!params.silent && askClearLogAfterRollback && logblock.hasPermission(sender, "logblock.clearlog") && questioner != null && sender instanceof Player) { + if (!params.silent && askClearLogAfterRollback && logblock.hasPermission(sender, "logblock.clearlog") && sender instanceof Player) { Thread.sleep(1000); - if (questioner.ask((Player) sender, "Do you want to delete the rollbacked log?", "yes", "no").equals("yes")) { + if (logblock.getQuestioner().ask((Player) sender, "Do you want to delete the rollbacked log?", "yes", "no").equals("yes")) { params.silent = true; new CommandClearLog(sender, params, false); } else { @@ -774,7 +771,7 @@ public void run() { } return; } - if (!params.silent && askRedos && questioner != null && sender instanceof Player && !questioner.ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { + if (!params.silent && askRedos && sender instanceof Player && !logblock.getQuestioner().ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { sender.sendMessage(ChatColor.RED + "Redo aborted"); return; } @@ -817,10 +814,10 @@ public void run() { rs = state.executeQuery("SELECT count(*) FROM `" + table + "-blocks` " + join + params.getWhere()); rs.next(); if ((deleted = rs.getInt(1)) > 0) { - if (!params.silent && askClearLogs && sender instanceof Player && questioner != null) { + if (!params.silent && askClearLogs && sender instanceof Player) { sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); sender.sendMessage(ChatColor.GREEN.toString() + deleted + " blocks found."); - if (!questioner.ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { + if (!logblock.getQuestioner().ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { sender.sendMessage(ChatColor.RED + "ClearLog aborted"); return; } diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 7d816fba..358cd5ce 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -2,6 +2,7 @@ import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.listeners.*; +import de.diddiz.LogBlock.questioner.Questioner; import de.diddiz.util.BukkitUtils; import de.diddiz.util.MySQLConnectionPool; import de.diddiz.worldedit.WorldEditLoggingHook; @@ -38,6 +39,7 @@ public class LogBlock extends JavaPlugin { private Timer timer = null; private boolean errorAtLoading = false, noDb = false, connected = true; private PlayerInfoLogging playerInfoLogging; + private Questioner questioner; public static LogBlock getInstance() { return logblock; @@ -137,6 +139,7 @@ public void onEnable() { pm.addPermission(perm); } } + questioner = new Questioner(this); try { Metrics metrics = new Metrics(this); metrics.start(); @@ -343,4 +346,8 @@ public int getCount(QueryParams params) throws SQLException { public File getFile() { return super.getFile(); } + + public Questioner getQuestioner() { + return questioner; + } } diff --git a/src/main/java/de/diddiz/LogBlock/questioner/Question.java b/src/main/java/de/diddiz/LogBlock/questioner/Question.java new file mode 100644 index 00000000..1c63c746 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/questioner/Question.java @@ -0,0 +1,73 @@ +package de.diddiz.LogBlock.questioner; + +import org.bukkit.entity.Player; + +public class Question { + private String answer; + private final String[] answers; + private final String questionMessage; + private final Player respondent; + private final long start; + + public Question(Player respondent, String questionMessage, String[] answers) { + this.start = System.currentTimeMillis(); + this.respondent = respondent; + this.questionMessage = questionMessage; + this.answers = answers; + } + + public synchronized String ask() { + StringBuilder options = new StringBuilder(); + for (String ans : this.answers) { + options.append("/" + ans + ", "); + } + options.delete(options.length() - 2, options.length()); + this.respondent.sendMessage(this.questionMessage); + this.respondent.sendMessage("- " + options + "?"); + while (answer == null) { + try { + wait(); + } catch (InterruptedException ex) { + if (answer == null) { + answer = "interrupted"; + } + } + } + return this.answer; + } + + public synchronized boolean isExpired(boolean forceExpire) { + if (forceExpire || System.currentTimeMillis() - this.start > 120000L || this.answer != null) { + if (answer == null) { + answer = "timed out"; + } + notifyAll(); + return true; + } + return false; + } + + public boolean returnAnswer(String answer) { + return returnAnswer(answer, false); + } + + public synchronized boolean returnAnswer(String answer, boolean forceReturn) { + if (forceReturn) { + if (this.answer == null) { + this.answer = answer; + } + notifyAll(); + return true; + } + for (String s : answers) { + if (s.equalsIgnoreCase(answer)) { + if (this.answer == null) { + this.answer = s; + } + notifyAll(); + return true; + } + } + return false; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/questioner/Questioner.java b/src/main/java/de/diddiz/LogBlock/questioner/Questioner.java new file mode 100644 index 00000000..f4746ec2 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/questioner/Questioner.java @@ -0,0 +1,75 @@ +package de.diddiz.LogBlock.questioner; + +import java.util.Iterator; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.Map.Entry; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; + +import de.diddiz.LogBlock.LogBlock; + +public class Questioner { + private final LogBlock logBlock; + private final ConcurrentHashMap questions = new ConcurrentHashMap(); + + public Questioner(LogBlock logBlock) { + this.logBlock = logBlock; + logBlock.getServer().getPluginManager().registerEvents(new QuestionerListener(), logBlock); + logBlock.getServer().getScheduler().scheduleSyncRepeatingTask(logBlock, new QuestionsReaper(), 600, 600); + } + + public String ask(Player respondent, String questionMessage, String... answers) { + if (Bukkit.isPrimaryThread()) { + throw new IllegalStateException("This method may not be called from the primary thread"); + } + Question question = new Question(respondent, questionMessage, answers); + Question oldQuestion = this.questions.put(respondent.getUniqueId(), question); + if (oldQuestion != null) { + oldQuestion.returnAnswer("no", true); + // wait a little time to let the other thread continue + try { + Thread.sleep(10); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + return question.ask(); + } + + private class QuestionsReaper implements Runnable { + public void run() { + if (questions.isEmpty()) { + return; + } + Iterator> it = questions.entrySet().iterator(); + while (it.hasNext()) { + Entry e = it.next(); + Question question = e.getValue(); + if (question.isExpired(logBlock.getServer().getPlayer(e.getKey()) == null)) { + it.remove(); + } + } + } + } + + private class QuestionerListener implements Listener { + @EventHandler(ignoreCancelled = true) + public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { + UUID player = event.getPlayer().getUniqueId(); + Question question; + question = questions.get(player); + if (question != null) { + String answer = event.getMessage().substring(1).toLowerCase(); + if (question.returnAnswer(answer)) { + questions.remove(player, question); + event.setCancelled(true); + } + } + } + } +} From 1b0a575945e12815aa678044b19db1a707554f3a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 1 Aug 2018 00:32:33 +0200 Subject: [PATCH 051/399] Remove worldedit-core from the pom It is implicitly added by worldedit-bukkit --- pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pom.xml b/pom.xml index 4d59272c..c88b5e34 100644 --- a/pom.xml +++ b/pom.xml @@ -45,12 +45,6 @@ 1.13-R0.1-SNAPSHOT provided - - com.sk89q.worldedit - worldedit-core - 7.0.0-SNAPSHOT - provided - com.sk89q.worldedit worldedit-bukkit From 4baa989e60ddc4ced8966888d5bf7610306d07f5 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 1 Aug 2018 00:38:49 +0200 Subject: [PATCH 052/399] Player name auto-completion does more harm than good, so don't do that Fixes #388 --- src/main/java/de/diddiz/LogBlock/QueryParams.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index adb7692b..55e96569 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -585,11 +585,8 @@ public void parseArgs(CommandSender sender, List args) throws IllegalArg if (playerName.contains("\"")) { players.add(playerName.replaceAll("[^a-zA-Z0-9_]", "")); } else { - final List matches = logblock.getServer().matchPlayer(playerName); - if (matches.size() > 1) { - throw new IllegalArgumentException("Ambiguous playername '" + param + "'"); - } - players.add(matches.size() == 1 ? matches.get(0).getName() : playerName.replaceAll("[^a-zA-Z0-9_]", "")); + final Player matches = logblock.getServer().getPlayerExact(playerName); + players.add(matches != null ? matches.getName() : playerName.replaceAll("[^a-zA-Z0-9_]", "")); } } } From 6d13c6436cf73cd5692085a70252f5f1ee503fe8 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 1 Aug 2018 01:46:50 +0200 Subject: [PATCH 053/399] BEDEXPLOSION logging Fixes #693 --- src/main/java/de/diddiz/LogBlock/Logging.java | 2 +- .../de/diddiz/LogBlock/config/Config.java | 3 ++ .../LogBlock/listeners/ExplosionLogging.java | 52 ++++++++++++++++++- src/main/java/de/diddiz/util/BukkitUtils.java | 31 +++++++++-- 4 files changed, 81 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index 3c4307b2..913d7d32 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -8,7 +8,7 @@ public enum Logging { PRESUREPLATEINTERACT, TRIPWIREINTERACT, CREATURECROPTRAMPLE, CROPTRAMPLE, NATURALSTRUCTUREGROW, GRASSGROWTH, MYCELIUMSPREAD, VINEGROWTH, MUSHROOMSPREAD, WITHER(true), WITHER_SKULL(true), BONEMEALSTRUCTUREGROW, - WORLDEDIT, TNTMINECARTEXPLOSION(true), ENDERCRYSTALEXPLOSION(true); + WORLDEDIT, TNTMINECARTEXPLOSION(true), ENDERCRYSTALEXPLOSION(true), BEDEXPLOSION(true); public static final int length = Logging.values().length; private final boolean defaultEnabled; diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index b6df65a0..138ada55 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -32,6 +32,7 @@ public class Config { public static List autoClearLog; public static int autoClearLogDelay; public static boolean dumpDeletedLog; + public static boolean logBedExplosionsAsPlayerWhoTriggeredThese; public static boolean logCreeperExplosionsAsPlayerWhoTriggeredThese, logPlayerInfo; public static LogKillsLevel logKillsLevel; public static Set dontRollback, replaceAnyway; @@ -85,6 +86,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("clearlog.enableAutoClearLog", false); def.put("clearlog.auto", Arrays.asList("world \"world\" before 365 days all", "world \"world\" player lavaflow waterflow leavesdecay before 7 days all", "world world_nether before 365 days all", "world world_nether player lavaflow before 7 days all")); def.put("clearlog.autoClearLogDelay", "6h"); + def.put("logging.logBedExplosionsAsPlayerWhoTriggeredThese", true); def.put("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false); def.put("logging.logKillsLevel", "PLAYERS"); def.put("logging.logEnvironmentalKills", false); @@ -155,6 +157,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti autoClearLog = config.getStringList("clearlog.auto"); dumpDeletedLog = config.getBoolean("clearlog.dumpDeletedLog", false); autoClearLogDelay = parseTimeSpec(config.getString("clearlog.autoClearLogDelay").split(" ")); + logBedExplosionsAsPlayerWhoTriggeredThese = config.getBoolean("logging.logBedExplosionsAsPlayerWhoTriggeredThese", true); logCreeperExplosionsAsPlayerWhoTriggeredThese = config.getBoolean("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false); logPlayerInfo = config.getBoolean("logging.logPlayerInfo", true); try { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index a9d7d31a..3098e6db 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -3,7 +3,12 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.WorldConfig; +import de.diddiz.util.BukkitUtils; + +import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; @@ -11,15 +16,24 @@ import org.bukkit.entity.minecart.ExplosiveMinecart; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockExplodeEvent; import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.projectiles.ProjectileSource; +import org.bukkit.scheduler.BukkitRunnable; import static de.diddiz.LogBlock.config.Config.getWorldConfig; import static de.diddiz.LogBlock.config.Config.logCreeperExplosionsAsPlayerWhoTriggeredThese; import static de.diddiz.util.BukkitUtils.getContainerBlocks; +import java.util.UUID; + public class ExplosionLogging extends LoggingListener { + + private UUID lastBedInteractionPlayer; + private Location lastBedInteractionLocation; + public ExplosionLogging(LogBlock lb) { super(lb); } @@ -111,16 +125,50 @@ public void onEntityExplode(EntityExplodeEvent event) { } } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerInteract(PlayerInteractEvent event) { + if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.hasBlock() && BukkitUtils.isBed(event.getClickedBlock().getType())) { + Block block = event.getClickedBlock(); + if (!Config.isLogging(block.getWorld(), Logging.BEDEXPLOSION)) { + return; + } + lastBedInteractionPlayer = event.getPlayer().getUniqueId(); + lastBedInteractionLocation = block.getLocation(); + new BukkitRunnable() { + @Override + public void run() { + lastBedInteractionPlayer = null; + lastBedInteractionLocation = null; + } + }.runTask(LogBlock.getInstance()); + } + } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockExplode(BlockExplodeEvent event) { + Player bedCause = null; + if (lastBedInteractionPlayer != null && lastBedInteractionLocation != null) { + Location block = event.getBlock().getLocation(); + if (lastBedInteractionLocation.getWorld() == block.getWorld() && block.distanceSquared(lastBedInteractionLocation) <= 1) { + bedCause = Bukkit.getPlayer(lastBedInteractionPlayer); + } + } + for (final Block block : event.blockList()) { final WorldConfig wcfg = getWorldConfig(block.getLocation().getWorld()); if (wcfg != null) { - if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { + Actor actor = new Actor("Explosion"); + if (bedCause != null) { + if (!wcfg.isLogging(Logging.BEDEXPLOSION)) { + return; + } + if (Config.logBedExplosionsAsPlayerWhoTriggeredThese) { + actor = Actor.actorFromEntity(bedCause); + } + } else if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { return; } - Actor actor = new Actor("Explosion"); final Material type = block.getType(); if (wcfg.isLogging(Logging.SIGNTEXT) & (type == Material.SIGN || type == Material.WALL_SIGN)) { diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 180ad815..8b1ca9ba 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -31,12 +31,14 @@ public class BukkitUtils { private static final Set cropBlocks; private static final Set containerBlocks; - + private static final Set singleBlockPlants; private static final Set doublePlants; - + private static final Set nonFluidProofBlocks; - + + private static final Set bedBlocks; + private static final Map projectileItems; static { @@ -203,7 +205,7 @@ public class BukkitUtils { projectileItems.put(EntityType.SPLASH_POTION, Material.SPLASH_POTION); projectileItems.put(EntityType.THROWN_EXP_BOTTLE, Material.EXPERIENCE_BOTTLE); projectileItems.put(EntityType.WITHER_SKULL, Material.WITHER_SKELETON_SKULL); - + nonFluidProofBlocks = EnumSet.noneOf(Material.class); nonFluidProofBlocks.addAll(singleBlockPlants); nonFluidProofBlocks.addAll(doublePlants); @@ -236,6 +238,23 @@ public class BukkitUtils { nonFluidProofBlocks.add(Material.DAYLIGHT_DETECTOR); nonFluidProofBlocks.addAll(Tag.CARPETS.getValues()); + bedBlocks = EnumSet.noneOf(Material.class); + bedBlocks.add(Material.BLACK_BED); + bedBlocks.add(Material.BLUE_BED); + bedBlocks.add(Material.LIGHT_GRAY_BED); + bedBlocks.add(Material.BROWN_BED); + bedBlocks.add(Material.CYAN_BED); + bedBlocks.add(Material.GRAY_BED); + bedBlocks.add(Material.GREEN_BED); + bedBlocks.add(Material.LIGHT_BLUE_BED); + bedBlocks.add(Material.MAGENTA_BED); + bedBlocks.add(Material.LIME_BED); + bedBlocks.add(Material.ORANGE_BED); + bedBlocks.add(Material.PINK_BED); + bedBlocks.add(Material.PURPLE_BED); + bedBlocks.add(Material.RED_BED); + bedBlocks.add(Material.WHITE_BED); + bedBlocks.add(Material.YELLOW_BED); } private static final BlockFace[] relativeBlockFaces = new BlockFace[]{ @@ -551,4 +570,8 @@ public static String formatMinecraftKey(String s) { } return new String(cap); } + + public static boolean isBed(Material type) { + return bedBlocks.contains(type); + } } From c30aba4f900ccfd206549006a7aad52899f74cf0 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 1 Aug 2018 02:36:06 +0200 Subject: [PATCH 054/399] Validate config tool params on execution Fixes #642 #686 --- .../java/de/diddiz/LogBlock/QueryParams.java | 16 +++++++++++++--- .../java/de/diddiz/LogBlock/config/Config.java | 2 +- .../diddiz/LogBlock/listeners/ToolListener.java | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 55e96569..f0146282 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -556,6 +556,10 @@ private void compileLocationQueryPart(StringBuilder where, String locValue, int } public void parseArgs(CommandSender sender, List args) throws IllegalArgumentException { + parseArgs(sender, args, true); + } + + public void parseArgs(CommandSender sender, List args, boolean validate) throws IllegalArgumentException { if (args == null || args.isEmpty()) { throw new IllegalArgumentException("No parameters specified."); } @@ -775,6 +779,15 @@ public void parseArgs(CommandSender sender, List args) throws IllegalArg } i += values.length; } + if (validate) { + validate(); + } + if (session != null) { + session.lastQuery = clone(); + } + } + + public void validate() { if (bct == BlockChangeType.KILLS) { if (world == null) { throw new IllegalArgumentException("No world specified"); @@ -794,9 +807,6 @@ public void parseArgs(CommandSender sender, List args) throws IllegalArg if (bct == BlockChangeType.CHAT && !Config.isLogging(Logging.CHAT)) { throw new IllegalArgumentException("Chat is not logged"); } - if (session != null) { - session.lastQuery = clone(); - } } public void setLocation(Location loc) { diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 138ada55..51c6048b 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -228,7 +228,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti final boolean canDrop = tSec.getBoolean("canDrop", false); final QueryParams params = new QueryParams(logblock); params.prepareToolQuery = true; - params.parseArgs(getConsoleSender(), Arrays.asList(tSec.getString("params").split(" "))); + params.parseArgs(getConsoleSender(), Arrays.asList(tSec.getString("params").split(" ")), false); final ToolMode mode = ToolMode.valueOf(tSec.getString("mode").toUpperCase()); final PermissionDefault pdef = PermissionDefault.valueOf(tSec.getString("permissionDefault").toUpperCase()); tools.add(new Tool(toolName, aliases, leftClickBehavior, rightClickBehavior, defaultEnabled, item, canDrop, params, mode, pdef)); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java index d10cc766..fda737eb 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java @@ -69,6 +69,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { } } try { + params.validate(); if (toolData.mode == ToolMode.ROLLBACK) { handler.new CommandRollback(player, params, true); } else if (toolData.mode == ToolMode.REDO) { From dd58019be1f10493880cb3f72220218da9abbf97 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 1 Aug 2018 02:47:27 +0200 Subject: [PATCH 055/399] Clone QueryParams before using them async Fixes #696, Fixes #684 --- src/main/java/de/diddiz/LogBlock/QueryParams.java | 2 +- src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index f0146282..3a127659 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -825,7 +825,7 @@ public void setPlayer(String playerName) { } @Override - protected QueryParams clone() { + public QueryParams clone() { try { final QueryParams params = (QueryParams) super.clone(); params.players = new ArrayList(players); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java index fda737eb..0ed9a411 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java @@ -48,7 +48,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { return; } final Block block = event.getClickedBlock(); - final QueryParams params = toolData.params; + final QueryParams params = toolData.params.clone(); params.loc = null; params.sel = null; if (behavior == ToolBehavior.BLOCK) { From 8084b3e4c0f62a98b3f6331c00194c5c5e481982 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 1 Aug 2018 02:53:49 +0200 Subject: [PATCH 056/399] Respect LAVAFLOW config setting in all cases Fixes #648 --- src/main/java/de/diddiz/LogBlock/LogBlock.java | 2 +- .../java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 358cd5ce..d8137fe7 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -158,7 +158,7 @@ private void registerEvents() { if (isLogging(Logging.BLOCKPLACE)) { pm.registerEvents(new BlockPlaceLogging(this), this); } - if (isLogging(Logging.BLOCKPLACE) || isLogging(Logging.LAVAFLOW) || isLogging(Logging.WATERFLOW)) { + if (isLogging(Logging.LAVAFLOW) || isLogging(Logging.WATERFLOW)) { pm.registerEvents(new FluidFlowLogging(this), this); } if (isLogging(Logging.BLOCKBREAK)) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index c1ebe5e2..7e9e1b1a 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -33,9 +33,9 @@ public void onBlockFromTo(BlockFromToEvent event) { final Block to = event.getToBlock(); final Material typeTo = to.getType(); final boolean canFlow = BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo); - if (typeFrom == Material.LAVA) { + if (typeFrom == Material.LAVA && wcfg.isLogging(Logging.LAVAFLOW)) { Levelled levelledFrom = (Levelled)blockDataFrom; - if (canFlow && wcfg.isLogging(Logging.LAVAFLOW)) { + if (canFlow) { if (isSurroundedByWater(to) && levelledFrom.getLevel() <= 2) { consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), Material.COBBLESTONE.createBlockData()); } else { From 7a5e46b65f621f039575e73b81db2f06556479ee Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 1 Aug 2018 03:38:19 +0200 Subject: [PATCH 057/399] Increase Updater batch size --- src/main/java/de/diddiz/LogBlock/Updater.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 4a7371c6..d54bcb62 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -32,6 +32,7 @@ class Updater { private final LogBlock logblock; final int UUID_CONVERT_BATCH_SIZE = 100; + final int BLOCKS_CONVERT_BATCH_SIZE = 200000; Updater(LogBlock logblock) { this.logblock = logblock; @@ -441,7 +442,7 @@ boolean update() { while (hadRow) { hadRow = false; - ResultSet entries = st.executeQuery("SELECT id, date, playerid, replaced, type, data, x, y, z FROM `" + wcfg.table + "` ORDER BY id ASC LIMIT 10000"); + ResultSet entries = st.executeQuery("SELECT id, date, playerid, replaced, type, data, x, y, z FROM `" + wcfg.table + "` ORDER BY id ASC LIMIT " + BLOCKS_CONVERT_BATCH_SIZE); while (entries.next()) { hadRow = true; int id = entries.getInt("id"); @@ -515,7 +516,7 @@ boolean update() { PreparedStatement insertChestData = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-chestdata` (id, item, itemremove, itemtype) VALUES (?, ?, ?, ?)"); PreparedStatement deleteChest = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-chest` WHERE id = ?"); while (true) { - rs = st.executeQuery("SELECT id, itemtype, itemamount, itemdata FROM `" + wcfg.table + "-chest` ORDER BY id ASC LIMIT 10000"); + rs = st.executeQuery("SELECT id, itemtype, itemamount, itemdata FROM `" + wcfg.table + "-chest` ORDER BY id ASC LIMIT " + BLOCKS_CONVERT_BATCH_SIZE); boolean anyRow = false; while (rs.next()) { anyRow = true; @@ -566,8 +567,8 @@ boolean update() { rs.close(); PreparedStatement updateWeaponStatement = conn.prepareStatement("UPDATE `" + wcfg.table + "-kills` SET weapon = ? WHERE id = ?"); - for (int start = 0;; start += 10000) { - rs = st.executeQuery("SELECT id, weapon FROM `" + wcfg.table + "-kills` ORDER BY id ASC LIMIT " + start + ",10000"); + for (int start = 0;; start += BLOCKS_CONVERT_BATCH_SIZE) { + rs = st.executeQuery("SELECT id, weapon FROM `" + wcfg.table + "-kills` ORDER BY id ASC LIMIT " + start + "," + BLOCKS_CONVERT_BATCH_SIZE); boolean anyUpdate = false; boolean anyRow = false; while (rs.next()) { @@ -651,7 +652,7 @@ boolean update() { PreparedStatement insertSignState = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-state` (id, replacedState, typeState) VALUES (?, ?, ?)"); PreparedStatement deleteSign = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-sign` WHERE id = ?"); while (true) { - rs = st.executeQuery("SELECT id, signtext, replaced, type FROM `" + wcfg.table + "-sign` LEFT JOIN `" + wcfg.table + "-blocks` USING (id) ORDER BY id ASC LIMIT 10000"); + rs = st.executeQuery("SELECT id, signtext, replaced, type FROM `" + wcfg.table + "-sign` LEFT JOIN `" + wcfg.table + "-blocks` USING (id) ORDER BY id ASC LIMIT " + BLOCKS_CONVERT_BATCH_SIZE); boolean anyRow = false; while (rs.next()) { anyRow = true; From 5a7ba770955e664d3037219f3afd115d71d47453 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 1 Aug 2018 16:53:34 +0200 Subject: [PATCH 058/399] Make the materials mappings safe to be used by multiple servers at the same time --- .../java/de/diddiz/LogBlock/Consumer.java | 58 -------- .../de/diddiz/LogBlock/MaterialConverter.java | 132 +++++++++++------- src/main/java/de/diddiz/LogBlock/Updater.java | 22 ++- 3 files changed, 102 insertions(+), 110 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 0d37b217..b192ca32 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -398,14 +398,6 @@ public void queueLeave(Player player, long onlineTime) { queue.add(new PlayerLeaveRow(player, onlineTime)); } - public void queueAddMaterialMapping(int key, String material) { - queue.add(new AddMaterialRow(key, material)); - } - - public void queueAddBlockStateMapping(int key, String blockState) { - queue.add(new AddBlockStateRow(key, blockState)); - } - @Override public synchronized void run() { if (queue.isEmpty() || !lock.tryLock()) { @@ -1046,56 +1038,6 @@ public Actor[] getActors() { } } - private class AddMaterialRow implements Row { - private final int key; - private final String material; - - AddMaterialRow(int key, String material) { - this.key = key; - this.material = material; - } - - @Override - public String[] getInserts() { - return new String[] { "INSERT INTO `lb-materials` (id, name) VALUES (" + key + ",'" + mysqlTextEscape(material) + "');" }; - } - - @Override - public String[] getPlayers() { - return new String[0]; - } - - @Override - public Actor[] getActors() { - return new Actor[0]; - } - } - - private class AddBlockStateRow implements Row { - private final int key; - private final String blockstate; - - AddBlockStateRow(int key, String blockstate) { - this.key = key; - this.blockstate = blockstate; - } - - @Override - public String[] getInserts() { - return new String[] { "INSERT INTO `lb-blockstates` (id, name) VALUES (" + key + ",'" + mysqlTextEscape(blockstate) + "');" }; - } - - @Override - public String[] getPlayers() { - return new String[0]; - } - - @Override - public Actor[] getActors() { - return new Actor[0]; - } - } - private int safeY(Location loc) { int safeY = loc.getBlockY(); if (safeY < 0) diff --git a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java index 2f48d864..ff89953a 100644 --- a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java +++ b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java @@ -1,11 +1,13 @@ package de.diddiz.LogBlock; import java.sql.Connection; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Arrays; import java.util.HashMap; +import java.util.logging.Level; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -40,18 +42,32 @@ public static int getOrAddMaterialId(String blockDataString) { materialString = blockDataString.substring(0, dataPart); } Integer key = materialToID.get(materialString); - if (key == null) { - key = nextMaterialId++; - materialToID.put(materialString, key); - int length = idToMaterial.length; - while (length <= key) { - length = (length * 3 / 2) + 5; + while (key == null) { + key = nextMaterialId; + Connection conn = LogBlock.getInstance().getConnection(); + try { + conn.setAutoCommit(false); + PreparedStatement smt = conn.prepareStatement("INSERT IGNORE INTO `lb-materials` (id, name) VALUES (?, ?)"); + smt.setInt(1, key); + smt.setString(2, materialString); + boolean couldAdd = smt.executeUpdate() > 0; + conn.commit(); + smt.close(); + if (couldAdd) { + internalAddMaterial(key, materialString); + } else { + initializeMaterials(conn); + } + } catch (SQLException e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not update lb-materials", e); + } finally { + try { + conn.close(); + } catch (SQLException e) { + // ignored + } } - if (length > idToMaterial.length) { - idToMaterial = Arrays.copyOf(idToMaterial, length); - } - idToMaterial[key] = materialString; - LogBlock.getInstance().getConsumer().queueAddMaterialMapping(key, materialString); + key = materialToID.get(materialString); } return key.intValue(); } @@ -63,18 +79,32 @@ public static int getOrAddBlockStateId(String blockDataString) { } String materialString = blockDataString.substring(dataPart); Integer key = blockStateToID.get(materialString); - if (key == null) { - key = nextBlockStateId++; - blockStateToID.put(materialString, key); - int length = idToBlockState.length; - while (length <= key) { - length = (length * 3 / 2) + 5; - } - if (length > idToBlockState.length) { - idToBlockState = Arrays.copyOf(idToBlockState, length); + while (key == null) { + key = nextBlockStateId; + Connection conn = LogBlock.getInstance().getConnection(); + try { + conn.setAutoCommit(false); + PreparedStatement smt = conn.prepareStatement("INSERT IGNORE INTO `lb-blockstates` (id, name) VALUES (?, ?)"); + smt.setInt(1, key); + smt.setString(2, materialString); + boolean couldAdd = smt.executeUpdate() > 0; + conn.commit(); + smt.close(); + if (couldAdd) { + internalAddBlockState(key, materialString); + } else { + initializeMaterials(conn); + } + } catch (SQLException e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not update lb-blockstates", e); + } finally { + try { + conn.close(); + } catch (SQLException e) { + // ignored + } } - idToBlockState[key] = materialString; - LogBlock.getInstance().getConsumer().queueAddBlockStateMapping(key, materialString); + key = blockStateToID.get(materialString); } return key.intValue(); } @@ -97,41 +127,47 @@ public static void initializeMaterials(Connection connection) throws SQLExceptio while (rs.next()) { int key = rs.getInt(1); String materialString = rs.getString(2); - - materialToID.put(materialString, key); - int length = idToMaterial.length; - while (length <= key) { - length = (length * 3 / 2) + 5; - } - if (length > idToMaterial.length) { - idToMaterial = Arrays.copyOf(idToMaterial, length); - } - idToMaterial[key] = materialString; - if (nextMaterialId <= key) { - nextMaterialId = key + 1; - } + internalAddMaterial(key, materialString); } rs.close(); rs = smt.executeQuery("SELECT id, name FROM `lb-blockstates`"); while (rs.next()) { int key = rs.getInt(1); String materialString = rs.getString(2); - - blockStateToID.put(materialString, key); - int length = idToBlockState.length; - while (length <= key) { - length = (length * 3 / 2) + 5; - } - if (length > idToBlockState.length) { - idToBlockState = Arrays.copyOf(idToBlockState, length); - } - idToBlockState[key] = materialString; - if (nextBlockStateId <= key) { - nextBlockStateId = key + 1; - } + internalAddBlockState(key, materialString); } rs.close(); smt.close(); connection.close(); } + + private synchronized static void internalAddMaterial(int key, String materialString) { + materialToID.put(materialString, key); + int length = idToMaterial.length; + while (length <= key) { + length = (length * 3 / 2) + 5; + } + if (length > idToMaterial.length) { + idToMaterial = Arrays.copyOf(idToMaterial, length); + } + idToMaterial[key] = materialString; + if (nextMaterialId <= key) { + nextMaterialId = key + 1; + } + } + + private synchronized static void internalAddBlockState(int key, String materialString) { + blockStateToID.put(materialString, key); + int length = idToBlockState.length; + while (length <= key) { + length = (length * 3 / 2) + 5; + } + if (length > idToBlockState.length) { + idToBlockState = Arrays.copyOf(idToBlockState, length); + } + idToBlockState[key] = materialString; + if (nextBlockStateId <= key) { + nextBlockStateId = key + 1; + } + } } diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index d54bcb62..34822b16 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -47,9 +47,9 @@ boolean update() { logblock.saveConfig(); } ComparableVersion configVersion = new ComparableVersion(versionString); - if (configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion().replace(" (manually compiled)", ""))) >= 0) { - return false; - } + // if (configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion().replace(" (manually compiled)", ""))) >= 0) { + // return false; + // } if (configVersion.compareTo(new ComparableVersion("1.2.7")) < 0) { logblock.getLogger().info("Updating tables to 1.2.7 ..."); if (isLogging(Logging.CHAT)) { @@ -623,7 +623,7 @@ boolean update() { } config.set("version", "1.13.0"); } - + if (configVersion.compareTo(new ComparableVersion("1.13.1")) < 0) { logblock.getLogger().info("Updating tables to 1.13.1 ..."); try { @@ -717,6 +717,8 @@ boolean update() { if (isLogging(Logging.CHAT)) { checkCharset("lb-chat", "message", st, true); } + createIndexIfDoesNotExist("lb-materials", "name", "UNIQUE KEY `name` (`name`(250))", st, true); + createIndexIfDoesNotExist("lb-blockstates", "name", "UNIQUE KEY `name` (`name`(250))", st, true); st.close(); conn.close(); @@ -729,6 +731,17 @@ boolean update() { return true; } + void createIndexIfDoesNotExist(String table, String indexName, String definition, Statement st, boolean silent) throws SQLException { + final ResultSet rs = st.executeQuery("SHOW INDEX FROM `" + table + "` WHERE Key_name = '" + indexName + "'"); + if (!rs.next()) { + st.execute("ALTER TABLE `" + table + "` ADD " + definition); + logblock.getLogger().info("Add index " + indexName + " to table " + table + ": Table modified"); + } else if (!silent) { + logblock.getLogger().info("Add index " + indexName + " to table " + table + ": Already fine, skipping it"); + } + rs.close(); + } + void checkCharset(String table, String column, Statement st, boolean silent) throws SQLException { final ResultSet rs = st.executeQuery("SHOW FULL COLUMNS FROM `" + table + "` WHERE field = '" + column + "'"); String charset = "utf8"; @@ -741,6 +754,7 @@ void checkCharset(String table, String column, Statement st, boolean silent) thr } else if (!silent) { logblock.getLogger().info("Table " + table + " already fine, skipping it"); } + rs.close(); } void checkTables() throws SQLException { From 92b1a2f394d414d68bf030e7c514463f9beee482 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 1 Aug 2018 20:01:51 +0200 Subject: [PATCH 059/399] Improve logging of fallable blocks Also in this commit: Bukkit's Tags are just broken --- .../LogBlock/listeners/BlockPlaceLogging.java | 67 ++------ src/main/java/de/diddiz/util/BukkitUtils.java | 153 ++++++++++++++---- src/main/java/de/diddiz/util/LoggingUtil.java | 38 ++++- 3 files changed, 172 insertions(+), 86 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java index f48aff8d..a8a832a7 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java @@ -3,20 +3,19 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; -import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.util.BukkitUtils; +import de.diddiz.LogBlock.config.Config; +import de.diddiz.util.LoggingUtil; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerBucketEmptyEvent; +import org.bukkit.inventory.meta.BlockStateMeta; +import org.bukkit.inventory.meta.ItemMeta; -import static de.diddiz.LogBlock.config.Config.getWorldConfig; import static de.diddiz.LogBlock.config.Config.isLogging; public class BlockPlaceLogging extends LoggingListener { @@ -26,62 +25,20 @@ public BlockPlaceLogging(LogBlock lb) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockPlace(BlockPlaceEvent event) { - final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld()); - if (wcfg != null && wcfg.isLogging(Logging.BLOCKPLACE)) { - final Material type = event.getBlock().getType(); + if (Config.isLogging(event.getBlock().getWorld(), Logging.BLOCKPLACE)) { final BlockState before = event.getBlockReplacedState(); final BlockState after = event.getBlockPlaced().getState(); final Actor actor = Actor.actorFromEntity(event.getPlayer()); - //Handle falling blocks - if (type.hasGravity()) { - - // Catch placed blocks overwriting something - if (!BukkitUtils.isEmpty(before.getType())) { - consumer.queueBlockBreak(actor, before); - } - - Location loc = event.getBlock().getLocation(); - int x = loc.getBlockX(); - int y = loc.getBlockY(); - int z = loc.getBlockZ(); - // Blocks only fall if they have a chance to start a velocity - if (BukkitUtils.isEmpty(event.getBlock().getRelative(BlockFace.DOWN).getType())) { - while (y > 0 && BukkitUtils.canFall(loc.getWorld(), x, (y - 1), z)) { - y--; - } - } - // If y is 0 then the sand block fell out of the world :( - if (y != 0) { - Location finalLoc = new Location(loc.getWorld(), x, y, z); - // Run this check to avoid false positives - if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) { - if (BukkitUtils.isEmpty(finalLoc.getBlock().getType()) || finalLoc.equals(event.getBlock().getLocation())) { - consumer.queueBlockPlace(actor, finalLoc, event.getBlock().getBlockData()); - } else { - consumer.queueBlockReplace(actor, finalLoc, finalLoc.getBlock().getBlockData(), event.getBlock().getBlockData()); - } - } + // Sign logging is handled elsewhere + if (Config.isLogging(after.getWorld(), Logging.SIGNTEXT) && (after.getType() == Material.SIGN || after.getType() == Material.WALL_SIGN)) { + ItemMeta inHandMeta = event.getItemInHand() != null ? event.getItemInHand().getItemMeta() : null; + if (!(inHandMeta instanceof BlockStateMeta) || !((BlockStateMeta) inHandMeta).hasBlockState()) { + return; } - return; } - - //Sign logging is handled elsewhere - if (wcfg.isLogging(Logging.SIGNTEXT) && (type == Material.SIGN || type == Material.WALL_SIGN)) { - return; - } - - //Delay queuing by one tick to allow data to be updated - LogBlock.getInstance().getServer().getScheduler().scheduleSyncDelayedTask(LogBlock.getInstance(), new Runnable() { - @Override - public void run() { - if (BukkitUtils.isEmpty(before.getType())) { - consumer.queueBlockPlace(actor, after); - } else { - consumer.queueBlockReplace(actor, before, after); - } - } - }, 1L); + + LoggingUtil.smartLogBlockPlace(consumer, actor, before, after); } } diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 8b1ca9ba..7cb9a8e3 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -1,12 +1,15 @@ package de.diddiz.util; import org.bukkit.*; +import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.DoubleChest; import org.bukkit.block.data.Bisected; import org.bukkit.block.data.Bisected.Half; import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.Slab; +import org.bukkit.block.data.type.Slab.Type; import org.bukkit.block.data.type.Stairs; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Entity; @@ -42,6 +45,64 @@ public class BukkitUtils { private static final Map projectileItems; static { + EnumSet pressurePlates = EnumSet.noneOf(Material.class); + pressurePlates.add(Material.OAK_PRESSURE_PLATE); + pressurePlates.add(Material.SPRUCE_PRESSURE_PLATE); + pressurePlates.add(Material.BIRCH_PRESSURE_PLATE); + pressurePlates.add(Material.JUNGLE_PRESSURE_PLATE); + pressurePlates.add(Material.ACACIA_PRESSURE_PLATE); + pressurePlates.add(Material.DARK_OAK_PRESSURE_PLATE); + pressurePlates.add(Material.STONE_PRESSURE_PLATE); + pressurePlates.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); + pressurePlates.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); + + EnumSet saplings = EnumSet.noneOf(Material.class); + saplings.add(Material.OAK_SAPLING); + saplings.add(Material.SPRUCE_SAPLING); + saplings.add(Material.BIRCH_SAPLING); + saplings.add(Material.JUNGLE_SAPLING); + saplings.add(Material.ACACIA_SAPLING); + saplings.add(Material.DARK_OAK_SAPLING); + + EnumSet carpets = EnumSet.noneOf(Material.class); + carpets.add(Material.BLACK_CARPET); + carpets.add(Material.BLUE_CARPET); + carpets.add(Material.LIGHT_GRAY_CARPET); + carpets.add(Material.BROWN_CARPET); + carpets.add(Material.CYAN_CARPET); + carpets.add(Material.GRAY_CARPET); + carpets.add(Material.GREEN_CARPET); + carpets.add(Material.LIGHT_BLUE_CARPET); + carpets.add(Material.MAGENTA_CARPET); + carpets.add(Material.LIME_CARPET); + carpets.add(Material.ORANGE_CARPET); + carpets.add(Material.PINK_CARPET); + carpets.add(Material.PURPLE_CARPET); + carpets.add(Material.RED_CARPET); + carpets.add(Material.WHITE_CARPET); + carpets.add(Material.YELLOW_CARPET); + + EnumSet slabs = EnumSet.noneOf(Material.class); + slabs.add(Material.OAK_SLAB); + slabs.add(Material.SPRUCE_SLAB); + slabs.add(Material.BIRCH_SLAB); + slabs.add(Material.JUNGLE_SLAB); + slabs.add(Material.ACACIA_SLAB); + slabs.add(Material.DARK_OAK_SLAB); + slabs.add(Material.STONE_SLAB); + slabs.add(Material.STONE_BRICK_SLAB); + slabs.add(Material.COBBLESTONE_SLAB); + slabs.add(Material.PETRIFIED_OAK_SLAB); + slabs.add(Material.SANDSTONE_SLAB); + slabs.add(Material.RED_SANDSTONE_SLAB); + slabs.add(Material.NETHER_BRICK_SLAB); + slabs.add(Material.PURPUR_SLAB); + slabs.add(Material.QUARTZ_SLAB); + slabs.add(Material.BRICK_SLAB); + slabs.add(Material.PRISMARINE_SLAB); + slabs.add(Material.DARK_PRISMARINE_SLAB); + slabs.add(Material.PRISMARINE_BRICK_SLAB); + singleBlockPlants = EnumSet.noneOf(Material.class); singleBlockPlants.add(Material.GRASS); singleBlockPlants.add(Material.FERN); @@ -82,7 +143,12 @@ public class BukkitUtils { relativeBreakable.add(Material.WALL_SIGN); relativeBreakable.add(Material.LADDER); relativeBreakable.add(Material.STONE_BUTTON); - relativeBreakable.addAll(Tag.WOODEN_BUTTONS.getValues()); + relativeBreakable.add(Material.OAK_BUTTON); + relativeBreakable.add(Material.SPRUCE_BUTTON); + relativeBreakable.add(Material.BIRCH_BUTTON); + relativeBreakable.add(Material.JUNGLE_BUTTON); + relativeBreakable.add(Material.ACACIA_BUTTON); + relativeBreakable.add(Material.DARK_OAK_BUTTON); relativeBreakable.add(Material.REDSTONE_WALL_TORCH); relativeBreakable.add(Material.LEVER); relativeBreakable.add(Material.WALL_TORCH); @@ -91,7 +157,7 @@ public class BukkitUtils { // Blocks that break when they are on top of a block relativeTopBreakable = EnumSet.noneOf(Material.class); - relativeTopBreakable.addAll(Tag.SAPLINGS.getValues()); + relativeTopBreakable.addAll(saplings); relativeTopBreakable.addAll(singleBlockPlants); relativeTopBreakable.add(Material.WHEAT); relativeTopBreakable.add(Material.POTATO); @@ -106,10 +172,7 @@ public class BukkitUtils { relativeTopBreakable.add(Material.RAIL); relativeTopBreakable.add(Material.REDSTONE_WIRE); relativeTopBreakable.add(Material.SIGN); - relativeTopBreakable.add(Material.STONE_PRESSURE_PLATE); - relativeTopBreakable.addAll(Tag.WOODEN_PRESSURE_PLATES.getValues()); - relativeTopBreakable.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); - relativeTopBreakable.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); + relativeTopBreakable.addAll(pressurePlates); relativeTopBreakable.add(Material.SNOW); relativeTopBreakable.add(Material.REPEATER); relativeTopBreakable.add(Material.COMPARATOR); @@ -117,27 +180,42 @@ public class BukkitUtils { relativeTopBreakable.add(Material.WALL_TORCH); relativeTopBreakable.add(Material.REDSTONE_TORCH); relativeTopBreakable.add(Material.REDSTONE_WALL_TORCH); - relativeTopBreakable.addAll(Tag.WOODEN_DOORS.getValues()); + relativeTopBreakable.add(Material.OAK_DOOR); + relativeTopBreakable.add(Material.SPRUCE_DOOR); + relativeTopBreakable.add(Material.BIRCH_DOOR); + relativeTopBreakable.add(Material.JUNGLE_DOOR); + relativeTopBreakable.add(Material.ACACIA_DOOR); + relativeTopBreakable.add(Material.DARK_OAK_DOOR); relativeTopBreakable.add(Material.IRON_DOOR); - relativeTopBreakable.addAll(Tag.CARPETS.getValues()); + relativeTopBreakable.addAll(carpets); relativeTopBreakable.addAll(doublePlants); // Blocks that break falling entities fallingEntityKillers = EnumSet.noneOf(Material.class); fallingEntityKillers.add(Material.SIGN); fallingEntityKillers.add(Material.WALL_SIGN); - fallingEntityKillers.addAll(Tag.WOODEN_PRESSURE_PLATES.getValues()); - fallingEntityKillers.add(Material.STONE_PRESSURE_PLATE); - fallingEntityKillers.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); - fallingEntityKillers.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); - fallingEntityKillers.addAll(Tag.SAPLINGS.getValues()); - fallingEntityKillers.addAll(singleBlockPlants); + fallingEntityKillers.addAll(pressurePlates); + fallingEntityKillers.addAll(saplings); + fallingEntityKillers.add(Material.DANDELION); + fallingEntityKillers.add(Material.POPPY); + fallingEntityKillers.add(Material.BLUE_ORCHID); + fallingEntityKillers.add(Material.ALLIUM); + fallingEntityKillers.add(Material.AZURE_BLUET); + fallingEntityKillers.add(Material.ORANGE_TULIP); + fallingEntityKillers.add(Material.WHITE_TULIP); + fallingEntityKillers.add(Material.PINK_TULIP); + fallingEntityKillers.add(Material.RED_TULIP); + fallingEntityKillers.add(Material.OXEYE_DAISY); + fallingEntityKillers.add(Material.BROWN_MUSHROOM); + fallingEntityKillers.add(Material.RED_MUSHROOM); + fallingEntityKillers.addAll(doublePlants); fallingEntityKillers.add(Material.WHEAT); fallingEntityKillers.add(Material.CARROT); fallingEntityKillers.add(Material.POTATO); fallingEntityKillers.add(Material.BEETROOT); fallingEntityKillers.add(Material.NETHER_WART); - fallingEntityKillers.addAll(Tag.SLABS.getValues()); + fallingEntityKillers.add(Material.COCOA); + fallingEntityKillers.addAll(slabs); fallingEntityKillers.add(Material.TORCH); fallingEntityKillers.add(Material.WALL_TORCH); fallingEntityKillers.add(Material.FLOWER_POT); @@ -152,7 +230,19 @@ public class BukkitUtils { fallingEntityKillers.add(Material.REPEATER); fallingEntityKillers.add(Material.COMPARATOR); fallingEntityKillers.add(Material.DAYLIGHT_DETECTOR); - fallingEntityKillers.addAll(Tag.CARPETS.getValues()); + fallingEntityKillers.addAll(carpets); + fallingEntityKillers.add(Material.PLAYER_HEAD); + fallingEntityKillers.add(Material.PLAYER_WALL_HEAD); + fallingEntityKillers.add(Material.CREEPER_HEAD); + fallingEntityKillers.add(Material.CREEPER_WALL_HEAD); + fallingEntityKillers.add(Material.DRAGON_HEAD); + fallingEntityKillers.add(Material.DRAGON_WALL_HEAD); + fallingEntityKillers.add(Material.ZOMBIE_HEAD); + fallingEntityKillers.add(Material.ZOMBIE_WALL_HEAD); + fallingEntityKillers.add(Material.SKELETON_SKULL); + fallingEntityKillers.add(Material.SKELETON_WALL_SKULL); + fallingEntityKillers.add(Material.WITHER_SKELETON_SKULL); + fallingEntityKillers.add(Material.WITHER_SKELETON_WALL_SKULL); // Crop Blocks cropBlocks = EnumSet.noneOf(Material.class); @@ -214,11 +304,8 @@ public class BukkitUtils { nonFluidProofBlocks.add(Material.WALL_TORCH); nonFluidProofBlocks.add(Material.TRIPWIRE_HOOK); nonFluidProofBlocks.add(Material.COCOA); - nonFluidProofBlocks.addAll(Tag.WOODEN_PRESSURE_PLATES.getValues()); - nonFluidProofBlocks.add(Material.STONE_PRESSURE_PLATE); - nonFluidProofBlocks.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); - nonFluidProofBlocks.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); - nonFluidProofBlocks.addAll(Tag.SAPLINGS.getValues()); + nonFluidProofBlocks.addAll(pressurePlates); + nonFluidProofBlocks.addAll(saplings); nonFluidProofBlocks.add(Material.WHEAT); nonFluidProofBlocks.add(Material.CARROT); nonFluidProofBlocks.add(Material.POTATO); @@ -236,7 +323,7 @@ public class BukkitUtils { nonFluidProofBlocks.add(Material.REPEATER); nonFluidProofBlocks.add(Material.COMPARATOR); nonFluidProofBlocks.add(Material.DAYLIGHT_DETECTOR); - nonFluidProofBlocks.addAll(Tag.CARPETS.getValues()); + nonFluidProofBlocks.addAll(carpets); bedBlocks = EnumSet.noneOf(Material.class); bedBlocks.add(Material.BLACK_BED); @@ -462,20 +549,26 @@ public static int modifyContainer(BlockState b, ItemStack item, boolean remove) return 0; } - public static boolean canFall(World world, int x, int y, int z) { - Material mat = world.getBlockAt(x, y, z).getType(); - - // Air - if (mat == Material.AIR) { + public static boolean canFallIn(World world, int x, int y, int z) { + Block block = world.getBlockAt(x, y, z); + Material mat = block.getType(); + if (canDirectlyFallIn(mat)) { return true; - } else if (mat == Material.WATER || mat == Material.LAVA) { // Fluids - return true; - } else if (getFallingEntityKillers().contains(mat) || mat == Material.FIRE || mat == Material.VINE || doublePlants.contains(mat) || mat == Material.DEAD_BUSH) { // Misc. + } else if (getFallingEntityKillers().contains(mat) || singleBlockPlants.contains(mat) || mat == Material.VINE) { + if (Tag.SLABS.isTagged(mat)) { + if (((Slab) block.getBlockData()).getType() != Type.BOTTOM) { + return false; + } + } return true; } return false; } + public static boolean canDirectlyFallIn(Material m) { + return isEmpty(m) || m == Material.WATER || m == Material.LAVA || m == Material.FIRE; + } + public static Material itemIDfromProjectileEntity(Entity e) { return projectileItems.get(e.getType()); } diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index 10e03c12..8848e3d4 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -9,6 +9,7 @@ import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Directional; @@ -20,6 +21,41 @@ public class LoggingUtil { + public static void smartLogBlockPlace(Consumer consumer, Actor actor, BlockState replaced, BlockState placed) { + Location loc = replaced.getLocation(); + if (!placed.getType().hasGravity() || !BukkitUtils.canDirectlyFallIn(replaced.getBlock().getRelative(BlockFace.DOWN).getType())) { + if (BukkitUtils.isEmpty(replaced.getType())) { + consumer.queueBlockPlace(actor, placed); + } else { + consumer.queueBlockReplace(actor, replaced, placed); + } + return; + } + int x = loc.getBlockX(); + int initialy = loc.getBlockY(); + int y = initialy; + int z = loc.getBlockZ(); + while (y > 0 && BukkitUtils.canFallIn(loc.getWorld(), x, (y - 1), z)) { + y--; + } + if (initialy != y && !BukkitUtils.isEmpty(replaced.getType())) { + // this is not the final location but the block got removed (vines etc) + consumer.queueBlockBreak(actor, replaced); + } + // If y is 0 then the block fell out of the world :( + if (y != 0) { + // Run this check to avoid false positives + Location finalLoc = new Location(loc.getWorld(), x, y, z); + if (y == initialy || !BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) { + if (BukkitUtils.isEmpty(finalLoc.getBlock().getType())) { + consumer.queueBlockPlace(actor, finalLoc, placed.getBlockData()); + } else { + consumer.queueBlockReplace(actor, finalLoc.getBlock().getState(), placed.getBlockData()); + } + } + } + } + public static void smartLogFallables(Consumer consumer, Actor actor, Block origin) { WorldConfig wcfg = getWorldConfig(origin.getWorld()); @@ -41,7 +77,7 @@ public static void smartLogFallables(Consumer consumer, Actor actor, Block origi int x = loc.getBlockX(); int y = loc.getBlockY(); int z = loc.getBlockZ(); - while (y > 0 && BukkitUtils.canFall(loc.getWorld(), x, (y - 1), z)) { + while (y > 0 && BukkitUtils.canFallIn(loc.getWorld(), x, (y - 1), z)) { y--; } // If y is 0 then the sand block fell out of the world :( From 95b7be57fcb410f315a1de33d967d77075772be3 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 1 Aug 2018 20:02:15 +0200 Subject: [PATCH 060/399] Dragon Egg teleport logging --- .../java/de/diddiz/LogBlock/LogBlock.java | 3 + src/main/java/de/diddiz/LogBlock/Logging.java | 4 +- .../LogBlock/listeners/DragonEggLogging.java | 73 +++++++++++++++++++ 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/listeners/DragonEggLogging.java diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index d8137fe7..1585c780 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -209,6 +209,9 @@ private void registerEvents() { if (isLogging(Logging.GRASSGROWTH) || isLogging(Logging.MYCELIUMSPREAD) || isLogging(Logging.VINEGROWTH) || isLogging(Logging.MUSHROOMSPREAD)) { pm.registerEvents(new BlockSpreadLogging(this), this); } + if (isLogging(Logging.DRAGONEGGTELEPORT)) { + pm.registerEvents(new DragonEggLogging(this), this); + } } @Override diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index 913d7d32..cd9323d8 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -7,8 +7,8 @@ public enum Logging { SWITCHINTERACT, CAKEEAT, ENDERMEN, NOTEBLOCKINTERACT, DIODEINTERACT, COMPARATORINTERACT, PRESUREPLATEINTERACT, TRIPWIREINTERACT, CREATURECROPTRAMPLE, CROPTRAMPLE, NATURALSTRUCTUREGROW, GRASSGROWTH, MYCELIUMSPREAD, VINEGROWTH, MUSHROOMSPREAD, - WITHER(true), WITHER_SKULL(true), BONEMEALSTRUCTUREGROW, - WORLDEDIT, TNTMINECARTEXPLOSION(true), ENDERCRYSTALEXPLOSION(true), BEDEXPLOSION(true); + WITHER(true), WITHER_SKULL(true), BONEMEALSTRUCTUREGROW, WORLDEDIT, TNTMINECARTEXPLOSION(true), + ENDERCRYSTALEXPLOSION(true), BEDEXPLOSION(true), DRAGONEGGTELEPORT(true); public static final int length = Logging.values().length; private final boolean defaultEnabled; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/DragonEggLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/DragonEggLogging.java new file mode 100644 index 00000000..45fde6d8 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/listeners/DragonEggLogging.java @@ -0,0 +1,73 @@ +package de.diddiz.LogBlock.listeners; + +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.BlockData; +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.block.BlockFromToEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.scheduler.BukkitRunnable; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.Config; +import de.diddiz.util.LoggingUtil; + +public class DragonEggLogging extends LoggingListener { + + private UUID lastDragonEggInteractionPlayer; + private Location lastDragonEggInteractionLocation; + + public DragonEggLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerInteract(PlayerInteractEvent event) { + if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.hasBlock() && event.getClickedBlock().getType() == Material.DRAGON_EGG) { + Block block = event.getClickedBlock(); + if (!Config.isLogging(block.getWorld(), Logging.DRAGONEGGTELEPORT)) { + return; + } + lastDragonEggInteractionPlayer = event.getPlayer().getUniqueId(); + lastDragonEggInteractionLocation = block.getLocation(); + new BukkitRunnable() { + @Override + public void run() { + lastDragonEggInteractionPlayer = null; + lastDragonEggInteractionLocation = null; + } + }.runTask(LogBlock.getInstance()); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onDragonEggTeleport(BlockFromToEvent event) { + Block block = event.getBlock(); + Player teleportCause = null; + if (lastDragonEggInteractionPlayer != null && lastDragonEggInteractionLocation != null && lastDragonEggInteractionLocation.equals(block.getLocation())) { + teleportCause = Bukkit.getPlayer(lastDragonEggInteractionPlayer); + } + + if (block.getType() == Material.DRAGON_EGG && Config.isLogging(block.getWorld(), Logging.DRAGONEGGTELEPORT)) { + Actor actor = new Actor("DragonEgg"); + if (teleportCause != null) { + actor = Actor.actorFromEntity(teleportCause); + } + BlockData data = block.getBlockData(); + consumer.queueBlockBreak(actor, block.getLocation(), data); + BlockState finalState = event.getToBlock().getState(); + finalState.setBlockData(data); + LoggingUtil.smartLogBlockPlace(consumer, actor, event.getToBlock().getState(), finalState); + } + } +} From 37ce2303dca53659cac7b27122d925180f04c186 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 1 Aug 2018 20:28:21 +0200 Subject: [PATCH 061/399] Improve sign logging Fixes #407 --- src/main/java/de/diddiz/LogBlock/BlockChange.java | 4 ++++ src/main/java/de/diddiz/LogBlock/Consumer.java | 2 +- src/main/java/de/diddiz/LogBlock/WorldEditor.java | 9 +++++++++ .../diddiz/LogBlock/listeners/BlockPlaceLogging.java | 10 ---------- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index af3be972..dddfa4b9 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -128,6 +128,10 @@ public String toString() { msg.append("stepped on ").append(type.getMaterial().name()); } else if (type.getMaterial() == Material.TRIPWIRE) { msg.append("ran into ").append(type.getMaterial().name()); + } else if (type.getMaterial() == Material.SIGN || type.getMaterial() == Material.WALL_SIGN) { + msg.append("edited a ").append(type.getMaterial().name()).append(" to ").append(typeDetails); + } else { + msg.append("replaced ").append(replaced.getMaterial().name()).append(replacedDetails).append(" with ").append(type.getMaterial().name()).append(typeDetails); } } else if (BukkitUtils.isEmpty(type.getMaterial())) { msg.append("destroyed ").append(replaced.getMaterial().name()).append(replacedDetails); diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index b192ca32..4b53b1d0 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -360,7 +360,7 @@ public void queueSignPlace(Actor actor, Location loc, BlockData type, String[] l if ((type.getMaterial() != Material.SIGN && type.getMaterial() != Material.WALL_SIGN) || lines == null || lines.length != 4) { return; } - queueBlock(actor, loc, null, type, null, Utils.serializeYamlConfiguration(BlockStateCodecSign.serialize(lines)), null); + queueBlock(actor, loc, type, type, null, Utils.serializeYamlConfiguration(BlockStateCodecSign.serialize(lines)), null); } /** diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index e4963fd0..3a5d53f0 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -200,6 +200,15 @@ PerformResult perform() throws WorldEditorException { throw new WorldEditorException("Not enough space left in " + block.getType(), block.getLocation()); } } + } else if (BlockStateCodecs.hasCodec(replacedBlock.getMaterial())) { + block.setBlockData(replacedBlock); + state = block.getState(); + try { + BlockStateCodecs.deserialize(state, replacedState); + state.update(); + } catch (Exception e) { + throw new WorldEditorException("Failed to restore blockstate of " + block.getType() + ": " + e, block.getLocation()); + } } else if (!block.getBlockData().equals(replacedBlock)) { block.setBlockData(replacedBlock); } else { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java index a8a832a7..0b0c9f2b 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java @@ -13,8 +13,6 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerBucketEmptyEvent; -import org.bukkit.inventory.meta.BlockStateMeta; -import org.bukkit.inventory.meta.ItemMeta; import static de.diddiz.LogBlock.config.Config.isLogging; @@ -29,14 +27,6 @@ public void onBlockPlace(BlockPlaceEvent event) { final BlockState before = event.getBlockReplacedState(); final BlockState after = event.getBlockPlaced().getState(); final Actor actor = Actor.actorFromEntity(event.getPlayer()); - - // Sign logging is handled elsewhere - if (Config.isLogging(after.getWorld(), Logging.SIGNTEXT) && (after.getType() == Material.SIGN || after.getType() == Material.WALL_SIGN)) { - ItemMeta inHandMeta = event.getItemInHand() != null ? event.getItemInHand().getItemMeta() : null; - if (!(inHandMeta instanceof BlockStateMeta) || !((BlockStateMeta) inHandMeta).hasBlockState()) { - return; - } - } LoggingUtil.smartLogBlockPlace(consumer, actor, before, after); } From 0eb2b0dbc8d7f958ac55ecda4c79699c083bb6d7 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 2 Aug 2018 00:50:03 +0200 Subject: [PATCH 062/399] Force CAVE_AIR and VOID_AIR to AIR + Cleanup rollbacks --- .../java/de/diddiz/LogBlock/Consumer.java | 4 +-- .../java/de/diddiz/LogBlock/WorldEditor.java | 33 +++---------------- 2 files changed, 6 insertions(+), 31 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 4b53b1d0..047e0744 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -578,10 +578,10 @@ private boolean addPlayer(Statement state, Actor actor) throws SQLException { } private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter, byte[] stateBefore, byte[] stateAfter, ChestAccess ca) { - if (typeBefore == null) { + if (typeBefore == null || typeBefore.getMaterial() == Material.CAVE_AIR || typeBefore.getMaterial() == Material.VOID_AIR) { typeBefore = Bukkit.createBlockData(Material.AIR); } - if (typeAfter == null) { + if (typeAfter == null || typeAfter.getMaterial() == Material.CAVE_AIR || typeAfter.getMaterial() == Material.VOID_AIR) { typeAfter = Bukkit.createBlockData(Material.AIR); } if (Config.fireCustomEvents) { diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 3a5d53f0..98cfb61e 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -176,23 +176,11 @@ PerformResult perform() throws WorldEditorException { world.loadChunk(block.getChunk()); } if (setBlock.equals(replacedBlock)) { - if (BukkitUtils.isEmpty(setBlock.getMaterial())) { - block.setType(Material.AIR); - } else if (ca != null) { - if (state instanceof InventoryHolder) { + if (ca != null) { + if (state instanceof InventoryHolder && state.getType() == replacedBlock.getMaterial()) { int leftover; try { leftover = modifyContainer(state, new ItemStack(ca.itemStack), !ca.remove); - // Special-case blocks which might be double chests - if (leftover > 0 && (setBlock.getMaterial() == Material.CHEST || setBlock.getMaterial() == Material.TRAPPED_CHEST)) { - for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) { - if (block.getRelative(face).getType() == setBlock.getMaterial()) { - ItemStack remaining = new ItemStack(ca.itemStack); - remaining.setAmount(leftover); - leftover = modifyContainer(block.getRelative(face).getState(), remaining, !ca.remove); - } - } - } } catch (final Exception ex) { throw new WorldEditorException(ex.getMessage(), block.getLocation()); } @@ -200,26 +188,13 @@ PerformResult perform() throws WorldEditorException { throw new WorldEditorException("Not enough space left in " + block.getType(), block.getLocation()); } } - } else if (BlockStateCodecs.hasCodec(replacedBlock.getMaterial())) { - block.setBlockData(replacedBlock); - state = block.getState(); - try { - BlockStateCodecs.deserialize(state, replacedState); - state.update(); - } catch (Exception e) { - throw new WorldEditorException("Failed to restore blockstate of " + block.getType() + ": " + e, block.getLocation()); - } - } else if (!block.getBlockData().equals(replacedBlock)) { - block.setBlockData(replacedBlock); - } else { - return PerformResult.NO_ACTION; + return PerformResult.SUCCESS; } - return PerformResult.SUCCESS; } if (block.getType() != setBlock.getMaterial() && !replaceAnyway.contains(block.getType())) { return PerformResult.NO_ACTION; } - if (state instanceof InventoryHolder) { + if (state instanceof InventoryHolder && replacedBlock.getMaterial() != block.getType()) { ((InventoryHolder) state).getInventory().clear(); state.update(); } From 3dbb7a6c4397bc760b41139143aaa196da2d7e2b Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 2 Aug 2018 01:18:43 +0200 Subject: [PATCH 063/399] Improve chest rollbacks Fixes #533 --- .../java/de/diddiz/LogBlock/WorldEditor.java | 26 ++++++++---- src/main/java/de/diddiz/util/BukkitUtils.java | 42 +++++++++++++++++++ 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 98cfb61e..17180148 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -8,10 +8,11 @@ import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.data.Bisected.Half; +import org.bukkit.block.data.Bisected; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.Bed; +import org.bukkit.block.data.type.Chest; import org.bukkit.block.data.type.Bed.Part; -import org.bukkit.block.data.type.Door; import org.bukkit.block.data.type.Piston; import org.bukkit.block.data.type.PistonHead; import org.bukkit.block.data.type.TechnicalPiston.Type; @@ -187,8 +188,9 @@ PerformResult perform() throws WorldEditorException { if (leftover > 0 && ca.remove) { throw new WorldEditorException("Not enough space left in " + block.getType(), block.getLocation()); } + return PerformResult.SUCCESS; } - return PerformResult.SUCCESS; + return PerformResult.NO_ACTION; } } if (block.getType() != setBlock.getMaterial() && !replaceAnyway.contains(block.getType())) { @@ -219,13 +221,13 @@ PerformResult perform() throws WorldEditorException { bed2.setPart(bed.getPart() == Part.HEAD ? Part.FOOT : Part.HEAD); secBlock.setBlockData(bed2); } - } else if (newData instanceof Door) { - final Door door = (Door) newData; - final Block secBlock = door.getHalf() == Half.TOP ? block.getRelative(BlockFace.DOWN) : block.getRelative(BlockFace.UP); + } else if (newData instanceof Bisected) { + final Bisected firstPart = (Bisected) newData; + final Block secBlock = block.getRelative(firstPart.getHalf() == Half.TOP ? BlockFace.DOWN : BlockFace.UP); if (secBlock.isEmpty()) { - Door door2 = (Door) door.clone(); - door2.setHalf(door.getHalf() == Half.TOP ? Half.BOTTOM : Half.TOP); - secBlock.setBlockData(door2); + Bisected secondPart = (Bisected) firstPart.clone(); + secondPart.setHalf(firstPart.getHalf() == Half.TOP ? Half.BOTTOM : Half.TOP); + secBlock.setBlockData(secondPart); } } else if ((curtype == Material.PISTON || curtype == Material.STICKY_PISTON)) { Piston piston = (Piston) newData; @@ -247,6 +249,14 @@ PerformResult perform() throws WorldEditorException { piston.setExtended(true); secBlock.setBlockData(piston); } + } else if (newData instanceof Chest) { + Chest chest = (Chest) newData; + if (chest.getType() != org.bukkit.block.data.type.Chest.Type.SINGLE) { + if (getConnectedChest(block) == null) { + chest.setType(org.bukkit.block.data.type.Chest.Type.SINGLE); + block.setBlockData(chest); + } + } } return PerformResult.SUCCESS; } diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 7cb9a8e3..c431ee53 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -667,4 +667,46 @@ public static String formatMinecraftKey(String s) { public static boolean isBed(Material type) { return bedBlocks.contains(type); } + + public static Block getConnectedChest(Block chestBlock) { + // is this a chest? + BlockData blockData = chestBlock.getBlockData(); + if (!(blockData instanceof org.bukkit.block.data.type.Chest)) { + return null; + } + // so check if is should have a neighbour + org.bukkit.block.data.type.Chest chestData = (org.bukkit.block.data.type.Chest) blockData; + org.bukkit.block.data.type.Chest.Type chestType = chestData.getType(); + if (chestType != org.bukkit.block.data.type.Chest.Type.SINGLE) { + // check if the neighbour exists + BlockFace chestFace = chestData.getFacing(); + BlockFace faceToSecondChest; + if (chestFace == BlockFace.WEST) { + faceToSecondChest = BlockFace.NORTH; + } else if (chestFace == BlockFace.NORTH) { + faceToSecondChest = BlockFace.EAST; + } else if (chestFace == BlockFace.EAST) { + faceToSecondChest = BlockFace.SOUTH; + } else if (chestFace == BlockFace.SOUTH) { + faceToSecondChest = BlockFace.WEST; + } else { + return null; + } + org.bukkit.block.data.type.Chest.Type wantedChestType = org.bukkit.block.data.type.Chest.Type.RIGHT; + if (chestType == org.bukkit.block.data.type.Chest.Type.RIGHT) { + faceToSecondChest = faceToSecondChest.getOppositeFace(); + wantedChestType = org.bukkit.block.data.type.Chest.Type.LEFT; + } + Block face = chestBlock.getRelative(faceToSecondChest); + if (face.getType() == chestBlock.getType()) { + // check is the neighbour connects to this chest + org.bukkit.block.data.type.Chest otherChestData = (org.bukkit.block.data.type.Chest) face.getBlockData(); + if(otherChestData.getType() != wantedChestType || otherChestData.getFacing() != chestFace) { + return null; + } + return face; + } + } + return null; + } } From 33d97ed971431b89cff9300654a0a3a84112caa2 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 2 Aug 2018 02:47:20 +0200 Subject: [PATCH 064/399] Improved + rollbackable interact logging Rollback door openings, comparator, repeater and noteblock modifications and similar things --- .../java/de/diddiz/LogBlock/BlockChange.java | 20 ++++-- src/main/java/de/diddiz/LogBlock/Logging.java | 2 +- .../LogBlock/listeners/InteractLogging.java | 69 ++++++++++++++++--- src/main/java/de/diddiz/util/BukkitUtils.java | 45 ++++++++---- 4 files changed, 107 insertions(+), 29 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index dddfa4b9..491c35fa 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -7,9 +7,14 @@ import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.Note; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Openable; import org.bukkit.block.data.Powerable; +import org.bukkit.block.data.type.Comparator; +import org.bukkit.block.data.type.DaylightDetector; +import org.bukkit.block.data.type.NoteBlock; +import org.bukkit.block.data.type.Repeater; import org.bukkit.block.data.type.Switch; import org.bukkit.inventory.ItemStack; @@ -100,7 +105,7 @@ public String toString() { if (actor != null) { msg.append(actor.getName()).append(" "); } - if (type.equals(replaced)) { + if (type.getMaterial().equals(replaced.getMaterial())) { if (BukkitUtils.isEmpty(type.getMaterial())) { msg.append("did an unspecified action"); } else if (ca != null) { @@ -117,13 +122,20 @@ public String toString() { // Door, Trapdoor, Fence gate msg.append(((Openable)type).isOpen() ? "opened" : "closed").append(" ").append(type.getMaterial().name()); } else if (type.getMaterial() == Material.LEVER) { - msg.append("switched ").append(type.getMaterial().name()); + msg.append("switched ").append(type.getMaterial().name()).append(" ").append(((Switch) type).isPowered() ? "on" : "off"); } else if (type instanceof Switch) { msg.append("pressed ").append(type.getMaterial().name()); } else if (type.getMaterial() == Material.CAKE) { msg.append("ate a piece of ").append(type.getMaterial().name()); - } else if (type.getMaterial() == Material.NOTE_BLOCK || type.getMaterial() == Material.REPEATER || type.getMaterial() == Material.COMPARATOR || type.getMaterial() == Material.DAYLIGHT_DETECTOR) { - msg.append("changed ").append(type.getMaterial().name()); + } else if (type.getMaterial() == Material.NOTE_BLOCK) { + Note note = ((NoteBlock) type).getNote(); + msg.append("set ").append(type.getMaterial().name()).append(" to ").append(note.getTone().name()).append(note.isSharped() ? "#" : ""); + } else if (type.getMaterial() == Material.REPEATER) { + msg.append("set ").append(type.getMaterial().name()).append(" to ").append(((Repeater) type).getDelay()).append(" ticks delay"); + } else if (type.getMaterial() == Material.COMPARATOR) { + msg.append("set ").append(type.getMaterial().name()).append(" to ").append(((Comparator) type).getMode()); + } else if (type.getMaterial() == Material.DAYLIGHT_DETECTOR) { + msg.append("set ").append(type.getMaterial().name()).append(" to ").append(((DaylightDetector) type).isInverted() ? "inverted" : "normal"); } else if (type instanceof Powerable) { msg.append("stepped on ").append(type.getMaterial().name()); } else if (type.getMaterial() == Material.TRIPWIRE) { diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index cd9323d8..b18a5be3 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -8,7 +8,7 @@ public enum Logging { PRESUREPLATEINTERACT, TRIPWIREINTERACT, CREATURECROPTRAMPLE, CROPTRAMPLE, NATURALSTRUCTUREGROW, GRASSGROWTH, MYCELIUMSPREAD, VINEGROWTH, MUSHROOMSPREAD, WITHER(true), WITHER_SKULL(true), BONEMEALSTRUCTUREGROW, WORLDEDIT, TNTMINECARTEXPLOSION(true), - ENDERCRYSTALEXPLOSION(true), BEDEXPLOSION(true), DRAGONEGGTELEPORT(true); + ENDERCRYSTALEXPLOSION(true), BEDEXPLOSION(true), DRAGONEGGTELEPORT(true), DAYLIGHTDETECTORINTERACT; public static final int length = Logging.values().length; private final boolean defaultEnabled; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index 8bfc2113..e0a6b5e4 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -7,10 +7,21 @@ import de.diddiz.util.BukkitUtils; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.Tag; +import org.bukkit.Note; +import org.bukkit.Note.Tone; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; +import org.bukkit.block.data.Bisected.Half; import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Openable; +import org.bukkit.block.data.type.Cake; +import org.bukkit.block.data.type.Comparator; +import org.bukkit.block.data.type.Comparator.Mode; +import org.bukkit.block.data.type.DaylightDetector; +import org.bukkit.block.data.type.Door; +import org.bukkit.block.data.type.NoteBlock; +import org.bukkit.block.data.type.Repeater; +import org.bukkit.block.data.type.Switch; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -51,27 +62,52 @@ public void onPlayerInteract(PlayerInteractEvent event) { case ACACIA_TRAPDOOR: case DARK_OAK_TRAPDOOR: if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + Openable newBlockData = (Openable) blockData.clone(); + newBlockData.setOpen(!newBlockData.isOpen()); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); } break; case CAKE: if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + Cake newBlockData = (Cake) blockData.clone(); + if (newBlockData.getBites() < 6) { + newBlockData.setBites(newBlockData.getBites() + 1); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } else { + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.AIR.createBlockData()); + } } break; case NOTE_BLOCK: if (wcfg.isLogging(Logging.NOTEBLOCKINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + NoteBlock newBlockData = (NoteBlock) blockData.clone(); + if (newBlockData.getNote().getOctave() == 2) { + newBlockData.setNote(new Note(0, Tone.F, true)); + } else { + newBlockData.setNote(newBlockData.getNote().sharped()); + } + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); } break; case REPEATER: if (wcfg.isLogging(Logging.DIODEINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + Repeater newBlockData = (Repeater) blockData.clone(); + newBlockData.setDelay((newBlockData.getDelay() % 4) + 1); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); } break; case COMPARATOR: if (wcfg.isLogging(Logging.COMPARATORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + Comparator newBlockData = (Comparator) blockData.clone(); + newBlockData.setMode(newBlockData.getMode() == Mode.COMPARE ? Mode.SUBTRACT : Mode.COMPARE); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + break; + case DAYLIGHT_DETECTOR: + if (wcfg.isLogging(Logging.DAYLIGHTDETECTORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + DaylightDetector newBlockData = (DaylightDetector) blockData.clone(); + newBlockData.setInverted(!newBlockData.isInverted()); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); } break; case OAK_PRESSURE_PLATE: @@ -104,14 +140,27 @@ public void onPlayerInteract(PlayerInteractEvent event) { } break; default: - if (Tag.BUTTONS.isTagged(type) || type == Material.LEVER) { + if (BukkitUtils.isButton(type) || type == Material.LEVER) { if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + Switch newBlockData = (Switch) blockData.clone(); + if (!newBlockData.isPowered() || type == Material.LEVER) { + newBlockData.setPowered(!newBlockData.isPowered()); + } + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); } } - if (Tag.WOODEN_DOORS.isTagged(type)) { + if (BukkitUtils.isWoodenDoor(type)) { if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + Door newBlockData = (Door) blockData.clone(); + newBlockData.setOpen(!newBlockData.isOpen()); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + Block otherBlock = clicked.getRelative(newBlockData.getHalf() == Half.TOP ? BlockFace.DOWN : BlockFace.UP); + if (otherBlock.getType() == type) { + BlockData blockData2 = otherBlock.getBlockData(); + Door newBlockData2 = (Door) blockData2.clone(); + newBlockData2.setOpen(!newBlockData2.isOpen()); + consumer.queueBlock(Actor.actorFromEntity(player), otherBlock.getLocation(), blockData2, newBlockData2); + } } } } diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index c431ee53..8e0aa149 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -43,9 +43,12 @@ public class BukkitUtils { private static final Set bedBlocks; private static final Map projectileItems; + private static final EnumSet buttons; + private static final EnumSet pressurePlates; + private static final EnumSet woodenDoors; static { - EnumSet pressurePlates = EnumSet.noneOf(Material.class); + pressurePlates = EnumSet.noneOf(Material.class); pressurePlates.add(Material.OAK_PRESSURE_PLATE); pressurePlates.add(Material.SPRUCE_PRESSURE_PLATE); pressurePlates.add(Material.BIRCH_PRESSURE_PLATE); @@ -56,6 +59,14 @@ public class BukkitUtils { pressurePlates.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); pressurePlates.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); + woodenDoors = EnumSet.noneOf(Material.class); + woodenDoors.add(Material.OAK_DOOR); + woodenDoors.add(Material.SPRUCE_DOOR); + woodenDoors.add(Material.BIRCH_DOOR); + woodenDoors.add(Material.JUNGLE_DOOR); + woodenDoors.add(Material.ACACIA_DOOR); + woodenDoors.add(Material.DARK_OAK_DOOR); + EnumSet saplings = EnumSet.noneOf(Material.class); saplings.add(Material.OAK_SAPLING); saplings.add(Material.SPRUCE_SAPLING); @@ -103,6 +114,15 @@ public class BukkitUtils { slabs.add(Material.DARK_PRISMARINE_SLAB); slabs.add(Material.PRISMARINE_BRICK_SLAB); + buttons = EnumSet.noneOf(Material.class); + buttons.add(Material.STONE_BUTTON); + buttons.add(Material.OAK_BUTTON); + buttons.add(Material.SPRUCE_BUTTON); + buttons.add(Material.BIRCH_BUTTON); + buttons.add(Material.JUNGLE_BUTTON); + buttons.add(Material.ACACIA_BUTTON); + buttons.add(Material.DARK_OAK_BUTTON); + singleBlockPlants = EnumSet.noneOf(Material.class); singleBlockPlants.add(Material.GRASS); singleBlockPlants.add(Material.FERN); @@ -142,13 +162,7 @@ public class BukkitUtils { relativeBreakable = EnumSet.noneOf(Material.class); relativeBreakable.add(Material.WALL_SIGN); relativeBreakable.add(Material.LADDER); - relativeBreakable.add(Material.STONE_BUTTON); - relativeBreakable.add(Material.OAK_BUTTON); - relativeBreakable.add(Material.SPRUCE_BUTTON); - relativeBreakable.add(Material.BIRCH_BUTTON); - relativeBreakable.add(Material.JUNGLE_BUTTON); - relativeBreakable.add(Material.ACACIA_BUTTON); - relativeBreakable.add(Material.DARK_OAK_BUTTON); + relativeBreakable.addAll(buttons); relativeBreakable.add(Material.REDSTONE_WALL_TORCH); relativeBreakable.add(Material.LEVER); relativeBreakable.add(Material.WALL_TORCH); @@ -180,12 +194,7 @@ public class BukkitUtils { relativeTopBreakable.add(Material.WALL_TORCH); relativeTopBreakable.add(Material.REDSTONE_TORCH); relativeTopBreakable.add(Material.REDSTONE_WALL_TORCH); - relativeTopBreakable.add(Material.OAK_DOOR); - relativeTopBreakable.add(Material.SPRUCE_DOOR); - relativeTopBreakable.add(Material.BIRCH_DOOR); - relativeTopBreakable.add(Material.JUNGLE_DOOR); - relativeTopBreakable.add(Material.ACACIA_DOOR); - relativeTopBreakable.add(Material.DARK_OAK_DOOR); + relativeTopBreakable.addAll(woodenDoors); relativeTopBreakable.add(Material.IRON_DOOR); relativeTopBreakable.addAll(carpets); relativeTopBreakable.addAll(doublePlants); @@ -577,6 +586,14 @@ public static boolean isDoublePlant(Material m) { return doublePlants.contains(m); } + public static boolean isWoodenDoor(Material m) { + return woodenDoors.contains(m); + } + + public static boolean isButton(Material m) { + return buttons.contains(m); + } + public static boolean isEmpty(Material m) { return m == Material.AIR || m == Material.CAVE_AIR || m == Material.VOID_AIR; } From d8e53173e01eb62818167cc5f0a242b0c1c588a4 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 2 Aug 2018 03:43:18 +0200 Subject: [PATCH 065/399] Set default time limit also for lookups Fixes #309 --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index fa37d8b5..e6540766 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -337,7 +337,11 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, if (command.equals("lookup")) { argsList.remove(0); } - new CommandLookup(sender, new QueryParams(logblock, sender, argsList), true); + final QueryParams params = new QueryParams(logblock); + params.since = defaultTime; + params.bct = BlockChangeType.ALL; + params.parseArgs(sender, argsList); + new CommandLookup(sender, params, true); } else { sender.sendMessage(ChatColor.RED + "You aren't allowed to do this"); } From 680db124a97a8153f63475000fbf6785967da41f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 2 Aug 2018 05:14:26 +0200 Subject: [PATCH 066/399] Build on java 8 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 89122a1d..a20cdb5a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: java jdk: - - oraclejdk7 + - oraclejdk8 notifications: email: false From cc939ab41304647440adfe0aa936f7a09293d528 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 2 Aug 2018 05:28:09 +0200 Subject: [PATCH 067/399] Spaces instead of tabs in the pom.xml --- pom.xml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index c88b5e34..f1d5d840 100644 --- a/pom.xml +++ b/pom.xml @@ -158,17 +158,17 @@ shade - - - com.zaxxer.hikari - de.diddiz.lib.com.zaxxer.hikari - - - org.slf4j - de.diddiz.lib.org.slf4j - - - + + + com.zaxxer.hikari + de.diddiz.lib.com.zaxxer.hikari + + + org.slf4j + de.diddiz.lib.org.slf4j + + + From ecae2abaf0433069830a9040dc7ad8dc788f1d02 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 01:01:54 +0200 Subject: [PATCH 068/399] Tags are still evil --- src/main/java/de/diddiz/util/BukkitUtils.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 8e0aa149..10917021 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -46,6 +46,7 @@ public class BukkitUtils { private static final EnumSet buttons; private static final EnumSet pressurePlates; private static final EnumSet woodenDoors; + private static final EnumSet slabs; static { pressurePlates = EnumSet.noneOf(Material.class); @@ -93,7 +94,7 @@ public class BukkitUtils { carpets.add(Material.WHITE_CARPET); carpets.add(Material.YELLOW_CARPET); - EnumSet slabs = EnumSet.noneOf(Material.class); + slabs = EnumSet.noneOf(Material.class); slabs.add(Material.OAK_SLAB); slabs.add(Material.SPRUCE_SLAB); slabs.add(Material.BIRCH_SLAB); @@ -564,7 +565,7 @@ public static boolean canFallIn(World world, int x, int y, int z) { if (canDirectlyFallIn(mat)) { return true; } else if (getFallingEntityKillers().contains(mat) || singleBlockPlants.contains(mat) || mat == Material.VINE) { - if (Tag.SLABS.isTagged(mat)) { + if (slabs.contains(mat)) { if (((Slab) block.getBlockData()).getType() != Type.BOTTOM) { return false; } From 39a0fbeafa2eec1f44b79b2bb7fe13734bceb0be Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 01:02:18 +0200 Subject: [PATCH 069/399] Set default time for tools in the config --- src/main/java/de/diddiz/LogBlock/config/Config.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 51c6048b..0a996cca 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -120,7 +120,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("tools.tool.defaultEnabled", true); def.put("tools.tool.item", Material.WOODEN_PICKAXE.name()); def.put("tools.tool.canDrop", true); - def.put("tools.tool.params", "area 0 all sum none limit 15 desc silent"); + def.put("tools.tool.params", "area 0 all sum none limit 15 desc since 60d silent"); def.put("tools.tool.mode", "LOOKUP"); def.put("tools.tool.permissionDefault", "OP"); def.put("tools.toolblock.aliases", Arrays.asList("tb")); @@ -129,7 +129,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("tools.toolblock.defaultEnabled", true); def.put("tools.toolblock.item", Material.BEDROCK.name()); def.put("tools.toolblock.canDrop", false); - def.put("tools.toolblock.params", "area 0 all sum none limit 15 desc silent"); + def.put("tools.toolblock.params", "area 0 all sum none limit 15 desc since 60d silent"); def.put("tools.toolblock.mode", "LOOKUP"); def.put("tools.toolblock.permissionDefault", "OP"); def.put("safety.id.check", true); From e98910615fd207c2fcafe0d6eb5804cf646c2325 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 01:03:07 +0200 Subject: [PATCH 070/399] Not all bisected blocks are double blocks --- src/main/java/de/diddiz/LogBlock/WorldEditor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 17180148..73e5fa71 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -221,7 +221,7 @@ PerformResult perform() throws WorldEditorException { bed2.setPart(bed.getPart() == Part.HEAD ? Part.FOOT : Part.HEAD); secBlock.setBlockData(bed2); } - } else if (newData instanceof Bisected) { + } else if (curtype == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(curtype) || BukkitUtils.isDoublePlant(curtype)) { final Bisected firstPart = (Bisected) newData; final Block secBlock = block.getRelative(firstPart.getHalf() == Half.TOP ? BlockFace.DOWN : BlockFace.UP); if (secBlock.isEmpty()) { From f85dbdbbdf1ad51f3fd168cba08c5c33cc4dfe8a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 01:03:36 +0200 Subject: [PATCH 071/399] Logging both halfes of a door on interact was a bad idea --- .../de/diddiz/LogBlock/listeners/InteractLogging.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index e0a6b5e4..18a3b95c 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -11,7 +11,6 @@ import org.bukkit.Note.Tone; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; -import org.bukkit.block.data.Bisected.Half; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Openable; import org.bukkit.block.data.type.Cake; @@ -154,13 +153,6 @@ public void onPlayerInteract(PlayerInteractEvent event) { Door newBlockData = (Door) blockData.clone(); newBlockData.setOpen(!newBlockData.isOpen()); consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - Block otherBlock = clicked.getRelative(newBlockData.getHalf() == Half.TOP ? BlockFace.DOWN : BlockFace.UP); - if (otherBlock.getType() == type) { - BlockData blockData2 = otherBlock.getBlockData(); - Door newBlockData2 = (Door) blockData2.clone(); - newBlockData2.setOpen(!newBlockData2.isOpen()); - consumer.queueBlock(Actor.actorFromEntity(player), otherBlock.getLocation(), blockData2, newBlockData2); - } } } } From 3d1f57cc7925f868e31d7979c1e16a325a3af2de Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 01:04:02 +0200 Subject: [PATCH 072/399] ServerPrepStmts ftw --- src/main/java/de/diddiz/util/MySQLConnectionPool.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/diddiz/util/MySQLConnectionPool.java b/src/main/java/de/diddiz/util/MySQLConnectionPool.java index 7db615a3..3727cd9a 100644 --- a/src/main/java/de/diddiz/util/MySQLConnectionPool.java +++ b/src/main/java/de/diddiz/util/MySQLConnectionPool.java @@ -28,6 +28,7 @@ public MySQLConnectionPool(String url, String user, String password) { ds.addDataSourceProperty("cachePrepStmts", "true"); ds.addDataSourceProperty("prepStmtCacheSize", "250"); ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); + ds.addDataSourceProperty("useServerPrepStmts", "true"); } @Override From a853230c8d4466a5341d98331f25dea2aff3b049 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 01:04:38 +0200 Subject: [PATCH 073/399] I don't like tags --- src/main/java/de/diddiz/util/LoggingUtil.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index 8848e3d4..c5026224 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -6,7 +6,6 @@ import de.diddiz.LogBlock.config.WorldConfig; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; @@ -112,14 +111,14 @@ public static void smartLogBlockBreak(Consumer consumer, Actor actor, Block orig if (BukkitUtils.getRelativeTopBreakabls().contains(checkBlock.getType())) { if (wcfg.isLogging(Logging.SIGNTEXT) && checkBlock.getType() == Material.SIGN) { consumer.queueSignBreak(actor, (Sign) checkBlock.getState()); - } else if (checkBlock.getType() == Material.IRON_DOOR || Tag.WOODEN_DOORS.isTagged(checkBlock.getType())) { + } else if (checkBlock.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(checkBlock.getType())) { Block doorBlock = checkBlock; // If the doorBlock is the top half a door the player simply punched a door // this will be handled later. if (!BukkitUtils.isTop(doorBlock.getBlockData())) { doorBlock = doorBlock.getRelative(BlockFace.UP); // Fall back check just in case the top half wasn't a door - if (doorBlock.getType() == Material.IRON_DOOR || Tag.WOODEN_DOORS.isTagged(doorBlock.getType())) { + if (doorBlock.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(doorBlock.getType())) { consumer.queueBlockBreak(actor, doorBlock.getState()); } consumer.queueBlockBreak(actor, checkBlock.getState()); @@ -159,7 +158,7 @@ public static void smartLogBlockBreak(Consumer consumer, Actor actor, Block orig } // Special door check - if (origin.getType() == Material.IRON_DOOR || Tag.WOODEN_DOORS.isTagged(origin.getType())) { + if (origin.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(origin.getType())) { Block doorBlock = origin; // Up or down? @@ -169,7 +168,7 @@ public static void smartLogBlockBreak(Consumer consumer, Actor actor, Block orig doorBlock = doorBlock.getRelative(BlockFace.DOWN); } - if (doorBlock.getType() == Material.IRON_DOOR || Tag.WOODEN_DOORS.isTagged(doorBlock.getType())) { + if (doorBlock.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(doorBlock.getType())) { consumer.queueBlockBreak(actor, doorBlock.getState()); } } else if (BukkitUtils.isDoublePlant(origin.getType())) { // Special double plant check From 1878b94781ce21bdf5eed0efe2e4068e194a3d16 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 01:35:33 +0200 Subject: [PATCH 074/399] Use batch import for dumped files, its much faster --- .../de/diddiz/LogBlock/DumpedLogImporter.java | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java b/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java index 42af3ed9..56cf5b87 100644 --- a/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java +++ b/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java @@ -32,26 +32,37 @@ public void run() { final Statement st = conn.createStatement(); final BufferedWriter writer = new BufferedWriter(new FileWriter(new File(logblock.getDataFolder(), "import/failed.txt"))); int successes = 0, errors = 0; - for (final File sqlFile : imports) { - logblock.getLogger().info("Trying to import " + sqlFile.getName() + " ..."); - final BufferedReader reader = new BufferedReader(new FileReader(sqlFile)); - String line; - while ((line = reader.readLine()) != null) { + try { + for (final File sqlFile : imports) { + String line = null; try { - st.execute(line); - successes++; + logblock.getLogger().info("Trying to import " + sqlFile.getName() + " ..."); + final BufferedReader reader = new BufferedReader(new FileReader(sqlFile)); + while ((line = reader.readLine()) != null) { + if (line.endsWith(";")) { + line = line.substring(0, line.length() - 1); + } + if(!line.isEmpty()) { + st.addBatch(line); + successes++; + } + } + st.executeBatch(); + conn.commit(); + reader.close(); + sqlFile.delete(); + logblock.getLogger().info("Successfully imported " + sqlFile.getName() + "."); } catch (final Exception ex) { logblock.getLogger().warning("Error while importing: '" + line + "': " + ex.getMessage()); writer.write(line + newline); errors++; + ex.printStackTrace(); + return; } } - conn.commit(); - reader.close(); - sqlFile.delete(); - logblock.getLogger().info("Successfully imported " + sqlFile.getName() + "."); + } finally { + writer.close(); } - writer.close(); st.close(); logblock.getLogger().info("Successfully imported stored queue. (" + successes + " rows imported, " + errors + " errors)"); } catch (final Exception ex) { From a37dd9cff138722856ee827f3f264beaf69f8f53 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 01:42:15 +0200 Subject: [PATCH 075/399] Material mappings don't use the consumer any more --- src/main/java/de/diddiz/LogBlock/Updater.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 34822b16..ede62551 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -493,7 +493,6 @@ boolean update() { deleteStatement.executeBatch(); } conn.commit(); - logblock.getConsumer().run(); // force a consumer run to save new material mappings logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); } insertStatement.close(); @@ -592,7 +591,6 @@ boolean update() { if (anyUpdate) { updateWeaponStatement.executeBatch(); conn.commit(); - logblock.getConsumer().run(); // force a consumer run to save new material mappings } logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); if (!anyRow) { From 60a049ed49ba731d187026d4d8082b42a8b1e13c Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 01:53:28 +0200 Subject: [PATCH 076/399] Rewrite the Consumer to be more stable and much faster - Use prepared statements and batching for all inserts - There is now one continuously running Consumer thread - Use proper synchronization Fixes #712, Fixes #710 Its a large rewrite so there could still be bugs.. --- .../de/diddiz/LogBlock/CommandsHandler.java | 18 +- .../java/de/diddiz/LogBlock/Consumer.java | 738 +++++++++--------- .../java/de/diddiz/LogBlock/LogBlock.java | 41 +- src/main/java/de/diddiz/util/Utils.java | 7 + 4 files changed, 366 insertions(+), 438 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index e6540766..ec8d8a82 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -562,20 +562,7 @@ public CommandSaveQueue(CommandSender sender, QueryParams params, boolean async) @Override public void run() { final Consumer consumer = logblock.getConsumer(); - if (consumer.getQueueSize() > 0) { - sender.sendMessage(ChatColor.DARK_AQUA + "Current queue size: " + consumer.getQueueSize()); - int lastSize = -1, fails = 0; - while (consumer.getQueueSize() > 0) { - fails = lastSize == consumer.getQueueSize() ? fails + 1 : 0; - if (fails > 10) { - sender.sendMessage(ChatColor.RED + "Unable to save queue"); - return; - } - lastSize = consumer.getQueueSize(); - consumer.run(); - } - sender.sendMessage(ChatColor.GREEN + "Queue saved successfully"); - } + sender.sendMessage(ChatColor.DARK_AQUA + "Current queue size: " + consumer.getQueueSize()); } } @@ -662,9 +649,6 @@ public void run() { if (!checkRestrictions(sender, params)) { return; } - if (logblock.getConsumer().getQueueSize() > 0) { - new CommandSaveQueue(sender, null, false); - } if (!params.silent) { sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); } diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 047e0744..f1d793ed 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -1,10 +1,32 @@ package de.diddiz.LogBlock; -import de.diddiz.LogBlock.blockstate.BlockStateCodecSign; -import de.diddiz.LogBlock.blockstate.BlockStateCodecs; -import de.diddiz.LogBlock.config.Config; -import de.diddiz.LogBlock.events.BlockChangePreLogEvent; -import de.diddiz.util.Utils; +import static de.diddiz.LogBlock.config.Config.getWorldConfig; +import static de.diddiz.LogBlock.config.Config.hiddenBlocks; +import static de.diddiz.LogBlock.config.Config.hiddenPlayers; +import static de.diddiz.LogBlock.config.Config.isLogged; +import static de.diddiz.LogBlock.config.Config.logPlayerInfo; +import static de.diddiz.util.BukkitUtils.compressInventory; +import static de.diddiz.util.BukkitUtils.itemIDfromProjectileEntity; +import static de.diddiz.util.Utils.mysqlTextEscape; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.logging.Level; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -20,26 +42,22 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.projectiles.ProjectileSource; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintWriter; -import java.sql.*; -import java.util.*; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.logging.Level; - -import static de.diddiz.LogBlock.config.Config.*; -import static de.diddiz.util.Utils.mysqlTextEscape; -import static de.diddiz.util.BukkitUtils.*; +import de.diddiz.LogBlock.blockstate.BlockStateCodecSign; +import de.diddiz.LogBlock.blockstate.BlockStateCodecs; +import de.diddiz.LogBlock.config.Config; +import de.diddiz.LogBlock.events.BlockChangePreLogEvent; +import de.diddiz.util.Utils; -public class Consumer extends TimerTask { - private final Queue queue = new LinkedBlockingQueue(); +public class Consumer extends Thread { + private final Deque queue = new ArrayDeque(); private final Set failedPlayers = new HashSet(); private final LogBlock logblock; private final Map playerIds = new HashMap(); - private final Lock lock = new ReentrantLock(); + private long addEntryCounter; + private long nextWarnCounter; + + private boolean shutdown; + private long shutdownInitialized; Consumer(LogBlock logblock) { this.logblock = logblock; @@ -309,7 +327,7 @@ public void queueKill(Location location, Actor killer, Actor victim, ItemStack w if (victim == null || !isLogged(location.getWorld())) { return; } - queue.add(new KillRow(location, killer == null ? null : killer, victim, weapon == null ? 0 : MaterialConverter.getOrAddMaterialId(weapon.getType().getKey().toString()))); + addQueueLast(new KillRow(location, killer == null ? null : killer, victim, weapon == null ? 0 : MaterialConverter.getOrAddMaterialId(weapon.getType().getKey().toString()))); } /** @@ -387,127 +405,152 @@ public void queueChat(Actor player, String message) { if (hiddenPlayers.contains(player.getName().toLowerCase())) { return; } - queue.add(new ChatRow(player, message)); + addQueueLast(new ChatRow(player, message)); } public void queueJoin(Player player) { - queue.add(new PlayerJoinRow(player)); + addQueueLast(new PlayerJoinRow(player)); } public void queueLeave(Player player, long onlineTime) { - queue.add(new PlayerLeaveRow(player, onlineTime)); + addQueueLast(new PlayerLeaveRow(player, onlineTime)); } - @Override - public synchronized void run() { - if (queue.isEmpty() || !lock.tryLock()) { - return; + public void shutdown() { + synchronized (queue) { + shutdown = true; + shutdownInitialized = System.currentTimeMillis(); + queue.notifyAll(); } - long startTime = System.currentTimeMillis(); - // int startSize = queue.size(); - int count = 0; - Connection conn = null; - Statement state = null; - try { - - conn = logblock.getConnection(); - if (Config.queueWarningSize > 0 && queue.size() >= Config.queueWarningSize) { - logblock.getLogger().info("[Consumer] Queue overloaded. Size: " + getQueueSize()); + while (isAlive()) { + try { + join(); + } catch (InterruptedException e) { + // ignore } + } + } - if (conn == null) { - return; - } - conn.setAutoCommit(false); - state = conn.createStatement(); - final long start = System.currentTimeMillis(); - process: while (!queue.isEmpty() && (System.currentTimeMillis() - start < timePerRun || count < forceToProcessAtLeast)) { - final Row r = queue.poll(); - if (r == null) { - continue; - } - for (final Actor actor : r.getActors()) { - if (!playerIds.containsKey(actor)) { - if (!addPlayer(state, actor)) { - if (!failedPlayers.contains(actor)) { - failedPlayers.add(actor); - logblock.getLogger().warning("[Consumer] Failed to add player " + actor.getName()); - } - continue process; + @Override + public void run() { + ArrayList currentRows = new ArrayList<>(); + Connection conn = null; + BatchHelper batchHelper = new BatchHelper(); + while (true) { + try { + if (conn == null) { + conn = logblock.getConnection(); + if (conn != null) { + // initialize connection + conn.setAutoCommit(false); + } else { + // we did not get a connection + boolean wantsShutdown; + synchronized (queue) { + wantsShutdown = shutdown; + } + if (wantsShutdown) { + // lets give up + break; + } + // wait for a connection + logblock.getLogger().severe("[Consumer] Could not connect to the database!"); + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + // ignore } + continue; } } - if (r instanceof PreparedStatementRow) { - PreparedStatementRow PSRow = (PreparedStatementRow) r; - if (r instanceof MergeableRow) { - int batchCount = count; - // if we've reached our row target but not exceeded our time target, allow merging of up to 50% of our row limit more rows - if (count > forceToProcessAtLeast) { - batchCount = forceToProcessAtLeast / 2; - } - while (!queue.isEmpty()) { - MergeableRow mRow = (MergeableRow) PSRow; - Row s = queue.peek(); - if (s == null) { + Row r; + boolean processBatch = false; + synchronized (queue) { + if (shutdown) { + // Give this thread some time to process the remaining entries + if (queue.isEmpty() || System.currentTimeMillis() - shutdownInitialized > 20000) { + if (currentRows.isEmpty()) { break; + } else { + processBatch = true; } - if (!(s instanceof MergeableRow)) { - break; + } + } + r = queue.pollFirst(); + if (r == null) { + try { + if (currentRows.isEmpty() && !shutdown) { + queue.wait(); // nothing to do for us + } else { + processBatch = true; } - MergeableRow mRow2 = (MergeableRow) s; - if (mRow.canMerge(mRow2)) { - PSRow = mRow.merge((MergeableRow) queue.poll()); - count++; - batchCount++; - if (batchCount > forceToProcessAtLeast) { - break; + } catch (InterruptedException e) { + // ignore + } + } + } + if (r != null) { + boolean failOnActors = false; + for (final Actor actor : r.getActors()) { + if (!playerIds.containsKey(actor)) { + if (!addPlayer(conn, actor)) { + if (failedPlayers.add(actor)) { + logblock.getLogger().warning("[Consumer] Failed to add player " + actor.getName()); } - } else { - break; + failOnActors = true; // skip this row } } } - PSRow.setConnection(conn); - try { - PSRow.executeStatements(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Consumer] SQL exception on insertion: ", ex); - break; + if (!failOnActors) { + currentRows.add(r); } - } else { - for (final String insert : r.getInserts()) { - try { - state.execute(insert); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Consumer] SQL exception on " + insert + ": ", ex); - break process; + r.process(conn, batchHelper); + } + if (currentRows.size() >= (processBatch ? 1 : (Config.forceToProcessAtLeast * 10))) { + batchHelper.processStatements(conn); + conn.commit(); + currentRows.clear(); + } + } catch (Exception e) { + logblock.getLogger().log(Level.SEVERE, "[Consumer] Could not insert entries!", e); + boolean retry = false; + if (e instanceof SQLException) { + // Retry on network errors: SQLSTATE = 08S01 08001 08004 HY000 40001 + String state = ((SQLException) e).getSQLState(); + retry = state != null && (state.equals("08S01") || state.equals("08001") || state.equals("08004") || state.equals("HY000") || state.equals("40001")); + } + if (retry) { + // readd rows to the queue + synchronized (queue) { + while (!currentRows.isEmpty()) { + queue.addFirst(currentRows.remove(currentRows.size() - 1)); } } } - - count++; - } - conn.commit(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Consumer] SQL exception", ex); - } finally { - try { - if (state != null) { - state.close(); - } + currentRows.clear(); + batchHelper.reset(); if (conn != null) { - conn.close(); + try { + conn.close(); + } catch (SQLException e1) { + // ignore + } } - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Consumer] SQL exception on close", ex); + conn = null; + } + } + if (conn != null) { + try { + conn.close(); + } catch (SQLException e1) { + // ignore } - lock.unlock(); + } - if (debug) { - long timeElapsed = System.currentTimeMillis() - startTime; - float rowPerTime = count / timeElapsed; - logblock.getLogger().log(Level.INFO, "[Consumer] Finished consumer cycle in " + timeElapsed + " milliseconds."); - logblock.getLogger().log(Level.INFO, "[Consumer] Total rows processed: " + count + ". row/time: " + String.format("%.4f", rowPerTime)); + // readd to queue - this can be saved later + synchronized (queue) { + while (!currentRows.isEmpty()) { + queue.addFirst(currentRows.remove(currentRows.size() - 1)); } } } @@ -518,8 +561,8 @@ public void writeToFile() throws FileNotFoundException { int counter = 0; new File("plugins/LogBlock/import/").mkdirs(); PrintWriter writer = new PrintWriter(new File("plugins/LogBlock/import/queue-" + time + "-0.sql")); - while (!queue.isEmpty()) { - final Row r = queue.poll(); + while (!isQueueEmpty()) { + final Row r = pollQueueFirst(); if (r == null) { continue; } @@ -543,7 +586,36 @@ public void writeToFile() throws FileNotFoundException { } int getQueueSize() { - return queue.size(); + synchronized (queue) { + return queue.size(); + } + } + + private boolean isQueueEmpty() { + synchronized (queue) { + return queue.isEmpty(); + } + } + + private void addQueueLast(Row row) { + synchronized (queue) { + boolean wasEmpty = queue.isEmpty(); + queue.addLast(row); + addEntryCounter++; + if (Config.queueWarningSize > 0 && queue.size() >= Config.queueWarningSize && addEntryCounter >= nextWarnCounter) { + logblock.getLogger().warning("[Consumer] Queue overloaded. Size: " + queue.size()); + nextWarnCounter = addEntryCounter + 1000; + } + if (wasEmpty) { + queue.notifyAll(); + } + } + } + + private Row pollQueueFirst() { + synchronized (queue) { + return queue.pollFirst(); + } } static void hide(Player player) { @@ -564,16 +636,18 @@ static boolean toggleHide(Player player) { return true; } - private boolean addPlayer(Statement state, Actor actor) throws SQLException { + private boolean addPlayer(Connection conn, Actor actor) throws SQLException { // Odd query contruction is to work around innodb auto increment behaviour - bug #492 String name = actor.getName(); String uuid = actor.getUUID(); + Statement state = conn.createStatement(); state.execute("INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + mysqlTextEscape(name) + "','" + uuid + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + uuid + "') LIMIT 1;"); final ResultSet rs = state.executeQuery("SELECT playerid FROM `lb-players` WHERE UUID = '" + uuid + "'"); if (rs.next()) { playerIds.put(actor, rs.getInt(1)); } rs.close(); + state.close(); return playerIds.containsKey(actor); } @@ -612,7 +686,7 @@ private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDa int typeMaterialId = MaterialConverter.getOrAddMaterialId(typeString); int typeStateId = MaterialConverter.getOrAddBlockStateId(typeString); - queue.add(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, stateBefore, typeMaterialId, typeStateId, stateAfter, ca)); + addQueueLast(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, stateBefore, typeMaterialId, typeStateId, stateAfter, ca)); } private String playerID(Actor actor) { @@ -636,34 +710,19 @@ private Integer playerIDAsInt(Actor actor) { private static interface Row { String[] getInserts(); - /** - * @deprecated - Names are not guaranteed to be unique. Use {@link #getActors() } - */ - String[] getPlayers(); + void process(Connection conn, BatchHelper batchHelper) throws SQLException; Actor[] getActors(); } - private interface PreparedStatementRow extends Row { - - abstract void setConnection(Connection connection); - - abstract void executeStatements() throws SQLException; - } - - private interface MergeableRow extends PreparedStatementRow { - abstract boolean isUnique(); - - abstract boolean canMerge(MergeableRow row); - - abstract MergeableRow merge(MergeableRow second); - } - - private class BlockRow extends BlockChange implements MergeableRow { - private Connection connection; + private class BlockRow extends BlockChange implements Row { + final String statementString; public BlockRow(Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { super(System.currentTimeMillis() / 1000, loc, actor, replaced, replacedData, replacedState, type, typeData, typeState, ca); + + final String table = getWorldConfig(loc.getWorld()).table; + statementString = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"; } @Override @@ -674,210 +733,52 @@ public String[] getInserts() { inserts[0] = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(actor) + ", " + replacedMaterial + ", " + replacedData + ", " + typeMaterial + ", " + typeData + ", '" + loc.getBlockX() + "', " + safeY(loc) + ", '" + loc.getBlockZ() + "');"; if (replacedState != null || typeState != null) { - inserts[1] = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES('" + Utils.mysqlEscapeBytes(replacedState) + "', '" + Utils.mysqlEscapeBytes(typeState) + "', LAST_INSERT_ID());"; + inserts[1] = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(" + Utils.mysqlPrepareBytesForInsertAllowNull(replacedState) + ", " + Utils.mysqlPrepareBytesForInsertAllowNull(typeState) + ", LAST_INSERT_ID());"; } else if (ca != null) { inserts[1] = "INSERT INTO `" + table + "-chestdata` (id, item, itemremove, itemtype) values (LAST_INSERT_ID(), '" + Utils.mysqlEscapeBytes(Utils.saveItemStack(ca.itemStack)) + "', " + (ca.remove ? 1 : 0) + ", " + ca.itemType + ");"; } return inserts; } - @Override - public String[] getPlayers() { - return new String[] { actor.getName() }; - } - @Override public Actor[] getActors() { return new Actor[] { actor }; } @Override - public void setConnection(Connection connection) { - this.connection = connection; - } - - @Override - public void executeStatements() throws SQLException { - final String table = getWorldConfig(loc.getWorld()).table; - - PreparedStatement ps1 = null; - PreparedStatement ps = null; - try { - ps1 = connection.prepareStatement("INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replacedData, type, typeData, x, y, z) VALUES(FROM_UNIXTIME(?), " + playerID(actor) + ", ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); - ps1.setLong(1, date); - ps1.setInt(2, replacedMaterial); - ps1.setInt(3, replacedData); - ps1.setInt(4, typeMaterial); - ps1.setInt(5, typeData); - ps1.setInt(6, loc.getBlockX()); - ps1.setInt(7, safeY(loc)); - ps1.setInt(8, loc.getBlockZ()); - ps1.executeUpdate(); - - int id; - ResultSet rs = ps1.getGeneratedKeys(); - rs.next(); - id = rs.getInt(1); - - if (typeState != null || replacedState != null) { - ps = connection.prepareStatement("INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(?, ?, ?)"); - ps.setBytes(1, replacedState); - ps.setBytes(2, typeState); - ps.setInt(3, id); - ps.executeUpdate(); - } else if (ca != null) { - ps = connection.prepareStatement("INSERT INTO `" + table + "-chestdata` (item, itemremove, id, itemtype) values (?, ?, ?, ?)"); - ps.setBytes(1, Utils.saveItemStack(ca.itemStack)); - ps.setInt(2, ca.remove ? 1 : 0); - ps.setInt(3, id); - ps.setInt(4, ca.itemType); - ps.executeUpdate(); - } - } catch (final SQLException ex) { - if (ps1 != null) { - logblock.getLogger().log(Level.SEVERE, "[Consumer] Troublesome query: " + ps1.toString()); - } - if (ps != null) { - logblock.getLogger().log(Level.SEVERE, "[Consumer] Troublesome query: " + ps.toString()); - } - throw ex; - } finally { - // individual try/catch here, though ugly, prevents resource leaks - if (ps1 != null) { - try { - ps1.close(); - } catch (SQLException e) { - // ideally should log to logger, none is available in this class - // at the time of this writing, so I'll leave that to the plugin - // maintainers to integrate if they wish - e.printStackTrace(); - } - } - - if (ps != null) { - try { - ps.close(); - } catch (SQLException e) { - e.printStackTrace(); + public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.RETURN_GENERATED_KEYS); + smt.setLong(1, date); + smt.setInt(2, playerIDAsInt(actor)); + smt.setInt(3, replacedMaterial); + smt.setInt(4, replacedData); + smt.setInt(5, typeMaterial); + smt.setInt(6, typeData); + smt.setInt(7, loc.getBlockX()); + smt.setInt(8, safeY(loc)); + smt.setInt(9, loc.getBlockZ()); + batchHelper.addBatch(smt, new IntCallback() { + @Override + public void call(int id) throws SQLException { + final String table = getWorldConfig(loc.getWorld()).table; + PreparedStatement ps; + if (typeState != null || replacedState != null) { + ps = batchHelper.getOrPrepareStatement(conn, "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(?, ?, ?)", Statement.NO_GENERATED_KEYS); + ps.setBytes(1, replacedState); + ps.setBytes(2, typeState); + ps.setInt(3, id); + batchHelper.addBatch(ps, null); } - } - } - } - - @Override - public boolean isUnique() { - return !(typeState == null && replacedState == null && ca == null && playerIds.containsKey(actor)); - } - - @Override - public boolean canMerge(MergeableRow row) { - return !this.isUnique() && !row.isUnique() && row instanceof BlockRow && getWorldConfig(loc.getWorld()).table.equals(getWorldConfig(((BlockRow) row).loc.getWorld()).table); - } - - @Override - public MergeableRow merge(MergeableRow singleRow) { - return new MultiBlockChangeRow(this, (BlockRow) singleRow); - } - } - - private class MultiBlockChangeRow implements MergeableRow { - private List rows = new ArrayList(); - private Connection connection; - private Set players = new HashSet(); - private Set actors = new HashSet(); - private String table; - - MultiBlockChangeRow(BlockRow first, BlockRow second) { - if (first.isUnique() || second.isUnique()) { - throw new IllegalArgumentException("Can't merge a unique row"); - } - rows.add(first); - rows.add(second); - actors.addAll(Arrays.asList(first.getActors())); - actors.addAll(Arrays.asList(second.getActors())); - players.addAll(Arrays.asList(first.getPlayers())); - players.addAll(Arrays.asList(second.getPlayers())); - table = getWorldConfig(first.loc.getWorld()).table; - } - - @Override - public void setConnection(Connection connection) { - this.connection = connection; - } - - @Override - public void executeStatements() throws SQLException { - PreparedStatement ps = null; - try { - ps = connection.prepareStatement("INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replacedData, type, typeData, x, y, z) VALUES(FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"); - for (BlockRow row : rows) { - ps.setLong(1, row.date); - ps.setInt(2, playerIds.get(row.actor)); - ps.setInt(3, row.replacedMaterial); - ps.setInt(4, row.replacedData); - ps.setInt(5, row.typeMaterial); - ps.setInt(6, row.typeData); - ps.setInt(7, row.loc.getBlockX()); - ps.setInt(8, safeY(row.loc)); - ps.setInt(9, row.loc.getBlockZ()); - ps.addBatch(); - } - ps.executeBatch(); - } catch (final SQLException ex) { - if (ps != null) { - logblock.getLogger().log(Level.SEVERE, "[Consumer] Troublesome query: " + ps.toString()); - } - throw ex; - } finally { - // individual try/catch here, though ugly, prevents resource leaks - if (ps != null) { - try { - ps.close(); - } catch (SQLException e) { - e.printStackTrace(); + if (ca != null) { + ps = batchHelper.getOrPrepareStatement(conn, "INSERT INTO `" + table + "-chestdata` (item, itemremove, id, itemtype) values (?, ?, ?, ?)", Statement.NO_GENERATED_KEYS); + ps.setBytes(1, Utils.saveItemStack(ca.itemStack)); + ps.setInt(2, ca.remove ? 1 : 0); + ps.setInt(3, id); + ps.setInt(4, ca.itemType); + batchHelper.addBatch(ps, null); } } - } - } - - @Override - public boolean isUnique() { - return true; - } - - @Override - public boolean canMerge(MergeableRow row) { - return !row.isUnique() && row instanceof BlockRow && table.equals(getWorldConfig(((BlockRow) row).loc.getWorld()).table); - } - - @Override - public MergeableRow merge(MergeableRow second) { - if (second.isUnique()) { - throw new IllegalArgumentException("Can't merge a unique row"); - } - rows.add((BlockRow) second); - actors.addAll(Arrays.asList(second.getActors())); - players.addAll(Arrays.asList(second.getPlayers())); - return this; - } - - @Override - public String[] getInserts() { - List l = new ArrayList(); - for (BlockRow row : rows) { - l.addAll(Arrays.asList(row.getInserts())); - } - return (String[]) l.toArray(); - } - - @Override - public String[] getPlayers() { - return (String[]) players.toArray(); - } - - @Override - public Actor[] getActors() { - return (Actor[]) actors.toArray(); + }); } } @@ -886,6 +787,7 @@ private class KillRow implements Row { final Actor killer, victim; final int weapon; final Location loc; + final String statementString; KillRow(Location loc, Actor attacker, Actor defender, int weapon) { date = System.currentTimeMillis() / 1000; @@ -893,6 +795,8 @@ private class KillRow implements Row { killer = attacker; victim = defender; this.weapon = weapon; + + statementString = "INSERT INTO `" + getWorldConfig(loc.getWorld()).table + "-kills` (date, killer, victim, weapon, x, y, z) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?)"; } @Override @@ -902,21 +806,31 @@ public String[] getInserts() { } @Override - public String[] getPlayers() { - return new String[] { killer.getName(), victim.getName() }; + public Actor[] getActors() { + return new Actor[] { killer, victim }; } @Override - public Actor[] getActors() { - return new Actor[] { killer, victim }; + public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); + smt.setLong(1, date); + smt.setInt(2, playerIDAsInt(killer)); + smt.setInt(3, playerIDAsInt(victim)); + smt.setInt(4, weapon); + smt.setInt(5, loc.getBlockX()); + smt.setInt(6, safeY(loc)); + smt.setInt(7, loc.getBlockZ()); + batchHelper.addBatch(smt, null); } } - private class ChatRow extends ChatMessage implements PreparedStatementRow { - private Connection connection; + private class ChatRow extends ChatMessage implements Row { + private String statementString; ChatRow(Actor player, String message) { super(player, message); + + statementString = "INSERT INTO `lb-chat` (date, playerid, message) VALUES (FROM_UNIXTIME(?), ?, ?)"; } @Override @@ -924,58 +838,18 @@ public String[] getInserts() { return new String[] { "INSERT INTO `lb-chat` (date, playerid, message) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(player) + ", '" + mysqlTextEscape(message) + "');" }; } - @Override - public String[] getPlayers() { - return new String[] { player.getName() }; - } - @Override public Actor[] getActors() { return new Actor[] { player }; } @Override - public void setConnection(Connection connection) { - this.connection = connection; - } - - @Override - public void executeStatements() throws SQLException { - boolean noID = false; - Integer id; - - String sql = "INSERT INTO `lb-chat` (date, playerid, message) VALUES (FROM_UNIXTIME(?), "; - if ((id = playerIDAsInt(player)) == null) { - noID = true; - sql += playerID(player) + ", "; - } else { - sql += "?, "; - } - sql += "?)"; - - PreparedStatement ps = null; - try { - ps = connection.prepareStatement(sql); - ps.setLong(1, date); - if (!noID) { - ps.setInt(2, id); - ps.setString(3, message); - } else { - ps.setString(2, message); - } - ps.execute(); - } - // we intentionally do not catch SQLException, it is thrown to the caller - finally { - if (ps != null) { - try { - ps.close(); - } catch (SQLException e) { - // should print to a Logger instead if one is ever added to this class - e.printStackTrace(); - } - } - } + public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); + smt.setLong(1, date); + smt.setInt(2, playerIDAsInt(player)); + smt.setString(3, message); + batchHelper.addBatch(smt, null); } } @@ -983,11 +857,18 @@ private class PlayerJoinRow implements Row { private final Actor player; private final long lastLogin; private final String ip; + private String statementString; PlayerJoinRow(Player player) { this.player = Actor.actorFromEntity(player); lastLogin = System.currentTimeMillis() / 1000; ip = player.getAddress().toString().replace("'", "\\'"); + + if (logPlayerInfo) { + statementString = "UPDATE `lb-players` SET lastlogin = FROM_UNIXTIME(?), firstlogin = IF(firstlogin = 0, FROM_UNIXTIME(?), firstlogin), ip = ?, playername = ? WHERE UUID = ?"; + } else { + statementString = "UPDATE `lb-players` SET playername = ? WHERE UUID = ?"; + } } @Override @@ -1000,23 +881,36 @@ public String[] getInserts() { } @Override - public String[] getPlayers() { - return new String[] { player.getName() }; + public Actor[] getActors() { + return new Actor[] { player }; } @Override - public Actor[] getActors() { - return new Actor[] { player }; + public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); + if (logPlayerInfo) { + smt.setLong(1, lastLogin); + smt.setLong(2, lastLogin); + smt.setString(3, ip); + smt.setString(4, player.getName()); + smt.setString(5, player.getUUID()); + } else { + smt.setString(1, player.getName()); + smt.setString(2, player.getUUID()); + } + batchHelper.addBatch(smt, null); } } private class PlayerLeaveRow implements Row { private final long onlineTime; private final Actor actor; + private String statementString; PlayerLeaveRow(Player player, long onlineTime) { this.onlineTime = onlineTime; actor = Actor.actorFromEntity(player); + statementString = "UPDATE `lb-players` SET onlinetime = onlinetime + ? WHERE lastlogin > 0 && UUID = ?"; } @Override @@ -1028,13 +922,16 @@ public String[] getInserts() { } @Override - public String[] getPlayers() { - return new String[] { actor.getName() }; + public Actor[] getActors() { + return new Actor[] { actor }; } @Override - public Actor[] getActors() { - return new Actor[] { actor }; + public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); + smt.setLong(1, onlineTime); + smt.setString(2, actor.getUUID()); + batchHelper.addBatch(smt, null); } } @@ -1046,4 +943,67 @@ private int safeY(Location loc) { safeY = 65535; return safeY; } + + private class BatchHelper { + private HashMap preparedStatements = new HashMap<>(); + private HashSet preparedStatementsWithGeneratedKeys = new HashSet<>(); + private LinkedHashMap> generatedKeyHandler = new LinkedHashMap<>(); + + public void reset() { + preparedStatements.clear(); + preparedStatementsWithGeneratedKeys.clear(); + generatedKeyHandler.clear(); + } + + public void processStatements(Connection conn) throws SQLException { + while (!generatedKeyHandler.isEmpty()) { + Entry> entry = generatedKeyHandler.entrySet().iterator().next(); + PreparedStatement smt = entry.getKey(); + ArrayList callbackList = entry.getValue(); + generatedKeyHandler.remove(smt); + smt.executeBatch(); + if (preparedStatementsWithGeneratedKeys.contains(smt)) { + ResultSet keys = smt.getGeneratedKeys(); + int[] results = new int[callbackList.size()]; + int pos = 0; + while (keys.next() && pos < results.length) { + results[pos++] = keys.getInt(1); + } + keys.close(); + for (int i = 0; i < results.length; i++) { + IntCallback callback = callbackList.get(i); + if (callback != null) { + callback.call(results[i]); + } + } + } + } + } + + public PreparedStatement getOrPrepareStatement(Connection conn, String sql, int autoGeneratedKeys) throws SQLException { + PreparedStatement smt = preparedStatements.get(sql); + if (smt == null) { + smt = conn.prepareStatement(sql, autoGeneratedKeys); + preparedStatements.put(sql, smt); + if (autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS) { + preparedStatementsWithGeneratedKeys.add(smt); + } + } + return smt; + } + + public void addBatch(PreparedStatement smt, IntCallback generatedKeysCallback) throws SQLException { + smt.addBatch(); + ArrayList callbackList = generatedKeyHandler.get(smt); + if (callbackList == null) { + callbackList = new ArrayList<>(); + generatedKeyHandler.put(smt, callbackList); + } + callbackList.add(generatedKeysCallback); + } + } + + protected interface IntCallback { + public void call(int value) throws SQLException; + } } diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 1585c780..ae95ba75 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -117,21 +117,9 @@ public void onEnable() { if (enableAutoClearLog && autoClearLogDelay > 0) { getServer().getScheduler().runTaskTimerAsynchronously(this, new AutoClearLog(this), 6000, autoClearLogDelay * 60 * 20); } - getServer().getScheduler().runTaskAsynchronously(this, new DumpedLogImporter(this)); + new DumpedLogImporter(this).run(); registerEvents(); - if (useBukkitScheduler) { - if (getServer().getScheduler().runTaskTimerAsynchronously(this, consumer, delayBetweenRuns < 20 ? 20 : delayBetweenRuns, delayBetweenRuns).getTaskId() > 0) { - getLogger().info("Scheduled consumer with bukkit scheduler."); - } else { - getLogger().warning("Failed to schedule consumer with bukkit scheduler. Now trying schedule with timer."); - timer = new Timer(); - timer.schedule(consumer, delayBetweenRuns < 20 ? 1000 : delayBetweenRuns * 50, delayBetweenRuns * 50); - } - } else { - timer = new Timer(); - timer.schedule(consumer, delayBetweenRuns < 20 ? 1000 : delayBetweenRuns * 50, delayBetweenRuns * 50); - getLogger().info("Scheduled consumer with timer."); - } + consumer.start(); getServer().getScheduler().runTaskAsynchronously(this, new Updater.PlayerCountChecker(this)); for (final Tool tool : toolsByType.values()) { if (pm.getPermission("logblock.tools." + tool.name) == null) { @@ -227,25 +215,14 @@ public void onDisable() { } } getLogger().info("Waiting for consumer ..."); - consumer.run(); + consumer.shutdown(); if (consumer.getQueueSize() > 0) { - int tries = 9; - while (consumer.getQueueSize() > 0) { - getLogger().info("Remaining queue size: " + consumer.getQueueSize()); - if (tries > 0) { - getLogger().info("Remaining tries: " + tries); - } else { - getLogger().info("Unable to save queue to database. Trying to write to a local file."); - try { - consumer.writeToFile(); - getLogger().info("Successfully dumped queue."); - } catch (final FileNotFoundException ex) { - getLogger().info("Failed to write. Given up."); - break; - } - } - consumer.run(); - tries--; + getLogger().info("Remaining queue size: " + consumer.getQueueSize() + ". Trying to write to a local file."); + try { + consumer.writeToFile(); + getLogger().info("Successfully dumped queue."); + } catch (final FileNotFoundException ex) { + getLogger().info("Failed to write. Given up."); } } } diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index 6b7b19f2..beb1305e 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -220,6 +220,13 @@ public static String mysqlEscapeBytes(byte[] bytes) { return new String(hexChars); } + public static String mysqlPrepareBytesForInsertAllowNull(byte[] bytes) { + if (bytes == null) { + return "null"; + } + return "'" + mysqlEscapeBytes(bytes) + "'"; + } + public static String mysqlTextEscape(String untrusted) { return untrusted.replace("\\", "\\\\").replace("'", "\\'"); } From 2c06c90c6d239b564d7aca38287c9dc5016abc6c Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 03:08:23 +0200 Subject: [PATCH 077/399] Set a name for the consumer thread --- src/main/java/de/diddiz/LogBlock/Consumer.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index f1d793ed..479fe7e3 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -61,10 +61,8 @@ public class Consumer extends Thread { Consumer(LogBlock logblock) { this.logblock = logblock; - try { - Class.forName("PlayerLeaveRow"); - } catch (final ClassNotFoundException ex) { - } + PlayerLeaveRow.class.getName(); // preload this class + setName("Logblock-Consumer"); } /** From d0f64070aef83b93095981ecfd37fd105fcf7ec1 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 03:14:16 +0200 Subject: [PATCH 078/399] Update the javadocs for the Consumer --- .../java/de/diddiz/LogBlock/Consumer.java | 74 +++++++------------ 1 file changed, 27 insertions(+), 47 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 479fe7e3..2914c6e8 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -73,11 +73,9 @@ public class Consumer extends Thread { * @param loc * Location of the block change * @param typeBefore - * Type of the block before the change + * BlockData of the block before the change * @param typeAfter - * Type of the block after the change - * @param data - * Data of the block after the change + * BlockData of the block after the change */ public void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter) { queueBlock(actor, loc, typeBefore, typeAfter, null, null, null); @@ -89,7 +87,7 @@ public void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDat * @param actor * Actor responsible for breaking the block * @param before - * Blockstate of the block before actually being destroyed. + * BlockState of the block before actually being destroyed. */ public void queueBlockBreak(Actor actor, BlockState before) { queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), null, BlockStateCodecs.serialize(before), null, null); @@ -103,9 +101,7 @@ public void queueBlockBreak(Actor actor, BlockState before) { * @param loc * Location of the broken block * @param typeBefore - * Type of the block before the break - * @param dataBefore - * Data of the block before the break + * BlockData of the block before the break */ public void queueBlockBreak(Actor actor, Location loc, BlockData typeBefore) { queueBlock(actor, loc, typeBefore, null); @@ -117,7 +113,7 @@ public void queueBlockBreak(Actor actor, Location loc, BlockData typeBefore) { * @param actor * Actor responsible for placing the block * @param after - * Blockstate of the block after actually being placed. + * BlockState of the block after actually being placed. */ public void queueBlockPlace(Actor actor, BlockState after) { queueBlock(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), null, after.getBlockData(), null, BlockStateCodecs.serialize(after), null); @@ -131,9 +127,7 @@ public void queueBlockPlace(Actor actor, BlockState after) { * @param loc * Location of the placed block * @param type - * Type of the placed block - * @param data - * Data of the placed block + * BlockData of the placed block */ public void queueBlockPlace(Actor actor, Location loc, BlockData type) { queueBlock(actor, loc, null, type); @@ -145,9 +139,9 @@ public void queueBlockPlace(Actor actor, Location loc, BlockData type) { * @param actor * Actor responsible for replacing the block * @param before - * Blockstate of the block before actually being destroyed. + * BlockState of the block before actually being destroyed. * @param after - * Blockstate of the block after actually being placed. + * BlockState of the block after actually being placed. */ public void queueBlockReplace(Actor actor, BlockState before, BlockState after) { queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), after.getBlockData(), BlockStateCodecs.serialize(before), BlockStateCodecs.serialize(after), null); @@ -159,11 +153,9 @@ public void queueBlockReplace(Actor actor, BlockState before, BlockState after) * @param actor * Actor responsible for replacing the block * @param before - * Blockstate of the block before being replaced. + * BlockState of the block before being replaced. * @param typeAfter - * Type of the block after being replaced - * @param dataAfter - * Data of the block after being replaced + * BlockData of the block after being replaced */ public void queueBlockReplace(Actor actor, BlockState before, BlockData typeAfter) { queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), typeAfter, BlockStateCodecs.serialize(before), null, null); @@ -175,11 +167,9 @@ public void queueBlockReplace(Actor actor, BlockState before, BlockData typeAfte * @param actor * Actor responsible for replacing the block * @param typeBefore - * Type of the block before being replaced - * @param dataBefore - * Data of the block before being replaced + * BlockData of the block before being replaced * @param after - * Blockstate of the block after actually being placed. + * BlockState of the block after actually being placed. */ public void queueBlockReplace(Actor actor, BlockData typeBefore, BlockState after) { queueBlock(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), typeBefore, after.getBlockData(), null, BlockStateCodecs.serialize(after), null); @@ -196,12 +186,10 @@ public void queueBlockReplace(Actor actor, Location loc, BlockData typeBefore, B * The actor interacting with the container * @param container * The respective container. Must be an instance of an InventoryHolder. - * @param itemType - * Type of the item taken/stored - * @param itemAmount - * Amount of the item taken/stored - * @param itemData - * Data of the item taken/stored + * @param itemStack + * Item taken/stored, including amount + * @param remove + * true if the item was removed */ public void queueChestAccess(Actor actor, BlockState container, ItemStack itemStack, boolean remove) { if (!(container instanceof InventoryHolder)) { @@ -218,13 +206,11 @@ public void queueChestAccess(Actor actor, BlockState container, ItemStack itemSt * @param loc * The location of the container block * @param type - * Type id of the container. - * @param itemType - * Type of the item taken/stored - * @param itemAmount - * Amount of the item taken/stored - * @param itemData - * Data of the item taken/stored + * BlockData of the container. + * @param itemStack + * Item taken/stored, including amount + * @param remove + * true if the item was removed */ 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().getKey()))); @@ -253,9 +239,7 @@ public void queueContainerBreak(Actor actor, BlockState container) { * @param loc * The location of the inventory block * @param type - * The type of the container block - * @param data - * The data of the container block + * BlockData of the container block * @param inv * The inventory of the container block */ @@ -319,7 +303,7 @@ public void queueKill(Actor killer, Entity victim) { * @param victim * Victim Actor. Can't be null. * @param weapon - * Item id of the weapon. 0 for no weapon. + * Item of the weapon. null for no weapon. */ public void queueKill(Location location, Actor killer, Actor victim, ItemStack weapon) { if (victim == null || !isLogged(location.getWorld())) { @@ -336,11 +320,9 @@ public void queueKill(Location location, Actor killer, Actor victim, ItemStack w * @param loc * Location of the broken sign * @param type - * Type of the sign. Must be 63 or 68. - * @param data - * Data of the sign being broken - * @param lines - * The four lines on the sign. + * BlockData of the sign. + * @param typeState + * Serialized text data of the sign */ public void queueSignBreak(Actor actor, Location loc, BlockData type, byte[] typeState) { queueBlock(actor, loc, type, null, typeState, null, null); @@ -366,9 +348,7 @@ public void queueSignBreak(Actor actor, Sign sign) { * @param loc * Location of the placed sign * @param type - * Type of the sign. Must be 63 or 68. - * @param data - * Data of the placed sign block + * BlockData of the sign * @param lines * The four lines on the sign. */ From 6168ef1713ccbf455018fc236c59da0ef15ef20d Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 14:09:09 +0200 Subject: [PATCH 079/399] Have an extra map for uncommited playerIds They will only added to the main list after a successful commit and cleared otherwise --- .../java/de/diddiz/LogBlock/Consumer.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 2914c6e8..c384f258 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -53,6 +53,7 @@ public class Consumer extends Thread { private final Set failedPlayers = new HashSet(); private final LogBlock logblock; private final Map playerIds = new HashMap(); + private final Map uncommitedPlayerIds = new HashMap(); private long addEntryCounter; private long nextWarnCounter; @@ -470,7 +471,7 @@ public void run() { if (r != null) { boolean failOnActors = false; for (final Actor actor : r.getActors()) { - if (!playerIds.containsKey(actor)) { + if (playerIDAsIntIncludeUncommited(actor) == null) { if (!addPlayer(conn, actor)) { if (failedPlayers.add(actor)) { logblock.getLogger().warning("[Consumer] Failed to add player " + actor.getName()); @@ -488,6 +489,8 @@ public void run() { batchHelper.processStatements(conn); conn.commit(); currentRows.clear(); + playerIds.putAll(uncommitedPlayerIds); + uncommitedPlayerIds.clear(); } } catch (Exception e) { logblock.getLogger().log(Level.SEVERE, "[Consumer] Could not insert entries!", e); @@ -507,6 +510,7 @@ public void run() { } currentRows.clear(); batchHelper.reset(); + uncommitedPlayerIds.clear(); if (conn != null) { try { conn.close(); @@ -622,11 +626,11 @@ private boolean addPlayer(Connection conn, Actor actor) throws SQLException { state.execute("INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + mysqlTextEscape(name) + "','" + uuid + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + uuid + "') LIMIT 1;"); final ResultSet rs = state.executeQuery("SELECT playerid FROM `lb-players` WHERE UUID = '" + uuid + "'"); if (rs.next()) { - playerIds.put(actor, rs.getInt(1)); + uncommitedPlayerIds.put(actor, rs.getInt(1)); } rs.close(); state.close(); - return playerIds.containsKey(actor); + return uncommitedPlayerIds.containsKey(actor); } private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter, byte[] stateBefore, byte[] stateAfter, ChestAccess ca) { @@ -678,11 +682,15 @@ private String playerID(Actor actor) { return "(SELECT playerid FROM `lb-players` WHERE UUID = '" + actor.getUUID() + "')"; } - private Integer playerIDAsInt(Actor actor) { + private Integer playerIDAsIntIncludeUncommited(Actor actor) { if (actor == null) { return null; } - return playerIds.get(actor); + Integer id = playerIds.get(actor); + if (id != null) { + return id; + } + return uncommitedPlayerIds.get(actor); } private static interface Row { @@ -727,7 +735,7 @@ public Actor[] getActors() { public void process(Connection conn, BatchHelper batchHelper) throws SQLException { PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.RETURN_GENERATED_KEYS); smt.setLong(1, date); - smt.setInt(2, playerIDAsInt(actor)); + smt.setInt(2, playerIDAsIntIncludeUncommited(actor)); smt.setInt(3, replacedMaterial); smt.setInt(4, replacedData); smt.setInt(5, typeMaterial); @@ -792,8 +800,8 @@ public Actor[] getActors() { public void process(Connection conn, BatchHelper batchHelper) throws SQLException { PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); smt.setLong(1, date); - smt.setInt(2, playerIDAsInt(killer)); - smt.setInt(3, playerIDAsInt(victim)); + smt.setInt(2, playerIDAsIntIncludeUncommited(killer)); + smt.setInt(3, playerIDAsIntIncludeUncommited(victim)); smt.setInt(4, weapon); smt.setInt(5, loc.getBlockX()); smt.setInt(6, safeY(loc)); @@ -825,7 +833,7 @@ public Actor[] getActors() { public void process(Connection conn, BatchHelper batchHelper) throws SQLException { PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); smt.setLong(1, date); - smt.setInt(2, playerIDAsInt(player)); + smt.setInt(2, playerIDAsIntIncludeUncommited(player)); smt.setString(3, message); batchHelper.addBatch(smt, null); } From 66070e2b38553439a57b9c4bb315b761586030d1 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 14:20:55 +0200 Subject: [PATCH 080/399] Do not spam exceptions when the database connection pool is closed When some database access is still running asynchronously, it will create an SQLException when the pool is closed (on shutdown). Just silently ignore them in this case. --- .../de/diddiz/LogBlock/CommandsHandler.java | 40 +++++++++++++------ .../java/de/diddiz/LogBlock/LogBlock.java | 9 ++++- src/main/java/de/diddiz/LogBlock/Updater.java | 4 +- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index ec8d8a82..13deb36d 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -426,7 +426,9 @@ public final void close() { rs.close(); } } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[CommandsHandler] SQL exception on close", ex); + if (logblock.isCompletelyEnabled()) { + logblock.getLogger().log(Level.SEVERE, "[CommandsHandler] SQL exception on close", ex); + } } } } @@ -490,8 +492,10 @@ public void run() { getSession(sender).lookupCache = null; } } catch (final Exception ex) { - sender.sendMessage(ChatColor.RED + "Exception, check error log"); - logblock.getLogger().log(Level.SEVERE, "[Lookup] " + params.getQuery() + ": ", ex); + if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { + sender.sendMessage(ChatColor.RED + "Exception, check error log"); + logblock.getLogger().log(Level.SEVERE, "[Lookup] " + params.getQuery() + ": ", ex); + } } finally { close(); } @@ -546,8 +550,10 @@ public void run() { writer.close(); sender.sendMessage(ChatColor.GREEN + "Wrote " + counter + " lines."); } catch (final Exception ex) { - sender.sendMessage(ChatColor.RED + "Exception, check error log"); - logblock.getLogger().log(Level.SEVERE, "[WriteLogFile] " + params.getQuery() + " (file was " + file.getAbsolutePath() + "): ", ex); + if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { + sender.sendMessage(ChatColor.RED + "Exception, check error log"); + logblock.getLogger().log(Level.SEVERE, "[WriteLogFile] " + params.getQuery() + " (file was " + file.getAbsolutePath() + "): ", ex); + } } finally { close(); } @@ -606,8 +612,10 @@ public void run() { sender.sendMessage(ChatColor.RED + "No block change found to teleport to"); } } catch (final Exception ex) { - sender.sendMessage(ChatColor.RED + "Exception, check error log"); - logblock.getLogger().log(Level.SEVERE, "[Teleport] " + params.getQuery() + ": ", ex); + if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { + sender.sendMessage(ChatColor.RED + "Exception, check error log"); + logblock.getLogger().log(Level.SEVERE, "[Teleport] " + params.getQuery() + ": ", ex); + } } finally { close(); } @@ -693,8 +701,10 @@ public void run() { } } } catch (final Exception ex) { - sender.sendMessage(ChatColor.RED + "Exception, check error log"); - logblock.getLogger().log(Level.SEVERE, "[Rollback] " + params.getQuery() + ": ", ex); + if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { + sender.sendMessage(ChatColor.RED + "Exception, check error log"); + logblock.getLogger().log(Level.SEVERE, "[Rollback] " + params.getQuery() + ": ", ex); + } } finally { close(); } @@ -766,8 +776,10 @@ public void run() { editor.start(); sender.sendMessage(ChatColor.GREEN + "Redo finished successfully (" + editor.getElapsedTime() + " ms, " + editor.getSuccesses() + "/" + changes + " blocks" + (editor.getErrors() > 0 ? ", " + ChatColor.RED + editor.getErrors() + " errors" + ChatColor.GREEN : "") + (editor.getBlacklistCollisions() > 0 ? ", " + editor.getBlacklistCollisions() + " blacklist collisions" : "") + ")"); } catch (final Exception ex) { - sender.sendMessage(ChatColor.RED + "Exception, check error log"); - logblock.getLogger().log(Level.SEVERE, "[Redo] " + params.getQuery() + ": ", ex); + if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { + sender.sendMessage(ChatColor.RED + "Exception, check error log"); + logblock.getLogger().log(Level.SEVERE, "[Redo] " + params.getQuery() + ": ", ex); + } } finally { close(); } @@ -841,8 +853,10 @@ public void run() { sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-chestdata. Deleted " + deleted + " entries."); } } catch (final Exception ex) { - sender.sendMessage(ChatColor.RED + "Exception, check error log"); - logblock.getLogger().log(Level.SEVERE, "[ClearLog] Exception: ", ex); + if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { + sender.sendMessage(ChatColor.RED + "Exception, check error log"); + logblock.getLogger().log(Level.SEVERE, "[ClearLog] Exception: ", ex); + } } finally { close(); } diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index ae95ba75..1c10bdc2 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -40,11 +40,16 @@ public class LogBlock extends JavaPlugin { private boolean errorAtLoading = false, noDb = false, connected = true; private PlayerInfoLogging playerInfoLogging; private Questioner questioner; + private volatile boolean isCompletelyEnabled; public static LogBlock getInstance() { return logblock; } + public boolean isCompletelyEnabled() { + return isCompletelyEnabled; + } + public Consumer getConsumer() { return consumer; } @@ -120,7 +125,6 @@ public void onEnable() { new DumpedLogImporter(this).run(); registerEvents(); consumer.start(); - getServer().getScheduler().runTaskAsynchronously(this, new Updater.PlayerCountChecker(this)); for (final Tool tool : toolsByType.values()) { if (pm.getPermission("logblock.tools." + tool.name) == null) { final Permission perm = new Permission("logblock.tools." + tool.name, tool.permissionDefault); @@ -128,6 +132,8 @@ public void onEnable() { } } questioner = new Questioner(this); + isCompletelyEnabled = true; + getServer().getScheduler().runTaskAsynchronously(this, new Updater.PlayerCountChecker(this)); try { Metrics metrics = new Metrics(this); metrics.start(); @@ -204,6 +210,7 @@ private void registerEvents() { @Override public void onDisable() { + isCompletelyEnabled = false; if (timer != null) { timer.cancel(); } diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index ede62551..7d2af312 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -825,7 +825,9 @@ public void run() { st.close(); conn.close(); } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + if (logblock.isCompletelyEnabled()) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + } } } } From cbf0011cd38af3c615c8c317e6e55aa2f634d775 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 14:52:39 +0200 Subject: [PATCH 081/399] Print a warning and skip invalid data in serialized blockstates --- src/main/java/de/diddiz/util/Utils.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index beb1305e..a3d6428f 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -16,6 +16,7 @@ import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; +import java.util.zip.ZipException; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; @@ -259,6 +260,9 @@ public static YamlConfiguration deserializeYamlConfiguration(byte[] data) throws conf.load(reader); reader.close(); return conf; + } catch (ZipException e) { + LogBlock.getInstance().getLogger().warning("Could not deserialize YamlConfiguration: " + e.getMessage()); + return conf; } catch (IOException e) { throw new RuntimeException("IOException should be impossible for ByteArrayInputStream", e); } From 47f7ddec01844381e86d0d1441d6e251ff1d496c Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 14:57:08 +0200 Subject: [PATCH 082/399] Limit query results lookup.limesLimit is now correctly used as default limit for lookups The new lookup.hardLimesLimit is the max limit that is enforced in all lookups + rollbacks (default 100000) Fixes #636, Fixes #128 --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 1 + src/main/java/de/diddiz/LogBlock/QueryParams.java | 5 ++++- src/main/java/de/diddiz/LogBlock/config/Config.java | 4 +++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 13deb36d..388bbe70 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -340,6 +340,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, final QueryParams params = new QueryParams(logblock); params.since = defaultTime; params.bct = BlockChangeType.ALL; + params.limit = Config.linesLimit; params.parseArgs(sender, argsList); new CommandLookup(sender, params, true); } else { diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 3a127659..fcb8419b 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -87,7 +87,10 @@ public static int getKeyWordMinArguments(String param) { } public String getLimit() { - return limit > 0 ? "LIMIT " + limit : ""; + if (Config.hardLinesLimit <= 0 || (limit > 0 && limit <= Config.hardLinesLimit)) { + return limit > 0 ? "LIMIT " + limit : ""; + } + return "LIMIT " + Config.hardLinesLimit; } public String getQuery() { diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 0a996cca..fec0a7d8 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -40,7 +40,7 @@ public class Config { public static Map toolsByName; public static Map toolsByType; public static int defaultDist, defaultTime; - public static int linesPerPage, linesLimit; + public static int linesPerPage, linesLimit, hardLinesLimit; public static boolean askRollbacks, askRedos, askClearLogs, askClearLogAfterRollback, askRollbackAfterBan; public static String banPermission; public static Set hiddenBlocks; @@ -102,6 +102,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("lookup.defaultTime", "30 minutes"); def.put("lookup.linesPerPage", 15); def.put("lookup.linesLimit", 1500); + def.put("lookup.hardLinesLimit", 100000); try { formatter = new SimpleDateFormat(config.getString("lookup.dateFormat", "MM-dd HH:mm:ss")); } catch (IllegalArgumentException e) { @@ -207,6 +208,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti defaultTime = parseTimeSpec(config.getString("lookup.defaultTime").split(" ")); linesPerPage = config.getInt("lookup.linesPerPage", 15); linesLimit = config.getInt("lookup.linesLimit", 1500); + hardLinesLimit = config.getInt("lookup.hardLinesLimit", 100000); askRollbacks = config.getBoolean("questioner.askRollbacks", true); askRedos = config.getBoolean("questioner.askRedos", true); askClearLogs = config.getBoolean("questioner.askClearLogs", true); From d04501baf4d08c779d30408ec6da85e2ebbee10e Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 15:36:39 +0200 Subject: [PATCH 083/399] Load the config after worlds are loaded Fixes #267 --- .../java/de/diddiz/LogBlock/LogBlock.java | 50 ++++++++----------- .../de/diddiz/LogBlock/config/Config.java | 7 ++- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 1c10bdc2..57039d16 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -24,7 +24,6 @@ import java.sql.Statement; import java.util.ArrayList; import java.util.List; -import java.util.Timer; import java.util.logging.Level; import static de.diddiz.LogBlock.config.Config.*; @@ -35,9 +34,7 @@ public class LogBlock extends JavaPlugin { private MySQLConnectionPool pool; private Consumer consumer = null; private CommandsHandler commandsHandler; - private Updater updater = null; - private Timer timer = null; - private boolean errorAtLoading = false, noDb = false, connected = true; + private boolean noDb = false, connected = true; private PlayerInfoLogging playerInfoLogging; private Questioner questioner; private volatile boolean isCompletelyEnabled; @@ -58,20 +55,25 @@ public CommandsHandler getCommandsHandler() { return commandsHandler; } - Updater getUpdater() { - return updater; - } - @Override - public void onLoad() { + public void onEnable() { logblock = this; + + BukkitUtils.isDoublePlant(Material.AIR); // Force static code to run + final PluginManager pm = getPluginManager(); + consumer = new Consumer(this); try { - updater = new Updater(this); Config.load(this); + } catch (final Exception ex) { + getLogger().log(Level.SEVERE, "Could not load LogBlock config! " + ex.getMessage()); + pm.disablePlugin(this); + return; + } + try { getLogger().info("Connecting to " + user + "@" + url + "..."); pool = new MySQLConnectionPool(url, user, password); - final Connection conn = getConnection(); + final Connection conn = getConnection(true); if (conn == null) { noDb = true; return; @@ -84,6 +86,7 @@ public void onLoad() { st.executeQuery("SET NAMES utf8mb4;"); } conn.close(); + Updater updater = new Updater(this); updater.checkTables(); MaterialConverter.initializeMaterials(getConnection()); MaterialConverter.getOrAddMaterialId(Material.AIR.getKey()); // AIR must be the first entry @@ -94,22 +97,10 @@ public void onLoad() { getLogger().log(Level.SEVERE, "Error while loading: ", ex); } catch (final Exception ex) { getLogger().log(Level.SEVERE, "Error while loading: " + ex.getMessage(), ex); - errorAtLoading = true; - return; - } - } - - @Override - public void onEnable() { - BukkitUtils.isDoublePlant(Material.AIR); // Force static code to run - final PluginManager pm = getPluginManager(); - if (errorAtLoading) { pm.disablePlugin(this); return; } - if (noDb) { - return; - } + if (pm.getPlugin("WorldEdit") != null) { if (Integer.parseInt(pm.getPlugin("WorldEdit").getDescription().getVersion().substring(0, 1)) > 5) { new WorldEditLoggingHook(this).hook(); @@ -211,9 +202,6 @@ private void registerEvents() { @Override public void onDisable() { isCompletelyEnabled = false; - if (timer != null) { - timer.cancel(); - } getServer().getScheduler().cancelTasks(this); if (consumer != null) { if (logPlayerInfo && playerInfoLogging != null) { @@ -251,6 +239,10 @@ public boolean hasPermission(CommandSender sender, String permission) { } public Connection getConnection() { + return getConnection(false); + } + + public Connection getConnection(boolean testConnection) { try { final Connection conn = pool.getConnection(); if (!connected) { @@ -259,7 +251,9 @@ public Connection getConnection() { } return conn; } catch (final Exception ex) { - if (connected) { + if (testConnection) { + getLogger().log(Level.SEVERE, "Could not connect to the Database! Please check your config! " + ex.getMessage()); + } else if (connected) { getLogger().log(Level.SEVERE, "Error while fetching connection: ", ex); connected = false; } else { diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index fec0a7d8..abe13e33 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -84,7 +84,12 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("consumer.queueWarningSize", 1000); def.put("clearlog.dumpDeletedLog", false); def.put("clearlog.enableAutoClearLog", false); - def.put("clearlog.auto", Arrays.asList("world \"world\" before 365 days all", "world \"world\" player lavaflow waterflow leavesdecay before 7 days all", "world world_nether before 365 days all", "world world_nether player lavaflow before 7 days all")); + final List autoClearlog = new ArrayList(); + for (final String world : worldNames) { + autoClearlog.add("world \"" + world + "\" before 365 days all"); + autoClearlog.add("world \"" + world + "\" player lavaflow waterflow leavesdecay before 7 days all"); + } + def.put("clearlog.auto", autoClearlog); def.put("clearlog.autoClearLogDelay", "6h"); def.put("logging.logBedExplosionsAsPlayerWhoTriggeredThese", true); def.put("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false); From 8d11ea3f5396bf234a58fff119ae88059edd9f59 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 15:59:33 +0200 Subject: [PATCH 084/399] Only remove tools on disable if the player could get them --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 388bbe70..d90ce1d1 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -144,7 +144,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, if (args.length == 1) { if (logblock.hasPermission(player, "logblock.spawnTools")) { giveTool(player, tool.item); - session.toolData.get(tool).enabled = true; + toolData.enabled = true; } else { sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); } @@ -153,7 +153,9 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, player.sendMessage(ChatColor.GREEN + "Tool enabled."); } else if (args[1].equalsIgnoreCase("disable") || args[1].equalsIgnoreCase("off")) { toolData.enabled = false; - player.getInventory().removeItem(new ItemStack(tool.item, 1)); + if (logblock.hasPermission(player, "logblock.spawnTools")) { + player.getInventory().removeItem(new ItemStack(tool.item, 1)); + } player.sendMessage(ChatColor.GREEN + "Tool disabled."); } else if (args[1].equalsIgnoreCase("mode")) { if (args.length == 3) { From e6310e6174b931f639d47f5157ee200d8aa2c0ff Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 16:04:07 +0200 Subject: [PATCH 085/399] Config option if a tool should be removed on disable --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 2 +- src/main/java/de/diddiz/LogBlock/Tool.java | 4 +++- src/main/java/de/diddiz/LogBlock/config/Config.java | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index d90ce1d1..3d8876ca 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -153,7 +153,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, player.sendMessage(ChatColor.GREEN + "Tool enabled."); } else if (args[1].equalsIgnoreCase("disable") || args[1].equalsIgnoreCase("off")) { toolData.enabled = false; - if (logblock.hasPermission(player, "logblock.spawnTools")) { + if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) { player.getInventory().removeItem(new ItemStack(tool.item, 1)); } player.sendMessage(ChatColor.GREEN + "Tool disabled."); diff --git a/src/main/java/de/diddiz/LogBlock/Tool.java b/src/main/java/de/diddiz/LogBlock/Tool.java index 17055b96..db198c2a 100644 --- a/src/main/java/de/diddiz/LogBlock/Tool.java +++ b/src/main/java/de/diddiz/LogBlock/Tool.java @@ -15,8 +15,9 @@ public class Tool { public final QueryParams params; public final ToolMode mode; public final PermissionDefault permissionDefault; + public final boolean removeOnDisable; - public Tool(String name, List aliases, ToolBehavior leftClickBehavior, ToolBehavior rightClickBehavior, boolean defaultEnabled, Material item, boolean canDrop, QueryParams params, ToolMode mode, PermissionDefault permissionDefault) { + public Tool(String name, List aliases, ToolBehavior leftClickBehavior, ToolBehavior rightClickBehavior, boolean defaultEnabled, Material item, boolean canDrop, QueryParams params, ToolMode mode, PermissionDefault permissionDefault, boolean removeOnDisable) { this.name = name; this.aliases = aliases; this.leftClickBehavior = leftClickBehavior; @@ -27,5 +28,6 @@ public Tool(String name, List aliases, ToolBehavior leftClickBehavior, T this.params = params; this.mode = mode; this.permissionDefault = permissionDefault; + this.removeOnDisable = removeOnDisable; } } diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index abe13e33..c9e857ad 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -126,6 +126,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("tools.tool.defaultEnabled", true); def.put("tools.tool.item", Material.WOODEN_PICKAXE.name()); def.put("tools.tool.canDrop", true); + def.put("tools.tool.removeOnDisable", true); def.put("tools.tool.params", "area 0 all sum none limit 15 desc since 60d silent"); def.put("tools.tool.mode", "LOOKUP"); def.put("tools.tool.permissionDefault", "OP"); @@ -135,6 +136,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("tools.toolblock.defaultEnabled", true); def.put("tools.toolblock.item", Material.BEDROCK.name()); def.put("tools.toolblock.canDrop", false); + def.put("tools.toolblock.removeOnDisable", true); def.put("tools.toolblock.params", "area 0 all sum none limit 15 desc since 60d silent"); def.put("tools.toolblock.mode", "LOOKUP"); def.put("tools.toolblock.permissionDefault", "OP"); @@ -233,12 +235,13 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti final boolean defaultEnabled = tSec.getBoolean("defaultEnabled", false); final Material item = Material.matchMaterial(tSec.getString("item","OAK_LOG")); final boolean canDrop = tSec.getBoolean("canDrop", false); + final boolean removeOnDisable = tSec.getBoolean("removeOnDisable", true); final QueryParams params = new QueryParams(logblock); params.prepareToolQuery = true; params.parseArgs(getConsoleSender(), Arrays.asList(tSec.getString("params").split(" ")), false); final ToolMode mode = ToolMode.valueOf(tSec.getString("mode").toUpperCase()); final PermissionDefault pdef = PermissionDefault.valueOf(tSec.getString("permissionDefault").toUpperCase()); - tools.add(new Tool(toolName, aliases, leftClickBehavior, rightClickBehavior, defaultEnabled, item, canDrop, params, mode, pdef)); + tools.add(new Tool(toolName, aliases, leftClickBehavior, rightClickBehavior, defaultEnabled, item, canDrop, params, mode, pdef, removeOnDisable)); } catch (final Exception ex) { getLogger().log(Level.WARNING, "Error at parsing tool '" + toolName + "': ", ex); } From 8b71a8a62b1cae73aea05289e5def6b9c78b6422 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 16:59:44 +0200 Subject: [PATCH 086/399] Tool config option dropToDisable If set to true, the tool will be disabled (and if removeOnDisable is true removed) when you try to drop it. Adds #548 --- src/main/java/de/diddiz/LogBlock/Tool.java | 4 ++- .../de/diddiz/LogBlock/config/Config.java | 5 +++- .../LogBlock/listeners/ToolListener.java | 27 ++++++++++++++++--- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Tool.java b/src/main/java/de/diddiz/LogBlock/Tool.java index db198c2a..7a9c8282 100644 --- a/src/main/java/de/diddiz/LogBlock/Tool.java +++ b/src/main/java/de/diddiz/LogBlock/Tool.java @@ -16,8 +16,9 @@ public class Tool { public final ToolMode mode; public final PermissionDefault permissionDefault; public final boolean removeOnDisable; + public final boolean dropToDisable; - public Tool(String name, List aliases, ToolBehavior leftClickBehavior, ToolBehavior rightClickBehavior, boolean defaultEnabled, Material item, boolean canDrop, QueryParams params, ToolMode mode, PermissionDefault permissionDefault, boolean removeOnDisable) { + public Tool(String name, List aliases, ToolBehavior leftClickBehavior, ToolBehavior rightClickBehavior, boolean defaultEnabled, Material item, boolean canDrop, QueryParams params, ToolMode mode, PermissionDefault permissionDefault, boolean removeOnDisable, boolean dropToDisable) { this.name = name; this.aliases = aliases; this.leftClickBehavior = leftClickBehavior; @@ -29,5 +30,6 @@ public Tool(String name, List aliases, ToolBehavior leftClickBehavior, T this.mode = mode; this.permissionDefault = permissionDefault; this.removeOnDisable = removeOnDisable; + this.dropToDisable = dropToDisable; } } diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index c9e857ad..723d9be3 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -127,6 +127,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("tools.tool.item", Material.WOODEN_PICKAXE.name()); def.put("tools.tool.canDrop", true); def.put("tools.tool.removeOnDisable", true); + def.put("tools.tool.dropToDisable", false); def.put("tools.tool.params", "area 0 all sum none limit 15 desc since 60d silent"); def.put("tools.tool.mode", "LOOKUP"); def.put("tools.tool.permissionDefault", "OP"); @@ -137,6 +138,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("tools.toolblock.item", Material.BEDROCK.name()); def.put("tools.toolblock.canDrop", false); def.put("tools.toolblock.removeOnDisable", true); + def.put("tools.toolblock.dropToDisable", false); def.put("tools.toolblock.params", "area 0 all sum none limit 15 desc since 60d silent"); def.put("tools.toolblock.mode", "LOOKUP"); def.put("tools.toolblock.permissionDefault", "OP"); @@ -236,12 +238,13 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti final Material item = Material.matchMaterial(tSec.getString("item","OAK_LOG")); final boolean canDrop = tSec.getBoolean("canDrop", false); final boolean removeOnDisable = tSec.getBoolean("removeOnDisable", true); + final boolean dropToDisable = tSec.getBoolean("dropToDisable", false); final QueryParams params = new QueryParams(logblock); params.prepareToolQuery = true; params.parseArgs(getConsoleSender(), Arrays.asList(tSec.getString("params").split(" ")), false); final ToolMode mode = ToolMode.valueOf(tSec.getString("mode").toUpperCase()); final PermissionDefault pdef = PermissionDefault.valueOf(tSec.getString("permissionDefault").toUpperCase()); - tools.add(new Tool(toolName, aliases, leftClickBehavior, rightClickBehavior, defaultEnabled, item, canDrop, params, mode, pdef, removeOnDisable)); + tools.add(new Tool(toolName, aliases, leftClickBehavior, rightClickBehavior, defaultEnabled, item, canDrop, params, mode, pdef, removeOnDisable, dropToDisable)); } catch (final Exception ex) { getLogger().log(Level.WARNING, "Error at parsing tool '" + toolName + "': ", ex); } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java index 0ed9a411..1d15a7fd 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java @@ -100,7 +100,9 @@ public void onPlayerChangedWorld(PlayerChangedWorldEvent event) { final ToolData toolData = entry.getValue(); if (toolData.enabled && !logblock.hasPermission(player, "logblock.tools." + tool.name)) { toolData.enabled = false; - player.getInventory().removeItem(new ItemStack(tool.item, 1)); + if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) { + player.getInventory().removeItem(new ItemStack(tool.item, 1)); + } player.sendMessage(ChatColor.GREEN + "Tool disabled."); } } @@ -116,9 +118,26 @@ public void onPlayerDropItem(PlayerDropItemEvent event) { final Tool tool = entry.getKey(); final ToolData toolData = entry.getValue(); final Material item = event.getItemDrop().getItemStack().getType(); - if (item == tool.item && toolData.enabled && !tool.canDrop) { - player.sendMessage(ChatColor.RED + "You cannot drop this tool."); - event.setCancelled(true); + if (item == tool.item && toolData.enabled) { + if (tool.dropToDisable) { + toolData.enabled = false; + if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) { + ItemStack stack = event.getItemDrop().getItemStack(); + if (stack.isSimilar(new ItemStack(item))) { + if (stack.getAmount() > 1) { + stack.setAmount(stack.getAmount() - 1); + event.getItemDrop().setItemStack(stack); + } else { + event.getItemDrop().remove(); + } + } + } + event.setCancelled(true); + player.sendMessage(ChatColor.GREEN + "Tool disabled."); + } else if (!tool.canDrop) { + player.sendMessage(ChatColor.RED + "You cannot drop this tool."); + event.setCancelled(true); + } } } } From cfea33e1fdb5821df11ea8b6e2359291b2e5d766 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 18:28:33 +0200 Subject: [PATCH 087/399] Fix clearlog table --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 3d8876ca..d497cfaa 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -834,7 +834,7 @@ public void run() { return; } } - state.execute("DELETE `" + table + "` FROM `" + table + "-blocks` " + join + params.getWhere()); + state.execute("DELETE `" + table + "-blocks` FROM `" + table + "-blocks` " + join + params.getWhere()); sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + ". Deleted " + deleted + " entries."); } rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-state` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL"); From c62352584732de8d13d9915eacd3bb79e3774122 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 18:29:22 +0200 Subject: [PATCH 088/399] More secure writelogfile command --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index d497cfaa..55359119 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -533,7 +533,7 @@ public void run() { return; } state = conn.createStatement(); - file = new File("plugins/LogBlock/log/" + params.getTitle().replace(":", ".") + ".log"); + file = new File("plugins/LogBlock/log/" + params.getTitle().replace(":", ".").replace("/", "_") + ".log"); sender.sendMessage(ChatColor.GREEN + "Creating " + file.getName()); rs = executeQuery(state, params.getQuery()); file.getParentFile().mkdirs(); From 89d9da02e35280741086ee75f6265e585437a657 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 3 Aug 2018 23:04:35 +0200 Subject: [PATCH 089/399] Do not enforce row limit for auto clear logs --- src/main/java/de/diddiz/LogBlock/AutoClearLog.java | 1 + src/main/java/de/diddiz/LogBlock/QueryParams.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/AutoClearLog.java b/src/main/java/de/diddiz/LogBlock/AutoClearLog.java index 0173ec8d..c4175431 100644 --- a/src/main/java/de/diddiz/LogBlock/AutoClearLog.java +++ b/src/main/java/de/diddiz/LogBlock/AutoClearLog.java @@ -19,6 +19,7 @@ public void run() { for (final String paramStr : autoClearLog) { try { final QueryParams params = new QueryParams(logblock, getConsoleSender(), Arrays.asList(paramStr.split(" "))); + params.noForcedLimit = true; handler.new CommandClearLog(getServer().getConsoleSender(), params, false); } catch (final Exception ex) { getLogger().log(Level.SEVERE, "Failed to schedule auto ClearLog: ", ex); diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index fcb8419b..5fa454aa 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -58,7 +58,7 @@ public final class QueryParams implements Cloneable { public List players = new ArrayList(); public List killers = new ArrayList(); public List victims = new ArrayList(); - public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, excludeBlocksMode = false, prepareToolQuery = false, silent = false; + public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, excludeBlocksMode = false, prepareToolQuery = false, silent = false, noForcedLimit = false; public CuboidRegion sel = null; public SummarizationMode sum = SummarizationMode.NONE; public List types = new ArrayList(); @@ -87,7 +87,7 @@ public static int getKeyWordMinArguments(String param) { } public String getLimit() { - if (Config.hardLinesLimit <= 0 || (limit > 0 && limit <= Config.hardLinesLimit)) { + if (noForcedLimit || Config.hardLinesLimit <= 0 || (limit > 0 && limit <= Config.hardLinesLimit)) { return limit > 0 ? "LIMIT " + limit : ""; } return "LIMIT " + Config.hardLinesLimit; From 83506e6cd928a5ca579012d8a34a8e606ee23900 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 4 Aug 2018 05:36:06 +0200 Subject: [PATCH 090/399] Cleanup query generation --- .../java/de/diddiz/LogBlock/QueryParams.java | 209 +++++++++++------- 1 file changed, 125 insertions(+), 84 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 5fa454aa..04972c78 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -93,11 +93,65 @@ public String getLimit() { return "LIMIT " + Config.hardLinesLimit; } - public String getQuery() { + public String getFrom() { + if (sum != SummarizationMode.NONE) { + throw new IllegalStateException("No implemented for summarization"); + } + if (bct == BlockChangeType.CHAT) { + String from = "FROM `lb-chat` "; + + if (needPlayer || players.size() > 0) { + from += "INNER JOIN `lb-players` USING (playerid) "; + } + return from; + } + if (bct == BlockChangeType.KILLS) { + String from = "FROM `" + getTable() + "-kills` "; + + if (needPlayer || needKiller || killers.size() > 0) { + from += "INNER JOIN `lb-players` as killers ON (killer=killers.playerid) "; + } + + if (needPlayer || needVictim || victims.size() > 0) { + from += "INNER JOIN `lb-players` as victims ON (victim=victims.playerid) "; + } + return from; + } + + String from = "FROM `" + getTable() + "-blocks` "; + if (needPlayer || players.size() > 0) { + from += "INNER JOIN `lb-players` USING (playerid) "; + } + if (!needCount && needData) { + from += "LEFT JOIN `" + getTable() + "-state` USING (id) "; + } + if (needChestAccess) + // If BlockChangeType is CHESTACCESS, we can use more efficient query + { + if (bct == BlockChangeType.CHESTACCESS) { + from += "RIGHT JOIN `" + getTable() + "-chestdata` USING (id) "; + } else { + from += "LEFT JOIN `" + getTable() + "-chestdata` USING (id) "; + } + } + return from; + } + + public String getOrder() { + if (sum != SummarizationMode.NONE) { + throw new IllegalStateException("No implemented for summarization"); + } + return "ORDER BY date " + order + ", id " + order + " "; + } + + public String getFields() { + if (sum != SummarizationMode.NONE) { + throw new IllegalStateException("No implemented for summarization"); + } if (bct == BlockChangeType.CHAT) { - String select = "SELECT "; + String select = ""; if (needCount) { - select += "COUNT(*) AS count"; + select += "COUNT(*) AS count "; } else { if (needId) { select += "id, "; @@ -111,105 +165,84 @@ public String getQuery() { if (needMessage) { select += "message, "; } - select = select.substring(0, select.length() - 2); + select = select.substring(0, select.length() - 2) + " "; } - String from = "FROM `lb-chat` "; - - if (needPlayer || players.size() > 0) { - from += "INNER JOIN `lb-players` USING (playerid) "; - } - return select + " " + from + getWhere() + "ORDER BY date " + order + ", id " + order + " " + getLimit(); + return select; } if (bct == BlockChangeType.KILLS) { - if (sum == SummarizationMode.NONE) { - String select = "SELECT "; - if (needCount) { - select += "COUNT(*) AS count"; - } else { - if (needId) { - select += "id, "; - } - if (needDate) { - select += "date, "; - } - if (needPlayer || needKiller) { - select += "killers.playername as killer, "; - } - if (needPlayer || needVictim) { - select += "victims.playername as victim, "; - } - if (needWeapon) { - select += "weapon, "; - } - if (needCoords) { - select += "x, y, z, "; - } - select = select.substring(0, select.length() - 2); - } - String from = "FROM `" + getTable() + "-kills` "; - - if (needPlayer || needKiller || killers.size() > 0) { - from += "INNER JOIN `lb-players` as killers ON (killer=killers.playerid) "; - } - - if (needPlayer || needVictim || victims.size() > 0) { - from += "INNER JOIN `lb-players` as victims ON (victim=victims.playerid) "; - } - - return select + " " + from + getWhere() + "ORDER BY date " + order + ", id " + order + " " + getLimit(); - } else if (sum == SummarizationMode.PLAYERS) { - return "SELECT playername, UUID, SUM(kills) AS kills, SUM(killed) AS killed FROM ((SELECT killer AS playerid, count(*) AS kills, 0 as killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY killer) UNION (SELECT victim AS playerid, 0 as kills, count(*) AS killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY victim)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(kills) + SUM(killed) " + order + " " + getLimit(); - } - } - if (sum == SummarizationMode.NONE) { - String select = "SELECT "; + String select = ""; if (needCount) { - select += "COUNT(*) AS count"; + select += "COUNT(*) AS count "; } else { if (needId) { - select += "`" + getTable() + "`-blocks.id, "; + select += "id, "; } if (needDate) { select += "date, "; } - if (needType) { - select += "replaced, type, "; + if (needPlayer || needKiller) { + select += "killers.playername as killer, "; } - if (needData) { - select += "replacedData, typeData, "; + if (needPlayer || needVictim) { + select += "victims.playername as victim, "; } - if (needPlayer) { - select += "playername, UUID, "; + if (needWeapon) { + select += "weapon, "; } if (needCoords) { select += "x, y, z, "; } - if (needData) { - select += "replacedState, typeState, "; - } - if (needChestAccess) { - select += "item, itemremove, itemtype, "; - } - select = select.substring(0, select.length() - 2); + select = select.substring(0, select.length() - 2) + " "; } - String from = "FROM `" + getTable() + "-blocks` "; - if (needPlayer || players.size() > 0) { - from += "INNER JOIN `lb-players` USING (playerid) "; + return select; + } + String select = ""; + if (needCount) { + select += "COUNT(*) AS count "; + } else { + if (needId) { + select += "`" + getTable() + "`-blocks.id, "; } - if (!needCount && needData) { - from += "LEFT JOIN `" + getTable() + "-state` USING (id) "; + if (needDate) { + select += "date, "; } - if (needChestAccess) - // If BlockChangeType is CHESTACCESS, we can use more efficient query - { - if (bct == BlockChangeType.CHESTACCESS) { - from += "RIGHT JOIN `" + getTable() + "-chestdata` USING (id) "; - } else { - from += "LEFT JOIN `" + getTable() + "-chestdata` USING (id) "; - } + if (needType) { + select += "replaced, type, "; + } + if (needData) { + select += "replacedData, typeData, "; } - return select + " " + from + getWhere() + "ORDER BY date " + order + ", id " + order + " " + getLimit(); - } else if (sum == SummarizationMode.TYPES) { + if (needPlayer) { + select += "playername, UUID, "; + } + if (needCoords) { + select += "x, y, z, "; + } + if (needData) { + select += "replacedState, typeState, "; + } + if (needChestAccess) { + select += "item, itemremove, itemtype, "; + } + select = select.substring(0, select.length() - 2) + " "; + } + return select; + } + + public String getQuery() { + if (sum == SummarizationMode.NONE) { + return "SELECT " + getFields() + getFrom() + getWhere() + getOrder() + getLimit(); + } + if (bct == BlockChangeType.CHAT) { + throw new IllegalStateException("Invalid summarization for chat"); + } + if (bct == BlockChangeType.KILLS) { + if (sum == SummarizationMode.PLAYERS) { + return "SELECT playername, UUID, SUM(kills) AS kills, SUM(killed) AS killed FROM ((SELECT killer AS playerid, count(*) AS kills, 0 as killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY killer) UNION (SELECT victim AS playerid, 0 as kills, count(*) AS killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY victim)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(kills) + SUM(killed) " + order + " " + getLimit(); + } + throw new IllegalStateException("Invalid summarization for kills"); + } + if (sum == SummarizationMode.TYPES) { return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.CREATED) + "GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); } else { return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); @@ -798,6 +831,9 @@ public void validate() { if (!getWorldConfig(world).isLogging(Logging.KILL)) { throw new IllegalArgumentException("Kill logging not enabled for world '" + world.getName() + "'"); } + if (sum != SummarizationMode.NONE && sum != SummarizationMode.PLAYERS) { + throw new IllegalArgumentException("Invalid summarization for kills"); + } } if (!prepareToolQuery && bct != BlockChangeType.CHAT) { if (world == null) { @@ -807,8 +843,13 @@ public void validate() { throw new IllegalArgumentException("This world ('" + world.getName() + "') isn't logged"); } } - if (bct == BlockChangeType.CHAT && !Config.isLogging(Logging.CHAT)) { - throw new IllegalArgumentException("Chat is not logged"); + if (bct == BlockChangeType.CHAT) { + if (!Config.isLogging(Logging.CHAT)) { + throw new IllegalArgumentException("Chat is not logged"); + } + if (sum != SummarizationMode.NONE) { + throw new IllegalArgumentException("Invalid summarization for chat"); + } } } From 466775631b8698828d1a78cd27c7fec8b90978aa Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 4 Aug 2018 15:09:57 +0200 Subject: [PATCH 091/399] Improve clearlog - Allow clearing of chat & kills table, Resolves #662 - Improve performance by using muti table delete, Fixes #179 - Do not use INTO OUTFILE for dumping logs --- .../de/diddiz/LogBlock/CommandsHandler.java | 172 +++++++++++++----- .../java/de/diddiz/LogBlock/QueryParams.java | 17 +- 2 files changed, 142 insertions(+), 47 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 55359119..885bb90c 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -17,8 +17,12 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.scheduler.BukkitScheduler; +import java.io.BufferedOutputStream; +import java.io.BufferedWriter; import java.io.File; +import java.io.FileOutputStream; import java.io.FileWriter; +import java.io.OutputStreamWriter; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; @@ -295,9 +299,10 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, } } else if (command.equals("clearlog")) { if (logblock.hasPermission(sender, "logblock.clearlog")) { - final QueryParams params = new QueryParams(logblock, sender, argsToList(args, 1)); - params.bct = BlockChangeType.ALL; + final QueryParams params = new QueryParams(logblock); params.limit = -1; + params.bct = BlockChangeType.ALL; + params.parseArgs(sender, argsToList(args, 1)); new CommandClearLog(sender, params, true); } else { sender.sendMessage(ChatColor.RED + "You aren't allowed to do this"); @@ -533,7 +538,11 @@ public void run() { return; } state = conn.createStatement(); - file = new File("plugins/LogBlock/log/" + params.getTitle().replace(":", ".").replace("/", "_") + ".log"); + final File dumpFolder = new File(logblock.getDataFolder(), "log"); + if (!dumpFolder.exists()) { + dumpFolder.mkdirs(); + } + file = new File(dumpFolder, params.getTitle().replace(":", ".").replace("/", "_").replace("\\", "_") + ".log"); sender.sendMessage(ChatColor.GREEN + "Creating " + file.getName()); rs = executeQuery(state, params.getQuery()); file.getParentFile().mkdirs(); @@ -798,6 +807,7 @@ public CommandClearLog(CommandSender sender, QueryParams params, boolean async) public void run() { try { conn = logblock.getConnection(); + conn.setAutoCommit(true); state = conn.createStatement(); if (conn == null) { sender.sendMessage(ChatColor.RED + "MySQL connection lost"); @@ -806,55 +816,131 @@ public void run() { if (!checkRestrictions(sender, params)) { return; } + if (params.sum != SummarizationMode.NONE) { + sender.sendMessage(ChatColor.RED + "Cannot summarize on ClearLog"); + return; + } + String tableBase; + String deleteFromTables; + String tableName; + params.needId = true; + params.needDate = true; + params.needPlayer = false; + params.needPlayerId = true; + if (params.bct == BlockChangeType.CHAT) { + params.needMessage = true; + tableBase = "lb-chat"; + deleteFromTables = "`lb-chat` "; + tableName = "lb-chat"; + } else if (params.bct == BlockChangeType.KILLS) { + params.needWeapon = true; + params.needCoords = true; + tableBase = params.getTable(); + deleteFromTables = "`" + tableBase + "-kills` "; + tableName = tableBase + "-kills"; + } else { + params.needType = true; + params.needCoords = true; + params.needData = true; + params.needChestAccess = true; + tableBase = params.getTable(); + deleteFromTables = "`" + tableBase + "-blocks`, `" + tableBase + "-state`, `" + tableBase + "-chestdata` "; + tableName = tableBase + "-blocks"; + } final File dumpFolder = new File(logblock.getDataFolder(), "dump"); if (!dumpFolder.exists()) { dumpFolder.mkdirs(); } - final String time = new SimpleDateFormat("yyMMddHHmmss").format(System.currentTimeMillis()); - int deleted; - final String table = params.getTable(); - final String join = params.players.size() > 0 ? "INNER JOIN `lb-players` USING (playerid) " : ""; - rs = state.executeQuery("SELECT count(*) FROM `" + table + "-blocks` " + join + params.getWhere()); - rs.next(); - if ((deleted = rs.getInt(1)) > 0) { - if (!params.silent && askClearLogs && sender instanceof Player) { - sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); - sender.sendMessage(ChatColor.GREEN.toString() + deleted + " blocks found."); - if (!logblock.getQuestioner().ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { - sender.sendMessage(ChatColor.RED + "ClearLog aborted"); - return; - } + rs = state.executeQuery("SELECT count(*) " + params.getFrom() + params.getWhere()); + int deleted = rs.next() ? rs.getInt(1) : 0; + rs.close(); + if (deleted == 0) { + if (!params.silent) { + sender.sendMessage(ChatColor.GREEN.toString() + deleted + " entries found."); + } + return; + } + if (!params.silent && askClearLogs && sender instanceof Player) { + sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); + sender.sendMessage(ChatColor.GREEN.toString() + deleted + " entries found."); + if (!logblock.getQuestioner().ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { + sender.sendMessage(ChatColor.RED + "ClearLog aborted"); + return; } - if (dumpDeletedLog) { + } + if (dumpDeletedLog) { + final String time = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss").format(System.currentTimeMillis()); + try { + File outFile = new File(dumpFolder, (time + " " + tableName + " " + params.getTitle() + ".sql").replace(':', '.').replace('/', '_').replace('\\', '_')); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(outFile)), "UTF-8")); try { - state.execute("SELECT * FROM `" + table + "-blocks` " + join + params.getWhere() + "INTO OUTFILE '" + new File(dumpFolder, time + " " + table + " " + params.getTitle().replace(":", ".") + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); - } catch (final SQLException ex) { - sender.sendMessage(ChatColor.RED + "Error while dumping log. Make sure your MySQL user has access to the LogBlock folder, or disable clearlog.dumpDeletedLog"); - logblock.getLogger().log(Level.SEVERE, "[ClearLog] Exception while dumping log: ", ex); - return; + rs = state.executeQuery("SELECT " + params.getFields() + params.getFrom() + params.getWhere()); + while (rs.next()) { + StringBuilder sb = new StringBuilder(); + if (params.bct == BlockChangeType.CHAT) { + sb.append("INSERT INTO `lb-chat` (`id`, `date`, `playerid`, `message`) VALUES ("); + sb.append(rs.getInt("id")).append(", FROM_UNIXTIME("); + sb.append(rs.getTimestamp("date").getTime() / 1000).append("), "); + sb.append(rs.getInt("playerid")).append(", '"); + sb.append(Utils.mysqlTextEscape(rs.getString("message"))); + sb.append("');\n"); + } else if (params.bct == BlockChangeType.KILLS) { + sb.append("INSERT INTO `").append(tableBase).append("-kills` (`id`, `date`, `killer`, `victim`, `weapon`, `x`, `y`, `z`) VALUES ("); + sb.append(rs.getInt("id")).append(", FROM_UNIXTIME("); + sb.append(rs.getTimestamp("date").getTime() / 1000).append("), "); + sb.append(rs.getInt("killerid")).append(", "); + sb.append(rs.getInt("victimid")).append(", "); + sb.append(rs.getInt("weapon")).append(", "); + sb.append(rs.getInt("x")).append(", "); + sb.append(rs.getInt("y")).append(", "); + sb.append(rs.getInt("z")); + sb.append(");\n"); + } else { + sb.append("INSERT INTO `").append(tableBase).append("-blocks` (`id`, `date`, `playerid`, `replaced`, `replacedData`, `type`, `typeData`, `x`, `y`, `z`) VALUES ("); + sb.append(rs.getInt("id")).append(", FROM_UNIXTIME("); + sb.append(rs.getTimestamp("date").getTime() / 1000).append("), "); + sb.append(rs.getInt("playerid")).append(", "); + sb.append(rs.getInt("replaced")).append(", "); + sb.append(rs.getInt("replacedData")).append(", "); + sb.append(rs.getInt("type")).append(", "); + sb.append(rs.getInt("typeData")).append(", "); + sb.append(rs.getInt("x")).append(", "); + sb.append(rs.getInt("y")).append(", "); + sb.append(rs.getInt("z")); + sb.append(");\n"); + byte[] replacedState = rs.getBytes("replacedState"); + byte[] typeState = rs.getBytes("typeState"); + if (replacedState != null || typeState != null) { + sb.append("INSERT INTO `").append(tableBase).append("-state` (`id`, `replacedState`, `typeState`) VALUES ("); + sb.append(rs.getInt("id")).append(", "); + sb.append(Utils.mysqlPrepareBytesForInsertAllowNull(replacedState)).append(", "); + sb.append(Utils.mysqlPrepareBytesForInsertAllowNull(typeState)); + sb.append(");\n"); + } + byte[] item = rs.getBytes("item"); + if (item != null) { + sb.append("INSERT INTO `").append(tableBase).append("-chestdata` (`id`, `item`, `itemremove`, `itemtype`) VALUES ("); + sb.append(rs.getInt("id")).append(", "); + sb.append(Utils.mysqlPrepareBytesForInsertAllowNull(item)).append(", "); + sb.append(rs.getInt("itemremove")).append(", "); + sb.append(rs.getInt("itemtype")); + sb.append(");\n"); + } + } + writer.write(sb.toString()); + } + rs.close(); + } finally { + writer.close(); } + } catch (final SQLException ex) { + sender.sendMessage(ChatColor.RED + "Error while dumping log."); + logblock.getLogger().log(Level.SEVERE, "[ClearLog] Exception while dumping log: ", ex); + return; } - state.execute("DELETE `" + table + "-blocks` FROM `" + table + "-blocks` " + join + params.getWhere()); - sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + ". Deleted " + deleted + " entries."); - } - rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-state` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL"); - rs.next(); - if ((deleted = rs.getInt(1)) > 0) { - if (dumpDeletedLog) { - state.execute("SELECT id, replacedState, typeState FROM `" + table + "-state` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-state " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); - } - state.execute("DELETE `" + table + "-state` FROM `" + table + "-state` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL;"); - sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-state. Deleted " + deleted + " entries."); - } - rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-chestdata` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL"); - rs.next(); - if ((deleted = rs.getInt(1)) > 0) { - if (dumpDeletedLog) { - state.execute("SELECT id, item, itemremove, itemtype FROM `" + table + "-chestdata` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-chest " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); - } - state.execute("DELETE `" + table + "-chestdata` FROM `" + table + "-chestdata` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL;"); - sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-chestdata. Deleted " + deleted + " entries."); } + state.executeUpdate("DELETE " + deleteFromTables + params.getFrom() + params.getWhere()); + sender.sendMessage(ChatColor.GREEN + "Cleared out table " + tableName + ". Deleted " + deleted + " entries."); } catch (final Exception ex) { if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { sender.sendMessage(ChatColor.RED + "Exception, check error log"); diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 04972c78..0fd9a548 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -65,7 +65,7 @@ public final class QueryParams implements Cloneable { public List typeIds = new ArrayList(); public World world = null; public String match = null; - public boolean needCount = false, needId = false, needDate = false, needType = false, needData = false, needPlayer = false, needCoords = false, needChestAccess = false, needMessage = false, needKiller = false, needVictim = false, needWeapon = false; + public boolean needCount = false, needId = false, needDate = false, needType = false, needData = false, needPlayerId = false, needPlayer = false, needCoords = false, needChestAccess = false, needMessage = false, needKiller = false, needVictim = false, needWeapon = false; private final LogBlock logblock; public QueryParams(LogBlock logblock) { @@ -160,7 +160,10 @@ public String getFields() { select += "date, "; } if (needPlayer) { - select += "playername, UUID,"; + select += "playername, UUID, "; + } + if (needPlayerId) { + select += "playerid, "; } if (needMessage) { select += "message, "; @@ -186,6 +189,9 @@ public String getFields() { if (needPlayer || needVictim) { select += "victims.playername as victim, "; } + if (needPlayerId) { + select += "killer as killerid, victim as victimid, "; + } if (needWeapon) { select += "weapon, "; } @@ -201,7 +207,7 @@ public String getFields() { select += "COUNT(*) AS count "; } else { if (needId) { - select += "`" + getTable() + "`-blocks.id, "; + select += "`" + getTable() + "-blocks`.id, "; } if (needDate) { select += "date, "; @@ -215,6 +221,9 @@ public String getFields() { if (needPlayer) { select += "playername, UUID, "; } + if (needPlayerId) { + select += "playerid, "; + } if (needCoords) { select += "x, y, z, "; } @@ -305,7 +314,7 @@ public String getTitle() { } else if (since > 0) { title.append("in the last ").append(since).append(" minutes "); } else if (before > 0) { - title.append("more than ").append(before * -1).append(" minutes ago "); + title.append("more than ").append(before).append(" minutes ago "); } if (loc != null) { if (radius > 0) { From dc4d7e0319dbb4d236a88a8f84d7a75c03e2ce4a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 4 Aug 2018 15:19:30 +0200 Subject: [PATCH 092/399] We might need the player in clearlog --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 885bb90c..d72c5089 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -825,7 +825,6 @@ public void run() { String tableName; params.needId = true; params.needDate = true; - params.needPlayer = false; params.needPlayerId = true; if (params.bct == BlockChangeType.CHAT) { params.needMessage = true; From 51b72bafa65644d122a496b727d3cdd54feac2f0 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 4 Aug 2018 15:42:55 +0200 Subject: [PATCH 093/399] Update slf4j-jdk14 dependency --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f1d5d840..8db6e049 100644 --- a/pom.xml +++ b/pom.xml @@ -66,7 +66,7 @@ org.slf4j slf4j-jdk14 - 1.7.10 + 1.7.25 compile From ce1a1c3bd27637d6b55541a86e56040e84755961 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 5 Aug 2018 05:45:05 +0200 Subject: [PATCH 094/399] Fix fire spread logging --- .../LogBlock/listeners/BlockBurnLogging.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java index b0571cde..87ad67f2 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java @@ -10,6 +10,8 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockBurnEvent; +import org.bukkit.event.block.BlockIgniteEvent; +import org.bukkit.event.block.BlockIgniteEvent.IgniteCause; import org.bukkit.event.player.PlayerInteractEvent; import static de.diddiz.LogBlock.config.Config.isLogging; @@ -29,6 +31,29 @@ public void onBlockBurn(BlockBurnEvent event) { } } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockIgnite(BlockIgniteEvent event) { + Actor actor = new Actor("Fire"); + if (event.getCause() == IgniteCause.FLINT_AND_STEEL) { + if(event.getIgnitingEntity() != null) { + return; // handled in block place + } else { + actor = new Actor("Dispenser"); + } + } else if(event.getCause() == IgniteCause.LIGHTNING) { + actor = new Actor("Lightning"); + } else if(event.getCause() == IgniteCause.EXPLOSION) { + actor = new Actor("Explosion"); + } else if(event.getCause() == IgniteCause.LAVA) { + actor = new Actor("Lava"); + } else if(event.getCause() == IgniteCause.ENDER_CRYSTAL) { + actor = new Actor("EnderCrystal"); + } + if (isLogging(event.getBlock().getWorld(), Logging.FIRE)) { + consumer.queueBlockPlace(actor, event.getBlock().getLocation(), Material.FIRE.createBlockData()); + } + } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onExtinguish(PlayerInteractEvent event) { if (event.getAction().equals(Action.LEFT_CLICK_BLOCK)) { From 572df51d285de8812e6c8bffb732b33ec8c2169d Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 9 Aug 2018 05:00:11 +0200 Subject: [PATCH 095/399] Change the api from using byte[] to YamlConfiguration byte[] is only used for database rows --- .../java/de/diddiz/LogBlock/BlockChange.java | 4 +- .../java/de/diddiz/LogBlock/Consumer.java | 14 +++--- .../java/de/diddiz/LogBlock/WorldEditor.java | 3 +- .../LogBlock/blockstate/BlockStateCodecs.java | 33 +++---------- .../events/BlockChangePreLogEvent.java | 48 ++++++------------- src/main/java/de/diddiz/util/Utils.java | 23 +++++---- 6 files changed, 47 insertions(+), 78 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 491c35fa..1dbff2d7 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -75,7 +75,7 @@ public String toString() { String typeDetails = null; if (BlockStateCodecs.hasCodec(type.getMaterial())) { try { - typeDetails = BlockStateCodecs.toString(type.getMaterial(), typeState); + typeDetails = BlockStateCodecs.toString(type.getMaterial(), Utils.deserializeYamlConfiguration(typeState)); } catch (Exception e) { LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + type.getMaterial(), e); } @@ -88,7 +88,7 @@ public String toString() { String replacedDetails = null; if (BlockStateCodecs.hasCodec(replaced.getMaterial())) { try { - replacedDetails = BlockStateCodecs.toString(replaced.getMaterial(), replacedState); + replacedDetails = BlockStateCodecs.toString(replaced.getMaterial(), Utils.deserializeYamlConfiguration(replacedState)); } catch (Exception e) { LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + replaced.getMaterial(), e); } diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index c384f258..31e315c8 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -34,6 +34,7 @@ import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.block.data.BlockData; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; @@ -325,7 +326,7 @@ public void queueKill(Location location, Actor killer, Actor victim, ItemStack w * @param typeState * Serialized text data of the sign */ - public void queueSignBreak(Actor actor, Location loc, BlockData type, byte[] typeState) { + public void queueSignBreak(Actor actor, Location loc, BlockData type, YamlConfiguration typeState) { queueBlock(actor, loc, type, null, typeState, null, null); } @@ -357,7 +358,7 @@ public void queueSignPlace(Actor actor, Location loc, BlockData type, String[] l if ((type.getMaterial() != Material.SIGN && type.getMaterial() != Material.WALL_SIGN) || lines == null || lines.length != 4) { return; } - queueBlock(actor, loc, type, type, null, Utils.serializeYamlConfiguration(BlockStateCodecSign.serialize(lines)), null); + queueBlock(actor, loc, type, type, null, BlockStateCodecSign.serialize(lines), null); } /** @@ -633,7 +634,7 @@ private boolean addPlayer(Connection conn, Actor actor) throws SQLException { return uncommitedPlayerIds.containsKey(actor); } - private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter, byte[] stateBefore, byte[] stateAfter, ChestAccess ca) { + private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter, YamlConfiguration stateBefore, YamlConfiguration stateAfter, ChestAccess ca) { if (typeBefore == null || typeBefore.getMaterial() == Material.CAVE_AIR || typeBefore.getMaterial() == Material.VOID_AIR) { typeBefore = Bukkit.createBlockData(Material.AIR); } @@ -642,7 +643,7 @@ private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDa } if (Config.fireCustomEvents) { // Create and call the event - BlockChangePreLogEvent event = new BlockChangePreLogEvent(actor, loc, typeBefore, typeAfter, null, ca); + BlockChangePreLogEvent event = new BlockChangePreLogEvent(actor, loc, typeBefore, typeAfter, stateBefore, stateAfter, ca); logblock.getServer().getPluginManager().callEvent(event); if (event.isCancelled()) { return; @@ -653,7 +654,8 @@ private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDa loc = event.getLocation(); typeBefore = event.getTypeBefore(); typeAfter = event.getTypeAfter(); - // signtext = event.getSignText(); + stateBefore = event.getStateBefore(); + stateAfter = event.getStateAfter(); ca = event.getChestAccess(); } // Do this last so LogBlock still has final say in what is being added @@ -668,7 +670,7 @@ private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDa int typeMaterialId = MaterialConverter.getOrAddMaterialId(typeString); int typeStateId = MaterialConverter.getOrAddBlockStateId(typeString); - addQueueLast(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, stateBefore, typeMaterialId, typeStateId, stateAfter, ca)); + addQueueLast(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, Utils.serializeYamlConfiguration(stateBefore), typeMaterialId, typeStateId, Utils.serializeYamlConfiguration(stateAfter), ca)); } private String playerID(Actor actor) { diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 73e5fa71..9f0d347f 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -22,6 +22,7 @@ import de.diddiz.LogBlock.blockstate.BlockStateCodecs; import de.diddiz.util.BukkitUtils; +import de.diddiz.util.Utils; import java.io.File; import java.io.PrintWriter; @@ -205,7 +206,7 @@ PerformResult perform() throws WorldEditorException { if (BlockStateCodecs.hasCodec(replacedBlock.getMaterial())) { state = block.getState(); try { - BlockStateCodecs.deserialize(state, replacedState); + BlockStateCodecs.deserialize(state, Utils.deserializeYamlConfiguration(replacedState)); state.update(); } catch (Exception e) { throw new WorldEditorException("Failed to restore blockstate of " + block.getType() + ": " + e, block.getLocation()); diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java index 8cac08ac..de446938 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java @@ -2,16 +2,11 @@ import java.util.EnumMap; import java.util.Map; -import java.util.logging.Level; import org.bukkit.Material; import org.bukkit.block.BlockState; -import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.util.Utils; - public class BlockStateCodecs { private static Map codecs = new EnumMap<>(Material.class); @@ -36,44 +31,28 @@ public static boolean hasCodec(Material material) { return codecs.containsKey(material); } - public static byte[] serialize(BlockState state) { + public static YamlConfiguration serialize(BlockState state) { BlockStateCodec codec = codecs.get(state.getType()); if (codec != null) { YamlConfiguration serialized = codec.serialize(state); if (serialized != null && !serialized.getKeys(false).isEmpty()) { - return Utils.serializeYamlConfiguration(serialized); + return serialized; } } return null; } - public static void deserialize(BlockState block, byte[] state) { + public static void deserialize(BlockState block, YamlConfiguration state) { BlockStateCodec codec = codecs.get(block.getType()); if (codec != null) { - YamlConfiguration conf = null; - try { - if (state != null) { - conf = Utils.deserializeYamlConfiguration(state); - } - } catch (InvalidConfigurationException e) { - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Exception while deserializing BlockState", e); - } - codec.deserialize(block, conf); + codec.deserialize(block, state); } } - public static String toString(Material material, byte[] state) { + public static String toString(Material material, YamlConfiguration state) { BlockStateCodec codec = codecs.get(material); if (codec != null) { - YamlConfiguration conf = null; - try { - if (state != null) { - conf = Utils.deserializeYamlConfiguration(state); - } - } catch (InvalidConfigurationException e) { - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Exception while deserializing BlockState", e); - } - return codec.toString(conf); + return codec.toString(state); } return null; } diff --git a/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java b/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java index 9d7bf62e..fdb25dad 100644 --- a/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java +++ b/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java @@ -2,13 +2,12 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.ChestAccess; -import de.diddiz.util.BukkitUtils; -import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.data.BlockData; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.event.HandlerList; public class BlockChangePreLogEvent extends PreLogEvent { @@ -16,17 +15,19 @@ public class BlockChangePreLogEvent extends PreLogEvent { private static final HandlerList handlers = new HandlerList(); private Location location; private BlockData typeBefore, typeAfter; - private String signText; private ChestAccess chestAccess; + private YamlConfiguration stateBefore; + private YamlConfiguration stateAfter; public BlockChangePreLogEvent(Actor owner, Location location, BlockData typeBefore, BlockData typeAfter, - String signText, ChestAccess chestAccess) { + YamlConfiguration stateBefore, YamlConfiguration stateAfter, ChestAccess chestAccess) { super(owner); this.location = location; this.typeBefore = typeBefore; this.typeAfter = typeAfter; - this.signText = signText; + this.stateBefore = stateBefore; + this.stateAfter = stateAfter; this.chestAccess = chestAccess; } @@ -64,39 +65,20 @@ public void setTypeAfter(BlockData typeAfter) { this.typeAfter = typeAfter; } - public String getSignText() { - - return signText; + public YamlConfiguration getStateBefore() { + return stateBefore; } - public void setSignText(String[] signText) { - - if (signText != null) { - // Check for block - Validate.isTrue(isValidSign(), "Must be valid sign block"); - - // Check for problems - Validate.noNullElements(signText, "No null lines"); - Validate.isTrue(signText.length == 4, "Sign text must be 4 strings"); - - this.signText = signText[0] + "\0" + signText[1] + "\0" + signText[2] + "\0" + signText[3]; - } else { - this.signText = null; - } + public YamlConfiguration getStateAfter() { + return stateAfter; } - private boolean isValidSign() { + public void setStateBefore(YamlConfiguration stateBefore) { + this.stateBefore = stateBefore; + } - if ((typeAfter.getMaterial() == Material.SIGN || typeAfter.getMaterial() == Material.WALL_SIGN) && BukkitUtils.isEmpty(typeBefore.getMaterial())) { - return true; - } - if ((typeBefore.getMaterial() == Material.SIGN || typeBefore.getMaterial() == Material.WALL_SIGN) && BukkitUtils.isEmpty(typeAfter.getMaterial())) { - return true; - } - if ((typeAfter.getMaterial() == Material.SIGN || typeAfter.getMaterial() == Material.WALL_SIGN) && typeBefore.equals(typeAfter)) { - return true; - } - return false; + public void setStateAfter(YamlConfiguration stateAfter) { + this.stateAfter = stateAfter; } public ChestAccess getChestAccess() { diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index a3d6428f..416c110b 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -11,7 +11,6 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; -import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; @@ -236,12 +235,8 @@ public static ItemStack loadItemStack(byte[] data) { if (data == null || data.length == 0) { return null; } - try { - return deserializeYamlConfiguration(data).getItemStack("stack"); - } catch (InvalidConfigurationException e) { - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Exception while deserializing ItemStack", e); - } - return null; + YamlConfiguration conf = deserializeYamlConfiguration(data); + return conf == null ? null : conf.getItemStack("stack"); } public static byte[] saveItemStack(ItemStack stack) { @@ -253,14 +248,17 @@ public static byte[] saveItemStack(ItemStack stack) { return serializeYamlConfiguration(conf); } - public static YamlConfiguration deserializeYamlConfiguration(byte[] data) throws InvalidConfigurationException { + public static YamlConfiguration deserializeYamlConfiguration(byte[] data) { + if (data == null || data.length == 0) { + return null; + } YamlConfiguration conf = new YamlConfiguration(); try { InputStreamReader reader = new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(data)), "UTF-8"); conf.load(reader); reader.close(); return conf; - } catch (ZipException e) { + } catch (ZipException | InvalidConfigurationException e) { LogBlock.getInstance().getLogger().warning("Could not deserialize YamlConfiguration: " + e.getMessage()); return conf; } catch (IOException e) { @@ -269,6 +267,9 @@ public static YamlConfiguration deserializeYamlConfiguration(byte[] data) throws } public static byte[] serializeYamlConfiguration(YamlConfiguration conf) { + if (conf == null || conf.getKeys(false).isEmpty()) { + return null; + } try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(new GZIPOutputStream(baos), "UTF-8"); @@ -279,4 +280,8 @@ public static byte[] serializeYamlConfiguration(YamlConfiguration conf) { throw new RuntimeException("IOException should be impossible for ByteArrayOutputStream", e); } } + + public static String serializeForSQL(YamlConfiguration conf) { + return mysqlPrepareBytesForInsertAllowNull(serializeYamlConfiguration(conf)); + } } From c997fb9db90c884a8b19302c0459bd5b6f72368e Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 13 Aug 2018 16:12:03 +0200 Subject: [PATCH 096/399] improve clearlog output when no rows are found --- .../java/de/diddiz/LogBlock/CommandsHandler.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index d72c5089..81d31c38 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -853,21 +853,15 @@ public void run() { rs = state.executeQuery("SELECT count(*) " + params.getFrom() + params.getWhere()); int deleted = rs.next() ? rs.getInt(1) : 0; rs.close(); - if (deleted == 0) { - if (!params.silent) { - sender.sendMessage(ChatColor.GREEN.toString() + deleted + " entries found."); - } - return; - } if (!params.silent && askClearLogs && sender instanceof Player) { sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); sender.sendMessage(ChatColor.GREEN.toString() + deleted + " entries found."); - if (!logblock.getQuestioner().ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { + if (deleted == 0 || !logblock.getQuestioner().ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { sender.sendMessage(ChatColor.RED + "ClearLog aborted"); return; } } - if (dumpDeletedLog) { + if (deleted > 0 && dumpDeletedLog) { final String time = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss").format(System.currentTimeMillis()); try { File outFile = new File(dumpFolder, (time + " " + tableName + " " + params.getTitle() + ".sql").replace(':', '.').replace('/', '_').replace('\\', '_')); @@ -938,7 +932,9 @@ public void run() { return; } } - state.executeUpdate("DELETE " + deleteFromTables + params.getFrom() + params.getWhere()); + if (deleted > 0) { + state.executeUpdate("DELETE " + deleteFromTables + params.getFrom() + params.getWhere()); + } sender.sendMessage(ChatColor.GREEN + "Cleared out table " + tableName + ". Deleted " + deleted + " entries."); } catch (final Exception ex) { if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { From eb0b969477c6c6eb5dcebc0d1666ef448a3eb620 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 16 Aug 2018 04:18:13 +0200 Subject: [PATCH 097/399] add jenkins ci to the readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 31a32700..9b17fdee 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,4 @@ LogBlock This plugin logs block changes such as breaking, placing, modifying, or burning to a MySQL Database. It can be used as an anti-griefing tool to find out who made a particular edit, or even roll back changes by certain players. Originally written by bootswithdefer, for hMod, ported to Bukkit by me, because of the inability to identfy griefers. BigBrother also did't work, so I was forced to do it myself. The honor belongs to bootswithdefer for the sourcecode, I only spent about 8 hours to transcribe. All functions except sign text logging shold work as in hMod. The use of permissions plugin is possible, but not necessary. -Questioner: http://git.io/u2MxKQ +You can download development builds [from our Jenkins server](https://www.iani.de/jenkins/job/LogBlock/). From 710de5b35a5717680cf3f3bd09ef750cdbb7870e Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 20 Aug 2018 18:25:40 +0200 Subject: [PATCH 098/399] Fix time restriction checking --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 81d31c38..b1523770 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -394,7 +394,7 @@ private boolean checkRestrictions(CommandSender sender, QueryParams params) { if (sender.isOp() || logblock.hasPermission(sender, "logblock.ignoreRestrictions")) { return true; } - if (rollbackMaxTime > 0 && (params.before > 0 || params.since > rollbackMaxTime)) { + if (rollbackMaxTime > 0 && (params.since <= 0 || params.since > rollbackMaxTime)) { sender.sendMessage(ChatColor.RED + "You are not allowed to rollback more than " + rollbackMaxTime + " minutes"); return false; } From 56404533db4535add10ae380ad0cbe2ed6bfb2b9 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 21 Aug 2018 06:17:24 +0200 Subject: [PATCH 099/399] Improved fire logging and rollback --- src/main/java/de/diddiz/LogBlock/Actor.java | 23 +++++++++++++ .../java/de/diddiz/LogBlock/Consumer.java | 34 ++++++++++++++++++- .../java/de/diddiz/LogBlock/WorldEditor.java | 2 +- .../de/diddiz/LogBlock/config/Config.java | 5 ++- .../LogBlock/listeners/BlockBurnLogging.java | 11 +++--- src/main/java/de/diddiz/util/LoggingUtil.java | 10 +++++- 6 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index 95d0f96b..f209c4b1 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -12,6 +12,8 @@ import static de.diddiz.util.BukkitUtils.entityName; import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.block.Block; public class Actor { @@ -36,23 +38,40 @@ public boolean equals(Object obj) { final String name; final String UUID; + final Location blockLocation; public Actor(String name, String UUID) { this.name = name; this.UUID = UUID; + this.blockLocation = null; + } + public Actor(String name, String UUID, Block block) { + this.name = name; + this.UUID = UUID; + this.blockLocation = block == null ? null : block.getLocation(); } public Actor(String name, java.util.UUID UUID) { this.name = name; this.UUID = UUID.toString(); + this.blockLocation = null; + } + public Actor(String name, java.util.UUID UUID, Block block) { + this.name = name; + this.UUID = UUID.toString(); + this.blockLocation = block == null ? null : block.getLocation(); } public Actor(String name) { this(name, generateUUID(name)); } + public Actor(String name, Block block) { + this(name, generateUUID(name), block); + } + public Actor(ResultSet rs) throws SQLException { this(rs.getString("playername"), rs.getString("UUID")); } @@ -65,6 +84,10 @@ public String getUUID() { return UUID; } + public Location getBlockLocation() { + return blockLocation; + } + public static Actor actorFromEntity(Entity entity) { if (entity instanceof Player) { return new Actor(entityName(entity), entity.getUniqueId()); diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 31e315c8..02ac4109 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -705,12 +705,14 @@ private static interface Row { private class BlockRow extends BlockChange implements Row { final String statementString; + final String selectActorIdStatementString; public BlockRow(Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { super(System.currentTimeMillis() / 1000, loc, actor, replaced, replacedData, replacedState, type, typeData, typeState, ca); final String table = getWorldConfig(loc.getWorld()).table; statementString = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"; + selectActorIdStatementString = "SELECT playerid FROM `" + table + "-blocks` WHERE x = ? AND y = ? AND z = ? ORDER BY date DESC LIMIT 1"; } @Override @@ -735,9 +737,27 @@ public Actor[] getActors() { @Override public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + int sourceActor = playerIDAsIntIncludeUncommited(actor); + Location actorBlockLocation = actor.getBlockLocation(); + if(actorBlockLocation != null) { + Integer tempSourceActor = batchHelper.getUncommitedBlockActor(actorBlockLocation); + if(tempSourceActor != null) { + sourceActor = tempSourceActor; + } else { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, selectActorIdStatementString, Statement.NO_GENERATED_KEYS); + smt.setInt(1, actorBlockLocation.getBlockX()); + smt.setInt(2, safeY(actorBlockLocation)); + smt.setInt(3, actorBlockLocation.getBlockZ()); + ResultSet rs = smt.executeQuery(); + if (rs.next()) { + sourceActor = rs.getInt(1); + } + rs.close(); + } + } PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.RETURN_GENERATED_KEYS); smt.setLong(1, date); - smt.setInt(2, playerIDAsIntIncludeUncommited(actor)); + smt.setInt(2, sourceActor); smt.setInt(3, replacedMaterial); smt.setInt(4, replacedData); smt.setInt(5, typeMaterial); @@ -745,6 +765,7 @@ public void process(Connection conn, BatchHelper batchHelper) throws SQLExceptio smt.setInt(7, loc.getBlockX()); smt.setInt(8, safeY(loc)); smt.setInt(9, loc.getBlockZ()); + batchHelper.addUncommitedBlockActorId(loc, sourceActor); batchHelper.addBatch(smt, new IntCallback() { @Override public void call(int id) throws SQLException { @@ -936,11 +957,21 @@ private class BatchHelper { private HashMap preparedStatements = new HashMap<>(); private HashSet preparedStatementsWithGeneratedKeys = new HashSet<>(); private LinkedHashMap> generatedKeyHandler = new LinkedHashMap<>(); + private HashMap uncommitedBlockActors = new HashMap<>(); public void reset() { preparedStatements.clear(); preparedStatementsWithGeneratedKeys.clear(); generatedKeyHandler.clear(); + uncommitedBlockActors.clear(); + } + + public void addUncommitedBlockActorId(Location loc, int actorId) { + uncommitedBlockActors.put(loc, actorId); + } + + public Integer getUncommitedBlockActor(Location loc) { + return uncommitedBlockActors.get(loc); } public void processStatements(Connection conn) throws SQLException { @@ -966,6 +997,7 @@ public void processStatements(Connection conn) throws SQLException { } } } + uncommitedBlockActors.clear(); } public PreparedStatement getOrPrepareStatement(Connection conn, String sql, int autoGeneratedKeys) throws SQLException { diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 9f0d347f..f590d9ae 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -194,7 +194,7 @@ PerformResult perform() throws WorldEditorException { return PerformResult.NO_ACTION; } } - if (block.getType() != setBlock.getMaterial() && !replaceAnyway.contains(block.getType())) { + if (block.getType() != setBlock.getMaterial() && !block.isEmpty() && !replaceAnyway.contains(block.getType())) { return PerformResult.NO_ACTION; } if (state instanceof InventoryHolder && replacedBlock.getMaterial() != block.getType()) { diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 723d9be3..0f520c2f 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -34,6 +34,7 @@ public class Config { public static boolean dumpDeletedLog; public static boolean logBedExplosionsAsPlayerWhoTriggeredThese; public static boolean logCreeperExplosionsAsPlayerWhoTriggeredThese, logPlayerInfo; + public static boolean logFireSpreadAsPlayerWhoCreatedIt; public static LogKillsLevel logKillsLevel; public static Set dontRollback, replaceAnyway; public static int rollbackMaxTime, rollbackMaxArea; @@ -93,6 +94,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("clearlog.autoClearLogDelay", "6h"); def.put("logging.logBedExplosionsAsPlayerWhoTriggeredThese", true); def.put("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false); + def.put("logging.logFireSpreadAsPlayerWhoCreatedIt", true); def.put("logging.logKillsLevel", "PLAYERS"); def.put("logging.logEnvironmentalKills", false); def.put("logging.logPlayerInfo", false); @@ -100,7 +102,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("logging.hiddenBlocks", Arrays.asList(Material.AIR.name(), Material.CAVE_AIR.name(), Material.VOID_AIR.name())); def.put("logging.ignoredChat", Arrays.asList("/register", "/login")); def.put("rollback.dontRollback", Arrays.asList(Material.LAVA.name(), Material.TNT.name(), Material.FIRE.name())); - def.put("rollback.replaceAnyway", Arrays.asList(Material.LAVA.name(), Material.WATER.name(), Material.FIRE.name())); + def.put("rollback.replaceAnyway", Arrays.asList(Material.LAVA.name(), Material.WATER.name(), Material.FIRE.name(), Material.GRASS_BLOCK.name())); def.put("rollback.maxTime", "2 days"); def.put("rollback.maxArea", 50); def.put("lookup.defaultDist", 20); @@ -169,6 +171,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti autoClearLogDelay = parseTimeSpec(config.getString("clearlog.autoClearLogDelay").split(" ")); logBedExplosionsAsPlayerWhoTriggeredThese = config.getBoolean("logging.logBedExplosionsAsPlayerWhoTriggeredThese", true); logCreeperExplosionsAsPlayerWhoTriggeredThese = config.getBoolean("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false); + logFireSpreadAsPlayerWhoCreatedIt = config.getBoolean("logging.logFireSpreadAsPlayerWhoCreatedIt", true); logPlayerInfo = config.getBoolean("logging.logPlayerInfo", true); try { logKillsLevel = LogKillsLevel.valueOf(config.getString("logging.logKillsLevel").toUpperCase()); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java index 87ad67f2..4d4ebc86 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java @@ -3,6 +3,8 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.Config; + import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Player; @@ -16,6 +18,7 @@ import static de.diddiz.LogBlock.config.Config.isLogging; import static de.diddiz.util.LoggingUtil.smartLogBlockBreak; +import static de.diddiz.util.LoggingUtil.smartLogBlockReplace; import static de.diddiz.util.LoggingUtil.smartLogFallables; public class BlockBurnLogging extends LoggingListener { @@ -26,16 +29,16 @@ public BlockBurnLogging(LogBlock lb) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockBurn(BlockBurnEvent event) { if (isLogging(event.getBlock().getWorld(), Logging.FIRE)) { - smartLogBlockBreak(consumer, new Actor("Fire"), event.getBlock()); - smartLogFallables(consumer, new Actor("Fire"), event.getBlock()); + smartLogBlockReplace(consumer, new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null), event.getBlock(), Material.FIRE.createBlockData()); + smartLogFallables(consumer, new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null), event.getBlock()); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockIgnite(BlockIgniteEvent event) { - Actor actor = new Actor("Fire"); + Actor actor = new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null); if (event.getCause() == IgniteCause.FLINT_AND_STEEL) { - if(event.getIgnitingEntity() != null) { + if (event.getIgnitingEntity() != null) { return; // handled in block place } else { actor = new Actor("Dispenser"); diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index c5026224..73d2f976 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -101,6 +101,10 @@ public static void smartLogFallables(Consumer consumer, Actor actor, Block origi } public static void smartLogBlockBreak(Consumer consumer, Actor actor, Block origin) { + smartLogBlockReplace(consumer, actor, origin, null); + } + + public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block origin, BlockData replacedWith) { WorldConfig wcfg = getWorldConfig(origin.getWorld()); if (wcfg == null) { @@ -187,7 +191,11 @@ public static void smartLogBlockBreak(Consumer consumer, Actor actor, Block orig } // Do this down here so that the block is added after blocks sitting on it - consumer.queueBlockBreak(actor, origin.getState()); + if (replacedWith == null) { + consumer.queueBlockBreak(actor, origin.getState()); + } else { + consumer.queueBlockReplace(actor, origin.getState(), replacedWith); + } } public static String checkText(String text) { From 681c4a20334419d26b8dafe511e6b3226794b3c1 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 21 Aug 2018 06:29:44 +0200 Subject: [PATCH 100/399] Reduce amount of string allocations --- src/main/java/de/diddiz/LogBlock/Consumer.java | 10 ++++------ .../java/de/diddiz/LogBlock/config/WorldConfig.java | 9 +++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 02ac4109..09b02887 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -710,9 +710,8 @@ private class BlockRow extends BlockChange implements Row { public BlockRow(Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { super(System.currentTimeMillis() / 1000, loc, actor, replaced, replacedData, replacedState, type, typeData, typeState, ca); - final String table = getWorldConfig(loc.getWorld()).table; - statementString = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"; - selectActorIdStatementString = "SELECT playerid FROM `" + table + "-blocks` WHERE x = ? AND y = ? AND z = ? ORDER BY date DESC LIMIT 1"; + statementString = getWorldConfig(loc.getWorld()).insertBlockStatementString; + selectActorIdStatementString = getWorldConfig(loc.getWorld()).selectBlockActorIdStatementString; } @Override @@ -769,17 +768,16 @@ public void process(Connection conn, BatchHelper batchHelper) throws SQLExceptio batchHelper.addBatch(smt, new IntCallback() { @Override public void call(int id) throws SQLException { - final String table = getWorldConfig(loc.getWorld()).table; PreparedStatement ps; if (typeState != null || replacedState != null) { - ps = batchHelper.getOrPrepareStatement(conn, "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(?, ?, ?)", Statement.NO_GENERATED_KEYS); + ps = batchHelper.getOrPrepareStatement(conn, getWorldConfig(loc.getWorld()).insertBlockStateStatementString, Statement.NO_GENERATED_KEYS); ps.setBytes(1, replacedState); ps.setBytes(2, typeState); ps.setInt(3, id); batchHelper.addBatch(ps, null); } if (ca != null) { - ps = batchHelper.getOrPrepareStatement(conn, "INSERT INTO `" + table + "-chestdata` (item, itemremove, id, itemtype) values (?, ?, ?, ?)", Statement.NO_GENERATED_KEYS); + ps = batchHelper.getOrPrepareStatement(conn, getWorldConfig(loc.getWorld()).insertBlockChestDataStatementString, Statement.NO_GENERATED_KEYS); ps.setBytes(1, Utils.saveItemStack(ca.itemStack)); ps.setInt(2, ca.remove ? 1 : 0); ps.setInt(3, id); diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index 7b705187..3fe0d99e 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -12,6 +12,10 @@ public class WorldConfig extends LoggingEnabledMapping { public final String world; public final String table; + public final String insertBlockStatementString; + public final String selectBlockActorIdStatementString; + public final String insertBlockStateStatementString; + public final String insertBlockChestDataStatementString; public WorldConfig(String world, File file) throws IOException { this.world = world; @@ -33,5 +37,10 @@ public WorldConfig(String world, File file) throws IOException { for (final Logging l : Logging.values()) { setLogging(l, config.getBoolean("logging." + l.toString())); } + + insertBlockStatementString = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"; + selectBlockActorIdStatementString = "SELECT playerid FROM `" + table + "-blocks` WHERE x = ? AND y = ? AND z = ? ORDER BY date DESC LIMIT 1"; + insertBlockStateStatementString = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(?, ?, ?)"; + insertBlockChestDataStatementString = "INSERT INTO `" + table + "-chestdata` (item, itemremove, id, itemtype) values (?, ?, ?, ?)"; } } From 282090459fb7b213f7b151b40292a4c27e6aa460 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 21 Aug 2018 06:50:09 +0200 Subject: [PATCH 101/399] Optionally log fluid flow as the player who created the fluid --- .../de/diddiz/LogBlock/config/Config.java | 3 ++ .../LogBlock/listeners/FluidFlowLogging.java | 36 ++++++++++--------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 0f520c2f..708f2e22 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -35,6 +35,7 @@ public class Config { public static boolean logBedExplosionsAsPlayerWhoTriggeredThese; public static boolean logCreeperExplosionsAsPlayerWhoTriggeredThese, logPlayerInfo; public static boolean logFireSpreadAsPlayerWhoCreatedIt; + public static boolean logFluidFlowAsPlayerWhoTriggeredIt; public static LogKillsLevel logKillsLevel; public static Set dontRollback, replaceAnyway; public static int rollbackMaxTime, rollbackMaxArea; @@ -95,6 +96,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("logging.logBedExplosionsAsPlayerWhoTriggeredThese", true); def.put("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false); def.put("logging.logFireSpreadAsPlayerWhoCreatedIt", true); + def.put("logging.logFluidFlowAsPlayerWhoTriggeredIt", false); def.put("logging.logKillsLevel", "PLAYERS"); def.put("logging.logEnvironmentalKills", false); def.put("logging.logPlayerInfo", false); @@ -172,6 +174,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti logBedExplosionsAsPlayerWhoTriggeredThese = config.getBoolean("logging.logBedExplosionsAsPlayerWhoTriggeredThese", true); logCreeperExplosionsAsPlayerWhoTriggeredThese = config.getBoolean("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false); logFireSpreadAsPlayerWhoCreatedIt = config.getBoolean("logging.logFireSpreadAsPlayerWhoCreatedIt", true); + logFluidFlowAsPlayerWhoTriggeredIt = config.getBoolean("logging.logFluidFlowAsPlayerWhoTriggeredIt", false); logPlayerInfo = config.getBoolean("logging.logPlayerInfo", true); try { logKillsLevel = LogKillsLevel.valueOf(config.getString("logging.logKillsLevel").toUpperCase()); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index 7e9e1b1a..4adf63a2 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -3,6 +3,7 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.util.BukkitUtils; @@ -29,56 +30,57 @@ public void onBlockFromTo(BlockFromToEvent event) { if (wcfg != null) { final BlockData blockDataFrom = event.getBlock().getBlockData(); final Material typeFrom = blockDataFrom.getMaterial(); - + + Block source = Config.logFluidFlowAsPlayerWhoTriggeredIt ? event.getBlock() : null; final Block to = event.getToBlock(); final Material typeTo = to.getType(); final boolean canFlow = BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo); if (typeFrom == Material.LAVA && wcfg.isLogging(Logging.LAVAFLOW)) { - Levelled levelledFrom = (Levelled)blockDataFrom; + Levelled levelledFrom = (Levelled) blockDataFrom; if (canFlow) { if (isSurroundedByWater(to) && levelledFrom.getLevel() <= 2) { - consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), Material.COBBLESTONE.createBlockData()); + consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData()); } else { Levelled newBlock = (Levelled) blockDataFrom.clone(); newBlock.setLevel(levelledFrom.getLevel() + 1); if (BukkitUtils.isEmpty(typeTo)) { - consumer.queueBlockPlace(new Actor("LavaFlow"), to.getLocation(), newBlock); + consumer.queueBlockPlace(new Actor("LavaFlow", source), to.getLocation(), newBlock); } else { - consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), newBlock); + consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), newBlock); } } } else if (typeTo == Material.WATER) { if (event.getFace() == BlockFace.DOWN) { - consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), Material.STONE.createBlockData()); + consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.STONE.createBlockData()); } else { - consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), Material.COBBLESTONE.createBlockData()); + consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData()); } } } else if ((typeFrom == Material.WATER) && wcfg.isLogging(Logging.WATERFLOW)) { - Levelled levelledFrom = (Levelled)blockDataFrom; + Levelled levelledFrom = (Levelled) blockDataFrom; Levelled newBlock = (Levelled) blockDataFrom.clone(); newBlock.setLevel(levelledFrom.getLevel() + 1); if (BukkitUtils.isEmpty(typeTo)) { - consumer.queueBlockPlace(new Actor("WaterFlow"), to.getLocation(), newBlock); + consumer.queueBlockPlace(new Actor("WaterFlow", source), to.getLocation(), newBlock); } else if (BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { - consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), newBlock); + consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), newBlock); } else if (typeTo == Material.LAVA) { - int toLevel = ((Levelled)to.getBlockData()).getLevel(); + int toLevel = ((Levelled) to.getBlockData()).getLevel(); if (toLevel == 0) { - consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), Material.OBSIDIAN.createBlockData()); + consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), Material.OBSIDIAN.createBlockData()); } else if (event.getFace() == BlockFace.DOWN) { - consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), Material.STONE.createBlockData()); + consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), Material.STONE.createBlockData()); } } if (BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { - for (final BlockFace face : new BlockFace[]{BlockFace.DOWN, BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH}) { + for (final BlockFace face : new BlockFace[] { BlockFace.DOWN, BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH }) { final Block lower = to.getRelative(face); if (lower.getType() == Material.LAVA) { - int toLevel = ((Levelled)lower.getBlockData()).getLevel(); + int toLevel = ((Levelled) lower.getBlockData()).getLevel(); if (toLevel == 0) { - consumer.queueBlockReplace(new Actor("WaterFlow"), lower.getState(), Material.OBSIDIAN.createBlockData()); + consumer.queueBlockReplace(new Actor("WaterFlow", source), lower.getState(), Material.OBSIDIAN.createBlockData()); } else if (event.getFace() == BlockFace.DOWN) { - consumer.queueBlockReplace(new Actor("WaterFlow"), lower.getState(), Material.STONE.createBlockData()); + consumer.queueBlockReplace(new Actor("WaterFlow", source), lower.getState(), Material.STONE.createBlockData()); } } } From 2afa3c88cd3b7bffe48883f3ed8b661b6d64edc7 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 27 Aug 2018 17:13:44 +0200 Subject: [PATCH 102/399] Update to Spigot 1.13.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8db6e049..70a7cbb9 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ org.spigotmc spigot-api - 1.13-R0.1-SNAPSHOT + 1.13.1-R0.1-SNAPSHOT provided From f65509408ea95dd2f8a8e0f7b0151f3cd38c8e2b Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 29 Aug 2018 02:41:10 +0200 Subject: [PATCH 103/399] Log fish buckets as water place, not lava place Fixes #715 --- .../java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java index 0b0c9f2b..9d7b5be7 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java @@ -35,7 +35,7 @@ public void onBlockPlace(BlockPlaceEvent event) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) { if (isLogging(event.getPlayer().getWorld(), Logging.BLOCKPLACE)) { - consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getRelative(event.getBlockFace()).getLocation(), Bukkit.createBlockData(event.getBucket() == Material.WATER_BUCKET ? Material.WATER : Material.LAVA)); + consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getRelative(event.getBlockFace()).getLocation(), Bukkit.createBlockData(event.getBucket() == Material.LAVA_BUCKET ? Material.LAVA : Material.WATER)); } } } From 2faa9cbd6d4eea7c66e71d7c15243e4396fd29b6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 29 Aug 2018 02:43:07 +0200 Subject: [PATCH 104/399] There is no older WorldEdit for Minecraft 1.13 Resolves #714 --- src/main/java/de/diddiz/LogBlock/LogBlock.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 57039d16..764eb01c 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -100,13 +100,9 @@ public void onEnable() { pm.disablePlugin(this); return; } - + if (pm.getPlugin("WorldEdit") != null) { - if (Integer.parseInt(pm.getPlugin("WorldEdit").getDescription().getVersion().substring(0, 1)) > 5) { - new WorldEditLoggingHook(this).hook(); - } else { - getLogger().warning("Failed to hook into WorldEdit. Your WorldEdit version seems to be outdated, please make sure WorldEdit is at least version 6."); - } + new WorldEditLoggingHook(this).hook(); } commandsHandler = new CommandsHandler(this); getCommand("lb").setExecutor(commandsHandler); From 8045ab1ecd8217ada0da1b86e7dec94ea18998ac Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 29 Aug 2018 03:56:34 +0200 Subject: [PATCH 105/399] Ignore deprecation in updater + remove unused method --- src/main/java/de/diddiz/LogBlock/Updater.java | 1 + src/main/java/de/diddiz/util/BukkitUtils.java | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 7d2af312..e125e6af 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -527,6 +527,7 @@ boolean update() { if (weaponMaterial == null) { weaponMaterial = Material.AIR; } + @SuppressWarnings("deprecation") ItemStack stack = weaponMaterial.getMaxDurability() > 0 ? new ItemStack(weaponMaterial, Math.abs(amount), (short)itemdata) : new ItemStack(weaponMaterial, Math.abs(amount)); insertChestData.setInt(1, id); insertChestData.setBytes(2, Utils.saveItemStack(stack)); diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 10917021..aeb55be5 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -522,10 +522,6 @@ public static void giveTool(Player player, Material type) { } } - public static short rawData(ItemStack item) { - return item.getType() != null ? item.getData() != null ? item.getDurability() : 0 : 0; - } - public static int saveSpawnHeight(Location loc) { final World world = loc.getWorld(); final Chunk chunk = world.getChunkAt(loc); From 76fce15305d6547fb376200b125f75ca6678e347 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 29 Aug 2018 18:33:31 +0200 Subject: [PATCH 106/399] Log watering waterlogged --- .../LogBlock/listeners/BlockBreakLogging.java | 14 +++++++++++- .../LogBlock/listeners/BlockPlaceLogging.java | 22 +++++++++++++++++-- .../LogBlock/listeners/FluidFlowLogging.java | 16 +++++++++----- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java index e89d0a66..e316fd82 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java @@ -11,6 +11,8 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockBreakEvent; @@ -59,7 +61,17 @@ public void onBlockBreak(BlockBreakEvent event) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerBucketFill(PlayerBucketFillEvent event) { if (isLogging(event.getBlockClicked().getWorld(), Logging.BLOCKBREAK)) { - consumer.queueBlockBreak(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getState()); + BlockData clickedBlockData = event.getBlockClicked().getBlockData(); + if (clickedBlockData instanceof Waterlogged) { + Waterlogged clickedWaterlogged = (Waterlogged) clickedBlockData; + if (clickedWaterlogged.isWaterlogged()) { + Waterlogged clickedWaterloggedWithoutWater = (Waterlogged) clickedWaterlogged.clone(); + clickedWaterloggedWithoutWater.setWaterlogged(false); + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), clickedWaterlogged, clickedWaterloggedWithoutWater); + } + } else { + consumer.queueBlockBreak(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getState()); + } } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java index 9d7b5be7..178990d0 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java @@ -6,9 +6,11 @@ import de.diddiz.LogBlock.config.Config; import de.diddiz.util.LoggingUtil; -import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.block.Block; import org.bukkit.block.BlockState; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockPlaceEvent; @@ -35,7 +37,23 @@ public void onBlockPlace(BlockPlaceEvent event) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) { if (isLogging(event.getPlayer().getWorld(), Logging.BLOCKPLACE)) { - consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getRelative(event.getBlockFace()).getLocation(), Bukkit.createBlockData(event.getBucket() == Material.LAVA_BUCKET ? Material.LAVA : Material.WATER)); + Material placedMaterial = event.getBucket() == Material.LAVA_BUCKET ? Material.LAVA : Material.WATER; + BlockData clickedBlockData = event.getBlockClicked().getBlockData(); + if (placedMaterial == Material.WATER && clickedBlockData instanceof Waterlogged) { + Waterlogged clickedWaterlogged = (Waterlogged) clickedBlockData; + if (!clickedWaterlogged.isWaterlogged()) { + Waterlogged clickedWaterloggedWithWater = (Waterlogged) clickedWaterlogged.clone(); + clickedWaterloggedWithWater.setWaterlogged(true); + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), clickedWaterlogged, clickedWaterloggedWithWater); + } + } else { + Block placedAt = event.getBlockClicked().getRelative(event.getBlockFace()); + if (placedAt.isEmpty()) { + consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedMaterial.createBlockData()); + } else { + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), placedAt.getBlockData(), placedMaterial.createBlockData()); + } + } } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index 4adf63a2..d56c9a27 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -12,6 +12,7 @@ import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Levelled; +import org.bukkit.block.data.Waterlogged; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockFromToEvent; @@ -27,9 +28,14 @@ public FluidFlowLogging(LogBlock lb) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockFromTo(BlockFromToEvent event) { final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld()); - if (wcfg != null) { + if (wcfg != null && (wcfg.isLogging(Logging.WATERFLOW) || wcfg.isLogging(Logging.LAVAFLOW))) { final BlockData blockDataFrom = event.getBlock().getBlockData(); - final Material typeFrom = blockDataFrom.getMaterial(); + Material typeFrom = blockDataFrom.getMaterial(); + boolean fromWaterlogged = false; + if (blockDataFrom instanceof Waterlogged) { + typeFrom = Material.WATER; + fromWaterlogged = true; + } Block source = Config.logFluidFlowAsPlayerWhoTriggeredIt ? event.getBlock() : null; final Block to = event.getToBlock(); @@ -57,9 +63,9 @@ public void onBlockFromTo(BlockFromToEvent event) { } } } else if ((typeFrom == Material.WATER) && wcfg.isLogging(Logging.WATERFLOW)) { - Levelled levelledFrom = (Levelled) blockDataFrom; - Levelled newBlock = (Levelled) blockDataFrom.clone(); - newBlock.setLevel(levelledFrom.getLevel() + 1); + Levelled levelledFrom = fromWaterlogged ? null : (Levelled) blockDataFrom; + Levelled newBlock = (Levelled) Material.WATER.createBlockData(); + newBlock.setLevel(fromWaterlogged ? 1 : levelledFrom.getLevel() + 1); if (BukkitUtils.isEmpty(typeTo)) { consumer.queueBlockPlace(new Actor("WaterFlow", source), to.getLocation(), newBlock); } else if (BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { From 1cbc192b317a957a5cddb445857171aa4093fe0c Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 29 Aug 2018 19:38:19 +0200 Subject: [PATCH 107/399] Log BlockFormEvent by fluids --- .../LogBlock/listeners/FluidFlowLogging.java | 21 +++++++++++++++-- src/main/java/de/diddiz/util/BukkitUtils.java | 23 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index d56c9a27..9aecf176 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -15,6 +15,7 @@ import org.bukkit.block.data.Waterlogged; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.BlockFromToEvent; import static de.diddiz.LogBlock.config.Config.getWorldConfig; @@ -95,9 +96,25 @@ public void onBlockFromTo(BlockFromToEvent event) { } } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockForm(BlockFormEvent event) { + final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld()); + if (wcfg != null && (wcfg.isLogging(Logging.WATERFLOW) || wcfg.isLogging(Logging.LAVAFLOW))) { + if (wcfg.isLogging(Logging.LAVAFLOW) && event.getBlock().getType() == Material.WATER && event.getNewState().getType() == Material.COBBLESTONE) { + consumer.queueBlockReplace(new Actor("LavaFlow"), event.getBlock().getBlockData(), event.getNewState()); + } + if (wcfg.isLogging(Logging.WATERFLOW) && event.getBlock().getType() == Material.LAVA) { + consumer.queueBlockReplace(new Actor("WaterFlow"), event.getBlock().getBlockData(), event.getNewState()); + } + if (wcfg.isLogging(Logging.WATERFLOW) && BukkitUtils.isConcreteBlock(event.getNewState().getType())) { + consumer.queueBlockReplace(new Actor("WaterFlow"), event.getBlock().getBlockData(), event.getNewState()); + } + } + } + private static boolean isSurroundedByWater(Block block) { - for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH}) { - if(block.getRelative(face).getType() == Material.WATER) { + for (final BlockFace face : new BlockFace[] { BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH }) { + if (block.getRelative(face).getType() == Material.WATER) { return true; } } diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index aeb55be5..369d1362 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -47,6 +47,7 @@ public class BukkitUtils { private static final EnumSet pressurePlates; private static final EnumSet woodenDoors; private static final EnumSet slabs; + private static final EnumSet concreteBlocks; static { pressurePlates = EnumSet.noneOf(Material.class); @@ -352,6 +353,24 @@ public class BukkitUtils { bedBlocks.add(Material.RED_BED); bedBlocks.add(Material.WHITE_BED); bedBlocks.add(Material.YELLOW_BED); + + concreteBlocks = EnumSet.noneOf(Material.class); + concreteBlocks.add(Material.BLACK_CONCRETE); + concreteBlocks.add(Material.BLUE_CONCRETE); + concreteBlocks.add(Material.LIGHT_GRAY_CONCRETE); + concreteBlocks.add(Material.BROWN_CONCRETE); + concreteBlocks.add(Material.CYAN_CONCRETE); + concreteBlocks.add(Material.GRAY_CONCRETE); + concreteBlocks.add(Material.GREEN_CONCRETE); + concreteBlocks.add(Material.LIGHT_BLUE_CONCRETE); + concreteBlocks.add(Material.MAGENTA_CONCRETE); + concreteBlocks.add(Material.LIME_CONCRETE); + concreteBlocks.add(Material.ORANGE_CONCRETE); + concreteBlocks.add(Material.PINK_CONCRETE); + concreteBlocks.add(Material.PURPLE_CONCRETE); + concreteBlocks.add(Material.RED_CONCRETE); + concreteBlocks.add(Material.WHITE_CONCRETE); + concreteBlocks.add(Material.YELLOW_CONCRETE); } private static final BlockFace[] relativeBlockFaces = new BlockFace[]{ @@ -494,6 +513,10 @@ public static Set getContainerBlocks() { return containerBlocks; } + public static boolean isConcreteBlock(Material m) { + return concreteBlocks.contains(m); + } + public static String entityName(Entity entity) { if (entity instanceof Player) { return ((Player) entity).getName(); From 404c9b91c05bd5df60626ed8a54585e8fd424ecc Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 29 Aug 2018 22:05:39 +0200 Subject: [PATCH 108/399] Fix bucket empty with waterlogged blocks --- .../diddiz/LogBlock/listeners/BlockPlaceLogging.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java index 178990d0..1672a31f 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java @@ -45,14 +45,14 @@ public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) { Waterlogged clickedWaterloggedWithWater = (Waterlogged) clickedWaterlogged.clone(); clickedWaterloggedWithWater.setWaterlogged(true); consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), clickedWaterlogged, clickedWaterloggedWithWater); + return; } + } + Block placedAt = event.getBlockClicked().getRelative(event.getBlockFace()); + if (placedAt.isEmpty()) { + consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedMaterial.createBlockData()); } else { - Block placedAt = event.getBlockClicked().getRelative(event.getBlockFace()); - if (placedAt.isEmpty()) { - consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedMaterial.createBlockData()); - } else { - consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), placedAt.getBlockData(), placedMaterial.createBlockData()); - } + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), placedAt.getBlockData(), placedMaterial.createBlockData()); } } } From 9c2a93dafbbd6ed8f23f366e0a3939f95b60f3dd Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 29 Aug 2018 22:26:37 +0200 Subject: [PATCH 109/399] Param for force replace not matching blocks --- .../java/de/diddiz/LogBlock/CommandsHandler.java | 5 +++-- src/main/java/de/diddiz/LogBlock/QueryParams.java | 4 ++++ src/main/java/de/diddiz/LogBlock/WorldEditor.java | 14 ++++++++++---- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index b1523770..42e841a9 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -92,6 +92,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, sender.sendMessage(ChatColor.GOLD + "time [number] [minutes|hours|days] -- Limits time"); sender.sendMessage(ChatColor.GOLD + "since -- Limits time to a fixed point"); sender.sendMessage(ChatColor.GOLD + "before -- Affects only blocks before a fixed time"); + sender.sendMessage(ChatColor.GOLD + "force -- Forces replacing not matching blocks"); sender.sendMessage(ChatColor.GOLD + "limit -- Limits the result to count of rows"); sender.sendMessage(ChatColor.GOLD + "sum [none|blocks|players] -- Sums the result"); sender.sendMessage(ChatColor.GOLD + "asc, desc -- Changes the order of the displayed log"); @@ -673,7 +674,7 @@ public void run() { sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); } rs = executeQuery(state, params.getQuery()); - final WorldEditor editor = new WorldEditor(logblock, params.world); + final WorldEditor editor = new WorldEditor(logblock, params.world, params.forceReplace); while (rs.next()) { ChestAccess chestaccess = null; @@ -762,7 +763,7 @@ public void run() { if (!params.silent) { sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); } - final WorldEditor editor = new WorldEditor(logblock, params.world); + final WorldEditor editor = new WorldEditor(logblock, params.world, params.forceReplace); while (rs.next()) { ChestAccess chestaccess = null; ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 0fd9a548..196f3068 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -50,6 +50,7 @@ public final class QueryParams implements Cloneable { keywords.put("killer", 1); keywords.put("victim", 1); keywords.put("both", 0); + keywords.put("force", 0); } public BlockChangeType bct = BlockChangeType.BOTH; public int limit = -1, before = 0, since = 0, radius = -1; @@ -59,6 +60,7 @@ public final class QueryParams implements Cloneable { public List killers = new ArrayList(); public List victims = new ArrayList(); public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, excludeBlocksMode = false, prepareToolQuery = false, silent = false, noForcedLimit = false; + public boolean forceReplace = false; public CuboidRegion sel = null; public SummarizationMode sum = SummarizationMode.NONE; public List types = new ArrayList(); @@ -802,6 +804,8 @@ public void parseArgs(CommandSender sender, List args, boolean validate) needCoords = true; } else if (param.equals("silent")) { silent = true; + } else if (param.equals("force")) { + forceReplace = true; } else if (param.equals("search") || param.equals("match")) { if (values.length == 0) { throw new IllegalArgumentException("No arguments for '" + param + "'"); diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index f590d9ae..82fc6033 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -50,10 +50,16 @@ public class WorldEditor implements Runnable { private int successes = 0, blacklistCollisions = 0; private long elapsedTime = 0; public LookupCacheElement[] errors; + private boolean forceReplace; public WorldEditor(LogBlock logblock, World world) { + this(logblock, world, false); + } + + public WorldEditor(LogBlock logblock, World world, boolean forceReplace) { this.logblock = logblock; this.world = world; + this.forceReplace = forceReplace; } public int getSize() { @@ -170,13 +176,13 @@ PerformResult perform() throws WorldEditorException { return PerformResult.BLACKLISTED; } final Block block = loc.getBlock(); + if (!world.isChunkLoaded(block.getChunk())) { + world.loadChunk(block.getChunk()); + } if (BukkitUtils.isEmpty(replacedBlock.getMaterial()) && BukkitUtils.isEmpty(block.getType())) { return PerformResult.NO_ACTION; } BlockState state = block.getState(); - if (!world.isChunkLoaded(block.getChunk())) { - world.loadChunk(block.getChunk()); - } if (setBlock.equals(replacedBlock)) { if (ca != null) { if (state instanceof InventoryHolder && state.getType() == replacedBlock.getMaterial()) { @@ -194,7 +200,7 @@ PerformResult perform() throws WorldEditorException { return PerformResult.NO_ACTION; } } - if (block.getType() != setBlock.getMaterial() && !block.isEmpty() && !replaceAnyway.contains(block.getType())) { + if (!forceReplace && block.getType() != setBlock.getMaterial() && !block.isEmpty() && !replaceAnyway.contains(block.getType())) { return PerformResult.NO_ACTION; } if (state instanceof InventoryHolder && replacedBlock.getMaterial() != block.getType()) { From 544385f2ade549af6dde03e177149c149be258a6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 29 Aug 2018 22:54:35 +0200 Subject: [PATCH 110/399] Log replaced fluids at the correct position --- .../java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java index 1672a31f..24b90a21 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java @@ -52,7 +52,7 @@ public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) { if (placedAt.isEmpty()) { consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedMaterial.createBlockData()); } else { - consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), placedAt.getBlockData(), placedMaterial.createBlockData()); + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedAt.getBlockData(), placedMaterial.createBlockData()); } } } From df8c8bcddaaa924605ec2d0fccad60a36237b607 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 2 Sep 2018 04:58:18 +0200 Subject: [PATCH 111/399] Fix clearing containers on rollback --- src/main/java/de/diddiz/LogBlock/WorldEditor.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 82fc6033..f46e3af3 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -7,6 +7,7 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; +import org.bukkit.block.Container; import org.bukkit.block.data.Bisected.Half; import org.bukkit.block.data.Bisected; import org.bukkit.block.data.BlockData; @@ -17,7 +18,6 @@ import org.bukkit.block.data.type.PistonHead; import org.bukkit.block.data.type.TechnicalPiston.Type; import org.bukkit.command.CommandSender; -import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import de.diddiz.LogBlock.blockstate.BlockStateCodecs; @@ -185,7 +185,7 @@ PerformResult perform() throws WorldEditorException { 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, new ItemStack(ca.itemStack), !ca.remove); @@ -203,8 +203,8 @@ PerformResult perform() throws WorldEditorException { if (!forceReplace && block.getType() != setBlock.getMaterial() && !block.isEmpty() && !replaceAnyway.contains(block.getType())) { return PerformResult.NO_ACTION; } - if (state instanceof InventoryHolder && replacedBlock.getMaterial() != block.getType()) { - ((InventoryHolder) state).getInventory().clear(); + if (state instanceof Container && replacedBlock.getMaterial() != block.getType()) { + ((Container) state).getSnapshotInventory().clear(); state.update(); } block.setBlockData(replacedBlock); From c390504b70984fff34f6b567eafadba1cb84fa9a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 5 Sep 2018 03:05:41 +0200 Subject: [PATCH 112/399] Sort files before importing them --- .../de/diddiz/LogBlock/DumpedLogImporter.java | 46 ++++++++++++++++++- src/main/java/de/diddiz/util/Utils.java | 2 +- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java b/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java index 56cf5b87..687d54b5 100644 --- a/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java +++ b/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java @@ -6,7 +6,10 @@ import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; +import java.util.Arrays; +import java.util.Comparator; import java.util.logging.Level; +import java.util.regex.Pattern; import static de.diddiz.util.Utils.newline; @@ -19,9 +22,10 @@ public class DumpedLogImporter implements Runnable { @Override public void run() { - final File[] imports = new File("plugins/LogBlock/import/").listFiles(new ExtensionFilenameFilter("sql")); + final File[] imports = new File(logblock.getDataFolder(), "import").listFiles(new ExtensionFilenameFilter("sql")); if (imports != null && imports.length > 0) { logblock.getLogger().info("Found " + imports.length + " imports."); + Arrays.sort(imports, new ImportsComparator()); Connection conn = null; try { conn = logblock.getConnection(); @@ -77,4 +81,44 @@ public void run() { } } } + + private static class ImportsComparator implements Comparator { + private final Pattern splitPattern = Pattern.compile("[\\-\\.]"); + + @Override + public int compare(File o1, File o2) { + String[] name1 = splitPattern.split(o1.getName()); + String[] name2 = splitPattern.split(o2.getName()); + if (name1.length > name2.length) { + return 1; + } else if (name1.length < name2.length) { + return -1; + } + for (int i = 0; i < name1.length; i++) { + String part1 = name1[i]; + String part2 = name2[i]; + if (part1.length() > 0 && part2.length() > 0) { + char first1 = part1.charAt(0); + char first2 = part2.charAt(0); + if (first1 >= '0' && first1 <= '9' && first2 >= '0' && first2 <= '9') { + try { + long long1 = Long.parseLong(part1); + long long2 = Long.parseLong(part2); + if (long1 == long2) { + continue; + } + return long1 > long2 ? 1 : -1; + } catch (NumberFormatException e) { + // fallthrough to string compare + } + } + } + int compareString = part1.compareTo(part2); + if (compareString != 0) { + return compareString; + } + } + return 0; + } + } } diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index 416c110b..c4ea0f90 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -197,7 +197,7 @@ public static class ExtensionFilenameFilter implements FilenameFilter { private final String ext; public ExtensionFilenameFilter(String ext) { - this.ext = ext; + this.ext = "." + ext; } @Override From 3c64376dd1d25aa605f113e820f819cd50f52fc0 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 5 Sep 2018 12:59:06 +0200 Subject: [PATCH 113/399] improve log importer - try importing line by line if the batch import did not work - print more informative error messages - fix writing failed imports to failed.txt --- .../de/diddiz/LogBlock/DumpedLogImporter.java | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java b/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java index 687d54b5..a871efaf 100644 --- a/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java +++ b/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java @@ -41,27 +41,51 @@ public void run() { String line = null; try { logblock.getLogger().info("Trying to import " + sqlFile.getName() + " ..."); + // first try batch import the whole file final BufferedReader reader = new BufferedReader(new FileReader(sqlFile)); + int statements = 0; while ((line = reader.readLine()) != null) { if (line.endsWith(";")) { line = line.substring(0, line.length() - 1); } - if(!line.isEmpty()) { + if (!line.isEmpty()) { + statements++; st.addBatch(line); - successes++; } } st.executeBatch(); conn.commit(); reader.close(); sqlFile.delete(); + successes += statements; logblock.getLogger().info("Successfully imported " + sqlFile.getName() + "."); - } catch (final Exception ex) { - logblock.getLogger().warning("Error while importing: '" + line + "': " + ex.getMessage()); - writer.write(line + newline); - errors++; - ex.printStackTrace(); - return; + } catch (final Exception ignored) { + // if the batch import did not work, retry line by line + try { + final BufferedReader reader = new BufferedReader(new FileReader(sqlFile)); + while ((line = reader.readLine()) != null) { + if (line.endsWith(";")) { + line = line.substring(0, line.length() - 1); + } + if (!line.isEmpty()) { + try { + st.execute(line); + successes++; + } catch (final SQLException ex) { + logblock.getLogger().severe("Error while importing: '" + line + "': " + ex.getMessage()); + writer.write(line + newline); + errors++; + } + } + } + conn.commit(); + reader.close(); + sqlFile.delete(); + logblock.getLogger().info("Successfully imported " + sqlFile.getName() + "."); + } catch (final Exception ex) { + logblock.getLogger().severe("Error while importing " + sqlFile.getName() + ": " + ex.getMessage()); + errors++; + } } } } finally { From 1b316dc11f6410aff58c2959775e514eb21e309b Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 5 Sep 2018 13:28:33 +0200 Subject: [PATCH 114/399] add alternative mvn repo for worldedit --- pom.xml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 70a7cbb9..26536fd5 100644 --- a/pom.xml +++ b/pom.xml @@ -71,13 +71,17 @@ + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + sk89q-repo https://maven.sk89q.com/repo/ - spigot-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + brokkonaut-repo + https://www.iani.de/nexus/content/groups/public/ From 3ef6e48ca46903e381536cffeeb8d5ed7d9beeac Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 5 Sep 2018 16:21:34 +0200 Subject: [PATCH 115/399] remove mcstats metrics its dead for a long time now --- .../java/de/diddiz/LogBlock/LogBlock.java | 7 - src/main/java/de/diddiz/LogBlock/Metrics.java | 750 ------------------ 2 files changed, 757 deletions(-) delete mode 100644 src/main/java/de/diddiz/LogBlock/Metrics.java diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 764eb01c..e3e35e88 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -17,7 +17,6 @@ import java.io.File; import java.io.FileNotFoundException; -import java.io.IOException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; @@ -121,12 +120,6 @@ public void onEnable() { questioner = new Questioner(this); isCompletelyEnabled = true; getServer().getScheduler().runTaskAsynchronously(this, new Updater.PlayerCountChecker(this)); - try { - Metrics metrics = new Metrics(this); - metrics.start(); - } catch (IOException ex) { - getLogger().info("Could not start metrics: " + ex.getMessage()); - } } private void registerEvents() { diff --git a/src/main/java/de/diddiz/LogBlock/Metrics.java b/src/main/java/de/diddiz/LogBlock/Metrics.java deleted file mode 100644 index 556efc7c..00000000 --- a/src/main/java/de/diddiz/LogBlock/Metrics.java +++ /dev/null @@ -1,750 +0,0 @@ -/* - * Copyright 2011-2013 Tyler Blair. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and contributors and should not be interpreted as representing official policies, - * either expressed or implied, of anybody else. - */ -package de.diddiz.LogBlock; - -import org.bukkit.Bukkit; -import org.bukkit.configuration.InvalidConfigurationException; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginDescriptionFile; -import org.bukkit.scheduler.BukkitTask; - -import java.io.*; -import java.net.Proxy; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLEncoder; -import java.util.*; -import java.util.logging.Level; -import java.util.zip.GZIPOutputStream; - -public class Metrics { - - /** - * The current revision number - */ - private final static int REVISION = 7; - - /** - * The base url of the metrics domain - */ - private static final String BASE_URL = "http://report.mcstats.org"; - - /** - * The url used to report a server's status - */ - private static final String REPORT_URL = "/plugin/%s"; - - /** - * Interval of time to ping (in minutes) - */ - private static final int PING_INTERVAL = 15; - - /** - * The plugin this metrics submits for - */ - private final Plugin plugin; - - /** - * All of the custom graphs to submit to metrics - */ - private final Set graphs = Collections.synchronizedSet(new HashSet()); - - /** - * The plugin configuration file - */ - private final YamlConfiguration configuration; - - /** - * The plugin configuration file - */ - private final File configurationFile; - - /** - * Unique server id - */ - private final String guid; - - /** - * Debug mode - */ - private final boolean debug; - - /** - * Lock for synchronization - */ - private final Object optOutLock = new Object(); - - /** - * The scheduled task - */ - private volatile BukkitTask task = null; - - public Metrics(final Plugin plugin) throws IOException { - if (plugin == null) { - throw new IllegalArgumentException("Plugin cannot be null"); - } - - this.plugin = plugin; - - // load the config - configurationFile = getConfigFile(); - configuration = YamlConfiguration.loadConfiguration(configurationFile); - - // add some defaults - configuration.addDefault("opt-out", false); - configuration.addDefault("guid", UUID.randomUUID().toString()); - configuration.addDefault("debug", false); - - // Do we need to create the file? - if (configuration.get("guid", null) == null) { - configuration.options().header("http://mcstats.org").copyDefaults(true); - configuration.save(configurationFile); - } - - // Load the guid then - guid = configuration.getString("guid"); - debug = configuration.getBoolean("debug", false); - } - - /** - * Construct and create a Graph that can be used to separate specific plotters to their own graphs on the metrics - * website. Plotters can be added to the graph object returned. - * - * @param name The name of the graph - * @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given - */ - public Graph createGraph(final String name) { - if (name == null) { - throw new IllegalArgumentException("Graph name cannot be null"); - } - - // Construct the graph object - final Graph graph = new Graph(name); - - // Now we can add our graph - graphs.add(graph); - - // and return back - return graph; - } - - /** - * Add a Graph object to BukkitMetrics that represents data for the plugin that should be sent to the backend - * - * @param graph The name of the graph - */ - public void addGraph(final Graph graph) { - if (graph == null) { - throw new IllegalArgumentException("Graph cannot be null"); - } - - graphs.add(graph); - } - - /** - * Start measuring statistics. This will immediately create an async repeating task as the plugin and send the - * initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200 - * ticks. - * - * @return True if statistics measuring is running, otherwise false. - */ - public boolean start() { - synchronized (optOutLock) { - // Did we opt out? - if (isOptOut()) { - return false; - } - - // Is metrics already running? - if (task != null) { - return true; - } - - // Begin hitting the server with glorious data - task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() { - - private boolean firstPost = true; - - public void run() { - try { - // This has to be synchronized or it can collide with the disable method. - synchronized (optOutLock) { - // Disable Task, if it is running and the server owner decided to opt-out - if (isOptOut() && task != null) { - task.cancel(); - task = null; - // Tell all plotters to stop gathering information. - for (Graph graph : graphs) { - graph.onOptOut(); - } - } - } - - // We use the inverse of firstPost because if it is the first time we are posting, - // it is not a interval ping, so it evaluates to FALSE - // Each time thereafter it will evaluate to TRUE, i.e PING! - postPlugin(!firstPost); - - // After the first post we set firstPost to false - // Each post thereafter will be a ping - firstPost = false; - } catch (IOException e) { - if (debug) { - Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage()); - } - } - } - }, 0, PING_INTERVAL * 1200); - - return true; - } - } - - /** - * Has the server owner denied plugin metrics? - * - * @return true if metrics should be opted out of it - */ - public boolean isOptOut() { - synchronized (optOutLock) { - try { - // Reload the metrics file - configuration.load(getConfigFile()); - } catch (IOException ex) { - if (debug) { - Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); - } - return true; - } catch (InvalidConfigurationException ex) { - if (debug) { - Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); - } - return true; - } - return configuration.getBoolean("opt-out", false); - } - } - - /** - * Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task. - * - * @throws java.io.IOException - */ - public void enable() throws IOException { - // This has to be synchronized or it can collide with the check in the task. - synchronized (optOutLock) { - // Check if the server owner has already set opt-out, if not, set it. - if (isOptOut()) { - configuration.set("opt-out", false); - configuration.save(configurationFile); - } - - // Enable Task, if it is not running - if (task == null) { - start(); - } - } - } - - /** - * Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task. - * - * @throws java.io.IOException - */ - public void disable() throws IOException { - // This has to be synchronized or it can collide with the check in the task. - synchronized (optOutLock) { - // Check if the server owner has already set opt-out, if not, set it. - if (!isOptOut()) { - configuration.set("opt-out", true); - configuration.save(configurationFile); - } - - // Disable Task, if it is running - if (task != null) { - task.cancel(); - task = null; - } - } - } - - /** - * Gets the File object of the config file that should be used to store data such as the GUID and opt-out status - * - * @return the File object for the config file - */ - public File getConfigFile() { - // I believe the easiest way to get the base folder (e.g craftbukkit set via -P) for plugins to use - // is to abuse the plugin object we already have - // plugin.getDataFolder() => base/plugins/PluginA/ - // pluginsFolder => base/plugins/ - // The base is not necessarily relative to the startup directory. - File pluginsFolder = plugin.getDataFolder().getParentFile(); - - // return => base/plugins/PluginMetrics/config.yml - return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml"); - } - - /** - * Generic method that posts a plugin to the metrics website - */ - private void postPlugin(final boolean isPing) throws IOException { - // Server software specific section - PluginDescriptionFile description = plugin.getDescription(); - String pluginName = description.getName(); - boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled - String pluginVersion = description.getVersion(); - String serverVersion = Bukkit.getVersion(); - int playersOnline = Bukkit.getServer().getOnlinePlayers().size(); - - // END server software specific section -- all code below does not use any code outside of this class / Java - - // Construct the post data - StringBuilder json = new StringBuilder(1024); - json.append('{'); - - // The plugin's description file containg all of the plugin data such as name, version, author, etc - appendJSONPair(json, "guid", guid); - appendJSONPair(json, "plugin_version", pluginVersion); - appendJSONPair(json, "server_version", serverVersion); - appendJSONPair(json, "players_online", Integer.toString(playersOnline)); - - // New data as of R6 - String osname = System.getProperty("os.name"); - String osarch = System.getProperty("os.arch"); - String osversion = System.getProperty("os.version"); - String java_version = System.getProperty("java.version"); - int coreCount = Runtime.getRuntime().availableProcessors(); - - // normalize os arch .. amd64 -> x86_64 - if (osarch.equals("amd64")) { - osarch = "x86_64"; - } - - appendJSONPair(json, "osname", osname); - appendJSONPair(json, "osarch", osarch); - appendJSONPair(json, "osversion", osversion); - appendJSONPair(json, "cores", Integer.toString(coreCount)); - appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0"); - appendJSONPair(json, "java_version", java_version); - - // If we're pinging, append it - if (isPing) { - appendJSONPair(json, "ping", "1"); - } - - if (graphs.size() > 0) { - synchronized (graphs) { - json.append(','); - json.append('"'); - json.append("graphs"); - json.append('"'); - json.append(':'); - json.append('{'); - - boolean firstGraph = true; - - final Iterator iter = graphs.iterator(); - - while (iter.hasNext()) { - Graph graph = iter.next(); - - StringBuilder graphJson = new StringBuilder(); - graphJson.append('{'); - - for (Plotter plotter : graph.getPlotters()) { - appendJSONPair(graphJson, plotter.getColumnName(), Integer.toString(plotter.getValue())); - } - - graphJson.append('}'); - - if (!firstGraph) { - json.append(','); - } - - json.append(escapeJSON(graph.getName())); - json.append(':'); - json.append(graphJson); - - firstGraph = false; - } - - json.append('}'); - } - } - - // close json - json.append('}'); - - // Create the url - URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName))); - - // Connect to the website - URLConnection connection; - - // Mineshafter creates a socks proxy, so we can safely bypass it - // It does not reroute POST requests so we need to go around it - if (isMineshafterPresent()) { - connection = url.openConnection(Proxy.NO_PROXY); - } else { - connection = url.openConnection(); - } - - - byte[] uncompressed = json.toString().getBytes(); - byte[] compressed = gzip(json.toString()); - - // Headers - connection.addRequestProperty("User-Agent", "MCStats/" + REVISION); - connection.addRequestProperty("Content-Type", "application/json"); - connection.addRequestProperty("Content-Encoding", "gzip"); - connection.addRequestProperty("Content-Length", Integer.toString(compressed.length)); - connection.addRequestProperty("Accept", "application/json"); - connection.addRequestProperty("Connection", "close"); - - connection.setDoOutput(true); - - if (debug) { - System.out.println("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length); - } - - // Write the data - OutputStream os = connection.getOutputStream(); - os.write(compressed); - os.flush(); - - // Now read the response - final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); - String response = reader.readLine(); - - // close resources - os.close(); - reader.close(); - - if (response == null || response.startsWith("ERR") || response.startsWith("7")) { - if (response == null) { - response = "null"; - } else if (response.startsWith("7")) { - response = response.substring(response.startsWith("7,") ? 2 : 1); - } - - throw new IOException(response); - } else { - // Is this the first update this hour? - if (response.equals("1") || response.contains("This is your first update this hour")) { - synchronized (graphs) { - final Iterator iter = graphs.iterator(); - - while (iter.hasNext()) { - final Graph graph = iter.next(); - - for (Plotter plotter : graph.getPlotters()) { - plotter.reset(); - } - } - } - } - } - } - - /** - * GZip compress a string of bytes - * - * @param input - * @return - */ - public static byte[] gzip(String input) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - GZIPOutputStream gzos = null; - - try { - gzos = new GZIPOutputStream(baos); - gzos.write(input.getBytes("UTF-8")); - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (gzos != null) { - try { - gzos.close(); - } catch (IOException ignore) { - } - } - } - - return baos.toByteArray(); - } - - /** - * Check if mineshafter is present. If it is, we need to bypass it to send POST requests - * - * @return true if mineshafter is installed on the server - */ - private boolean isMineshafterPresent() { - try { - Class.forName("mineshafter.MineServer"); - return true; - } catch (Exception e) { - return false; - } - } - - /** - * Appends a json encoded key/value pair to the given string builder. - * - * @param json - * @param key - * @param value - * @throws UnsupportedEncodingException - */ - private static void appendJSONPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException { - boolean isValueNumeric = false; - - try { - if (value.equals("0") || !value.endsWith("0")) { - Double.parseDouble(value); - isValueNumeric = true; - } - } catch (NumberFormatException e) { - isValueNumeric = false; - } - - if (json.charAt(json.length() - 1) != '{') { - json.append(','); - } - - json.append(escapeJSON(key)); - json.append(':'); - - if (isValueNumeric) { - json.append(value); - } else { - json.append(escapeJSON(value)); - } - } - - /** - * Escape a string to create a valid JSON string - * - * @param text - * @return - */ - private static String escapeJSON(String text) { - StringBuilder builder = new StringBuilder(); - - builder.append('"'); - for (int index = 0; index < text.length(); index++) { - char chr = text.charAt(index); - - switch (chr) { - case '"': - case '\\': - builder.append('\\'); - builder.append(chr); - break; - case '\b': - builder.append("\\b"); - break; - case '\t': - builder.append("\\t"); - break; - case '\n': - builder.append("\\n"); - break; - case '\r': - builder.append("\\r"); - break; - default: - if (chr < ' ') { - String t = "000" + Integer.toHexString(chr); - builder.append("\\u" + t.substring(t.length() - 4)); - } else { - builder.append(chr); - } - break; - } - } - builder.append('"'); - - return builder.toString(); - } - - /** - * Encode text as UTF-8 - * - * @param text the text to encode - * @return the encoded text, as UTF-8 - */ - private static String urlEncode(final String text) throws UnsupportedEncodingException { - return URLEncoder.encode(text, "UTF-8"); - } - - /** - * Represents a custom graph on the website - */ - public static class Graph { - - /** - * The graph's name, alphanumeric and spaces only :) If it does not comply to the above when submitted, it is - * rejected - */ - private final String name; - - /** - * The set of plotters that are contained within this graph - */ - private final Set plotters = new LinkedHashSet(); - - private Graph(final String name) { - this.name = name; - } - - /** - * Gets the graph's name - * - * @return the Graph's name - */ - public String getName() { - return name; - } - - /** - * Add a plotter to the graph, which will be used to plot entries - * - * @param plotter the plotter to add to the graph - */ - public void addPlotter(final Plotter plotter) { - plotters.add(plotter); - } - - /** - * Remove a plotter from the graph - * - * @param plotter the plotter to remove from the graph - */ - public void removePlotter(final Plotter plotter) { - plotters.remove(plotter); - } - - /** - * Gets an unmodifiable set of the plotter objects in the graph - * - * @return an unmodifiable {@link java.util.Set} of the plotter objects - */ - public Set getPlotters() { - return Collections.unmodifiableSet(plotters); - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public boolean equals(final Object object) { - if (!(object instanceof Graph)) { - return false; - } - - final Graph graph = (Graph) object; - return graph.name.equals(name); - } - - /** - * Called when the server owner decides to opt-out of BukkitMetrics while the server is running. - */ - protected void onOptOut() { - } - } - - /** - * Interface used to collect custom data for a plugin - */ - public static abstract class Plotter { - - /** - * The plot's name - */ - private final String name; - - /** - * Construct a plotter with the default plot name - */ - public Plotter() { - this("Default"); - } - - /** - * Construct a plotter with a specific plot name - * - * @param name the name of the plotter to use, which will show up on the website - */ - public Plotter(final String name) { - this.name = name; - } - - /** - * Get the current value for the plotted point. Since this function defers to an external function it may or may - * not return immediately thus cannot be guaranteed to be thread friendly or safe. This function can be called - * from any thread so care should be taken when accessing resources that need to be synchronized. - * - * @return the current value for the point to be plotted. - */ - public abstract int getValue(); - - /** - * Get the column name for the plotted point - * - * @return the plotted point's column name - */ - public String getColumnName() { - return name; - } - - /** - * Called after the website graphs have been updated - */ - public void reset() { - } - - @Override - public int hashCode() { - return getColumnName().hashCode(); - } - - @Override - public boolean equals(final Object object) { - if (!(object instanceof Plotter)) { - return false; - } - - final Plotter plotter = (Plotter) object; - return plotter.name.equals(name) && plotter.getValue() == getValue(); - } - } -} \ No newline at end of file From d214b646db06ee0da3c739d343c9091cde0f8ab8 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 12 Sep 2018 21:18:43 +0200 Subject: [PATCH 116/399] cleanup: getBlockSet/Replaced in class BlockChange --- src/main/java/de/diddiz/LogBlock/BlockChange.java | 12 ++++++++++-- src/main/java/de/diddiz/LogBlock/WorldEditor.java | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 1dbff2d7..d7bb2351 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -70,8 +70,8 @@ public BlockChange(ResultSet rs, QueryParams p) throws SQLException { @Override public String toString() { - BlockData type = MaterialConverter.getBlockData(typeMaterial, typeData); - BlockData replaced = MaterialConverter.getBlockData(replacedMaterial, replacedData); + BlockData type = getBlockSet(); + BlockData replaced = getBlockReplaced(); String typeDetails = null; if (BlockStateCodecs.hasCodec(type.getMaterial())) { try { @@ -158,6 +158,14 @@ public String toString() { return msg.toString(); } + public BlockData getBlockReplaced() { + return MaterialConverter.getBlockData(replacedMaterial, replacedData); + } + + public BlockData getBlockSet() { + return MaterialConverter.getBlockData(typeMaterial, typeData); + } + @Override public Location getLocation() { return loc; diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index f46e3af3..d5c1f163 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -165,8 +165,8 @@ public Edit(long time, Location loc, Actor actor, int replaced, int replaceData, } PerformResult perform() throws WorldEditorException { - BlockData replacedBlock = MaterialConverter.getBlockData(this.replacedMaterial, replacedData); - BlockData setBlock = MaterialConverter.getBlockData(this.typeMaterial, typeData); + BlockData replacedBlock = getBlockReplaced(); + BlockData setBlock = getBlockSet(); if (replacedBlock == null || setBlock == null) { throw new WorldEditorException("Could not parse the material", loc.clone()); } From 2bb9e099592b7cb456832bc8b1a83893c333e247 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 13 Sep 2018 02:04:33 +0200 Subject: [PATCH 117/399] Cleanup Actor.equals() and .hashCode() + some formatting --- src/main/java/de/diddiz/LogBlock/Actor.java | 44 ++++++++++----------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index f209c4b1..55a72750 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -19,21 +19,16 @@ public class Actor { @Override public int hashCode() { - int hash = 5; - hash = 79 * hash + (this.UUID != null ? this.UUID.hashCode() : 0); - return hash; + return this.UUID != null ? this.UUID.hashCode() : 0; } @Override public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { + if (obj == null || getClass() != obj.getClass()) { return false; } final Actor other = (Actor) obj; - return ((this.UUID == null && other.UUID == null) || this.UUID.equals(other.UUID)); + return this.UUID == null ? other.UUID == null : this.UUID.equals(other.UUID); } final String name; @@ -111,20 +106,21 @@ public static Actor actorFromProjectileSource(ProjectileSource psource) { } } -/** - * Generate an Actor object from a String name, trying to guess if it's an online player - * and if so, setting the UUID accordingly. This only checks against currently online - * players and is a "best effort" attempt for use with the pre-UUID API - *

- * If you know something is an entity (player or otherwise) use the {@link #actorFromEntity(org.bukkit.entity.Entity) } - * or {@link #actorFromEntity(org.bukkit.entity.EntityType) } methods - *

- * If you know something is a server effect (like gravity) use {@link #Actor(java.lang.String)} - * @deprecated Only use this if you have a String of unknown origin - * - * @param actorName String of unknown origin - * @return - */ + + /** + * Generate an Actor object from a String name, trying to guess if it's an online player + * and if so, setting the UUID accordingly. This only checks against currently online + * players and is a "best effort" attempt for use with the pre-UUID API + *

+ * If you know something is an entity (player or otherwise) use the {@link #actorFromEntity(org.bukkit.entity.Entity) } + * or {@link #actorFromEntity(org.bukkit.entity.EntityType) } methods + *

+ * If you know something is a server effect (like gravity) use {@link #Actor(java.lang.String)} + * @deprecated Only use this if you have a String of unknown origin + * + * @param actorName String of unknown origin + * @return + */ public static Actor actorFromString(String actorName) { Collection players = Bukkit.getServer().getOnlinePlayers(); for (Player p : players) { @@ -132,8 +128,8 @@ public static Actor actorFromString(String actorName) { return actorFromEntity(p); } } - // No player found online with that name, assuming non-player entity/effect - return new Actor(actorName); + // No player found online with that name, assuming non-player entity/effect + return new Actor(actorName); } public static boolean isValidUUID(String uuid) { From 0bdeb7dc86b8e0b09269a86aaa80be63b6bc0a9b Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 13 Sep 2018 02:17:19 +0200 Subject: [PATCH 118/399] Escape UUID in database querys --- src/main/java/de/diddiz/LogBlock/Consumer.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 09b02887..267a4332 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -552,7 +552,7 @@ public void writeToFile() throws FileNotFoundException { for (final Actor actor : r.getActors()) { if (!playerIds.containsKey(actor) && !insertedPlayers.contains(actor)) { // Odd query contruction is to work around innodb auto increment behaviour - bug #492 - writer.println("INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + mysqlTextEscape(actor.getName()) + "','" + actor.getUUID() + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + actor.getUUID() + "') LIMIT 1;"); + writer.println("INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + mysqlTextEscape(actor.getName()) + "','" + mysqlTextEscape(actor.getUUID()) + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(actor.getUUID()) + "') LIMIT 1;"); insertedPlayers.add(actor); } } @@ -624,8 +624,8 @@ private boolean addPlayer(Connection conn, Actor actor) throws SQLException { String name = actor.getName(); String uuid = actor.getUUID(); Statement state = conn.createStatement(); - state.execute("INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + mysqlTextEscape(name) + "','" + uuid + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + uuid + "') LIMIT 1;"); - final ResultSet rs = state.executeQuery("SELECT playerid FROM `lb-players` WHERE UUID = '" + uuid + "'"); + state.execute("INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + mysqlTextEscape(name) + "','" + mysqlTextEscape(uuid) + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(uuid) + "') LIMIT 1;"); + final ResultSet rs = state.executeQuery("SELECT playerid FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(uuid) + "'"); if (rs.next()) { uncommitedPlayerIds.put(actor, rs.getInt(1)); } @@ -681,7 +681,7 @@ private String playerID(Actor actor) { if (id != null) { return id.toString(); } - return "(SELECT playerid FROM `lb-players` WHERE UUID = '" + actor.getUUID() + "')"; + return "(SELECT playerid FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(actor.getUUID()) + "')"; } private Integer playerIDAsIntIncludeUncommited(Actor actor) { @@ -884,7 +884,7 @@ public String[] getInserts() { return new String[] { "UPDATE `lb-players` SET lastlogin = FROM_UNIXTIME(" + lastLogin + "), firstlogin = IF(firstlogin = 0, FROM_UNIXTIME(" + lastLogin + "), firstlogin), ip = '" + ip + "', playername = '" + mysqlTextEscape(player.getName()) + "' WHERE UUID = '" + player.getUUID() + "';" }; } - return new String[] { "UPDATE `lb-players` SET playername = '" + mysqlTextEscape(player.getName()) + "' WHERE UUID = '" + player.getUUID() + "';" }; + return new String[] { "UPDATE `lb-players` SET playername = '" + mysqlTextEscape(player.getName()) + "' WHERE UUID = '" + mysqlTextEscape(player.getUUID()) + "';" }; } @Override @@ -923,7 +923,7 @@ private class PlayerLeaveRow implements Row { @Override public String[] getInserts() { if (logPlayerInfo) { - return new String[] { "UPDATE `lb-players` SET onlinetime = onlinetime + " + onlineTime + " WHERE lastlogin > 0 && UUID = '" + actor.getUUID() + "';" }; + return new String[] { "UPDATE `lb-players` SET onlinetime = onlinetime + " + onlineTime + " WHERE lastlogin > 0 && UUID = '" + mysqlTextEscape(actor.getUUID()) + "';" }; } return new String[0]; } From faaab7c4f64759cce3dcb634f789af7d059e2336 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 13 Sep 2018 02:25:34 +0200 Subject: [PATCH 119/399] Limit UUIDs to 36 chars + prevent null UUIDs --- src/main/java/de/diddiz/LogBlock/Actor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index 55a72750..2eaf55ac 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -37,13 +37,13 @@ public boolean equals(Object obj) { public Actor(String name, String UUID) { this.name = name; - this.UUID = UUID; + this.UUID = UUID == null ? "unknown" : (UUID.length() > 36 ? UUID.substring(0, 36) : UUID); this.blockLocation = null; } public Actor(String name, String UUID, Block block) { this.name = name; - this.UUID = UUID; + this.UUID = UUID == null ? "unknown" : (UUID.length() > 36 ? UUID.substring(0, 36) : UUID); this.blockLocation = block == null ? null : block.getLocation(); } From 421f16784f224094eb416d6e3f454b7ff1b1a22a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 13 Sep 2018 02:29:21 +0200 Subject: [PATCH 120/399] Don't try to process row if actors could not be inserted --- src/main/java/de/diddiz/LogBlock/Consumer.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 267a4332..8c3fd341 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -51,7 +51,6 @@ public class Consumer extends Thread { private final Deque queue = new ArrayDeque(); - private final Set failedPlayers = new HashSet(); private final LogBlock logblock; private final Map playerIds = new HashMap(); private final Map uncommitedPlayerIds = new HashMap(); @@ -474,17 +473,15 @@ public void run() { for (final Actor actor : r.getActors()) { if (playerIDAsIntIncludeUncommited(actor) == null) { if (!addPlayer(conn, actor)) { - if (failedPlayers.add(actor)) { - logblock.getLogger().warning("[Consumer] Failed to add player " + actor.getName()); - } + logblock.getLogger().warning("[Consumer] Failed to add player " + actor.getName()); failOnActors = true; // skip this row } } } if (!failOnActors) { currentRows.add(r); + r.process(conn, batchHelper); } - r.process(conn, batchHelper); } if (currentRows.size() >= (processBatch ? 1 : (Config.forceToProcessAtLeast * 10))) { batchHelper.processStatements(conn); From a55cbabbdde787bde9dcf6ba367890b0d8a53908 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 15 Sep 2018 03:36:52 +0200 Subject: [PATCH 121/399] Add some debug output when adding players fails --- src/main/java/de/diddiz/LogBlock/Actor.java | 2 +- src/main/java/de/diddiz/LogBlock/Consumer.java | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index 2eaf55ac..0307870e 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -28,7 +28,7 @@ public boolean equals(Object obj) { return false; } final Actor other = (Actor) obj; - return this.UUID == null ? other.UUID == null : this.UUID.equals(other.UUID); + return (this.UUID == null) ? (other.UUID == null) : this.UUID.equals(other.UUID); } final String name; diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 8c3fd341..41f513a4 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -473,7 +473,6 @@ public void run() { for (final Actor actor : r.getActors()) { if (playerIDAsIntIncludeUncommited(actor) == null) { if (!addPlayer(conn, actor)) { - logblock.getLogger().warning("[Consumer] Failed to add player " + actor.getName()); failOnActors = true; // skip this row } } @@ -621,10 +620,17 @@ private boolean addPlayer(Connection conn, Actor actor) throws SQLException { String name = actor.getName(); String uuid = actor.getUUID(); Statement state = conn.createStatement(); - state.execute("INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + mysqlTextEscape(name) + "','" + mysqlTextEscape(uuid) + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(uuid) + "') LIMIT 1;"); - final ResultSet rs = state.executeQuery("SELECT playerid FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(uuid) + "'"); + String q1 = "INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + mysqlTextEscape(name) + "','" + mysqlTextEscape(uuid) + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(uuid) + "') LIMIT 1;"; + String q2 = "SELECT playerid FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(uuid) + "'"; + int q1Result = state.executeUpdate(q1); + final ResultSet rs = state.executeQuery(q2); if (rs.next()) { uncommitedPlayerIds.put(actor, rs.getInt(1)); + } else { + logblock.getLogger().warning("[Consumer] Failed to add player " + actor.getName()); + logblock.getLogger().warning("[Consumer-Debug] Query 1: " + q1); + logblock.getLogger().warning("[Consumer-Debug] Query 1 - Result: " + q1Result); + logblock.getLogger().warning("[Consumer-Debug] Query 2: " + q2); } rs.close(); state.close(); From eb99b6d278090e34b31c39ddac81e9ed6cf88385 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 15 Sep 2018 04:05:17 +0200 Subject: [PATCH 122/399] Add players: Try a less odd query if the first one failed --- .../java/de/diddiz/LogBlock/Consumer.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 41f513a4..2ff34afe 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -620,19 +620,27 @@ private boolean addPlayer(Connection conn, Actor actor) throws SQLException { String name = actor.getName(); String uuid = actor.getUUID(); Statement state = conn.createStatement(); - String q1 = "INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + mysqlTextEscape(name) + "','" + mysqlTextEscape(uuid) + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(uuid) + "') LIMIT 1;"; + String q1 = "INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + mysqlTextEscape(name) + "','" + mysqlTextEscape(uuid) + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(uuid) + "') LIMIT 1"; String q2 = "SELECT playerid FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(uuid) + "'"; int q1Result = state.executeUpdate(q1); - final ResultSet rs = state.executeQuery(q2); + ResultSet rs = state.executeQuery(q2); if (rs.next()) { uncommitedPlayerIds.put(actor, rs.getInt(1)); - } else { - logblock.getLogger().warning("[Consumer] Failed to add player " + actor.getName()); - logblock.getLogger().warning("[Consumer-Debug] Query 1: " + q1); - logblock.getLogger().warning("[Consumer-Debug] Query 1 - Result: " + q1Result); - logblock.getLogger().warning("[Consumer-Debug] Query 2: " + q2); } rs.close(); + if (!uncommitedPlayerIds.containsKey(actor)) { + state.executeUpdate("INSERT IGNORE INTO `lb-players` (playername,UUID) VALUES ('" + mysqlTextEscape(name) + "','" + mysqlTextEscape(uuid) + "')"); + rs = state.executeQuery(q2); + if (rs.next()) { + uncommitedPlayerIds.put(actor, rs.getInt(1)); + } else { + logblock.getLogger().warning("[Consumer] Failed to add player " + actor.getName()); + logblock.getLogger().warning("[Consumer-Debug] Query 1: " + q1); + logblock.getLogger().warning("[Consumer-Debug] Query 1 - Result: " + q1Result); + logblock.getLogger().warning("[Consumer-Debug] Query 2: " + q2); + } + rs.close(); + } state.close(); return uncommitedPlayerIds.containsKey(actor); } From 210d6cec3761110c66ef9dffcddcfed4fb1e06dc Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 21 Sep 2018 00:42:28 +0200 Subject: [PATCH 123/399] Log turtle egg trampling --- .../listeners/CreatureInteractLogging.java | 14 ++++++++++++++ .../diddiz/LogBlock/listeners/InteractLogging.java | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java index b4bfc60a..542a9246 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java @@ -9,10 +9,12 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; +import org.bukkit.block.data.type.TurtleEgg; import org.bukkit.entity.EntityType; 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.entity.EntityInteractEvent; import static de.diddiz.LogBlock.config.Config.getWorldConfig; @@ -48,6 +50,18 @@ public void onEntityInteract(EntityInteractEvent event) { consumer.queueBlockBreak(new Actor("CreatureTrample"), trampledCrop.getState()); } } + } else if (type == Material.TURTLE_EGG) { + if (wcfg.isLogging(Logging.CREATURECROPTRAMPLE)) { + TurtleEgg turtleEggData = (TurtleEgg) clicked.getBlockData(); + int eggs = turtleEggData.getEggs(); + if (eggs > 1) { + TurtleEgg turtleEggData2 = (TurtleEgg) turtleEggData.clone(); + turtleEggData2.setEggs(eggs - 1); + consumer.queueBlock(new Actor("CreatureTrample"), loc, turtleEggData, turtleEggData2); + } else { + consumer.queueBlock(new Actor("CreatureTrample"), loc, turtleEggData, Material.AIR.createBlockData()); + } + } } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index 18a3b95c..8de3a235 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -21,6 +21,7 @@ import org.bukkit.block.data.type.NoteBlock; import org.bukkit.block.data.type.Repeater; import org.bukkit.block.data.type.Switch; +import org.bukkit.block.data.type.TurtleEgg; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -138,6 +139,19 @@ public void onPlayerInteract(PlayerInteractEvent event) { } } break; + case TURTLE_EGG: + if (event.getAction() == Action.PHYSICAL) { + TurtleEgg turtleEggData = (TurtleEgg) blockData; + int eggs = turtleEggData.getEggs(); + if (eggs > 1) { + TurtleEgg turtleEggData2 = (TurtleEgg) turtleEggData.clone(); + turtleEggData2.setEggs(eggs - 1); + consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, turtleEggData2); + } else { + consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, Material.AIR.createBlockData()); + } + } + break; default: if (BukkitUtils.isButton(type) || type == Material.LEVER) { if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { From 91315b10c87db5c05a0241eb2ff1186d5e2fab61 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 21 Sep 2018 22:22:52 +0200 Subject: [PATCH 124/399] New param "nocache" to prevent replacing the lookup cache (useful for tools) --- .../java/de/diddiz/LogBlock/CommandsHandler.java | 13 ++++++++++--- src/main/java/de/diddiz/LogBlock/QueryParams.java | 7 +++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 42e841a9..554fc888 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -97,6 +97,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, sender.sendMessage(ChatColor.GOLD + "sum [none|blocks|players] -- Sums the result"); sender.sendMessage(ChatColor.GOLD + "asc, desc -- Changes the order of the displayed log"); sender.sendMessage(ChatColor.GOLD + "coords -- Shows coordinates for each block"); + sender.sendMessage(ChatColor.GOLD + "nocache -- Don't set the lookup cache"); sender.sendMessage(ChatColor.GOLD + "silent -- Displays lesser messages"); } else if (command.equals("permissions")) { sender.sendMessage(ChatColor.DARK_AQUA + "You've got the following permissions:"); @@ -484,7 +485,9 @@ public void run() { while (rs.next()) { blockchanges.add(factory.getLookupCacheElement(rs)); } - getSession(sender).lookupCache = blockchanges.toArray(new LookupCacheElement[blockchanges.size()]); + if (!params.noCache) { + getSession(sender).lookupCache = blockchanges.toArray(new LookupCacheElement[blockchanges.size()]); + } if (blockchanges.size() > linesPerPage) { sender.sendMessage(ChatColor.DARK_AQUA.toString() + blockchanges.size() + " changes found." + (blockchanges.size() == linesLimit ? " Use 'limit -1' to see all changes." : "")); } @@ -498,7 +501,9 @@ public void run() { showPage(sender, 1); } else { sender.sendMessage(ChatColor.DARK_AQUA + "No results found."); - getSession(sender).lookupCache = null; + if (!params.noCache) { + getSession(sender).lookupCache = null; + } } } catch (final Exception ex) { if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { @@ -702,7 +707,9 @@ public void run() { return; } editor.start(); - getSession(sender).lookupCache = editor.errors; + if (!params.noCache) { + getSession(sender).lookupCache = editor.errors; + } sender.sendMessage(ChatColor.GREEN + "Rollback finished successfully (" + editor.getElapsedTime() + " ms, " + editor.getSuccesses() + "/" + changes + " blocks" + (editor.getErrors() > 0 ? ", " + ChatColor.RED + editor.getErrors() + " errors" + ChatColor.GREEN : "") + (editor.getBlacklistCollisions() > 0 ? ", " + editor.getBlacklistCollisions() + " blacklist collisions" : "") + ")"); if (!params.silent && askClearLogAfterRollback && logblock.hasPermission(sender, "logblock.clearlog") && sender instanceof Player) { Thread.sleep(1000); diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 196f3068..5314268f 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -51,6 +51,7 @@ public final class QueryParams implements Cloneable { keywords.put("victim", 1); keywords.put("both", 0); keywords.put("force", 0); + keywords.put("nocache", 0); } public BlockChangeType bct = BlockChangeType.BOTH; public int limit = -1, before = 0, since = 0, radius = -1; @@ -60,7 +61,7 @@ public final class QueryParams implements Cloneable { public List killers = new ArrayList(); public List victims = new ArrayList(); public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, excludeBlocksMode = false, prepareToolQuery = false, silent = false, noForcedLimit = false; - public boolean forceReplace = false; + public boolean forceReplace = false, noCache = false; public CuboidRegion sel = null; public SummarizationMode sum = SummarizationMode.NONE; public List types = new ArrayList(); @@ -806,6 +807,8 @@ public void parseArgs(CommandSender sender, List args, boolean validate) silent = true; } else if (param.equals("force")) { forceReplace = true; + } else if (param.equals("nocache")) { + noCache = true; } else if (param.equals("search") || param.equals("match")) { if (values.length == 0) { throw new IllegalArgumentException("No arguments for '" + param + "'"); @@ -831,7 +834,7 @@ public void parseArgs(CommandSender sender, List args, boolean validate) if (validate) { validate(); } - if (session != null) { + if (session != null && !noCache) { session.lastQuery = clone(); } } From b1e0f91bd75f0a89dce30d35f6a6cdfe73b1438c Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 21 Sep 2018 22:36:34 +0200 Subject: [PATCH 125/399] exclude bStats from WorldEdit dependency as it breaks the build --- pom.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 26536fd5..b3da93d6 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,5 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 de.diddiz @@ -50,6 +50,12 @@ worldedit-bukkit 7.0.0-SNAPSHOT provided + + + org.bstats + bstats-bukkit + + junit From 96c9b694b8a1c5ff4d2f837e56345066ddee2b4c Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 22 Sep 2018 14:20:13 +0200 Subject: [PATCH 126/399] Fix: nocache parameter showed entries from the previous lookup --- .../de/diddiz/LogBlock/CommandsHandler.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 554fc888..3d3f27c2 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -371,19 +371,24 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, } private static void showPage(CommandSender sender, int page) { - final Session session = getSession(sender); - if (session.lookupCache != null && session.lookupCache.length > 0) { + showPage(sender, page, getSession(sender).lookupCache, true); + } + + private static void showPage(CommandSender sender, int page, LookupCacheElement[] lookupElements, boolean setSessionPage) { + if (lookupElements != null && lookupElements.length > 0) { final int startpos = (page - 1) * linesPerPage; - if (page > 0 && startpos <= session.lookupCache.length - 1) { - final int stoppos = startpos + linesPerPage >= session.lookupCache.length ? session.lookupCache.length - 1 : startpos + linesPerPage - 1; - final int numberOfPages = (int) Math.ceil(session.lookupCache.length / (double) linesPerPage); + if (page > 0 && startpos <= lookupElements.length - 1) { + final int stoppos = startpos + linesPerPage >= lookupElements.length ? lookupElements.length - 1 : startpos + linesPerPage - 1; + final int numberOfPages = (int) Math.ceil(lookupElements.length / (double) linesPerPage); if (numberOfPages != 1) { sender.sendMessage(ChatColor.DARK_AQUA + "Page " + page + "/" + numberOfPages); } for (int i = startpos; i <= stoppos; i++) { - sender.sendMessage(ChatColor.GOLD + (session.lookupCache[i].getLocation() != null ? "(" + (i + 1) + ") " : "") + session.lookupCache[i].getMessage()); + sender.sendMessage(ChatColor.GOLD + (lookupElements[i].getLocation() != null ? "(" + (i + 1) + ") " : "") + lookupElements[i].getMessage()); + } + if (setSessionPage) { + getSession(sender).page = page; } - session.page = page; } else { sender.sendMessage(ChatColor.RED + "There isn't a page '" + page + "'"); } @@ -485,8 +490,9 @@ public void run() { while (rs.next()) { blockchanges.add(factory.getLookupCacheElement(rs)); } + LookupCacheElement[] blockChangeArray = blockchanges.toArray(new LookupCacheElement[blockchanges.size()]); if (!params.noCache) { - getSession(sender).lookupCache = blockchanges.toArray(new LookupCacheElement[blockchanges.size()]); + getSession(sender).lookupCache = blockChangeArray; } if (blockchanges.size() > linesPerPage) { sender.sendMessage(ChatColor.DARK_AQUA.toString() + blockchanges.size() + " changes found." + (blockchanges.size() == linesLimit ? " Use 'limit -1' to see all changes." : "")); @@ -498,7 +504,11 @@ public void run() { sender.sendMessage(ChatColor.GOLD + "Created - Destroyed - " + (params.sum == SummarizationMode.TYPES ? "Block" : "Player")); } } - showPage(sender, 1); + if (!params.noCache) { + showPage(sender, 1); + } else { + showPage(sender, 1, blockChangeArray, false); + } } else { sender.sendMessage(ChatColor.DARK_AQUA + "No results found."); if (!params.noCache) { From 7a8551d94fa5bb205806613808e87799dcdea926 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 22 Sep 2018 14:21:25 +0200 Subject: [PATCH 127/399] Get the session by entity, not by name --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 3d3f27c2..ed1a6b29 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -145,7 +145,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, if (logblock.hasPermission(sender, "logblock.tools." + tool.name)) { if (sender instanceof Player) { final Player player = (Player) sender; - final Session session = Session.getSession(player.getName()); + final Session session = Session.getSession(player); final ToolData toolData = session.toolData.get(tool); if (args.length == 1) { if (logblock.hasPermission(player, "logblock.spawnTools")) { From a4368ea77f2ce986cc478ddfc07f12eeb4f785d7 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 12 Oct 2018 22:30:34 +0200 Subject: [PATCH 128/399] Fix sign logging --- src/main/java/de/diddiz/util/LoggingUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index 73d2f976..020c7487 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -150,7 +150,7 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or Block block = location.getBlock(); BlockData blockData = block.getBlockData(); if (blockData instanceof Directional) { - if (block.getRelative(((Directional) blockData).getFacing()).equals(origin)) { + if (block.getRelative(((Directional) blockData).getFacing().getOppositeFace()).equals(origin)) { if (wcfg.isLogging(Logging.SIGNTEXT) && block.getType() == Material.WALL_SIGN) { consumer.queueSignBreak(actor, (Sign) block.getState()); } else { From eec8c91a42b54c4c37e1b7fc803a1b3f5cdf7952 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 12 Oct 2018 22:31:24 +0200 Subject: [PATCH 129/399] Fix worldedit dependency (again..) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b3da93d6..1a320dc1 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,7 @@ provided - org.bstats + org.bstats.bStats-Metrics bstats-bukkit From 91a08e7ea0c57a8851c3dd4ceaecde1c44da266b Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 12 Oct 2018 22:35:23 +0200 Subject: [PATCH 130/399] Fix worldedit dependency (one more exclusion..) --- pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pom.xml b/pom.xml index 1a320dc1..722a0dc8 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,10 @@ org.bstats.bStats-Metrics bstats-bukkit + + io.papermc + paperlib + From 90dbc8d8dfc30849ce9b247dc002ea81cf065a2d Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 15 Oct 2018 02:49:46 +0200 Subject: [PATCH 131/399] Improve water flow logging --- .../java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index 9aecf176..4256ff88 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -37,6 +37,9 @@ public void onBlockFromTo(BlockFromToEvent event) { typeFrom = Material.WATER; fromWaterlogged = true; } + if (typeFrom == Material.SEAGRASS || typeFrom == Material.KELP_PLANT || typeFrom == Material.KELP) { + typeFrom = Material.WATER; + } Block source = Config.logFluidFlowAsPlayerWhoTriggeredIt ? event.getBlock() : null; final Block to = event.getToBlock(); From 497e844486f9b9f81118d5eaaf76477add8df1e2 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 15 Oct 2018 03:05:58 +0200 Subject: [PATCH 132/399] Split long chat lines (for example from command blocks) --- src/main/java/de/diddiz/LogBlock/Consumer.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 2ff34afe..cc0ad974 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -384,6 +384,10 @@ public void queueChat(Actor player, String message) { if (hiddenPlayers.contains(player.getName().toLowerCase())) { return; } + while(message.length() > 256) { + addQueueLast(new ChatRow(player, message.substring(0, 256))); + message = message.substring(256); + } addQueueLast(new ChatRow(player, message)); } From be5ee9f792d838ab98dfc918f33a1f189993e711 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 17 Oct 2018 14:59:35 +0200 Subject: [PATCH 133/399] Fix NPE in FluidFlowLogging Fixes #724 --- src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index 4256ff88..18808fcf 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -39,6 +39,7 @@ public void onBlockFromTo(BlockFromToEvent event) { } if (typeFrom == Material.SEAGRASS || typeFrom == Material.KELP_PLANT || typeFrom == Material.KELP) { typeFrom = Material.WATER; + fromWaterlogged = true; } Block source = Config.logFluidFlowAsPlayerWhoTriggeredIt ? event.getBlock() : null; From 396b79ab6883ef8f616457ef4f9b4f73a81bdd1e Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 19 Oct 2018 15:50:04 +0200 Subject: [PATCH 134/399] Remove unused import --- .../de/diddiz/LogBlock/listeners/CreatureInteractLogging.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java index 542a9246..7eb97fc5 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java @@ -14,7 +14,6 @@ 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.entity.EntityInteractEvent; import static de.diddiz.LogBlock.config.Config.getWorldConfig; From 3e836c2f508e0b192c12d1ea894a2aa52dd73ed1 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 19 Oct 2018 16:40:17 +0200 Subject: [PATCH 135/399] Remove LogBlockQuestioner soft dependency, as it is no longer a separate plugin --- src/main/resources/plugin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index f3dcab98..94b65bee 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -5,7 +5,7 @@ authors: [md_5, ammar2, frymaster] website: http://dev.bukkit.org/server-mods/logblock/ main: de.diddiz.LogBlock.LogBlock description: ${project.description} -softdepend: [LogBlockQuestioner, WorldEdit] +softdepend: [WorldEdit] api-version: 1.13 commands: lb: From fde6927aeb11b42dbeb7152fc375ecc32e11745e Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 21 Oct 2018 04:21:59 +0200 Subject: [PATCH 136/399] Improve recovering from broken connections --- src/main/java/de/diddiz/LogBlock/Consumer.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index cc0ad974..b89b3006 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -419,9 +419,12 @@ public void run() { ArrayList currentRows = new ArrayList<>(); Connection conn = null; BatchHelper batchHelper = new BatchHelper(); + int lastCommitsFailed = 0; while (true) { try { if (conn == null) { + batchHelper.reset(); + logblock.getLogger().info("[Consumer] Connecting to the database!"); conn = logblock.getConnection(); if (conn != null) { // initialize connection @@ -492,22 +495,27 @@ public void run() { currentRows.clear(); playerIds.putAll(uncommitedPlayerIds); uncommitedPlayerIds.clear(); + lastCommitsFailed = 0; } } catch (Exception e) { - logblock.getLogger().log(Level.SEVERE, "[Consumer] Could not insert entries!", e); - boolean retry = false; + boolean retry = lastCommitsFailed < 2; + String state = "unknown"; if (e instanceof SQLException) { // Retry on network errors: SQLSTATE = 08S01 08001 08004 HY000 40001 - String state = ((SQLException) e).getSQLState(); - retry = state != null && (state.equals("08S01") || state.equals("08001") || state.equals("08004") || state.equals("HY000") || state.equals("40001")); + state = ((SQLException) e).getSQLState(); + retry = retry || (state != null && (state.equals("08S01") || state.equals("08001") || state.equals("08004") || state.equals("HY000") || state.equals("40001"))); } + lastCommitsFailed += 1; if (retry) { + logblock.getLogger().log(Level.WARNING, "[Consumer] Database connection lost, reconnecting! SQLState: " + state); // readd rows to the queue synchronized (queue) { while (!currentRows.isEmpty()) { queue.addFirst(currentRows.remove(currentRows.size() - 1)); } } + } else { + logblock.getLogger().log(Level.SEVERE, "[Consumer] Could not insert entries! SQLState: " + state, e); } currentRows.clear(); batchHelper.reset(); From 40531988b0fbe685889df1c19a20ef707cfdec49 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 2 Nov 2018 03:33:38 +0100 Subject: [PATCH 137/399] optimize log lookup --- src/main/java/de/diddiz/LogBlock/QueryParams.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 5314268f..99d689c9 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -122,6 +122,14 @@ public String getFrom() { } String from = "FROM `" + getTable() + "-blocks` "; + + // heuristics - for a small radius using coords index is much faster, but mysql sometimes does not use it + if ((loc != null && radius <= 500) || (sel != null && sel.getSizeX() <= 1000)) { + if (since < 0 || since > 11000) { + from += "USE INDEX (coords) "; + } + } + if (needPlayer || players.size() > 0) { from += "INNER JOIN `lb-players` USING (playerid) "; } From 35e62e03e92db31f22c4674e154ffa83229e90da Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 2 Nov 2018 23:57:12 +0100 Subject: [PATCH 138/399] order results by id only (date is not needed there) --- .../java/de/diddiz/LogBlock/QueryParams.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 99d689c9..4405abe3 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -98,7 +98,7 @@ public String getLimit() { public String getFrom() { if (sum != SummarizationMode.NONE) { - throw new IllegalStateException("No implemented for summarization"); + throw new IllegalStateException("Not implemented for summarization"); } if (bct == BlockChangeType.CHAT) { String from = "FROM `lb-chat` "; @@ -123,13 +123,6 @@ public String getFrom() { String from = "FROM `" + getTable() + "-blocks` "; - // heuristics - for a small radius using coords index is much faster, but mysql sometimes does not use it - if ((loc != null && radius <= 500) || (sel != null && sel.getSizeX() <= 1000)) { - if (since < 0 || since > 11000) { - from += "USE INDEX (coords) "; - } - } - if (needPlayer || players.size() > 0) { from += "INNER JOIN `lb-players` USING (playerid) "; } @@ -150,14 +143,21 @@ public String getFrom() { public String getOrder() { if (sum != SummarizationMode.NONE) { - throw new IllegalStateException("No implemented for summarization"); + throw new IllegalStateException("Not implemented for summarization"); } - return "ORDER BY date " + order + ", id " + order + " "; + + // heuristics, for small time spans this might be faster + final int twoDaysInSeconds = 60 * 24 * 2; + if (since > 0 && since <= twoDaysInSeconds) { + return "ORDER BY date " + order + ", id " + order + " "; + } + + return "ORDER BY id " + order + " "; } public String getFields() { if (sum != SummarizationMode.NONE) { - throw new IllegalStateException("No implemented for summarization"); + throw new IllegalStateException("Not implemented for summarization"); } if (bct == BlockChangeType.CHAT) { String select = ""; From f2dc3daad038a3bb90477e39a43684fe0900fb87 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 6 Nov 2018 01:56:25 +0100 Subject: [PATCH 139/399] Adapt to latest WorldEdit changes + Compile against Spigot 1.13.2 --- pom.xml | 2 +- src/main/java/de/diddiz/worldedit/CuboidRegion.java | 12 +++++------- .../de/diddiz/worldedit/WorldEditLoggingHook.java | 6 +++--- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index 722a0dc8..d8b0bf40 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ org.spigotmc spigot-api - 1.13.1-R0.1-SNAPSHOT + 1.13.2-R0.1-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/worldedit/CuboidRegion.java b/src/main/java/de/diddiz/worldedit/CuboidRegion.java index 8bb02098..9fe937c1 100644 --- a/src/main/java/de/diddiz/worldedit/CuboidRegion.java +++ b/src/main/java/de/diddiz/worldedit/CuboidRegion.java @@ -4,6 +4,7 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import org.bukkit.Location; @@ -11,7 +12,6 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.util.BlockVector; -import org.bukkit.util.Vector; public class CuboidRegion implements Cloneable { @@ -19,7 +19,7 @@ public class CuboidRegion implements Cloneable { private BlockVector min = new BlockVector(); private BlockVector max = new BlockVector(); - public CuboidRegion(World world, Vector first, Vector second) { + public CuboidRegion(World world, BlockVector3 first, BlockVector3 second) { this.world = world; this.min.setX(Math.min(first.getBlockX(),second.getBlockX())); this.min.setY(Math.min(first.getBlockY(),second.getBlockY())); @@ -48,15 +48,13 @@ public static CuboidRegion fromPlayerSelection(Player player, Plugin worldEditPl if (!(selection instanceof com.sk89q.worldedit.regions.CuboidRegion)) { throw new IllegalArgumentException("You have to define a cuboid selection"); } - com.sk89q.worldedit.Vector weMin = selection.getMinimumPoint(); - com.sk89q.worldedit.Vector weMax = selection.getMaximumPoint(); - Vector min = new Vector(weMin.getBlockX(), weMin.getBlockY(), weMin.getBlockZ()); - Vector max = new Vector(weMax.getBlockX(), weMax.getBlockY(), weMax.getBlockZ()); + BlockVector3 min = selection.getMinimumPoint(); + BlockVector3 max = selection.getMaximumPoint(); return new CuboidRegion(world, min, max); } public static CuboidRegion fromCorners(World world, Location first, Location second) { - return new CuboidRegion(world, first.toVector(), second.toVector()); + return new CuboidRegion(world, BukkitAdapter.asBlockVector(first), BukkitAdapter.asBlockVector(second)); } public World getWorld() { diff --git a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java index 783c9ddc..28b3d6e0 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java @@ -1,7 +1,6 @@ package de.diddiz.worldedit; import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -9,6 +8,7 @@ import com.sk89q.worldedit.event.extent.EditSessionEvent; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.eventbus.Subscribe; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -87,12 +87,12 @@ public void wrapForLogging(final EditSessionEvent event) { event.setExtent(new AbstractDelegateExtent(event.getExtent()) { @Override - public final boolean setBlock(Vector position, @SuppressWarnings("rawtypes") BlockStateHolder block) throws WorldEditException { + public final boolean setBlock(BlockVector3 position, @SuppressWarnings("rawtypes") BlockStateHolder block) throws WorldEditException { onBlockChange(position, block); return super.setBlock(position, block); } - protected void onBlockChange(Vector pt, BlockStateHolder block) { + protected void onBlockChange(BlockVector3 pt, BlockStateHolder block) { if (event.getStage() != EditSession.Stage.BEFORE_CHANGE) { return; From 737afcd1fa4d95e3524dcc807864eee01b1971d0 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 7 Nov 2018 02:55:29 +0100 Subject: [PATCH 140/399] Simplify we adapter --- .../worldedit/WorldEditLoggingHook.java | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java index 28b3d6e0..ac53acf6 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java @@ -4,7 +4,6 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.event.extent.EditSessionEvent; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.AbstractDelegateExtent; @@ -18,7 +17,6 @@ import de.diddiz.LogBlock.config.Config; import de.diddiz.util.BukkitUtils; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -45,20 +43,6 @@ private de.diddiz.LogBlock.Actor AtoA(Actor weActor) { return new de.diddiz.LogBlock.Actor(weActor.getName()); } - private World adapt(com.sk89q.worldedit.world.World weWorld) { - if (weWorld == null) { - throw new NullPointerException("[Logblock-Worldedit] The provided world was null."); - } - if (weWorld instanceof BukkitWorld) { - return ((BukkitWorld) weWorld).getWorld(); - } - World world = Bukkit.getServer().getWorld(weWorld.getName()); - if (world == null) { - throw new IllegalArgumentException("Can't find a Bukkit world for " + weWorld); - } - return world; - } - public void hook() { WorldEdit.getInstance().getEventBus().register(new Object() { @Subscribe @@ -71,9 +55,8 @@ public void wrapForLogging(final EditSessionEvent event) { // Check to ensure the world should be logged final World world; - final com.sk89q.worldedit.world.World k = event.getWorld(); try { - world = adapt(k); + world = BukkitAdapter.adapt(event.getWorld()); } catch (RuntimeException ex) { plugin.getLogger().warning("Failed to register logging for WorldEdit!"); plugin.getLogger().log(Level.WARNING, ex.getMessage(), ex); From 8c6ee4cf0c75b0c5a1e6a87e04e3f030908d01f3 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 7 Nov 2018 20:45:57 +0100 Subject: [PATCH 141/399] Improve CuboidRegion not to use WorldEdit vectors when not needed --- src/main/java/de/diddiz/worldedit/CuboidRegion.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/worldedit/CuboidRegion.java b/src/main/java/de/diddiz/worldedit/CuboidRegion.java index 9fe937c1..3755a063 100644 --- a/src/main/java/de/diddiz/worldedit/CuboidRegion.java +++ b/src/main/java/de/diddiz/worldedit/CuboidRegion.java @@ -19,7 +19,7 @@ public class CuboidRegion implements Cloneable { private BlockVector min = new BlockVector(); private BlockVector max = new BlockVector(); - public CuboidRegion(World world, BlockVector3 first, BlockVector3 second) { + public CuboidRegion(World world, BlockVector first, BlockVector second) { this.world = world; this.min.setX(Math.min(first.getBlockX(),second.getBlockX())); this.min.setY(Math.min(first.getBlockY(),second.getBlockY())); @@ -50,11 +50,11 @@ public static CuboidRegion fromPlayerSelection(Player player, Plugin worldEditPl } BlockVector3 min = selection.getMinimumPoint(); BlockVector3 max = selection.getMaximumPoint(); - return new CuboidRegion(world, min, max); + return new CuboidRegion(world, new BlockVector(min.getBlockX(), min.getBlockY(), min.getBlockZ()), new BlockVector(max.getBlockX(), max.getBlockY(), max.getBlockZ())); } public static CuboidRegion fromCorners(World world, Location first, Location second) { - return new CuboidRegion(world, BukkitAdapter.asBlockVector(first), BukkitAdapter.asBlockVector(second)); + return new CuboidRegion(world, new BlockVector(first.getBlockX(), first.getBlockY(), first.getBlockZ()), new BlockVector(second.getBlockX(), second.getBlockY(), second.getBlockZ())); } public World getWorld() { @@ -85,7 +85,7 @@ public CuboidRegion clone() { clone.max = max.clone(); return clone; } catch (final CloneNotSupportedException ex) { - throw new Error("RegionContainer should be cloneable", ex); + throw new Error("CuboidRegion should be cloneable", ex); } } } From 4af5b3f1ea2b95daaa4046019aa70f1fbdc8bd33 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 7 Nov 2018 20:55:44 +0100 Subject: [PATCH 142/399] There can only one of selection/location be set --- src/main/java/de/diddiz/LogBlock/QueryParams.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 4405abe3..958ebeb4 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -879,11 +879,13 @@ public void validate() { public void setLocation(Location loc) { this.loc = loc; + this.sel = null; world = loc.getWorld(); } public void setSelection(CuboidRegion container) { this.sel = container; + this.loc = null; world = sel.getWorld(); } From 4ce7ad0f7d825a6bfaa713026ea679d3707743d8 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 7 Nov 2018 20:56:58 +0100 Subject: [PATCH 143/399] Tool lookups no longer require WorldEdit for double chests --- .../diddiz/LogBlock/listeners/ToolListener.java | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java index 1d15a7fd..ed2239dd 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java @@ -1,11 +1,11 @@ package de.diddiz.LogBlock.listeners; import de.diddiz.LogBlock.*; +import de.diddiz.util.BukkitUtils; import de.diddiz.worldedit.CuboidRegion; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -53,19 +53,14 @@ public void onPlayerInteract(PlayerInteractEvent event) { params.sel = null; if (behavior == ToolBehavior.BLOCK) { params.setLocation(block.getRelative(event.getBlockFace()).getLocation()); - } else if ((block.getType() != Material.CHEST && block.getType() != Material.TRAPPED_CHEST) || tool.params.radius != 0) { + } else if (tool.params.radius != 0) { params.setLocation(block.getLocation()); } else { - if (logblock.getServer().getPluginManager().isPluginEnabled("WorldEdit")) { - for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) { - if (block.getRelative(face).getType() == block.getType()) { - params.setSelection(CuboidRegion.fromCorners(event.getPlayer().getWorld(), - block.getLocation(), block.getRelative(face).getLocation())); - } - } - } - if (params.sel == null) { + Block otherHalfChest = BukkitUtils.getConnectedChest(block); + if (otherHalfChest == null) { params.setLocation(block.getLocation()); + } else { + params.setSelection(CuboidRegion.fromCorners(block.getLocation().getWorld(), block.getLocation(), otherHalfChest.getLocation())); } } try { From 5ad0f06d169453932b05e4a7f0e6b3c44d019ef3 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 8 Nov 2018 02:44:04 +0100 Subject: [PATCH 144/399] Don't use MyISAM tables --- src/main/java/de/diddiz/LogBlock/Updater.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index e125e6af..6322b22e 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -57,7 +57,7 @@ boolean update() { try { conn.setAutoCommit(true); final Statement st = conn.createStatement(); - st.execute("ALTER TABLE `lb-chat` ENGINE = MyISAM, ADD FULLTEXT message (message)"); + st.execute("ALTER TABLE `lb-chat` ADD FULLTEXT message (message)"); st.close(); conn.close(); } catch (final SQLException ex) { @@ -775,11 +775,11 @@ void checkTables() throws SQLException { state.execute("INSERT IGNORE INTO `lb-players` (UUID,playername) VALUES ('log_dummy_record','dummy_record')"); } if (isLogging(Logging.CHAT)) { - createTable(dbm, 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)) ENGINE=MyISAM DEFAULT CHARSET " + charset); + createTable(dbm, 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(dbm, state, "lb-materials", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) ENGINE=MyISAM DEFAULT CHARSET " + charset); - createTable(dbm, state, "lb-blockstates", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) ENGINE=MyISAM DEFAULT CHARSET " + charset); - + createTable(dbm, state, "lb-materials", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); + createTable(dbm, state, "lb-blockstates", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); + for (final WorldConfig wcfg : getLoggedWorlds()) { createTable(dbm, state, wcfg.table + "-blocks", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced SMALLINT UNSIGNED NOT NULL, replacedData SMALLINT NOT NULL, type SMALLINT UNSIGNED NOT NULL, typeData SMALLINT NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))"); // createTable(dbm, state, wcfg.table + "-sign", "(id INT UNSIGNED NOT NULL, signtext VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); From 707e0a1eed26ba869ee4ee651c39bcbb1caf7f34 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 8 Nov 2018 05:16:21 +0100 Subject: [PATCH 145/399] Incomplete entity logging --- src/main/java/de/diddiz/LogBlock/Actor.java | 18 ++- .../java/de/diddiz/LogBlock/Consumer.java | 122 +++++++++++++++++- .../java/de/diddiz/LogBlock/EntityChange.java | 98 ++++++++++++++ .../diddiz/LogBlock/EntityTypeConverter.java | 82 ++++++++++++ .../java/de/diddiz/LogBlock/LogBlock.java | 6 +- .../java/de/diddiz/LogBlock/QueryParams.java | 28 +++- src/main/java/de/diddiz/LogBlock/Updater.java | 4 +- .../diddiz/LogBlock/config/WorldConfig.java | 2 + .../diddiz/worldedit/AdvancedKillLogging.java | 50 +++++++ .../de/diddiz/worldedit/CuboidRegion.java | 3 +- .../de/diddiz/worldedit/WorldEditHelper.java | 60 +++++++++ 11 files changed, 458 insertions(+), 15 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/EntityChange.java create mode 100644 src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java create mode 100644 src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java create mode 100644 src/main/java/de/diddiz/worldedit/WorldEditHelper.java diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index 0307870e..1fde0725 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -3,6 +3,7 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; import org.bukkit.projectiles.BlockProjectileSource; import org.bukkit.projectiles.ProjectileSource; @@ -86,9 +87,14 @@ public Location getBlockLocation() { public static Actor actorFromEntity(Entity entity) { if (entity instanceof Player) { return new Actor(entityName(entity), entity.getUniqueId()); - } else { - return new Actor(entityName(entity)); } + if (entity instanceof Projectile) { + ProjectileSource shooter = ((Projectile) entity).getShooter(); + if (shooter != null) { + return actorFromProjectileSource(shooter); + } + } + return new Actor(entityName(entity)); } public static Actor actorFromEntity(EntityType entity) { @@ -109,17 +115,19 @@ public static Actor actorFromProjectileSource(ProjectileSource psource) { /** * Generate an Actor object from a String name, trying to guess if it's an online player - * and if so, setting the UUID accordingly. This only checks against currently online + * and if so, setting the UUID accordingly. This only checks against currently online * players and is a "best effort" attempt for use with the pre-UUID API *

* If you know something is an entity (player or otherwise) use the {@link #actorFromEntity(org.bukkit.entity.Entity) } * or {@link #actorFromEntity(org.bukkit.entity.EntityType) } methods *

* If you know something is a server effect (like gravity) use {@link #Actor(java.lang.String)} + * * @deprecated Only use this if you have a String of unknown origin * - * @param actorName String of unknown origin - * @return + * @param actorName + * String of unknown origin + * @return */ public static Actor actorFromString(String actorName) { Collection players = Bukkit.getServer().getOnlinePlayers(); diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index b89b3006..d96daa12 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -26,16 +26,19 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.UUID; import java.util.logging.Level; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.block.data.BlockData; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.inventory.Inventory; @@ -43,6 +46,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.projectiles.ProjectileSource; +import de.diddiz.LogBlock.EntityChange.EntityChangeType; import de.diddiz.LogBlock.blockstate.BlockStateCodecSign; import de.diddiz.LogBlock.blockstate.BlockStateCodecs; import de.diddiz.LogBlock.config.Config; @@ -52,8 +56,10 @@ public class Consumer extends Thread { private final Deque queue = new ArrayDeque(); private final LogBlock logblock; - private final Map playerIds = new HashMap(); - private final Map uncommitedPlayerIds = new HashMap(); + private final Map playerIds = new HashMap<>(); + private final Map uncommitedPlayerIds = new HashMap<>(); + private final Map> uncommitedEntityIds = new HashMap<>(); + private long addEntryCounter; private long nextWarnCounter; @@ -495,6 +501,7 @@ public void run() { currentRows.clear(); playerIds.putAll(uncommitedPlayerIds); uncommitedPlayerIds.clear(); + uncommitedEntityIds.clear(); lastCommitsFailed = 0; } } catch (Exception e) { @@ -520,6 +527,7 @@ public void run() { currentRows.clear(); batchHelper.reset(); uncommitedPlayerIds.clear(); + uncommitedEntityIds.clear(); if (conn != null) { try { conn.close(); @@ -657,6 +665,48 @@ private boolean addPlayer(Connection conn, Actor actor) throws SQLException { return uncommitedPlayerIds.containsKey(actor); } + private int getEntityUUID(Connection conn, World world, UUID uuid) throws SQLException { + Map uncommitedEntityIdsHere = uncommitedEntityIds.get(world); + if (uncommitedEntityIdsHere == null) { + uncommitedEntityIdsHere = new HashMap<>(); + uncommitedEntityIds.put(world, uncommitedEntityIdsHere); + } + Integer existing = uncommitedEntityIdsHere.get(uuid); + if (existing != null) { + return existing; + } + + // Odd query contruction is to work around innodb auto increment behaviour - bug #492 + final String table = getWorldConfig(world).table; + String uuidString = uuid.toString(); + Statement state = conn.createStatement(); + String q1 = "INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) SELECT '" + mysqlTextEscape(uuidString) + "' FROM `" + table + "-entityids` WHERE NOT EXISTS (SELECT NULL FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(uuidString) + "') LIMIT 1"; + String q2 = "SELECT entityid FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(uuidString) + "'"; + int q1Result = state.executeUpdate(q1); + ResultSet rs = state.executeQuery(q2); + if (rs.next()) { + uncommitedEntityIdsHere.put(uuid, rs.getInt(1)); + } + rs.close(); + // if there was not any row in the table the query above does not work, so we need to try this one + if (!uncommitedEntityIdsHere.containsKey(uuid)) { + state.executeUpdate("INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) VALUES ('" + mysqlTextEscape(uuidString) + "')"); + rs = state.executeQuery(q2); + if (rs.next()) { + uncommitedEntityIdsHere.put(uuid, rs.getInt(1)); + } else { + logblock.getLogger().warning("[Consumer] Failed to add entity uuid " + uuidString.toString()); + logblock.getLogger().warning("[Consumer-Debug] World: " + world.getName()); + logblock.getLogger().warning("[Consumer-Debug] Query 1: " + q1); + logblock.getLogger().warning("[Consumer-Debug] Query 1 - Result: " + q1Result); + logblock.getLogger().warning("[Consumer-Debug] Query 2: " + q2); + } + rs.close(); + } + state.close(); + return uncommitedEntityIdsHere.get(uuid); + } + private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter, YamlConfiguration stateBefore, YamlConfiguration stateAfter, ChestAccess ca) { if (typeBefore == null || typeBefore.getMaterial() == Material.CAVE_AIR || typeBefore.getMaterial() == Material.VOID_AIR) { typeBefore = Bukkit.createBlockData(Material.AIR); @@ -696,6 +746,13 @@ private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDa addQueueLast(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, Utils.serializeYamlConfiguration(stateBefore), typeMaterialId, typeStateId, Utils.serializeYamlConfiguration(stateAfter), ca)); } + public void queueEntityModification(Actor actor, UUID entityId, EntityType entityType, Location loc, EntityChangeType changeType, YamlConfiguration data) { + if (actor == null || loc == null || changeType == null || entityId == null || entityType == null || hiddenPlayers.contains(actor.getName().toLowerCase()) || !isLogged(loc.getWorld())) { + return; + } + addQueueLast(new EntityRow(loc, actor, entityType, entityId, changeType, Utils.serializeYamlConfiguration(data))); + } + private String playerID(Actor actor) { if (actor == null) { return "NULL"; @@ -965,6 +1022,67 @@ public void process(Connection conn, BatchHelper batchHelper) throws SQLExceptio } } + private class EntityRow extends EntityChange implements Row { + final String statementString; + final String selectActorIdStatementString; + + public EntityRow(Location loc, Actor actor, EntityType type, UUID entityid, EntityChangeType changeType, byte[] data) { + super(System.currentTimeMillis() / 1000, loc, actor, type, entityid, changeType, data); + statementString = getWorldConfig(loc.getWorld()).insertEntityStatementString; + selectActorIdStatementString = getWorldConfig(loc.getWorld()).selectBlockActorIdStatementString; + } + + @Override + public String[] getInserts() { + final String table = getWorldConfig(loc.getWorld()).table; + final String[] inserts = new String[2]; + + inserts[0] = "INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) SELECT '" + mysqlTextEscape(entityid.toString()) + "' FROM `" + table + "-entityids` WHERE NOT EXISTS (SELECT NULL FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(entityid.toString()) + "') LIMIT 1"; + int entityTypeId = EntityTypeConverter.getOrAddEntityTypeId(type); + inserts[1] = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(actor) + ", " + "(SELECT entityid FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(entityid.toString()) + "')" + + ", " + entityTypeId + ", '" + loc.getBlockX() + "', " + safeY(loc) + ", '" + loc.getBlockZ() + "', " + changeType.ordinal() + ", " + Utils.mysqlPrepareBytesForInsertAllowNull(data) + ");"; + return inserts; + } + + @Override + public Actor[] getActors() { + return new Actor[] { actor }; + } + + @Override + public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + int sourceActor = playerIDAsIntIncludeUncommited(actor); + Location actorBlockLocation = actor.getBlockLocation(); + if (actorBlockLocation != null) { + Integer tempSourceActor = batchHelper.getUncommitedBlockActor(actorBlockLocation); + if (tempSourceActor != null) { + sourceActor = tempSourceActor; + } else { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, selectActorIdStatementString, Statement.NO_GENERATED_KEYS); + smt.setInt(1, actorBlockLocation.getBlockX()); + smt.setInt(2, safeY(actorBlockLocation)); + smt.setInt(3, actorBlockLocation.getBlockZ()); + ResultSet rs = smt.executeQuery(); + if (rs.next()) { + sourceActor = rs.getInt(1); + } + rs.close(); + } + } + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.RETURN_GENERATED_KEYS); + smt.setLong(1, date); + smt.setInt(2, sourceActor); + smt.setInt(3, getEntityUUID(conn, loc.getWorld(), entityid)); + smt.setInt(4, EntityTypeConverter.getOrAddEntityTypeId(type)); + smt.setInt(5, loc.getBlockX()); + smt.setInt(6, safeY(loc)); + smt.setInt(7, loc.getBlockZ()); + smt.setInt(8, changeType.ordinal()); + smt.setBytes(9, data); + batchHelper.addBatch(smt, null); + } + } + private int safeY(Location loc) { int safeY = loc.getBlockY(); if (safeY < 0) diff --git a/src/main/java/de/diddiz/LogBlock/EntityChange.java b/src/main/java/de/diddiz/LogBlock/EntityChange.java new file mode 100644 index 00000000..878464db --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/EntityChange.java @@ -0,0 +1,98 @@ +package de.diddiz.LogBlock; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +import org.bukkit.Location; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; + +import de.diddiz.LogBlock.config.Config; + +public class EntityChange implements LookupCacheElement { + public static enum EntityChangeType { + CREATE, + KILL, + MODIFY, + ADDEQUIP, + REMOVEEQUIP; + + private static EntityChangeType[] values = values(); + + public static EntityChangeType valueOf(int ordinal) { + return values[ordinal]; + } + } + + public final long id, date; + public final Location loc; + public final Actor actor; + public final EntityType type; + public final UUID entityid; + public final EntityChangeType changeType; + public final byte[] data; + + public EntityChange(long date, Location loc, Actor actor, EntityType type, UUID entityid, EntityChangeType changeType, byte[] data) { + id = 0; + this.date = date; + this.loc = loc; + this.actor = actor; + this.type = type; + this.entityid = entityid; + this.changeType = changeType; + this.data = data; + } + + public EntityChange(ResultSet rs, QueryParams p) throws SQLException { + id = p.needId ? rs.getInt("id") : 0; + date = p.needDate ? rs.getTimestamp("date").getTime() : 0; + loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null; + actor = p.needPlayer ? new Actor(rs) : null; + type = p.needType ? EntityTypeConverter.getEntityType(rs.getInt("entitytypeid")) : null; + entityid = p.needType ? UUID.fromString(rs.getString("entityuuid")) : null; + changeType = p.needType ? EntityChangeType.valueOf(rs.getInt("action")) : null; + data = p.needType ? rs.getBytes("data") : null; + } + + @Override + public String toString() { + final StringBuilder msg = new StringBuilder(); + if (date > 0) { + msg.append(Config.formatter.format(date)).append(" "); + } + if (actor != null) { + msg.append(actor.getName()).append(" "); + } + if (type != null) { + boolean living = LivingEntity.class.isAssignableFrom(type.getEntityClass()) && !ArmorStand.class.isAssignableFrom(type.getDeclaringClass()); + if (changeType == EntityChangeType.CREATE) { + msg.append("created "); + } else if (changeType == EntityChangeType.KILL) { + msg.append(living ? "killed " : "destroyed "); + } else if (changeType == EntityChangeType.ADDEQUIP) { + msg.append("added an item to "); + } else if (changeType == EntityChangeType.REMOVEEQUIP) { + msg.append("removed an item from "); + } else if (changeType == EntityChangeType.MODIFY) { + msg.append("modified "); + } + msg.append(type.name()); + } + if (loc != null) { + msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ()); + } + return msg.toString(); + } + + @Override + public Location getLocation() { + return loc; + } + + @Override + public String getMessage() { + return toString(); + } +} diff --git a/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java b/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java new file mode 100644 index 00000000..83e8c1b5 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java @@ -0,0 +1,82 @@ +package de.diddiz.LogBlock; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Arrays; +import java.util.HashMap; +import java.util.logging.Level; + +import org.bukkit.entity.EntityType; + +public class EntityTypeConverter { + private static EntityType[] idToEntityType = new EntityType[10]; + private static HashMap entityTypeToId = new HashMap<>(); + private static int nextEntityTypeId; + + public static int getOrAddEntityTypeId(EntityType entityType) { + Integer key = entityTypeToId.get(entityType); + while (key == null) { + key = nextEntityTypeId; + Connection conn = LogBlock.getInstance().getConnection(); + try { + conn.setAutoCommit(false); + PreparedStatement smt = conn.prepareStatement("INSERT IGNORE INTO `lb-entitytypes` (id, name) VALUES (?, ?)"); + smt.setInt(1, key); + smt.setString(2, entityType.name()); + boolean couldAdd = smt.executeUpdate() > 0; + conn.commit(); + smt.close(); + if (couldAdd) { + internalAddEntityType(key, entityType); + } else { + initializeEntityTypes(conn); + } + } catch (SQLException e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not update lb-entitytypes", e); + } finally { + try { + conn.close(); + } catch (SQLException e) { + // ignored + } + } + key = entityTypeToId.get(entityType); + } + return key.intValue(); + } + + public static EntityType getEntityType(int entityTypeId) { + return idToEntityType[entityTypeId]; + } + + public static void initializeEntityTypes(Connection connection) throws SQLException { + Statement smt = connection.createStatement(); + ResultSet rs = smt.executeQuery("SELECT id, name FROM `lb-entitytypes`"); + while (rs.next()) { + int key = rs.getInt(1); + EntityType entityType = EntityType.valueOf(rs.getString(2)); + internalAddEntityType(key, entityType); + } + rs.close(); + smt.close(); + connection.close(); + } + + private synchronized static void internalAddEntityType(int key, EntityType entityType) { + entityTypeToId.put(entityType, key); + int length = idToEntityType.length; + while (length <= key) { + length = (length * 3 / 2) + 5; + } + if (length > idToEntityType.length) { + idToEntityType = Arrays.copyOf(idToEntityType, length); + } + idToEntityType[key] = entityType; + if (nextEntityTypeId <= key) { + nextEntityTypeId = key + 1; + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index e3e35e88..65bf474a 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -5,6 +5,8 @@ import de.diddiz.LogBlock.questioner.Questioner; import de.diddiz.util.BukkitUtils; import de.diddiz.util.MySQLConnectionPool; +import de.diddiz.worldedit.AdvancedKillLogging; +import de.diddiz.worldedit.WorldEditHelper; import de.diddiz.worldedit.WorldEditLoggingHook; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -89,6 +91,7 @@ public void onEnable() { updater.checkTables(); MaterialConverter.initializeMaterials(getConnection()); MaterialConverter.getOrAddMaterialId(Material.AIR.getKey()); // AIR must be the first entry + EntityTypeConverter.initializeEntityTypes(getConnection()); if (updater.update()) { load(this); } @@ -100,7 +103,7 @@ public void onEnable() { return; } - if (pm.getPlugin("WorldEdit") != null) { + if (WorldEditHelper.hasWorldEdit()) { new WorldEditLoggingHook(this).hook(); } commandsHandler = new CommandsHandler(this); @@ -186,6 +189,7 @@ private void registerEvents() { if (isLogging(Logging.DRAGONEGGTELEPORT)) { pm.registerEvents(new DragonEggLogging(this), this); } + pm.registerEvents(new AdvancedKillLogging(this), this); } @Override diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 958ebeb4..506dd575 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -3,12 +3,13 @@ import de.diddiz.LogBlock.config.Config; import de.diddiz.util.Utils; import de.diddiz.worldedit.CuboidRegion; +import de.diddiz.worldedit.WorldEditHelper; + import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; import java.util.*; @@ -120,6 +121,17 @@ public String getFrom() { } return from; } + if (bct == BlockChangeType.ENTITIES) { + String from = "FROM `" + getTable() + "-entities` "; + + if (needPlayer || players.size() > 0) { + from += "INNER JOIN `lb-players` USING (playerid) "; + } + if (!needCount && needType) { + from += "LEFT JOIN `" + getTable() + "-entityids` USING (entityid) "; + } + return from; + } String from = "FROM `" + getTable() + "-blocks` "; @@ -262,6 +274,9 @@ public String getQuery() { } throw new IllegalStateException("Invalid summarization for kills"); } + if (bct == BlockChangeType.ENTITIES) { + throw new IllegalStateException("Not implemented yet"); + } if (sum == SummarizationMode.TYPES) { return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.CREATED) + "GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); } else { @@ -281,6 +296,8 @@ public String getTitle() { title.append("chat messages "); } else if (bct == BlockChangeType.KILLS) { title.append("kills "); + } else if (bct == BlockChangeType.ENTITIES) { + title.append("entity changes "); } else { if (!types.isEmpty()) { if (excludeBlocksMode) { @@ -745,9 +762,8 @@ public void parseArgs(CommandSender sender, List args, boolean validate) if (player == null) { throw new IllegalArgumentException("You have to be a player to use selection"); } - final Plugin we = player.getServer().getPluginManager().getPlugin("WorldEdit"); - if (we != null) { - setSelection(CuboidRegion.fromPlayerSelection(player, we)); + if (WorldEditHelper.hasWorldEdit()) { + setSelection(CuboidRegion.fromPlayerSelection(player)); } else { throw new IllegalArgumentException("WorldEdit not found!"); } @@ -786,6 +802,8 @@ public void parseArgs(CommandSender sender, List args, boolean validate) bct = BlockChangeType.CHAT; } else if (param.equals("kills")) { bct = BlockChangeType.KILLS; + } else if (param.equals("entities")) { + bct = BlockChangeType.ENTITIES; } else if (param.equals("all")) { bct = BlockChangeType.ALL; } else if (param.equals("limit")) { @@ -963,7 +981,7 @@ public void merge(QueryParams p) { } public static enum BlockChangeType { - ALL, BOTH, CHESTACCESS, CREATED, DESTROYED, CHAT, KILLS + ALL, BOTH, CHESTACCESS, CREATED, DESTROYED, CHAT, KILLS, ENTITIES } public static enum Order { diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 6322b22e..d164e098 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -779,15 +779,17 @@ void checkTables() throws SQLException { } createTable(dbm, state, "lb-materials", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); createTable(dbm, state, "lb-blockstates", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); + createTable(dbm, 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(dbm, state, wcfg.table + "-blocks", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced SMALLINT UNSIGNED NOT NULL, replacedData SMALLINT NOT NULL, type SMALLINT UNSIGNED NOT NULL, typeData SMALLINT NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))"); - // createTable(dbm, state, wcfg.table + "-sign", "(id INT UNSIGNED NOT NULL, signtext VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); createTable(dbm, state, wcfg.table + "-chestdata", "(id INT UNSIGNED NOT NULL, item MEDIUMBLOB, itemremove TINYINT, itemtype SMALLINT NOT NULL DEFAULT '0', PRIMARY KEY (id))"); createTable(dbm, state, wcfg.table + "-state", "(id INT UNSIGNED NOT NULL, replacedState MEDIUMBLOB NULL, typeState MEDIUMBLOB NULL, PRIMARY KEY (id))"); if (wcfg.isLogging(Logging.KILL)) { createTable(dbm, state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id))"); } + createTable(dbm, 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(dbm, 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))"); } state.close(); conn.close(); diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index 3fe0d99e..8b647d35 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -16,6 +16,7 @@ public class WorldConfig extends LoggingEnabledMapping { public final String selectBlockActorIdStatementString; public final String insertBlockStateStatementString; public final String insertBlockChestDataStatementString; + public final String insertEntityStatementString; public WorldConfig(String world, File file) throws IOException { this.world = world; @@ -42,5 +43,6 @@ public WorldConfig(String world, File file) throws IOException { selectBlockActorIdStatementString = "SELECT playerid FROM `" + table + "-blocks` WHERE x = ? AND y = ? AND z = ? ORDER BY date DESC LIMIT 1"; insertBlockStateStatementString = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(?, ?, ?)"; insertBlockChestDataStatementString = "INSERT INTO `" + table + "-chestdata` (item, itemremove, id, itemtype) values (?, ?, ?, ?)"; + insertEntityStatementString = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"; } } diff --git a/src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java b/src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java new file mode 100644 index 00000000..2c851221 --- /dev/null +++ b/src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java @@ -0,0 +1,50 @@ +package de.diddiz.worldedit; + +import org.bukkit.Location; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Animals; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Villager; +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 de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.EntityChange; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.listeners.LoggingListener; + +public class AdvancedKillLogging extends LoggingListener { + + public AdvancedKillLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onEntityDeath(EntityDeathEvent event) { + LivingEntity entity = event.getEntity(); + if (!(entity instanceof Animals) && !(entity instanceof Villager)) { + return; + } + Actor killer; + EntityDamageEvent lastDamage = entity.getLastDamageCause(); + if (lastDamage instanceof EntityDamageByEntityEvent) { + killer = Actor.actorFromEntity(((EntityDamageByEntityEvent) lastDamage).getDamager()); + } else { + killer = new Actor(lastDamage.getCause().toString()); + } + Location location = entity.getLocation(); + YamlConfiguration data = new YamlConfiguration(); + data.set("x", location.getX()); + data.set("y", location.getX()); + data.set("z", location.getX()); + data.set("yaw", location.getYaw()); + data.set("pitch", location.getPitch()); + + data.set("worldedit", WorldEditHelper.serializeEntity(entity)); + + consumer.queueEntityModification(killer, entity.getUniqueId(), entity.getType(), location, EntityChange.EntityChangeType.KILL, data); + } +} diff --git a/src/main/java/de/diddiz/worldedit/CuboidRegion.java b/src/main/java/de/diddiz/worldedit/CuboidRegion.java index 3755a063..7b094298 100644 --- a/src/main/java/de/diddiz/worldedit/CuboidRegion.java +++ b/src/main/java/de/diddiz/worldedit/CuboidRegion.java @@ -29,7 +29,8 @@ public CuboidRegion(World world, BlockVector first, BlockVector second) { this.max.setZ(Math.max(first.getBlockZ(),second.getBlockZ())); } - public static CuboidRegion fromPlayerSelection(Player player, Plugin worldEditPlugin) { + public static CuboidRegion fromPlayerSelection(Player player) { + Plugin worldEditPlugin = player.getServer().getPluginManager().getPlugin("WorldEdit"); LocalSession session = ((WorldEditPlugin) worldEditPlugin).getSession(player); World world = player.getWorld(); com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(world); diff --git a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java b/src/main/java/de/diddiz/worldedit/WorldEditHelper.java new file mode 100644 index 00000000..08441b3b --- /dev/null +++ b/src/main/java/de/diddiz/worldedit/WorldEditHelper.java @@ -0,0 +1,60 @@ +package de.diddiz.worldedit; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Entity; +import org.bukkit.plugin.Plugin; + +import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.entity.BaseEntity; + +public class WorldEditHelper { + private static boolean checkedForWorldEdit; + private static boolean hasWorldEdit; + + public static boolean hasWorldEdit() { + if (!checkedForWorldEdit) { + checkedForWorldEdit = true; + Plugin worldEdit = Bukkit.getPluginManager().getPlugin("WorldEdit"); + hasWorldEdit = worldEdit != null; + Internal.setWorldEdit(worldEdit); + } + return hasWorldEdit; + } + + public static byte[] serializeEntity(Entity entity) { + if (!hasWorldEdit()) { + return null; + } + return Internal.serializeEntity(entity); + } + + private static class Internal { + // private static WorldEditPlugin worldEdit; + + public static void setWorldEdit(Plugin worldEdit) { + // Internal.worldEdit = (WorldEditPlugin) worldEdit; + } + + public static byte[] serializeEntity(Entity entity) { + com.sk89q.worldedit.entity.Entity weEntity = BukkitAdapter.adapt(entity); + BaseEntity state = weEntity.getState(); + if (state != null) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + NBTOutputStream nbtos = new NBTOutputStream(baos); + nbtos.writeNamedTag("entity", state.getNbtData()); + nbtos.close(); + return baos.toByteArray(); + } catch (IOException e) { + throw new RuntimeException("This IOException should be impossible", e); + } + } + return null; + } + + } +} From f9d246dd63b7f59ab81a0f8d5e12b23d61687e08 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 8 Nov 2018 05:44:21 +0100 Subject: [PATCH 146/399] Implement basic entity change lookup --- .../java/de/diddiz/LogBlock/EntityChange.java | 4 +- .../LogBlock/LookupCacheElementFactory.java | 7 ++ .../java/de/diddiz/LogBlock/QueryParams.java | 78 +++++++++---------- 3 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/EntityChange.java b/src/main/java/de/diddiz/LogBlock/EntityChange.java index 878464db..35cf6c38 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityChange.java +++ b/src/main/java/de/diddiz/LogBlock/EntityChange.java @@ -51,9 +51,9 @@ public EntityChange(ResultSet rs, QueryParams p) throws SQLException { loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null; actor = p.needPlayer ? new Actor(rs) : null; type = p.needType ? EntityTypeConverter.getEntityType(rs.getInt("entitytypeid")) : null; - entityid = p.needType ? UUID.fromString(rs.getString("entityuuid")) : null; + entityid = p.needData ? UUID.fromString(rs.getString("entityuuid")) : null; changeType = p.needType ? EntityChangeType.valueOf(rs.getInt("action")) : null; - data = p.needType ? rs.getBytes("data") : null; + data = p.needData ? rs.getBytes("data") : null; } @Override diff --git a/src/main/java/de/diddiz/LogBlock/LookupCacheElementFactory.java b/src/main/java/de/diddiz/LogBlock/LookupCacheElementFactory.java index 6a1af349..dc97d53f 100755 --- a/src/main/java/de/diddiz/LogBlock/LookupCacheElementFactory.java +++ b/src/main/java/de/diddiz/LogBlock/LookupCacheElementFactory.java @@ -26,6 +26,13 @@ public LookupCacheElement getLookupCacheElement(ResultSet rs) throws SQLExceptio return new SummedKills(rs, params, spaceFactor); } } + if (params.bct == BlockChangeType.ENTITIES) { + if (params.sum == SummarizationMode.NONE) { + return new EntityChange(rs, params); + } else if (params.sum == SummarizationMode.PLAYERS) { + throw new IllegalArgumentException(); + } + } if (params.sum == SummarizationMode.NONE) { return new BlockChange(rs, params); } diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 506dd575..94b87a7c 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -53,6 +53,8 @@ public final class QueryParams implements Cloneable { keywords.put("both", 0); keywords.put("force", 0); keywords.put("nocache", 0); + keywords.put("entities", 0); + keywords.put("entity", 0); } public BlockChangeType bct = BlockChangeType.BOTH; public int limit = -1, before = 0, since = 0, radius = -1; @@ -127,7 +129,7 @@ public String getFrom() { if (needPlayer || players.size() > 0) { from += "INNER JOIN `lb-players` USING (playerid) "; } - if (!needCount && needType) { + if (!needCount && needData) { from += "LEFT JOIN `" + getTable() + "-entityids` USING (entityid) "; } return from; @@ -230,16 +232,22 @@ public String getFields() { select += "COUNT(*) AS count "; } else { if (needId) { - select += "`" + getTable() + "-blocks`.id, "; + if (bct != BlockChangeType.ENTITIES) { + select += "`" + getTable() + "-blocks`.id, "; + } else { + select += "`" + getTable() + "-entities`.id, "; + } } if (needDate) { select += "date, "; } - if (needType) { - select += "replaced, type, "; - } - if (needData) { - select += "replacedData, typeData, "; + if (bct != BlockChangeType.ENTITIES) { + if (needType) { + select += "replaced, type, "; + } + if (needData) { + select += "replacedData, typeData, "; + } } if (needPlayer) { select += "playername, UUID, "; @@ -250,11 +258,20 @@ public String getFields() { if (needCoords) { select += "x, y, z, "; } - if (needData) { - select += "replacedState, typeState, "; - } - if (needChestAccess) { - select += "item, itemremove, itemtype, "; + if (bct != BlockChangeType.ENTITIES) { + if (needData) { + select += "replacedState, typeState, "; + } + if (needChestAccess) { + select += "item, itemremove, itemtype, "; + } + } else { + if (needType) { + select += "entitytypeid, action, "; + } + if(needData) { + select += "entityuuid, data, "; + } } select = select.substring(0, select.length() - 2) + " "; } @@ -436,32 +453,7 @@ public String getWhere(BlockChangeType blockChangeType) { } } } - - if (loc != null) { - if (radius == 0) { - compileLocationQuery( - where, - loc.getBlockX(), loc.getBlockX(), - loc.getBlockY(), loc.getBlockY(), - loc.getBlockZ(), loc.getBlockZ() - ); - } else if (radius > 0) { - compileLocationQuery( - where, - loc.getBlockX() - radius + 1, loc.getBlockX() + radius - 1, - loc.getBlockY() - radius + 1, loc.getBlockY() + radius - 1, - loc.getBlockZ() - radius + 1, loc.getBlockZ() + radius - 1 - ); - } - - } else if (sel != null) { - compileLocationQuery( - where, - sel.getMinimumPoint().getBlockX(), sel.getMaximumPoint().getBlockX(), - sel.getMinimumPoint().getBlockY(), sel.getMaximumPoint().getBlockY(), - sel.getMinimumPoint().getBlockZ(), sel.getMaximumPoint().getBlockZ() - ); - } + } else if (blockChangeType == BlockChangeType.ENTITIES) { } else { switch (blockChangeType) { @@ -546,6 +538,8 @@ public String getWhere(BlockChangeType blockChangeType) { default: break; } + } + if(blockChangeType != BlockChangeType.CHAT) { if (loc != null) { if (radius == 0) { compileLocationQuery( @@ -571,7 +565,6 @@ public String getWhere(BlockChangeType blockChangeType) { sel.getMinimumPoint().getBlockZ(), sel.getMaximumPoint().getBlockZ() ); } - } if (!players.isEmpty() && sum != SummarizationMode.PLAYERS && blockChangeType != BlockChangeType.KILLS) { if (!excludePlayersMode) { @@ -802,7 +795,7 @@ public void parseArgs(CommandSender sender, List args, boolean validate) bct = BlockChangeType.CHAT; } else if (param.equals("kills")) { bct = BlockChangeType.KILLS; - } else if (param.equals("entities")) { + } else if (param.equals("entities") || param.equals("entity")) { bct = BlockChangeType.ENTITIES; } else if (param.equals("all")) { bct = BlockChangeType.ALL; @@ -893,6 +886,11 @@ public void validate() { throw new IllegalArgumentException("Invalid summarization for chat"); } } + if(bct == BlockChangeType.ENTITIES) { + if (sum != SummarizationMode.NONE) { + throw new IllegalStateException("Summarization not implemented yet"); + } + } } public void setLocation(Location loc) { From 868c56ef6ab5590db43a88e9535328acb9836124 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 8 Nov 2018 15:54:59 +0100 Subject: [PATCH 147/399] Allow other edits than block edits --- .../java/de/diddiz/LogBlock/CommandsHandler.java | 4 ++-- src/main/java/de/diddiz/LogBlock/WorldEditor.java | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index ed1a6b29..ee22647b 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -697,7 +697,7 @@ public void run() { if (stack != null) { chestaccess = new ChestAccess(stack, rs.getBoolean("itemremove"), rs.getInt("itemtype")); } - editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), chestaccess); + editor.queueBlockEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), chestaccess); } final int changes = editor.getSize(); if (changes > 10000) { @@ -787,7 +787,7 @@ public void run() { if (stack != null) { chestaccess = new ChestAccess(stack, !rs.getBoolean("itemremove"), rs.getInt("itemtype")); } - editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), chestaccess); + editor.queueBlockEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), chestaccess); } final int changes = editor.getSize(); if (!params.silent) { diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index d5c1f163..0cf16013 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -83,8 +83,8 @@ public void setSender(CommandSender sender) { this.sender = sender; } - public void queueEdit(int x, int y, int z, int replaced, int replaceData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess item) { - edits.add(new Edit(0, new Location(world, x, y, z), null, replaced, replaceData, replacedState, type, typeData, typeState, item)); + public void queueBlockEdit(int x, int y, int z, int replaced, int replaceData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess item) { + edits.add(new BlockEdit(0, new Location(world, x, y, z), null, replaced, replaceData, replacedState, type, typeData, typeState, item)); } public long getElapsedTime() { @@ -159,12 +159,16 @@ private static enum PerformResult { SUCCESS, BLACKLISTED, NO_ACTION } - private class Edit extends BlockChange { - public Edit(long time, Location loc, Actor actor, int replaced, int replaceData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { + private interface Edit { + PerformResult perform() throws WorldEditorException; + } + + private class BlockEdit extends BlockChange implements Edit { + public BlockEdit(long time, Location loc, Actor actor, int replaced, int replaceData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { super(time, loc, actor, replaced, replaceData,replacedState , type, typeData, typeState, ca); } - PerformResult perform() throws WorldEditorException { + public PerformResult perform() throws WorldEditorException { BlockData replacedBlock = getBlockReplaced(); BlockData setBlock = getBlockSet(); if (replacedBlock == null || setBlock == null) { From 3a2c1d8d6fb6192e74623dcfb0e5bc27e08fbdd8 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 8 Nov 2018 19:13:13 +0100 Subject: [PATCH 148/399] Rollback of killed entities works! --- .../de/diddiz/LogBlock/CommandsHandler.java | 17 ++---- .../java/de/diddiz/LogBlock/WorldEditor.java | 46 ++++++++++++++-- .../diddiz/worldedit/AdvancedKillLogging.java | 4 +- .../de/diddiz/worldedit/WorldEditHelper.java | 53 ++++++++++++++++++- 4 files changed, 101 insertions(+), 19 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index ee22647b..9bdf4094 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -690,14 +690,9 @@ public void run() { } rs = executeQuery(state, params.getQuery()); final WorldEditor editor = new WorldEditor(logblock, params.world, params.forceReplace); - + WorldEditorEditFactory editFactory = new WorldEditorEditFactory(editor, params, true); while (rs.next()) { - ChestAccess chestaccess = null; - ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); - if (stack != null) { - chestaccess = new ChestAccess(stack, rs.getBoolean("itemremove"), rs.getInt("itemtype")); - } - editor.queueBlockEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), chestaccess); + editFactory.processRow(rs); } final int changes = editor.getSize(); if (changes > 10000) { @@ -781,13 +776,9 @@ public void run() { sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); } final WorldEditor editor = new WorldEditor(logblock, params.world, params.forceReplace); + WorldEditorEditFactory editFactory = new WorldEditorEditFactory(editor, params, false); while (rs.next()) { - ChestAccess chestaccess = null; - ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); - if (stack != null) { - chestaccess = new ChestAccess(stack, !rs.getBoolean("itemremove"), rs.getInt("itemtype")); - } - editor.queueBlockEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), chestaccess); + editFactory.processRow(rs); } final int changes = editor.getSize(); if (!params.silent) { diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 0cf16013..16f5c895 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -18,14 +18,19 @@ import org.bukkit.block.data.type.PistonHead; import org.bukkit.block.data.type.TechnicalPiston.Type; import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Entity; import org.bukkit.inventory.ItemStack; import de.diddiz.LogBlock.blockstate.BlockStateCodecs; import de.diddiz.util.BukkitUtils; import de.diddiz.util.Utils; +import de.diddiz.worldedit.WorldEditHelper; import java.io.File; import java.io.PrintWriter; +import java.sql.ResultSet; +import java.sql.SQLException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; @@ -87,6 +92,10 @@ public void queueBlockEdit(int x, int y, int z, int replaced, int replaceData, b edits.add(new BlockEdit(0, new Location(world, x, y, z), null, replaced, replaceData, replacedState, type, typeData, typeState, item)); } + public void queueEntityEdit(ResultSet rs, QueryParams p, boolean rollback) throws SQLException { + edits.add(new EntityEdit(rs, p, rollback)); + } + public long getElapsedTime() { return elapsedTime; } @@ -155,15 +164,46 @@ public synchronized void run() { } } - private static enum PerformResult { + public static enum PerformResult { SUCCESS, BLACKLISTED, NO_ACTION } - private interface Edit { + public interface Edit { PerformResult perform() throws WorldEditorException; } - private class BlockEdit extends BlockChange implements Edit { + public class EntityEdit extends EntityChange implements Edit { + private boolean rollback; + + public EntityEdit(ResultSet rs, QueryParams p, boolean rollback) throws SQLException { + super(rs, p); + this.rollback = rollback; + } + + @Override + public PerformResult perform() throws WorldEditorException { + if (changeType == EntityChangeType.KILL && rollback) { + YamlConfiguration deserialized = Utils.deserializeYamlConfiguration(data); + double x = deserialized.getDouble("x"); + double y = deserialized.getDouble("y"); + double z = deserialized.getDouble("z"); + float yaw = (float) deserialized.getDouble("yaw"); + float pitch = (float) deserialized.getDouble("pitch"); + Location location = new Location(world, x, y, z, yaw, pitch); + byte[] serializedWorldEditEntity = (byte[]) deserialized.get("worldedit"); + if (serializedWorldEditEntity != null) { + Entity result = WorldEditHelper.restoreEntity(location, type, serializedWorldEditEntity); + if (result == null) { + throw new WorldEditorException("Could not restore " + type, location); + } + return PerformResult.SUCCESS; + } + } + return PerformResult.NO_ACTION; + } + } + + public class BlockEdit extends BlockChange implements Edit { public BlockEdit(long time, Location loc, Actor actor, int replaced, int replaceData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { super(time, loc, actor, replaced, replaceData,replacedState , type, typeData, typeState, ca); } diff --git a/src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java b/src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java index 2c851221..5cbd20fa 100644 --- a/src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java +++ b/src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java @@ -38,8 +38,8 @@ public void onEntityDeath(EntityDeathEvent event) { Location location = entity.getLocation(); YamlConfiguration data = new YamlConfiguration(); data.set("x", location.getX()); - data.set("y", location.getX()); - data.set("z", location.getX()); + data.set("y", location.getY()); + data.set("z", location.getZ()); data.set("yaw", location.getYaw()); data.set("pitch", location.getPitch()); diff --git a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java b/src/main/java/de/diddiz/worldedit/WorldEditHelper.java index 08441b3b..5bfcd33f 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditHelper.java @@ -1,13 +1,27 @@ package de.diddiz.worldedit; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.UUID; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.plugin.Plugin; +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.bukkit.BukkitAdapter; import com.sk89q.worldedit.entity.BaseEntity; @@ -32,6 +46,10 @@ public static byte[] serializeEntity(Entity entity) { return Internal.serializeEntity(entity); } + public static Entity restoreEntity(Location location, EntityType type, byte[] serialized) { + return Internal.restoreEntity(location, type, serialized); + } + private static class Internal { // private static WorldEditPlugin worldEdit; @@ -39,6 +57,33 @@ public static void setWorldEdit(Plugin worldEdit) { // Internal.worldEdit = (WorldEditPlugin) worldEdit; } + public static Entity restoreEntity(Location location, EntityType type, byte[] serialized) { + com.sk89q.worldedit.world.entity.EntityType weType = BukkitAdapter.adapt(type); + com.sk89q.worldedit.util.Location weLocation = BukkitAdapter.adapt(location); + try { + NBTInputStream nbtis = new NBTInputStream(new ByteArrayInputStream(serialized)); + NamedTag namedTag = nbtis.readNamedTag(); + nbtis.close(); + UUID newUUID = null; + if (namedTag.getName().equals("entity") && namedTag.getTag() instanceof CompoundTag) { + CompoundTag serializedState = (CompoundTag) namedTag.getTag(); + BaseEntity state = new BaseEntity(weType, serializedState); + CompoundTag oldNbt = state.getNbtData(); + UUID oldUUID = new UUID(oldNbt.getLong("UUIDMost"), oldNbt.getLong("UUIDLeast")); + com.sk89q.worldedit.entity.Entity weEntity = weLocation.getExtent().createEntity(weLocation, state); + if (weEntity != null) { + CompoundTag newNbt = weEntity.getState().getNbtData(); + newUUID = new UUID(newNbt.getLong("UUIDMost"), newNbt.getLong("UUIDLeast")); + System.out.println("Old UUID: " + oldUUID); + System.out.println("New UUID: " + newUUID); + } + } + return newUUID == null ? null : Bukkit.getEntity(newUUID); + } catch (IOException e) { + throw new RuntimeException("This IOException should be impossible", e); + } + } + public static byte[] serializeEntity(Entity entity) { com.sk89q.worldedit.entity.Entity weEntity = BukkitAdapter.adapt(entity); BaseEntity state = weEntity.getState(); @@ -46,7 +91,13 @@ public static byte[] serializeEntity(Entity entity) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); NBTOutputStream nbtos = new NBTOutputStream(baos); - nbtos.writeNamedTag("entity", state.getNbtData()); + CompoundTag nbt = state.getNbtData(); + LinkedHashMap 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) { From 9d1baee2e26ed691230af73fcc2a3569bbb7b6d7 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 9 Nov 2018 00:40:36 +0100 Subject: [PATCH 149/399] Improve entity logging/rollbacks - Allow UUID changes on respawn - Log Spawn - Implement rollback and redo for entities --- .../java/de/diddiz/LogBlock/Consumer.java | 56 +++++++++++++++++-- .../java/de/diddiz/LogBlock/EntityChange.java | 9 ++- .../java/de/diddiz/LogBlock/QueryParams.java | 2 +- .../java/de/diddiz/LogBlock/WorldEditor.java | 44 +++++++++++++-- .../LogBlock/WorldEditorEditFactory.java | 38 +++++++++++++ .../diddiz/LogBlock/config/WorldConfig.java | 2 + src/main/java/de/diddiz/util/Utils.java | 28 ++++++++++ .../diddiz/worldedit/AdvancedKillLogging.java | 36 ++++++++++-- .../de/diddiz/worldedit/WorldEditHelper.java | 4 -- 9 files changed, 198 insertions(+), 21 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index d96daa12..c5e40f04 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -753,6 +753,18 @@ public void queueEntityModification(Actor actor, UUID entityId, EntityType entit addQueueLast(new EntityRow(loc, actor, entityType, entityId, changeType, Utils.serializeYamlConfiguration(data))); } + /** + * Change the UUID that is stored for an entity in the database. This is needed when an entity is respawned + * and now has a different UUID. + * + * @param world the world that contains the entity + * @param entityId the database id of the entity + * @param entityUUID the new UUID of the entity + */ + public void queueEntityUUIDChange(World world, int entityId, UUID entityUUID) { + addQueueLast(new EntityUUIDChange(world, entityId, entityUUID)); + } + private String playerID(Actor actor) { if (actor == null) { return "NULL"; @@ -1037,9 +1049,9 @@ public String[] getInserts() { final String table = getWorldConfig(loc.getWorld()).table; final String[] inserts = new String[2]; - inserts[0] = "INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) SELECT '" + mysqlTextEscape(entityid.toString()) + "' FROM `" + table + "-entityids` WHERE NOT EXISTS (SELECT NULL FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(entityid.toString()) + "') LIMIT 1"; + inserts[0] = "INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) SELECT '" + mysqlTextEscape(entityUUID.toString()) + "' FROM `" + table + "-entityids` WHERE NOT EXISTS (SELECT NULL FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(entityUUID.toString()) + "') LIMIT 1"; int entityTypeId = EntityTypeConverter.getOrAddEntityTypeId(type); - inserts[1] = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(actor) + ", " + "(SELECT entityid FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(entityid.toString()) + "')" + inserts[1] = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(actor) + ", " + "(SELECT entityid FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(entityUUID.toString()) + "')" + ", " + entityTypeId + ", '" + loc.getBlockX() + "', " + safeY(loc) + ", '" + loc.getBlockZ() + "', " + changeType.ordinal() + ", " + Utils.mysqlPrepareBytesForInsertAllowNull(data) + ");"; return inserts; } @@ -1069,10 +1081,10 @@ public void process(Connection conn, BatchHelper batchHelper) throws SQLExceptio rs.close(); } } - PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.RETURN_GENERATED_KEYS); + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); smt.setLong(1, date); smt.setInt(2, sourceActor); - smt.setInt(3, getEntityUUID(conn, loc.getWorld(), entityid)); + smt.setInt(3, getEntityUUID(conn, loc.getWorld(), entityUUID)); smt.setInt(4, EntityTypeConverter.getOrAddEntityTypeId(type)); smt.setInt(5, loc.getBlockX()); smt.setInt(6, safeY(loc)); @@ -1083,6 +1095,42 @@ public void process(Connection conn, BatchHelper batchHelper) throws SQLExceptio } } + private class EntityUUIDChange implements Row { + private final World world; + private final int entityId; + private final UUID entityUUID; + final String updateEntityUUIDString; + + public EntityUUIDChange(World world, int entityId, UUID entityUUID) { + this.world = world; + this.entityId = entityId; + this.entityUUID = entityUUID; + updateEntityUUIDString = getWorldConfig(world).updateEntityUUIDString; + } + + @Override + public String[] getInserts() { + final String table = getWorldConfig(world).table; + final String[] inserts = new String[1]; + + inserts[0] = "UPDATE `" + table + "-entityids` SET entityuuid = '" + mysqlTextEscape(entityUUID.toString()) + "' WHERE entityid = " + entityId; + return inserts; + } + + @Override + public Actor[] getActors() { + return new Actor[0]; + } + + @Override + public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, updateEntityUUIDString, Statement.NO_GENERATED_KEYS); + smt.setString(1, entityUUID.toString()); + smt.setInt(2, entityId); + smt.executeUpdate(); + } + } + private int safeY(Location loc) { int safeY = loc.getBlockY(); if (safeY < 0) diff --git a/src/main/java/de/diddiz/LogBlock/EntityChange.java b/src/main/java/de/diddiz/LogBlock/EntityChange.java index 35cf6c38..2230789a 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityChange.java +++ b/src/main/java/de/diddiz/LogBlock/EntityChange.java @@ -30,7 +30,8 @@ public static EntityChangeType valueOf(int ordinal) { public final Location loc; public final Actor actor; public final EntityType type; - public final UUID entityid; + public final int entityId; + public final UUID entityUUID; public final EntityChangeType changeType; public final byte[] data; @@ -40,7 +41,8 @@ public EntityChange(long date, Location loc, Actor actor, EntityType type, UUID this.loc = loc; this.actor = actor; this.type = type; - this.entityid = entityid; + this.entityId = -1; + this.entityUUID = entityid; this.changeType = changeType; this.data = data; } @@ -51,7 +53,8 @@ public EntityChange(ResultSet rs, QueryParams p) throws SQLException { loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null; actor = p.needPlayer ? new Actor(rs) : null; type = p.needType ? EntityTypeConverter.getEntityType(rs.getInt("entitytypeid")) : null; - entityid = p.needData ? UUID.fromString(rs.getString("entityuuid")) : null; + entityId = p.needData ? rs.getInt("entityid") : 0; + entityUUID = p.needData ? UUID.fromString(rs.getString("entityuuid")) : null; changeType = p.needType ? EntityChangeType.valueOf(rs.getInt("action")) : null; data = p.needData ? rs.getBytes("data") : null; } diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 94b87a7c..afceadd1 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -270,7 +270,7 @@ public String getFields() { select += "entitytypeid, action, "; } if(needData) { - select += "entityuuid, data, "; + select += "entityid, entityuuid, data, "; } } select = select.substring(0, select.length() - 2) + " "; diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 16f5c895..d03c58f6 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -33,8 +33,10 @@ import java.sql.SQLException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Queue; +import java.util.UUID; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; @@ -56,6 +58,7 @@ public class WorldEditor implements Runnable { private long elapsedTime = 0; public LookupCacheElement[] errors; private boolean forceReplace; + private HashMap uuidReplacements = new HashMap<>(); public WorldEditor(LogBlock logblock, World world) { this(logblock, world, false); @@ -164,6 +167,11 @@ public synchronized void run() { } } + protected UUID getReplacedUUID(int entityid, UUID unreplaced) { + UUID replaced = uuidReplacements.get(entityid); + return replaced != null ? replaced : unreplaced; + } + public static enum PerformResult { SUCCESS, BLACKLISTED, NO_ACTION } @@ -182,7 +190,10 @@ public EntityEdit(ResultSet rs, QueryParams p, boolean rollback) throws SQLExcep @Override public PerformResult perform() throws WorldEditorException { - if (changeType == EntityChangeType.KILL && rollback) { + if (changeType == (rollback ? EntityChangeType.KILL : EntityChangeType.CREATE)) { + // spawn entity + UUID uuid = getReplacedUUID(entityId, entityUUID); + Entity result = null; YamlConfiguration deserialized = Utils.deserializeYamlConfiguration(data); double x = deserialized.getDouble("x"); double y = deserialized.getDouble("y"); @@ -190,14 +201,39 @@ public PerformResult perform() throws WorldEditorException { float yaw = (float) deserialized.getDouble("yaw"); float pitch = (float) deserialized.getDouble("pitch"); Location location = new Location(world, x, y, z, yaw, pitch); + Entity existing = Utils.loadChunksForEntity(location.getChunk(), uuid); + if (existing != null) { + return PerformResult.NO_ACTION; + } byte[] serializedWorldEditEntity = (byte[]) deserialized.get("worldedit"); if (serializedWorldEditEntity != null) { - Entity result = WorldEditHelper.restoreEntity(location, type, serializedWorldEditEntity); - if (result == null) { - throw new WorldEditorException("Could not restore " + type, location); + result = WorldEditHelper.restoreEntity(location, type, serializedWorldEditEntity); + } + if (result == null) { + throw new WorldEditorException("Could not restore " + type, location); + } else { + if (!result.getUniqueId().equals(uuid)) { + logblock.getConsumer().queueEntityUUIDChange(world, entityId, result.getUniqueId()); + uuidReplacements.put(entityId, result.getUniqueId()); } + } + return PerformResult.SUCCESS; + } else if (changeType == (rollback ? EntityChangeType.CREATE : EntityChangeType.KILL)) { + // kill entity + UUID uuid = getReplacedUUID(entityId, entityUUID); + YamlConfiguration deserialized = Utils.deserializeYamlConfiguration(data); + double x = deserialized.getDouble("x"); + double y = deserialized.getDouble("y"); + double z = deserialized.getDouble("z"); + float yaw = (float) deserialized.getDouble("yaw"); + float pitch = (float) deserialized.getDouble("pitch"); + Location location = new Location(world, x, y, z, yaw, pitch); + Entity existing = Utils.loadChunksForEntity(location.getChunk(), uuid); + if (existing != null) { + existing.remove(); return PerformResult.SUCCESS; } + return PerformResult.NO_ACTION; // the entity is not there, so we cannot do anything } return PerformResult.NO_ACTION; } diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java b/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java new file mode 100644 index 00000000..e23dc6b6 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java @@ -0,0 +1,38 @@ +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.util.Utils; + +public class WorldEditorEditFactory { + private final WorldEditor editor; + private final boolean rollback; + private final QueryParams params; + + public WorldEditorEditFactory(WorldEditor editor, QueryParams params, boolean rollback) { + this.editor = editor; + this.params = params; + this.rollback = rollback; + } + + public void processRow(ResultSet rs) throws SQLException { + if (params.bct == BlockChangeType.ENTITIES) { + editor.queueEntityEdit(rs, params, rollback); + return; + } + ChestAccess chestaccess = null; + ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); + if (stack != null) { + chestaccess = new ChestAccess(stack, rs.getBoolean("itemremove") == rollback, rs.getInt("itemtype")); + } + if (rollback) { + editor.queueBlockEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), chestaccess); + } else { + editor.queueBlockEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), chestaccess); + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index 8b647d35..b8542b96 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -17,6 +17,7 @@ public class WorldConfig extends LoggingEnabledMapping { public final String insertBlockStateStatementString; public final String insertBlockChestDataStatementString; public final String insertEntityStatementString; + public final String updateEntityUUIDString; public WorldConfig(String world, File file) throws IOException { this.world = world; @@ -44,5 +45,6 @@ public WorldConfig(String world, File file) throws IOException { insertBlockStateStatementString = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(?, ?, ?)"; insertBlockChestDataStatementString = "INSERT INTO `" + table + "-chestdata` (item, itemremove, id, itemtype) values (?, ?, ?, ?)"; insertEntityStatementString = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"; + updateEntityUUIDString = "UPDATE `" + table + "-entityids` SET entityuuid = ? WHERE entityid = ?"; } } diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index c4ea0f90..ee16bc45 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -11,14 +11,18 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import java.util.zip.ZipException; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Entity; import org.bukkit.inventory.ItemStack; import de.diddiz.LogBlock.LogBlock; @@ -284,4 +288,28 @@ public static byte[] serializeYamlConfiguration(YamlConfiguration conf) { public static String serializeForSQL(YamlConfiguration conf) { return mysqlPrepareBytesForInsertAllowNull(serializeYamlConfiguration(conf)); } + + public static Entity loadChunksForEntity(Chunk chunk, UUID uuid) { + Entity e = Bukkit.getEntity(uuid); + if (e != null) { + return e; + } + chunk.load(); + e = Bukkit.getEntity(uuid); + if (e != null) { + return e; + } + int chunkx = chunk.getX(); + int chunkz = chunk.getZ(); + for (int i = 0; i < 8; i++) { + int x = i < 3 ? chunkx - 1 : (i < 5 ? chunkx : chunkx + 1); + int z = i == 0 || i == 3 || i == 5 ? chunkz - 1 : (i == 1 || i == 6 ? chunkz : chunkz + 1); + chunk.getWorld().loadChunk(x, z); + e = Bukkit.getEntity(uuid); + if (e != null) { + return e; + } + } + return null; + } } diff --git a/src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java b/src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java index 5cbd20fa..ed2a94aa 100644 --- a/src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java +++ b/src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java @@ -7,9 +7,12 @@ import org.bukkit.entity.Villager; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntitySpawnEvent; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.EntityChange; @@ -28,12 +31,12 @@ public void onEntityDeath(EntityDeathEvent event) { if (!(entity instanceof Animals) && !(entity instanceof Villager)) { return; } - Actor killer; + Actor actor; EntityDamageEvent lastDamage = entity.getLastDamageCause(); if (lastDamage instanceof EntityDamageByEntityEvent) { - killer = Actor.actorFromEntity(((EntityDamageByEntityEvent) lastDamage).getDamager()); + actor = Actor.actorFromEntity(((EntityDamageByEntityEvent) lastDamage).getDamager()); } else { - killer = new Actor(lastDamage.getCause().toString()); + actor = new Actor(lastDamage.getCause().toString()); } Location location = entity.getLocation(); YamlConfiguration data = new YamlConfiguration(); @@ -44,7 +47,30 @@ public void onEntityDeath(EntityDeathEvent event) { data.set("pitch", location.getPitch()); data.set("worldedit", WorldEditHelper.serializeEntity(entity)); - - consumer.queueEntityModification(killer, entity.getUniqueId(), entity.getType(), location, EntityChange.EntityChangeType.KILL, data); + + consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), location, EntityChange.EntityChangeType.KILL, data); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onEntitySpawn(CreatureSpawnEvent event) { + if (event.getSpawnReason() == SpawnReason.CUSTOM) { + return; + } + LivingEntity entity = event.getEntity(); + if (!(entity instanceof Animals) && !(entity instanceof Villager)) { + return; + } + Actor actor = new Actor(event.getSpawnReason().toString()); + Location location = entity.getLocation(); + YamlConfiguration data = new YamlConfiguration(); + data.set("x", location.getX()); + data.set("y", location.getY()); + data.set("z", location.getZ()); + data.set("yaw", location.getYaw()); + data.set("pitch", location.getPitch()); + + data.set("worldedit", WorldEditHelper.serializeEntity(entity)); + + consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), location, EntityChange.EntityChangeType.CREATE, data); } } diff --git a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java b/src/main/java/de/diddiz/worldedit/WorldEditHelper.java index 5bfcd33f..69285fdf 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditHelper.java @@ -68,14 +68,10 @@ public static Entity restoreEntity(Location location, EntityType type, byte[] se if (namedTag.getName().equals("entity") && namedTag.getTag() instanceof CompoundTag) { CompoundTag serializedState = (CompoundTag) namedTag.getTag(); BaseEntity state = new BaseEntity(weType, serializedState); - CompoundTag oldNbt = state.getNbtData(); - UUID oldUUID = new UUID(oldNbt.getLong("UUIDMost"), oldNbt.getLong("UUIDLeast")); com.sk89q.worldedit.entity.Entity weEntity = weLocation.getExtent().createEntity(weLocation, state); if (weEntity != null) { CompoundTag newNbt = weEntity.getState().getNbtData(); newUUID = new UUID(newNbt.getLong("UUIDMost"), newNbt.getLong("UUIDLeast")); - System.out.println("Old UUID: " + oldUUID); - System.out.println("New UUID: " + newUUID); } } return newUUID == null ? null : Bukkit.getEntity(newUUID); From ea16656fcb732c5b86ff992e0ed76627324a83d9 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 9 Nov 2018 02:37:48 +0100 Subject: [PATCH 150/399] Log armor stands, item frames and paintings --- .../java/de/diddiz/LogBlock/LogBlock.java | 3 +- .../listeners/AdvancedEntityLogging.java | 162 ++++++++++++++++++ src/main/java/de/diddiz/util/Utils.java | 20 ++- .../diddiz/worldedit/AdvancedKillLogging.java | 76 -------- 4 files changed, 175 insertions(+), 86 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java delete mode 100644 src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 65bf474a..5c8f1052 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -5,7 +5,6 @@ import de.diddiz.LogBlock.questioner.Questioner; import de.diddiz.util.BukkitUtils; import de.diddiz.util.MySQLConnectionPool; -import de.diddiz.worldedit.AdvancedKillLogging; import de.diddiz.worldedit.WorldEditHelper; import de.diddiz.worldedit.WorldEditLoggingHook; import org.bukkit.ChatColor; @@ -189,7 +188,7 @@ private void registerEvents() { if (isLogging(Logging.DRAGONEGGTELEPORT)) { pm.registerEvents(new DragonEggLogging(this), this); } - pm.registerEvents(new AdvancedKillLogging(this), this); + pm.registerEvents(new AdvancedEntityLogging(this), this); } @Override diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java new file mode 100644 index 00000000..1517320d --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -0,0 +1,162 @@ +package de.diddiz.LogBlock.listeners; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Animals; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Golem; +import org.bukkit.entity.Hanging; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.hanging.HangingBreakByEntityEvent; +import org.bukkit.event.hanging.HangingBreakEvent; +import org.bukkit.event.hanging.HangingPlaceEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.EntityChange; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.worldedit.WorldEditHelper; + +public class AdvancedEntityLogging extends LoggingListener { + + private Player lastSpawner; + private Class lastSpawning; + private boolean lastSpawnerEgg; + + public AdvancedEntityLogging(LogBlock lb) { + super(lb); + new BukkitRunnable() { + @Override + public void run() { + resetLastSpawner(); + } + }.runTaskTimer(lb, 1, 1); + } + + private void resetLastSpawner() { + lastSpawner = null; + lastSpawning = null; + lastSpawnerEgg = false; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onEntityDeath(EntityDeathEvent event) { + LivingEntity entity = event.getEntity(); + if (!(entity instanceof Animals) && !(entity instanceof Villager) && !(entity instanceof Golem) && !(entity instanceof ArmorStand)) { + return; + } + Actor actor; + EntityDamageEvent lastDamage = entity.getLastDamageCause(); + if (lastDamage instanceof EntityDamageByEntityEvent) { + actor = Actor.actorFromEntity(((EntityDamageByEntityEvent) lastDamage).getDamager()); + } else { + actor = new Actor(lastDamage.getCause().toString()); + } + queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerInteract(PlayerInteractEvent event) { + if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { + ItemStack inHand = event.getItem(); + if (inHand != null) { + Material mat = inHand.getType(); + if (mat == Material.ARMOR_STAND) { + lastSpawner = event.getPlayer(); + lastSpawning = ArmorStand.class; + lastSpawnerEgg = false; + } else if (mat.name().endsWith("_SPAWN_EGG")) { + lastSpawner = event.getPlayer(); + lastSpawning = null; + lastSpawnerEgg = true; + } + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { + ItemStack inHand = event.getHand() == EquipmentSlot.HAND ? event.getPlayer().getInventory().getItemInMainHand() : event.getPlayer().getInventory().getItemInOffHand(); + if (inHand != null) { + Material mat = inHand.getType(); + if (mat.name().endsWith("_SPAWN_EGG")) { + lastSpawner = event.getPlayer(); + lastSpawning = null; + lastSpawnerEgg = true; + } + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onEntitySpawn(CreatureSpawnEvent event) { + if (!event.isCancelled()) { + if (event.getSpawnReason() == SpawnReason.CUSTOM) { + return; + } + LivingEntity entity = event.getEntity(); + if (!(entity instanceof Animals) && !(entity instanceof Villager) && !(entity instanceof Golem) && !(entity instanceof ArmorStand)) { + return; + } + Actor actor = null; + if (lastSpawner != null) { + if (lastSpawnerEgg && event.getSpawnReason() == SpawnReason.SPAWNER_EGG) { + actor = Actor.actorFromEntity(lastSpawner); + } else if (lastSpawning != null && lastSpawning.isAssignableFrom(entity.getClass())) { + actor = Actor.actorFromEntity(lastSpawner); + } + } + if (actor == null) { + actor = new Actor(event.getSpawnReason().toString()); + } + queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE); + } + resetLastSpawner(); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onHangingBreak(HangingBreakEvent event) { + Entity entity = event.getEntity(); + Actor actor; + if (event instanceof HangingBreakByEntityEvent) { + actor = Actor.actorFromEntity(((HangingBreakByEntityEvent) event).getRemover()); + } else { + actor = new Actor(event.getCause().toString()); + } + queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onHangingPlace(HangingPlaceEvent event) { + Hanging entity = event.getEntity(); + Actor actor = Actor.actorFromEntity(event.getPlayer()); + queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE); + } + + protected void queueEntitySpawnOrKill(Entity entity, Actor actor, EntityChange.EntityChangeType changeType) { + Location location = entity.getLocation(); + YamlConfiguration data = new YamlConfiguration(); + data.set("x", location.getX()); + data.set("y", location.getY()); + data.set("z", location.getZ()); + data.set("yaw", location.getYaw()); + data.set("pitch", location.getPitch()); + data.set("worldedit", WorldEditHelper.serializeEntity(entity)); + consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), location, changeType, data); + } +} diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index ee16bc45..baf03797 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -294,20 +294,24 @@ public static Entity loadChunksForEntity(Chunk chunk, UUID uuid) { if (e != null) { return e; } - chunk.load(); - e = Bukkit.getEntity(uuid); - if (e != null) { - return e; + if (!chunk.isLoaded()) { + chunk.load(); + e = Bukkit.getEntity(uuid); + if (e != null) { + return e; + } } int chunkx = chunk.getX(); int chunkz = chunk.getZ(); for (int i = 0; i < 8; i++) { int x = i < 3 ? chunkx - 1 : (i < 5 ? chunkx : chunkx + 1); int z = i == 0 || i == 3 || i == 5 ? chunkz - 1 : (i == 1 || i == 6 ? chunkz : chunkz + 1); - chunk.getWorld().loadChunk(x, z); - e = Bukkit.getEntity(uuid); - if (e != null) { - return e; + if (!chunk.getWorld().isChunkLoaded(x, z)) { + chunk.getWorld().loadChunk(x, z); + e = Bukkit.getEntity(uuid); + if (e != null) { + return e; + } } } return null; diff --git a/src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java b/src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java deleted file mode 100644 index ed2a94aa..00000000 --- a/src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java +++ /dev/null @@ -1,76 +0,0 @@ -package de.diddiz.worldedit; - -import org.bukkit.Location; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Animals; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Villager; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.entity.EntityDeathEvent; -import org.bukkit.event.entity.EntitySpawnEvent; -import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; - -import de.diddiz.LogBlock.Actor; -import de.diddiz.LogBlock.EntityChange; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.listeners.LoggingListener; - -public class AdvancedKillLogging extends LoggingListener { - - public AdvancedKillLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onEntityDeath(EntityDeathEvent event) { - LivingEntity entity = event.getEntity(); - if (!(entity instanceof Animals) && !(entity instanceof Villager)) { - return; - } - Actor actor; - EntityDamageEvent lastDamage = entity.getLastDamageCause(); - if (lastDamage instanceof EntityDamageByEntityEvent) { - actor = Actor.actorFromEntity(((EntityDamageByEntityEvent) lastDamage).getDamager()); - } else { - actor = new Actor(lastDamage.getCause().toString()); - } - Location location = entity.getLocation(); - YamlConfiguration data = new YamlConfiguration(); - data.set("x", location.getX()); - data.set("y", location.getY()); - data.set("z", location.getZ()); - data.set("yaw", location.getYaw()); - data.set("pitch", location.getPitch()); - - data.set("worldedit", WorldEditHelper.serializeEntity(entity)); - - consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), location, EntityChange.EntityChangeType.KILL, data); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onEntitySpawn(CreatureSpawnEvent event) { - if (event.getSpawnReason() == SpawnReason.CUSTOM) { - return; - } - LivingEntity entity = event.getEntity(); - if (!(entity instanceof Animals) && !(entity instanceof Villager)) { - return; - } - Actor actor = new Actor(event.getSpawnReason().toString()); - Location location = entity.getLocation(); - YamlConfiguration data = new YamlConfiguration(); - data.set("x", location.getX()); - data.set("y", location.getY()); - data.set("z", location.getZ()); - data.set("yaw", location.getYaw()); - data.set("pitch", location.getPitch()); - - data.set("worldedit", WorldEditHelper.serializeEntity(entity)); - - consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), location, EntityChange.EntityChangeType.CREATE, data); - } -} From 4e1a79ca0f25db77570dc49a47b01ba2b55afa0a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 9 Nov 2018 04:04:31 +0100 Subject: [PATCH 151/399] Configurable entity logging --- .../de/diddiz/LogBlock/EntityLogging.java | 28 +++++ .../de/diddiz/LogBlock/config/Config.java | 6 + .../diddiz/LogBlock/config/WorldConfig.java | 86 +++++++++++++ .../listeners/AdvancedEntityLogging.java | 115 +++++++++++------- src/main/java/de/diddiz/util/Utils.java | 22 ++++ 5 files changed, 210 insertions(+), 47 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/EntityLogging.java diff --git a/src/main/java/de/diddiz/LogBlock/EntityLogging.java b/src/main/java/de/diddiz/LogBlock/EntityLogging.java new file mode 100644 index 00000000..80c38785 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/EntityLogging.java @@ -0,0 +1,28 @@ +package de.diddiz.LogBlock; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.bukkit.entity.EntityType; + +public enum EntityLogging { + SPAWN(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.IRON_GOLEM.name(), EntityType.SNOWMAN.name() }), + DESTROY(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.VILLAGER.name(), EntityType.IRON_GOLEM.name(), EntityType.SNOWMAN.name(), "ANIMAL" }), + MODIFY(new String[] { "ALL" }); + + public static final int length = EntityLogging.values().length; + private final List defaultEnabled; + + private EntityLogging() { + this(null); + } + + private EntityLogging(String[] defaultEnabled) { + this.defaultEnabled = defaultEnabled == null ? Collections.emptyList() : Collections.unmodifiableList(Arrays.asList(defaultEnabled)); + } + + public List getDefaultEnabled() { + return defaultEnabled; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 708f2e22..0aecb970 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -6,6 +6,7 @@ import org.bukkit.Material; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Entity; import org.bukkit.permissions.PermissionDefault; import java.io.File; @@ -322,6 +323,11 @@ public static boolean isLogging(Logging l) { public static Collection getLoggedWorlds() { return worldConfigs.values(); } + + public static boolean isLogging(World world, EntityLogging logging, Entity entity) { + final WorldConfig wcfg = worldConfigs.get(world.getName()); + return wcfg != null && wcfg.isLogging(logging, entity); + } } class LoggingEnabledMapping { diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index b8542b96..50ba6aa0 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -1,13 +1,30 @@ package de.diddiz.LogBlock.config; +import de.diddiz.LogBlock.EntityLogging; +import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; +import de.diddiz.util.Utils; + import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Ambient; +import org.bukkit.entity.Animals; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Player; +import org.bukkit.entity.WaterMob; import java.io.File; import java.io.IOException; +import java.util.EnumMap; +import java.util.EnumSet; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.logging.Level; public class WorldConfig extends LoggingEnabledMapping { public final String world; @@ -19,6 +36,8 @@ public class WorldConfig extends LoggingEnabledMapping { public final String insertEntityStatementString; public final String updateEntityUUIDString; + private final EnumMap entityLogging = new EnumMap<>(EntityLogging.class); + public WorldConfig(String world, File file) throws IOException { this.world = world; final Map def = new HashMap(); @@ -34,6 +53,12 @@ public WorldConfig(String world, File file) throws IOException { config.set(e.getKey(), e.getValue()); } } + for (EntityLogging el : EntityLogging.values()) { + if (!(config.get("entity." + el.name().toLowerCase()) instanceof List)) { + config.set("entity." + el.name().toLowerCase(), el.getDefaultEnabled()); + } + entityLogging.put(el, new EntitiyLoggingList(config.getStringList("entity." + el.name().toLowerCase()))); + } config.save(file); table = config.getString("table"); for (final Logging l : Logging.values()) { @@ -47,4 +72,65 @@ public WorldConfig(String world, File file) throws IOException { insertEntityStatementString = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"; updateEntityUUIDString = "UPDATE `" + table + "-entityids` SET entityuuid = ? WHERE entityid = ?"; } + + public boolean isLogging(EntityLogging logging, Entity entity) { + return entityLogging.get(logging).isLogging(entity); + } + + private class EntitiyLoggingList { + private final EnumSet logged = EnumSet.noneOf(EntityType.class); + private final boolean logAll; + private final boolean logAnimals; + private final boolean logMonsters; + private final boolean logLiving; + + public EntitiyLoggingList(List types) { + boolean all = false; + boolean animals = false; + boolean monsters = false; + boolean living = false; + for (String type : types) { + EntityType et = Utils.matchEntityType(type); + if (et != null) { + logged.add(et); + } else { + if (type.equalsIgnoreCase("all")) { + all = true; + } else if (type.equalsIgnoreCase("animal") || type.equalsIgnoreCase("animals")) { + animals = true; + } else if (type.equalsIgnoreCase("monster") || type.equalsIgnoreCase("monsters")) { + monsters = true; + } else if (type.equalsIgnoreCase("living")) { + living = true; + } else { + LogBlock.getInstance().getLogger().log(Level.WARNING, "Unkown entity type in config for " + world + ": " + type); + } + } + } + logAll = all; + logAnimals = animals; + logMonsters = monsters; + logLiving = living; + } + + public boolean isLogging(Entity entity) { + if (entity == null || (entity instanceof Player)) { + return false; + } + EntityType type = entity.getType(); + if (logAll || logged.contains(type)) { + return true; + } + if (logLiving && LivingEntity.class.isAssignableFrom(entity.getClass()) && !(entity instanceof ArmorStand)) { + return true; + } + if (logAnimals && (Animals.class.isAssignableFrom(entity.getClass()) || WaterMob.class.isAssignableFrom(entity.getClass()) || Ambient.class.isAssignableFrom(entity.getClass()))) { + return true; + } + if (logMonsters && (Monster.class.isAssignableFrom(entity.getClass()) || entity.getType() == EntityType.SLIME || entity.getType() == EntityType.WITHER || entity.getType() == EntityType.ENDER_DRAGON || entity.getType() == EntityType.SHULKER || entity.getType() == EntityType.GHAST)) { + return true; + } + return false; + } + } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index 1517320d..35e575a9 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -2,18 +2,20 @@ import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.BlockFace; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Animals; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; -import org.bukkit.entity.Golem; import org.bukkit.entity.Hanging; +import org.bukkit.entity.IronGolem; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; -import org.bukkit.entity.Villager; +import org.bukkit.entity.Snowman; +import org.bukkit.entity.Wither; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.event.entity.EntityDamageByEntityEvent; @@ -30,7 +32,9 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.EntityChange; +import de.diddiz.LogBlock.EntityLogging; import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.config.Config; import de.diddiz.worldedit.WorldEditHelper; public class AdvancedEntityLogging extends LoggingListener { @@ -55,20 +59,25 @@ private void resetLastSpawner() { lastSpawnerEgg = false; } + private void setLastSpawner(Player player, Class spawning, boolean spawnEgg) { + lastSpawner = player; + lastSpawning = spawning; + lastSpawnerEgg = spawnEgg; + } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onEntityDeath(EntityDeathEvent event) { - LivingEntity entity = event.getEntity(); - if (!(entity instanceof Animals) && !(entity instanceof Villager) && !(entity instanceof Golem) && !(entity instanceof ArmorStand)) { - return; - } - Actor actor; - EntityDamageEvent lastDamage = entity.getLastDamageCause(); - if (lastDamage instanceof EntityDamageByEntityEvent) { - actor = Actor.actorFromEntity(((EntityDamageByEntityEvent) lastDamage).getDamager()); - } else { - actor = new Actor(lastDamage.getCause().toString()); + public void onPlayerBlockPlace(BlockPlaceEvent event) { + Material placed = event.getBlock().getType(); + if (placed == Material.WITHER_SKELETON_SKULL) { + setLastSpawner(event.getPlayer(), Wither.class, false); + } else if (placed == Material.CARVED_PUMPKIN) { + Material below = event.getBlock().getRelative(BlockFace.DOWN).getType(); + if (below == Material.SNOW_BLOCK) { + setLastSpawner(event.getPlayer(), Snowman.class, false); + } else if (below == Material.IRON_BLOCK) { + setLastSpawner(event.getPlayer(), IronGolem.class, false); + } } - queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -78,13 +87,9 @@ public void onPlayerInteract(PlayerInteractEvent event) { if (inHand != null) { Material mat = inHand.getType(); if (mat == Material.ARMOR_STAND) { - lastSpawner = event.getPlayer(); - lastSpawning = ArmorStand.class; - lastSpawnerEgg = false; + setLastSpawner(event.getPlayer(), ArmorStand.class, false); } else if (mat.name().endsWith("_SPAWN_EGG")) { - lastSpawner = event.getPlayer(); - lastSpawning = null; - lastSpawnerEgg = true; + setLastSpawner(event.getPlayer(), null, true); } } } @@ -96,9 +101,7 @@ public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { if (inHand != null) { Material mat = inHand.getType(); if (mat.name().endsWith("_SPAWN_EGG")) { - lastSpawner = event.getPlayer(); - lastSpawning = null; - lastSpawnerEgg = true; + setLastSpawner(event.getPlayer(), null, true); } } } @@ -110,42 +113,60 @@ public void onEntitySpawn(CreatureSpawnEvent event) { return; } LivingEntity entity = event.getEntity(); - if (!(entity instanceof Animals) && !(entity instanceof Villager) && !(entity instanceof Golem) && !(entity instanceof ArmorStand)) { - return; - } - Actor actor = null; - if (lastSpawner != null) { - if (lastSpawnerEgg && event.getSpawnReason() == SpawnReason.SPAWNER_EGG) { - actor = Actor.actorFromEntity(lastSpawner); - } else if (lastSpawning != null && lastSpawning.isAssignableFrom(entity.getClass())) { - actor = Actor.actorFromEntity(lastSpawner); + if (Config.isLogging(entity.getWorld(), EntityLogging.SPAWN, entity)) { + Actor actor = null; + if (lastSpawner != null && lastSpawner.getWorld() == entity.getWorld() && lastSpawner.getLocation().distance(entity.getLocation()) < 10) { + if (lastSpawnerEgg && event.getSpawnReason() == SpawnReason.SPAWNER_EGG) { + actor = Actor.actorFromEntity(lastSpawner); + } else if (lastSpawning != null && lastSpawning.isAssignableFrom(entity.getClass())) { + actor = Actor.actorFromEntity(lastSpawner); + } } + if (actor == null) { + actor = new Actor(event.getSpawnReason().toString()); + } + queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE); } - if (actor == null) { - actor = new Actor(event.getSpawnReason().toString()); - } - queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE); } resetLastSpawner(); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onHangingBreak(HangingBreakEvent event) { - Entity entity = event.getEntity(); - Actor actor; - if (event instanceof HangingBreakByEntityEvent) { - actor = Actor.actorFromEntity(((HangingBreakByEntityEvent) event).getRemover()); - } else { - actor = new Actor(event.getCause().toString()); + public void onEntityDeath(EntityDeathEvent event) { + LivingEntity entity = event.getEntity(); + if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) { + Actor actor; + EntityDamageEvent lastDamage = entity.getLastDamageCause(); + if (lastDamage instanceof EntityDamageByEntityEvent) { + actor = Actor.actorFromEntity(((EntityDamageByEntityEvent) lastDamage).getDamager()); + } else { + actor = new Actor(lastDamage.getCause().toString()); + } + queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); } - queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onHangingPlace(HangingPlaceEvent event) { Hanging entity = event.getEntity(); - Actor actor = Actor.actorFromEntity(event.getPlayer()); - queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE); + if (Config.isLogging(entity.getWorld(), EntityLogging.SPAWN, entity)) { + Actor actor = Actor.actorFromEntity(event.getPlayer()); + queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onHangingBreak(HangingBreakEvent event) { + Entity entity = event.getEntity(); + if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) { + Actor actor; + if (event instanceof HangingBreakByEntityEvent) { + actor = Actor.actorFromEntity(((HangingBreakByEntityEvent) event).getRemover()); + } else { + actor = new Actor(event.getCause().toString()); + } + queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); + } } protected void queueEntitySpawnOrKill(Entity entity, Actor actor, EntityChange.EntityChangeType changeType) { diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index baf03797..60306ff6 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -10,6 +10,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.UUID; import java.util.regex.Matcher; @@ -23,6 +24,7 @@ import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import de.diddiz.LogBlock.LogBlock; @@ -316,4 +318,24 @@ public static Entity loadChunksForEntity(Chunk chunk, UUID uuid) { } return null; } + + private static final HashMap types = new HashMap<>(); + static { + for (EntityType t : EntityType.values()) { + types.put(t.name().toLowerCase(), t); + @SuppressWarnings("deprecation") + String typeName = t.getName(); + if (typeName != null) { + types.put(typeName.toLowerCase(), t); + } + Class ec = t.getEntityClass(); + if (ec != null) { + types.put(ec.getSimpleName().toLowerCase(), t); + } + } + } + + public static EntityType matchEntityType(String typeName) { + return types.get(typeName.toLowerCase()); + } } From a5ffa3b709da2a9f16714f90a3a70bc731d78cd3 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 9 Nov 2018 05:00:32 +0100 Subject: [PATCH 152/399] Log & rollback armor stand/item frame modifications --- .../java/de/diddiz/LogBlock/EntityChange.java | 19 ++++- .../java/de/diddiz/LogBlock/WorldEditor.java | 55 +++++++++++- .../diddiz/LogBlock/config/WorldConfig.java | 4 +- .../listeners/AdvancedEntityLogging.java | 67 ++++++++++++++- src/main/java/de/diddiz/util/BukkitUtils.java | 83 +++++++++++++++++++ src/main/java/de/diddiz/util/Utils.java | 54 ------------ 6 files changed, 221 insertions(+), 61 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/EntityChange.java b/src/main/java/de/diddiz/LogBlock/EntityChange.java index 2230789a..90c389b3 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityChange.java +++ b/src/main/java/de/diddiz/LogBlock/EntityChange.java @@ -5,11 +5,14 @@ import java.util.UUID; import org.bukkit.Location; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; +import org.bukkit.inventory.ItemStack; import de.diddiz.LogBlock.config.Config; +import de.diddiz.util.Utils; public class EntityChange implements LookupCacheElement { public static enum EntityChangeType { @@ -75,9 +78,21 @@ public String toString() { } else if (changeType == EntityChangeType.KILL) { msg.append(living ? "killed " : "destroyed "); } else if (changeType == EntityChangeType.ADDEQUIP) { - msg.append("added an item to "); + YamlConfiguration conf = Utils.deserializeYamlConfiguration(data); + ItemStack stack = conf == null ? null : conf.getItemStack("item"); + if (stack == null) { + msg.append("added an item to "); + } else { + msg.append("added " + stack.getType() + " to "); + } } else if (changeType == EntityChangeType.REMOVEEQUIP) { - msg.append("removed an item from "); + YamlConfiguration conf = Utils.deserializeYamlConfiguration(data); + ItemStack stack = conf == null ? null : conf.getItemStack("item"); + if (stack == null) { + msg.append("removed an item from "); + } else { + msg.append("removed " + stack.getType() + " from "); + } } else if (changeType == EntityChangeType.MODIFY) { msg.append("modified "); } diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index d03c58f6..c4f621b4 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -19,7 +19,10 @@ import org.bukkit.block.data.type.TechnicalPiston.Type; import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; +import org.bukkit.entity.ItemFrame; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import de.diddiz.LogBlock.blockstate.BlockStateCodecs; @@ -201,7 +204,7 @@ public PerformResult perform() throws WorldEditorException { float yaw = (float) deserialized.getDouble("yaw"); float pitch = (float) deserialized.getDouble("pitch"); Location location = new Location(world, x, y, z, yaw, pitch); - Entity existing = Utils.loadChunksForEntity(location.getChunk(), uuid); + Entity existing = BukkitUtils.loadEntityAround(location.getChunk(), uuid); if (existing != null) { return PerformResult.NO_ACTION; } @@ -228,12 +231,60 @@ public PerformResult perform() throws WorldEditorException { float yaw = (float) deserialized.getDouble("yaw"); float pitch = (float) deserialized.getDouble("pitch"); Location location = new Location(world, x, y, z, yaw, pitch); - Entity existing = Utils.loadChunksForEntity(location.getChunk(), uuid); + Entity existing = BukkitUtils.loadEntityAround(location.getChunk(), uuid); if (existing != null) { existing.remove(); return PerformResult.SUCCESS; } return PerformResult.NO_ACTION; // the entity is not there, so we cannot do anything + } else if (changeType == (rollback ? EntityChangeType.REMOVEEQUIP : EntityChangeType.ADDEQUIP)) { + // set equip + UUID uuid = getReplacedUUID(entityId, entityUUID); + Entity existing = BukkitUtils.loadEntityAround(loc.getChunk(), uuid); + if (existing != null) { + YamlConfiguration deserialized = Utils.deserializeYamlConfiguration(data); + ItemStack item = deserialized.getItemStack("item"); + if (item != null && existing instanceof ItemFrame) { + ItemStack old = ((ItemFrame) existing).getItem(); + if (old == null || old.getType() == Material.AIR) { + ((ItemFrame) existing).setItem(item); + return PerformResult.SUCCESS; + } + } else if (item != null && existing instanceof ArmorStand) { + EquipmentSlot slot = EquipmentSlot.valueOf(deserialized.getString("slot")); + ArmorStand stand = (ArmorStand) existing; + ItemStack old = BukkitUtils.getItemInSlot(stand, slot); + if (old == null || old.getType() == Material.AIR) { + BukkitUtils.setItemInSlot(stand, slot, item); + return PerformResult.SUCCESS; + } + } + } + return PerformResult.NO_ACTION; // the entity is not there, or equip does not match + } else if (changeType == (rollback ? EntityChangeType.ADDEQUIP : EntityChangeType.REMOVEEQUIP)) { + // remove equip + UUID uuid = getReplacedUUID(entityId, entityUUID); + Entity existing = BukkitUtils.loadEntityAround(loc.getChunk(), uuid); + if (existing != null) { + YamlConfiguration deserialized = Utils.deserializeYamlConfiguration(data); + ItemStack item = deserialized.getItemStack("item"); + if (item != null && existing instanceof ItemFrame) { + ItemStack old = ((ItemFrame) existing).getItem(); + if (old != null && old.isSimilar(item)) { + ((ItemFrame) existing).setItem(null); + return PerformResult.SUCCESS; + } + } else if (item != null && existing instanceof ArmorStand) { + EquipmentSlot slot = EquipmentSlot.valueOf(deserialized.getString("slot")); + ArmorStand stand = (ArmorStand) existing; + ItemStack old = BukkitUtils.getItemInSlot(stand, slot); + if (old != null && old.isSimilar(item)) { + BukkitUtils.setItemInSlot(stand, slot, null); + return PerformResult.SUCCESS; + } + } + } + return PerformResult.NO_ACTION; // the entity is not there, or equip does not match } return PerformResult.NO_ACTION; } diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index 50ba6aa0..ca6d9b86 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -3,7 +3,7 @@ import de.diddiz.LogBlock.EntityLogging; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; -import de.diddiz.util.Utils; +import de.diddiz.util.BukkitUtils; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Ambient; @@ -90,7 +90,7 @@ public EntitiyLoggingList(List types) { boolean monsters = false; boolean living = false; for (String type : types) { - EntityType et = Utils.matchEntityType(type); + EntityType et = BukkitUtils.matchEntityType(type); if (et != null) { logged.add(et); } else { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index 35e575a9..52997fdc 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -8,6 +8,7 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Hanging; import org.bukkit.entity.IronGolem; +import org.bukkit.entity.ItemFrame; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Snowman; @@ -24,6 +25,7 @@ import org.bukkit.event.hanging.HangingBreakByEntityEvent; import org.bukkit.event.hanging.HangingBreakEvent; import org.bukkit.event.hanging.HangingPlaceEvent; +import org.bukkit.event.player.PlayerArmorStandManipulateEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.EquipmentSlot; @@ -98,11 +100,26 @@ public void onPlayerInteract(PlayerInteractEvent event) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { ItemStack inHand = event.getHand() == EquipmentSlot.HAND ? event.getPlayer().getInventory().getItemInMainHand() : event.getPlayer().getInventory().getItemInOffHand(); - if (inHand != null) { + if (inHand != null && inHand.getType() != Material.AIR) { Material mat = inHand.getType(); if (mat.name().endsWith("_SPAWN_EGG")) { setLastSpawner(event.getPlayer(), null, true); } + + Entity entity = event.getRightClicked(); + if (entity instanceof ItemFrame) { + ItemStack oldItem = ((ItemFrame) entity).getItem(); + if (oldItem == null || oldItem.getType() == Material.AIR) { + if (Config.isLogging(entity.getWorld(), EntityLogging.MODIFY, entity)) { + Actor actor = Actor.actorFromEntity(event.getPlayer()); + YamlConfiguration data = new YamlConfiguration(); + inHand = inHand.clone(); + inHand.setAmount(1); + data.set("item", inHand); + consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.ADDEQUIP, data); + } + } + } } } @@ -169,6 +186,54 @@ public void onHangingBreak(HangingBreakEvent event) { } } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onEntityDamage(EntityDamageEvent event) { + Entity entity = event.getEntity(); + if (entity instanceof ItemFrame) { + ItemStack oldItem = ((ItemFrame) entity).getItem(); + if (oldItem != null && oldItem.getType() != Material.AIR) { + if (Config.isLogging(entity.getWorld(), EntityLogging.MODIFY, entity)) { + Actor actor; + if (event instanceof EntityDamageByEntityEvent) { + actor = Actor.actorFromEntity(((EntityDamageByEntityEvent) event).getDamager()); + } else { + actor = new Actor(event.getCause().toString()); + } + YamlConfiguration data = new YamlConfiguration(); + data.set("item", oldItem); + consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.REMOVEEQUIP, data); + } + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerArmorStandManipulate(PlayerArmorStandManipulateEvent event) { + ArmorStand entity = event.getRightClicked(); + ItemStack oldItem = event.getArmorStandItem(); + ItemStack newItem = event.getPlayerItem(); + boolean oldEmpty = oldItem == null || oldItem.getType() == Material.AIR; + boolean newEmpty = newItem == null || newItem.getType() == Material.AIR; + if ((!oldEmpty || !newEmpty) && Config.isLogging(entity.getWorld(), EntityLogging.MODIFY, entity)) { + Actor actor = Actor.actorFromEntity(event.getPlayer()); + if (!oldEmpty && !newEmpty && newItem.getAmount() > 1) { + return; + } + if (!oldEmpty) { + YamlConfiguration data = new YamlConfiguration(); + data.set("item", oldItem); + data.set("slot", event.getSlot().name()); + consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.REMOVEEQUIP, data); + } + if (!newEmpty) { + YamlConfiguration data = new YamlConfiguration(); + data.set("item", newItem); + data.set("slot", event.getSlot().name()); + consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.ADDEQUIP, data); + } + } + } + protected void queueEntitySpawnOrKill(Entity entity, Actor actor, EntityChange.EntityChangeType changeType) { Location location = entity.getLocation(); YamlConfiguration data = new YamlConfiguration(); diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 369d1362..5cf05aa5 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -12,10 +12,12 @@ import org.bukkit.block.data.type.Slab.Type; import org.bukkit.block.data.type.Stairs; import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.entity.TNTPrimed; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; @@ -746,4 +748,85 @@ public static Block getConnectedChest(Block chestBlock) { } return null; } + + public static Entity loadEntityAround(Chunk chunk, UUID uuid) { + Entity e = Bukkit.getEntity(uuid); + if (e != null) { + return e; + } + if (!chunk.isLoaded()) { + chunk.load(); + e = Bukkit.getEntity(uuid); + if (e != null) { + return e; + } + } + int chunkx = chunk.getX(); + int chunkz = chunk.getZ(); + for (int i = 0; i < 8; i++) { + int x = i < 3 ? chunkx - 1 : (i < 5 ? chunkx : chunkx + 1); + int z = i == 0 || i == 3 || i == 5 ? chunkz - 1 : (i == 1 || i == 6 ? chunkz : chunkz + 1); + if (!chunk.getWorld().isChunkLoaded(x, z)) { + chunk.getWorld().loadChunk(x, z); + e = Bukkit.getEntity(uuid); + if (e != null) { + return e; + } + } + } + return null; + } + + private static final HashMap types = new HashMap<>(); + static { + for (EntityType t : EntityType.values()) { + types.put(t.name().toLowerCase(), t); + @SuppressWarnings("deprecation") + String typeName = t.getName(); + if (typeName != null) { + types.put(typeName.toLowerCase(), t); + } + Class ec = t.getEntityClass(); + if (ec != null) { + types.put(ec.getSimpleName().toLowerCase(), t); + } + } + } + + public static EntityType matchEntityType(String typeName) { + return types.get(typeName.toLowerCase()); + } + + public static ItemStack getItemInSlot(ArmorStand stand, EquipmentSlot slot) { + if (slot == EquipmentSlot.HAND) { + return stand.getEquipment().getItemInMainHand(); + } else if (slot == EquipmentSlot.OFF_HAND) { + return stand.getEquipment().getItemInOffHand(); + } else if (slot == EquipmentSlot.FEET) { + return stand.getEquipment().getBoots(); + } else if (slot == EquipmentSlot.LEGS) { + return stand.getEquipment().getLeggings(); + } else if (slot == EquipmentSlot.CHEST) { + return stand.getEquipment().getChestplate(); + } else if (slot == EquipmentSlot.HEAD) { + return stand.getEquipment().getHelmet(); + } + return null; + } + + public static void setItemInSlot(ArmorStand stand, EquipmentSlot slot, ItemStack stack) { + if (slot == EquipmentSlot.HAND) { + stand.getEquipment().setItemInMainHand(stack); + } else if (slot == EquipmentSlot.OFF_HAND) { + stand.getEquipment().setItemInOffHand(stack); + } else if (slot == EquipmentSlot.FEET) { + stand.getEquipment().setBoots(stack); + } else if (slot == EquipmentSlot.LEGS) { + stand.getEquipment().setLeggings(stack); + } else if (slot == EquipmentSlot.CHEST) { + stand.getEquipment().setChestplate(stack); + } else if (slot == EquipmentSlot.HEAD) { + stand.getEquipment().setHelmet(stack); + } + } } diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index 60306ff6..c4ea0f90 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -10,21 +10,15 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import java.util.zip.ZipException; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import de.diddiz.LogBlock.LogBlock; @@ -290,52 +284,4 @@ public static byte[] serializeYamlConfiguration(YamlConfiguration conf) { public static String serializeForSQL(YamlConfiguration conf) { return mysqlPrepareBytesForInsertAllowNull(serializeYamlConfiguration(conf)); } - - public static Entity loadChunksForEntity(Chunk chunk, UUID uuid) { - Entity e = Bukkit.getEntity(uuid); - if (e != null) { - return e; - } - if (!chunk.isLoaded()) { - chunk.load(); - e = Bukkit.getEntity(uuid); - if (e != null) { - return e; - } - } - int chunkx = chunk.getX(); - int chunkz = chunk.getZ(); - for (int i = 0; i < 8; i++) { - int x = i < 3 ? chunkx - 1 : (i < 5 ? chunkx : chunkx + 1); - int z = i == 0 || i == 3 || i == 5 ? chunkz - 1 : (i == 1 || i == 6 ? chunkz : chunkz + 1); - if (!chunk.getWorld().isChunkLoaded(x, z)) { - chunk.getWorld().loadChunk(x, z); - e = Bukkit.getEntity(uuid); - if (e != null) { - return e; - } - } - } - return null; - } - - private static final HashMap types = new HashMap<>(); - static { - for (EntityType t : EntityType.values()) { - types.put(t.name().toLowerCase(), t); - @SuppressWarnings("deprecation") - String typeName = t.getName(); - if (typeName != null) { - types.put(typeName.toLowerCase(), t); - } - Class ec = t.getEntityClass(); - if (ec != null) { - types.put(ec.getSimpleName().toLowerCase(), t); - } - } - } - - public static EntityType matchEntityType(String typeName) { - return types.get(typeName.toLowerCase()); - } } From 1eace44cce61e712173a67d344a0e190a0ac888a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 9 Nov 2018 05:04:37 +0100 Subject: [PATCH 153/399] Better messages --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 9bdf4094..324c20e1 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -699,7 +699,7 @@ public void run() { editor.setSender(sender); } if (!params.silent) { - sender.sendMessage(ChatColor.GREEN.toString() + changes + " blocks found."); + sender.sendMessage(ChatColor.GREEN.toString() + changes + " " + (params.bct == BlockChangeType.ENTITIES ? "entities" : "blocks") + " found."); } if (changes == 0) { if (!params.silent) { @@ -782,7 +782,7 @@ public void run() { } final int changes = editor.getSize(); if (!params.silent) { - sender.sendMessage(ChatColor.GREEN.toString() + changes + " blocks found."); + sender.sendMessage(ChatColor.GREEN.toString() + changes + " " + (params.bct == BlockChangeType.ENTITIES ? "entities" : "blocks") + " found."); } if (changes == 0) { if (!params.silent) { From 76aeb5f602c88dfa2b17d40cf65765a3c181f30b Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 9 Nov 2018 06:24:36 +0100 Subject: [PATCH 154/399] Filter for entity types --- .../java/de/diddiz/LogBlock/QueryParams.java | 65 ++++++++++++++++--- 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index afceadd1..107d926c 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -1,6 +1,7 @@ package de.diddiz.LogBlock; import de.diddiz.LogBlock.config.Config; +import de.diddiz.util.BukkitUtils; import de.diddiz.util.Utils; import de.diddiz.worldedit.CuboidRegion; import de.diddiz.worldedit.WorldEditHelper; @@ -9,6 +10,7 @@ import org.bukkit.Material; import org.bukkit.World; import org.bukkit.command.CommandSender; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import java.util.*; @@ -63,12 +65,14 @@ public final class QueryParams implements Cloneable { public List players = new ArrayList(); public List killers = new ArrayList(); public List victims = new ArrayList(); - public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, excludeBlocksMode = false, prepareToolQuery = false, silent = false, noForcedLimit = false; + public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, excludeBlocksEntitiesMode = false, prepareToolQuery = false, silent = false, noForcedLimit = false; public boolean forceReplace = false, noCache = false; public CuboidRegion sel = null; public SummarizationMode sum = SummarizationMode.NONE; public List types = new ArrayList(); public List typeIds = new ArrayList(); + public List entityTypes = new ArrayList(); + public List entityTypeIds = new ArrayList(); public World world = null; public String match = null; public boolean needCount = false, needId = false, needDate = false, needType = false, needData = false, needPlayerId = false, needPlayer = false, needCoords = false, needChestAccess = false, needMessage = false, needKiller = false, needVictim = false, needWeapon = false; @@ -314,10 +318,21 @@ public String getTitle() { } else if (bct == BlockChangeType.KILLS) { title.append("kills "); } else if (bct == BlockChangeType.ENTITIES) { - title.append("entity changes "); + if (!entityTypes.isEmpty()) { + if (excludeBlocksEntitiesMode) { + title.append("all entities except "); + } + final String[] entityTypeNames = new String[entityTypes.size()]; + for (int i = 0; i < entityTypes.size(); i++) { + entityTypeNames[i] = entityTypes.get(i).name(); + } + title.append(listing(entityTypeNames, ", ", " and ")).append(" "); + } else { + title.append("entity changes "); + } } else { if (!types.isEmpty()) { - if (excludeBlocksMode) { + if (excludeBlocksEntitiesMode) { title.append("all blocks except "); } final String[] blocknames = new String[types.size()]; @@ -454,12 +469,23 @@ public String getWhere(BlockChangeType blockChangeType) { } } } else if (blockChangeType == BlockChangeType.ENTITIES) { - + if (!entityTypeIds.isEmpty()) { + if (excludeBlocksEntitiesMode) { + where.append("NOT "); + } + where.append('('); + for (final Integer entityType : entityTypeIds) { + where.append("(entitytypeid = ").append(entityType); + where.append(") OR "); + } + where.delete(where.length() - 4, where.length() - 1); + where.append(") AND "); + } } else { switch (blockChangeType) { case ALL: if (!typeIds.isEmpty()) { - if (excludeBlocksMode) { + if (excludeBlocksEntitiesMode) { where.append("NOT "); } where.append('('); @@ -474,7 +500,7 @@ public String getWhere(BlockChangeType blockChangeType) { break; case BOTH: if (!typeIds.isEmpty()) { - if (excludeBlocksMode) { + if (excludeBlocksEntitiesMode) { where.append("NOT "); } where.append('('); @@ -490,7 +516,7 @@ public String getWhere(BlockChangeType blockChangeType) { break; case CREATED: if (!typeIds.isEmpty()) { - if (excludeBlocksMode) { + if (excludeBlocksEntitiesMode) { where.append("NOT "); } where.append('('); @@ -506,7 +532,7 @@ public String getWhere(BlockChangeType blockChangeType) { break; case DESTROYED: if (!typeIds.isEmpty()) { - if (excludeBlocksMode) { + if (excludeBlocksEntitiesMode) { where.append("NOT "); } where.append('('); @@ -522,7 +548,7 @@ public String getWhere(BlockChangeType blockChangeType) { break; case CHESTACCESS: if (!typeIds.isEmpty()) { - if (excludeBlocksMode) { + if (excludeBlocksEntitiesMode) { where.append("NOT "); } where.append('('); @@ -722,7 +748,7 @@ public void parseArgs(CommandSender sender, List args, boolean validate) } for (String blockName : values) { if (blockName.startsWith("!")) { - excludeBlocksMode = true; + excludeBlocksEntitiesMode = true; blockName = blockName.substring(1); } @@ -797,6 +823,21 @@ public void parseArgs(CommandSender sender, List args, boolean validate) bct = BlockChangeType.KILLS; } else if (param.equals("entities") || param.equals("entity")) { bct = BlockChangeType.ENTITIES; + if (values.length > 0) { + for (String entityTypeName : values) { + if (entityTypeName.startsWith("!")) { + excludeBlocksEntitiesMode = true; + entityTypeName = entityTypeName.substring(1); + } + + final EntityType entityType = BukkitUtils.matchEntityType(entityTypeName); + if (entityType == null) { + throw new IllegalArgumentException("No entity type matching: '" + entityTypeName + "'"); + } + entityTypes.add(entityType); + entityTypeIds.add(EntityTypeConverter.getOrAddEntityTypeId(entityType)); + } + } } else if (param.equals("all")) { bct = BlockChangeType.ALL; } else if (param.equals("limit")) { @@ -919,6 +960,8 @@ public QueryParams clone() { params.victims = new ArrayList(victims); params.typeIds = new ArrayList(typeIds); params.types = new ArrayList(types); + params.entityTypeIds = new ArrayList(entityTypeIds); + params.entityTypes = new ArrayList(entityTypes); params.loc = loc == null ? null : loc.clone(); params.sel = sel == null ? null : sel.clone(); return params; @@ -963,6 +1006,8 @@ public void merge(QueryParams p) { excludePlayersMode = p.excludePlayersMode; typeIds.addAll(p.typeIds); types.addAll(p.types); + entityTypeIds.addAll(p.entityTypeIds); + entityTypes.addAll(p.entityTypes); loc = p.loc == null ? null : p.loc.clone(); radius = p.radius; sel = p.sel == null ? null : p.sel.clone(); From 9ea7a47b4eeeebe76b5917fe6217d4d76741b30b Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 9 Nov 2018 06:27:21 +0100 Subject: [PATCH 155/399] Animals should not contain ambient entities --- .../java/de/diddiz/LogBlock/{ => config}/EntityLogging.java | 2 +- src/main/java/de/diddiz/LogBlock/config/WorldConfig.java | 4 +--- .../de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) rename src/main/java/de/diddiz/LogBlock/{ => config}/EntityLogging.java (96%) diff --git a/src/main/java/de/diddiz/LogBlock/EntityLogging.java b/src/main/java/de/diddiz/LogBlock/config/EntityLogging.java similarity index 96% rename from src/main/java/de/diddiz/LogBlock/EntityLogging.java rename to src/main/java/de/diddiz/LogBlock/config/EntityLogging.java index 80c38785..8e1e75a3 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/config/EntityLogging.java @@ -1,4 +1,4 @@ -package de.diddiz.LogBlock; +package de.diddiz.LogBlock.config; import java.util.Arrays; import java.util.Collections; diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index ca6d9b86..de2bb4a1 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -1,12 +1,10 @@ package de.diddiz.LogBlock.config; -import de.diddiz.LogBlock.EntityLogging; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import de.diddiz.util.BukkitUtils; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Ambient; import org.bukkit.entity.Animals; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; @@ -124,7 +122,7 @@ public boolean isLogging(Entity entity) { if (logLiving && LivingEntity.class.isAssignableFrom(entity.getClass()) && !(entity instanceof ArmorStand)) { return true; } - if (logAnimals && (Animals.class.isAssignableFrom(entity.getClass()) || WaterMob.class.isAssignableFrom(entity.getClass()) || Ambient.class.isAssignableFrom(entity.getClass()))) { + if (logAnimals && (Animals.class.isAssignableFrom(entity.getClass()) || WaterMob.class.isAssignableFrom(entity.getClass()))) { return true; } if (logMonsters && (Monster.class.isAssignableFrom(entity.getClass()) || entity.getType() == EntityType.SLIME || entity.getType() == EntityType.WITHER || entity.getType() == EntityType.ENDER_DRAGON || entity.getType() == EntityType.SHULKER || entity.getType() == EntityType.GHAST)) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index 52997fdc..7b56a97d 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -34,9 +34,9 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.EntityChange; -import de.diddiz.LogBlock.EntityLogging; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.config.Config; +import de.diddiz.LogBlock.config.EntityLogging; import de.diddiz.worldedit.WorldEditHelper; public class AdvancedEntityLogging extends LoggingListener { From 8a1897e102d3351ab1d963f3533e397ab0d4daea Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 9 Nov 2018 06:29:26 +0100 Subject: [PATCH 156/399] Add entities to params command --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 324c20e1..0986f2ca 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -86,6 +86,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, sender.sendMessage(ChatColor.GOLD + "block [type1] -- List of block types"); sender.sendMessage(ChatColor.GOLD + "created, destroyed -- Show only created/destroyed blocks"); sender.sendMessage(ChatColor.GOLD + "chestaccess -- Show only chest accesses"); + sender.sendMessage(ChatColor.GOLD + "entities [type1] -- List of entity types; can not be combined with blocks"); sender.sendMessage(ChatColor.GOLD + "area -- Area around you"); sender.sendMessage(ChatColor.GOLD + "selection, sel -- Inside current WorldEdit selection"); sender.sendMessage(ChatColor.GOLD + "world [worldname] -- Changes the world"); From 27c72b43c1c415b4e1eb47b631ed845577a921c5 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 9 Nov 2018 17:31:39 +0100 Subject: [PATCH 157/399] Error message if entity logging is enabled, but no compatible WorldEdit is found --- .../java/de/diddiz/LogBlock/LogBlock.java | 9 ++++- .../de/diddiz/LogBlock/config/Config.java | 9 +++++ .../diddiz/LogBlock/config/WorldConfig.java | 21 +++++++++--- .../de/diddiz/worldedit/WorldEditHelper.java | 34 +++++++++++++++++-- 4 files changed, 65 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 5c8f1052..34493e91 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -188,7 +188,14 @@ private void registerEvents() { if (isLogging(Logging.DRAGONEGGTELEPORT)) { pm.registerEvents(new DragonEggLogging(this), this); } - pm.registerEvents(new AdvancedEntityLogging(this), this); + if (Config.isLoggingAnyEntities()) { + if (!WorldEditHelper.hasFullWorldEdit()) { + getLogger().severe("No compatible WorldEdit found, entity logging will not work!"); + } else { + pm.registerEvents(new AdvancedEntityLogging(this), this); + getLogger().info("Entity logging enabled!"); + } + } } @Override diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 0aecb970..9fb8429a 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -328,6 +328,15 @@ public static boolean isLogging(World world, EntityLogging logging, Entity entit final WorldConfig wcfg = worldConfigs.get(world.getName()); return wcfg != null && wcfg.isLogging(logging, entity); } + + public static boolean isLoggingAnyEntities() { + for (WorldConfig worldConfig : worldConfigs.values()) { + if (worldConfig.isLoggingAnyEntities()) { + return true; + } + } + return false; + } } class LoggingEnabledMapping { diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index de2bb4a1..e4aea94d 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -34,7 +34,7 @@ public class WorldConfig extends LoggingEnabledMapping { public final String insertEntityStatementString; public final String updateEntityUUIDString; - private final EnumMap entityLogging = new EnumMap<>(EntityLogging.class); + private final EnumMap entityLogging = new EnumMap<>(EntityLogging.class); public WorldConfig(String world, File file) throws IOException { this.world = world; @@ -55,7 +55,7 @@ public WorldConfig(String world, File file) throws IOException { if (!(config.get("entity." + el.name().toLowerCase()) instanceof List)) { config.set("entity." + el.name().toLowerCase(), el.getDefaultEnabled()); } - entityLogging.put(el, new EntitiyLoggingList(config.getStringList("entity." + el.name().toLowerCase()))); + entityLogging.put(el, new EntityLoggingList(config.getStringList("entity." + el.name().toLowerCase()))); } config.save(file); table = config.getString("table"); @@ -75,14 +75,23 @@ public boolean isLogging(EntityLogging logging, Entity entity) { return entityLogging.get(logging).isLogging(entity); } - private class EntitiyLoggingList { + public boolean isLoggingAnyEntities() { + for (EntityLoggingList list : entityLogging.values()) { + if (list.isLoggingAnyEntities()) { + return true; + } + } + return false; + } + + private class EntityLoggingList { private final EnumSet logged = EnumSet.noneOf(EntityType.class); private final boolean logAll; private final boolean logAnimals; private final boolean logMonsters; private final boolean logLiving; - public EntitiyLoggingList(List types) { + public EntityLoggingList(List types) { boolean all = false; boolean animals = false; boolean monsters = false; @@ -130,5 +139,9 @@ public boolean isLogging(Entity entity) { } return false; } + + public boolean isLoggingAnyEntities() { + return logAll || logAnimals || logLiving || logMonsters || !logged.isEmpty(); + } } } diff --git a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java b/src/main/java/de/diddiz/worldedit/WorldEditHelper.java index 69285fdf..5d7b9ecd 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditHelper.java @@ -3,9 +3,11 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; 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; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -23,8 +25,11 @@ import com.sk89q.jnbt.ShortTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.entity.BaseEntity; +import de.diddiz.LogBlock.LogBlock; + public class WorldEditHelper { private static boolean checkedForWorldEdit; private static boolean hasWorldEdit; @@ -39,6 +44,10 @@ public static boolean hasWorldEdit() { return hasWorldEdit; } + public static boolean hasFullWorldEdit() { + return hasWorldEdit && Internal.hasBukkitImplAdapter(); + } + public static byte[] serializeEntity(Entity entity) { if (!hasWorldEdit()) { return null; @@ -51,10 +60,29 @@ public static Entity restoreEntity(Location location, EntityType type, byte[] se } private static class Internal { - // private static WorldEditPlugin worldEdit; + private static WorldEditPlugin worldEdit; + private static Method getBukkitImplAdapter; public static void setWorldEdit(Plugin worldEdit) { - // Internal.worldEdit = (WorldEditPlugin) worldEdit; + Internal.worldEdit = (WorldEditPlugin) worldEdit; + } + + public static boolean hasBukkitImplAdapter() { + if (getBukkitImplAdapter == null) { + try { + getBukkitImplAdapter = WorldEditPlugin.class.getDeclaredMethod("getBukkitImplAdapter"); + getBukkitImplAdapter.setAccessible(true); + } catch (Exception e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Exception while checking for BukkitImplAdapter", e); + return false; + } + } + try { + return getBukkitImplAdapter.invoke(worldEdit) != null; + } catch (Exception e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Exception while checking for BukkitImplAdapter", e); + return false; + } } public static Entity restoreEntity(Location location, EntityType type, byte[] serialized) { @@ -90,7 +118,7 @@ public static byte[] serializeEntity(Entity entity) { CompoundTag nbt = state.getNbtData(); LinkedHashMap 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("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)); From c3b0fda0171d9a5509f7c4585309d65ac92fc6ca Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 9 Nov 2018 21:05:08 +0100 Subject: [PATCH 158/399] Improve worldeditor row ordering --- .../de/diddiz/LogBlock/CommandsHandler.java | 12 +++- .../java/de/diddiz/LogBlock/WorldEditor.java | 66 +++++++++++++++++-- .../LogBlock/WorldEditorEditFactory.java | 4 +- 3 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 0986f2ca..734edd22 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -671,11 +671,11 @@ public void run() { sender.sendMessage(ChatColor.RED + "Cannot rollback summarized changes"); return; } + params.needDate = true; params.needCoords = true; params.needType = true; params.needData = true; params.needChestAccess = true; - params.order = Order.DESC; params.sum = SummarizationMode.NONE; conn = logblock.getConnection(); if (conn == null) { @@ -695,6 +695,10 @@ public void run() { while (rs.next()) { editFactory.processRow(rs); } + if (params.order == Order.DESC) { + editor.reverseRowOrder(); + } + editor.sortRows(Order.DESC); final int changes = editor.getSize(); if (changes > 10000) { editor.setSender(sender); @@ -757,11 +761,11 @@ public void run() { sender.sendMessage(ChatColor.RED + "Cannot redo summarized changes"); return; } + params.needDate = true; params.needCoords = true; params.needType = true; params.needData = true; params.needChestAccess = true; - params.order = Order.ASC; params.sum = SummarizationMode.NONE; conn = logblock.getConnection(); if (conn == null) { @@ -781,6 +785,10 @@ public void run() { while (rs.next()) { editFactory.processRow(rs); } + if (params.order == Order.ASC) { + editor.reverseRowOrder(); + } + editor.sortRows(Order.ASC); final int changes = editor.getSize(); if (!params.silent) { sender.sendMessage(ChatColor.GREEN.toString() + changes + " " + (params.bct == BlockChangeType.ENTITIES ? "entities" : "blocks") + " found."); diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index c4f621b4..b54b4015 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -25,6 +25,7 @@ import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; +import de.diddiz.LogBlock.QueryParams.Order; import de.diddiz.LogBlock.blockstate.BlockStateCodecs; import de.diddiz.util.BukkitUtils; import de.diddiz.util.Utils; @@ -36,11 +37,11 @@ import java.sql.SQLException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; -import java.util.Queue; import java.util.UUID; -import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; import static de.diddiz.LogBlock.config.Config.dontRollback; @@ -49,7 +50,7 @@ public class WorldEditor implements Runnable { private final LogBlock logblock; - private final Queue edits = new LinkedBlockingQueue(); + private final ArrayList edits = new ArrayList<>(); private final World world; /** @@ -62,6 +63,7 @@ public class WorldEditor implements Runnable { public LookupCacheElement[] errors; private boolean forceReplace; private HashMap uuidReplacements = new HashMap<>(); + private boolean started = false; public WorldEditor(LogBlock logblock, World world) { this(logblock, world, false); @@ -94,19 +96,43 @@ public void setSender(CommandSender sender) { this.sender = sender; } - public void queueBlockEdit(int x, int y, int z, int replaced, int replaceData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess item) { - edits.add(new BlockEdit(0, new Location(world, x, y, z), null, replaced, replaceData, replacedState, type, typeData, typeState, item)); + public void queueBlockEdit(long time, int x, int y, int z, int replaced, int replaceData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess item) { + if (started) { + throw new IllegalStateException("Already started"); + } + edits.add(new BlockEdit(time, new Location(world, x, y, z), null, replaced, replaceData, replacedState, type, typeData, typeState, item)); } public void queueEntityEdit(ResultSet rs, QueryParams p, boolean rollback) throws SQLException { + if (started) { + throw new IllegalStateException("Already started"); + } edits.add(new EntityEdit(rs, p, rollback)); } + public void reverseRowOrder() { + if (started) { + throw new IllegalStateException("Already started"); + } + Collections.reverse(edits); + } + + public void sortRows(QueryParams.Order order) { + if (started) { + throw new IllegalStateException("Already started"); + } + edits.sort(new EditComparator(order)); + } + public long getElapsedTime() { return elapsedTime; } synchronized public void start() throws Exception { + if (started) { + throw new IllegalStateException("Already started"); + } + started = true; final long start = System.currentTimeMillis(); taskID = logblock.getServer().getScheduler().scheduleSyncRepeatingTask(logblock, this, 0, 1); if (taskID == -1) { @@ -127,7 +153,7 @@ public synchronized void run() { float size = edits.size(); while (!edits.isEmpty() && counter < 100) { try { - switch (edits.poll().perform()) { + switch (edits.remove(edits.size() - 1).perform()) { case SUCCESS: successes++; break; @@ -181,6 +207,8 @@ public static enum PerformResult { public interface Edit { PerformResult perform() throws WorldEditorException; + + public long getTime(); } public class EntityEdit extends EntityChange implements Edit { @@ -191,6 +219,11 @@ public EntityEdit(ResultSet rs, QueryParams p, boolean rollback) throws SQLExcep this.rollback = rollback; } + @Override + public long getTime() { + return date; + } + @Override public PerformResult perform() throws WorldEditorException { if (changeType == (rollback ? EntityChangeType.KILL : EntityChangeType.CREATE)) { @@ -292,7 +325,12 @@ public PerformResult perform() throws WorldEditorException { public class BlockEdit extends BlockChange implements Edit { public BlockEdit(long time, Location loc, Actor actor, int replaced, int replaceData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { - super(time, loc, actor, replaced, replaceData,replacedState , type, typeData, typeState, ca); + super(time, loc, actor, replaced, replaceData, replacedState, type, typeData, typeState, ca); + } + + @Override + public long getTime() { + return date; } public PerformResult perform() throws WorldEditorException { @@ -400,6 +438,20 @@ public PerformResult perform() throws WorldEditorException { } } + public static class EditComparator implements Comparator { + private final int mult; + public EditComparator(QueryParams.Order order) { + mult = order == Order.DESC ? 1 : -1; + } + + @Override + public int compare(Edit edit1, Edit edit2) { + long time1 = edit1.getTime(); + long time2 = edit2.getTime(); + return time1 > time2 ? mult : time1 < time2 ? -mult : 0; + } + } + @SuppressWarnings("serial") public static class WorldEditorException extends Exception implements LookupCacheElement { private final Location loc; diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java b/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java index e23dc6b6..80728cce 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java @@ -30,9 +30,9 @@ public void processRow(ResultSet rs) throws SQLException { chestaccess = new ChestAccess(stack, rs.getBoolean("itemremove") == rollback, rs.getInt("itemtype")); } if (rollback) { - editor.queueBlockEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), chestaccess); + editor.queueBlockEdit(rs.getTimestamp("date").getTime(), rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), chestaccess); } else { - editor.queueBlockEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), chestaccess); + editor.queueBlockEdit(rs.getTimestamp("date").getTime(), rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), chestaccess); } } } From cd798e86de040a3f86db11b047ecf310fd662f5d Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 10 Nov 2018 04:00:10 +0100 Subject: [PATCH 159/399] Summarization for entities --- .../de/diddiz/LogBlock/CommandsHandler.java | 2 +- .../LogBlock/LookupCacheElementFactory.java | 5 ++- .../java/de/diddiz/LogBlock/QueryParams.java | 36 ++++++++++--------- .../diddiz/LogBlock/SummedEntityChanges.java | 35 ++++++++++++++++++ 4 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 734edd22..7fd5f9c4 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -502,7 +502,7 @@ public void run() { if (params.bct == BlockChangeType.KILLS && params.sum == SummarizationMode.PLAYERS) { sender.sendMessage(ChatColor.GOLD + "Kills - Killed - Player"); } else { - sender.sendMessage(ChatColor.GOLD + "Created - Destroyed - " + (params.sum == SummarizationMode.TYPES ? "Block" : "Player")); + sender.sendMessage(ChatColor.GOLD + "Created - Destroyed - " + (params.sum == SummarizationMode.TYPES ? (params.bct == BlockChangeType.ENTITIES ? "Entity" : "Block") : "Player")); } } if (!params.noCache) { diff --git a/src/main/java/de/diddiz/LogBlock/LookupCacheElementFactory.java b/src/main/java/de/diddiz/LogBlock/LookupCacheElementFactory.java index dc97d53f..cc579e28 100755 --- a/src/main/java/de/diddiz/LogBlock/LookupCacheElementFactory.java +++ b/src/main/java/de/diddiz/LogBlock/LookupCacheElementFactory.java @@ -26,12 +26,11 @@ public LookupCacheElement getLookupCacheElement(ResultSet rs) throws SQLExceptio return new SummedKills(rs, params, spaceFactor); } } - if (params.bct == BlockChangeType.ENTITIES) { + if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) { if (params.sum == SummarizationMode.NONE) { return new EntityChange(rs, params); - } else if (params.sum == SummarizationMode.PLAYERS) { - throw new IllegalArgumentException(); } + return new SummedEntityChanges(rs, params, spaceFactor); } if (params.sum == SummarizationMode.NONE) { return new BlockChange(rs, params); diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 107d926c..0d7ad206 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -127,7 +127,7 @@ public String getFrom() { } return from; } - if (bct == BlockChangeType.ENTITIES) { + if (bct == BlockChangeType.ENTITIES || bct == BlockChangeType.ENTITIES_CREATED || bct == BlockChangeType.ENTITIES_KILLED) { String from = "FROM `" + getTable() + "-entities` "; if (needPlayer || players.size() > 0) { @@ -236,7 +236,7 @@ public String getFields() { select += "COUNT(*) AS count "; } else { if (needId) { - if (bct != BlockChangeType.ENTITIES) { + if (bct != BlockChangeType.ENTITIES && bct != BlockChangeType.ENTITIES_CREATED && bct != BlockChangeType.ENTITIES_KILLED) { select += "`" + getTable() + "-blocks`.id, "; } else { select += "`" + getTable() + "-entities`.id, "; @@ -245,7 +245,7 @@ public String getFields() { if (needDate) { select += "date, "; } - if (bct != BlockChangeType.ENTITIES) { + if (bct != BlockChangeType.ENTITIES && bct != BlockChangeType.ENTITIES_CREATED && bct != BlockChangeType.ENTITIES_KILLED) { if (needType) { select += "replaced, type, "; } @@ -262,7 +262,7 @@ public String getFields() { if (needCoords) { select += "x, y, z, "; } - if (bct != BlockChangeType.ENTITIES) { + if (bct != BlockChangeType.ENTITIES && bct != BlockChangeType.ENTITIES_CREATED && bct != BlockChangeType.ENTITIES_KILLED) { if (needData) { select += "replacedState, typeState, "; } @@ -295,8 +295,12 @@ public String getQuery() { } throw new IllegalStateException("Invalid summarization for kills"); } - if (bct == BlockChangeType.ENTITIES) { - throw new IllegalStateException("Not implemented yet"); + if (bct == BlockChangeType.ENTITIES || bct == BlockChangeType.ENTITIES_CREATED || bct == BlockChangeType.ENTITIES_KILLED) { + if (sum == SummarizationMode.TYPES) { + return "SELECT entitytypeid, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT entitytypeid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-entities` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.ENTITIES_CREATED) + "GROUP BY entitytypeid) UNION (SELECT entitytypeid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-entities` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.ENTITIES_KILLED) + "GROUP BY entitytypeid)) AS t GROUP BY entitytypeid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); + } else { + return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-entities` " + getWhere(BlockChangeType.ENTITIES_CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-entities` " + getWhere(BlockChangeType.ENTITIES_KILLED) + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); + } } if (sum == SummarizationMode.TYPES) { return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.CREATED) + "GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); @@ -317,7 +321,7 @@ public String getTitle() { title.append("chat messages "); } else if (bct == BlockChangeType.KILLS) { title.append("kills "); - } else if (bct == BlockChangeType.ENTITIES) { + } else if (bct == BlockChangeType.ENTITIES || bct == BlockChangeType.ENTITIES_CREATED || bct == BlockChangeType.ENTITIES_KILLED) { if (!entityTypes.isEmpty()) { if (excludeBlocksEntitiesMode) { title.append("all entities except "); @@ -395,7 +399,7 @@ public String getTitle() { title.append("in ").append(friendlyWorldname(world.getName())).append(" "); } if (sum != SummarizationMode.NONE) { - title.append("summed up by ").append(sum == SummarizationMode.TYPES ? "blocks" : "players").append(" "); + title.append("summed up by ").append(sum == SummarizationMode.TYPES ? ((bct == BlockChangeType.ENTITIES || bct == BlockChangeType.ENTITIES_CREATED || bct == BlockChangeType.ENTITIES_KILLED) ? "entities" : "blocks") : "players").append(" "); } title.deleteCharAt(title.length() - 1); title.setCharAt(0, String.valueOf(title.charAt(0)).toUpperCase().toCharArray()[0]); @@ -468,7 +472,7 @@ public String getWhere(BlockChangeType blockChangeType) { } } } - } else if (blockChangeType == BlockChangeType.ENTITIES) { + } else if (blockChangeType == BlockChangeType.ENTITIES || blockChangeType == BlockChangeType.ENTITIES_CREATED || blockChangeType == BlockChangeType.ENTITIES_KILLED) { if (!entityTypeIds.isEmpty()) { if (excludeBlocksEntitiesMode) { where.append("NOT "); @@ -481,6 +485,11 @@ public String getWhere(BlockChangeType blockChangeType) { where.delete(where.length() - 4, where.length() - 1); where.append(") AND "); } + if (blockChangeType == BlockChangeType.ENTITIES_CREATED) { + where.append("action = " + EntityChange.EntityChangeType.CREATE.ordinal() + " AND "); + } else if (blockChangeType == BlockChangeType.ENTITIES_KILLED) { + where.append("action = " + EntityChange.EntityChangeType.KILL.ordinal() + " AND "); + } } else { switch (blockChangeType) { case ALL: @@ -802,7 +811,7 @@ public void parseArgs(CommandSender sender, List args, boolean validate) } if (values[0].startsWith("p")) { sum = SummarizationMode.PLAYERS; - } else if (values[0].startsWith("b")) { + } else if (values[0].startsWith("b") || values[0].startsWith("e")) { sum = SummarizationMode.TYPES; } else if (values[0].startsWith("n")) { sum = SummarizationMode.NONE; @@ -927,11 +936,6 @@ public void validate() { throw new IllegalArgumentException("Invalid summarization for chat"); } } - if(bct == BlockChangeType.ENTITIES) { - if (sum != SummarizationMode.NONE) { - throw new IllegalStateException("Summarization not implemented yet"); - } - } } public void setLocation(Location loc) { @@ -1024,7 +1028,7 @@ public void merge(QueryParams p) { } public static enum BlockChangeType { - ALL, BOTH, CHESTACCESS, CREATED, DESTROYED, CHAT, KILLS, ENTITIES + ALL, BOTH, CHESTACCESS, CREATED, DESTROYED, CHAT, KILLS, ENTITIES, ENTITIES_CREATED, ENTITIES_KILLED, } public static enum Order { diff --git a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java new file mode 100644 index 00000000..c47ab8c0 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java @@ -0,0 +1,35 @@ +package de.diddiz.LogBlock; + +import de.diddiz.LogBlock.QueryParams.SummarizationMode; +import org.bukkit.Location; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import static de.diddiz.util.Utils.spaces; + +public class SummedEntityChanges implements LookupCacheElement { + private final int type; + private final int created, destroyed; + private final float spaceFactor; + private final Actor actor; + + public SummedEntityChanges(ResultSet rs, QueryParams p, float spaceFactor) throws SQLException { + // Actor currently useless here as we don't yet output UUID in results anywhere + actor = p.sum == SummarizationMode.PLAYERS ? new Actor(rs) : null; + type = p.sum == SummarizationMode.TYPES ? rs.getInt("entitytypeid") : 0; + created = rs.getInt("created"); + destroyed = rs.getInt("destroyed"); + this.spaceFactor = spaceFactor; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public String getMessage() { + return created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)) + destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)) + (actor != null ? actor.getName() : EntityTypeConverter.getEntityType(type).toString()); + } +} From 83157ad64f5b20233fe624c73773d5a2a3b94c56 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 10 Nov 2018 04:22:52 +0100 Subject: [PATCH 160/399] clearlog for entities --- .../java/de/diddiz/LogBlock/CommandsHandler.java | 14 +++++++++++++- .../java/de/diddiz/LogBlock/config/Config.java | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 7fd5f9c4..c19f5651 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -569,7 +569,7 @@ public void run() { file.getParentFile().mkdirs(); int counter = 0; if (params.sum != SummarizationMode.NONE) { - writer.write("Created - Destroyed - " + (params.sum == SummarizationMode.TYPES ? "Block" : "Player") + newline); + writer.write("Created - Destroyed - " + (params.sum == SummarizationMode.TYPES ? (params.bct == BlockChangeType.ENTITIES ? "Entity" : "Block") : "Player") + newline); } final LookupCacheElementFactory factory = new LookupCacheElementFactory(params, sender instanceof Player ? 2 / 3f : 1); while (rs.next()) { @@ -855,6 +855,13 @@ public void run() { tableBase = params.getTable(); deleteFromTables = "`" + tableBase + "-kills` "; tableName = tableBase + "-kills"; + } else if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) { + params.needType = true; + params.needCoords = true; + params.needData = true; + tableBase = params.getTable(); + deleteFromTables = "`" + tableBase + "-entities` "; + tableName = tableBase + "-entities"; } else { params.needType = true; params.needCoords = true; @@ -906,6 +913,8 @@ public void run() { sb.append(rs.getInt("y")).append(", "); sb.append(rs.getInt("z")); sb.append(");\n"); + } else if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) { + } else { sb.append("INSERT INTO `").append(tableBase).append("-blocks` (`id`, `date`, `playerid`, `replaced`, `replacedData`, `type`, `typeData`, `x`, `y`, `z`) VALUES ("); sb.append(rs.getInt("id")).append(", FROM_UNIXTIME("); @@ -952,6 +961,9 @@ public void run() { } if (deleted > 0) { state.executeUpdate("DELETE " + deleteFromTables + params.getFrom() + params.getWhere()); + if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) { + state.executeUpdate("DELETE `" + tableBase + "-entityids` FROM `" + tableBase + "-entityids` LEFT JOIN `" + tableBase + "-entities` USING (entityid) WHERE `" + tableBase + "-entities`.entityid IS NULL"); + } } sender.sendMessage(ChatColor.GREEN + "Cleared out table " + tableName + ". Deleted " + deleted + " entries."); } catch (final Exception ex) { diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 9fb8429a..c054383b 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -91,6 +91,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti for (final String world : worldNames) { autoClearlog.add("world \"" + world + "\" before 365 days all"); autoClearlog.add("world \"" + world + "\" player lavaflow waterflow leavesdecay before 7 days all"); + autoClearlog.add("world \"" + world + "\" entities before 365 days"); } def.put("clearlog.auto", autoClearlog); def.put("clearlog.autoClearLogDelay", "6h"); From 7f3bb300efe53687b03503b49e6ae429b552f938 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 10 Nov 2018 04:26:27 +0100 Subject: [PATCH 161/399] Version 1.13.2 --- pom.xml | 2 +- src/main/java/de/diddiz/LogBlock/Updater.java | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index d8b0bf40..5bc70d82 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.13.1-SNAPSHOT + 1.13.2-SNAPSHOT jar LogBlock diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index d164e098..be9f6f2b 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -703,10 +703,14 @@ boolean update() { logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } - + config.set("version", "1.13.1"); } + if (configVersion.compareTo(new ComparableVersion("1.13.2")) < 0) { + config.set("version", "1.13.2"); + } + // this can always be checked try { final Connection conn = logblock.getConnection(); @@ -718,14 +722,14 @@ boolean update() { } createIndexIfDoesNotExist("lb-materials", "name", "UNIQUE KEY `name` (`name`(250))", st, true); createIndexIfDoesNotExist("lb-blockstates", "name", "UNIQUE KEY `name` (`name`(250))", st, true); - + st.close(); conn.close(); } catch (final SQLException ex) { logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } - + logblock.saveConfig(); return true; } From 0e8bb2599cd85ca0dd02770297a8470e4b2e18cb Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 12 Nov 2018 04:30:50 +0100 Subject: [PATCH 162/399] WorldEdit changed the bstats artifact group again --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5bc70d82..4e304b33 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,7 @@ provided - org.bstats.bStats-Metrics + org.bstats bstats-bukkit From ab7c8ffbb2a8df512e213c2eadcbe03d90cf6915 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 13 Nov 2018 23:51:35 +0100 Subject: [PATCH 163/399] Fix key limit issues with some mysql versions Fixes #728 --- src/main/java/de/diddiz/LogBlock/Updater.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index be9f6f2b..35bb9188 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -720,8 +720,8 @@ boolean update() { if (isLogging(Logging.CHAT)) { checkCharset("lb-chat", "message", st, true); } - createIndexIfDoesNotExist("lb-materials", "name", "UNIQUE KEY `name` (`name`(250))", st, true); - createIndexIfDoesNotExist("lb-blockstates", "name", "UNIQUE KEY `name` (`name`(250))", st, true); + createIndexIfDoesNotExist("lb-materials", "name", "UNIQUE KEY `name` (`name`(150))", st, true); + createIndexIfDoesNotExist("lb-blockstates", "name", "UNIQUE KEY `name` (`name`(150))", st, true); st.close(); conn.close(); From 7e47a0c375300d58a50515207975a5a552799f96 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 24 Nov 2018 03:34:09 +0100 Subject: [PATCH 164/399] Skip duplicate rows instead of canceling the conversion --- src/main/java/de/diddiz/LogBlock/Updater.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 35bb9188..d7db9855 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -488,12 +488,21 @@ boolean update() { done++; } entries.close(); + int failedRows = 0; if (hadRow) { - insertStatement.executeBatch(); + try { + insertStatement.executeBatch(); + } catch (BatchUpdateException e) { + for (int result : e.getUpdateCounts()) { + if (result == Statement.EXECUTE_FAILED) { + failedRows++; + } + } + } deleteStatement.executeBatch(); } conn.commit(); - logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " " + (failedRows > 0 ? "Duplicates: " + failedRows + " " : "") + "(" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); } insertStatement.close(); deleteStatement.close(); From d847908d3c5ea21b2b1d1756a7d25dbb317b70f5 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 24 Nov 2018 03:39:05 +0100 Subject: [PATCH 165/399] Skip duplicates for chest/sign conversion too --- src/main/java/de/diddiz/LogBlock/Updater.java | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index d7db9855..b3ba8b0e 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -552,10 +552,19 @@ boolean update() { if (!anyRow) { break; } - insertChestData.executeBatch(); + int failedRows = 0; + try { + insertChestData.executeBatch(); + } catch (BatchUpdateException e) { + for (int result : e.getUpdateCounts()) { + if (result == Statement.EXECUTE_FAILED) { + failedRows++; + } + } + } deleteChest.executeBatch(); conn.commit(); - logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " " + (failedRows > 0 ? "Duplicates: " + failedRows + " " : "") + "(" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); } insertChestData.close(); deleteChest.close(); @@ -693,10 +702,19 @@ boolean update() { if (!anyRow) { break; } - insertSignState.executeBatch(); + int failedRows = 0; + try { + insertSignState.executeBatch(); + } catch (BatchUpdateException e) { + for (int result : e.getUpdateCounts()) { + if (result == Statement.EXECUTE_FAILED) { + failedRows++; + } + } + } deleteSign.executeBatch(); conn.commit(); - logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " " + (failedRows > 0 ? "Duplicates: " + failedRows + " " : "") + "(" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); } insertSignState.close(); deleteSign.close(); From ab464e1dd527062b23285c9ca7924af252c1dca0 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 26 Nov 2018 06:20:02 +0100 Subject: [PATCH 166/399] Use long instead of int to avoid overflow in converter --- src/main/java/de/diddiz/LogBlock/Updater.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index b3ba8b0e..df121473 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -427,12 +427,12 @@ boolean update() { logblock.getLogger().info("Processing world " + wcfg.world + "..."); logblock.getLogger().info("Processing block changes..."); boolean hadRow = true; - int rowsToConvert = 0; - int done = 0; + long rowsToConvert = 0; + long done = 0; try { ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "`"); if (rs.next()) { - rowsToConvert = rs.getInt(1); + rowsToConvert = rs.getLong(1); logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table); } rs.close(); @@ -516,7 +516,7 @@ boolean update() { try { ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-chest`"); if (rs.next()) { - rowsToConvert = rs.getInt(1); + rowsToConvert = rs.getLong(1); logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-chest"); } rs.close(); @@ -579,7 +579,7 @@ boolean update() { try { ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-kills`"); if (rs.next()) { - rowsToConvert = rs.getInt(1); + rowsToConvert = rs.getLong(1); logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-kills"); } rs.close(); @@ -656,12 +656,12 @@ boolean update() { rsCol.close(); conn.commit(); if (wcfg.isLogging(Logging.SIGNTEXT)) { - int rowsToConvert = 0; - int done = 0; + long rowsToConvert = 0; + long done = 0; try { ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-sign`"); if (rs.next()) { - rowsToConvert = rs.getInt(1); + rowsToConvert = rs.getLong(1); logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-sign"); } rs.close(); From d5ee15ebbad11d0764c6103bd0cb9e147a6227fd Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 27 Nov 2018 06:05:00 +0100 Subject: [PATCH 167/399] Improve stability for material table updates --- .../diddiz/LogBlock/EntityTypeConverter.java | 25 +++++++++++-- .../de/diddiz/LogBlock/MaterialConverter.java | 35 ++++++++++++++++--- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java b/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java index 83e8c1b5..b55c6e51 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java +++ b/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java @@ -18,7 +18,9 @@ public class EntityTypeConverter { public static int getOrAddEntityTypeId(EntityType entityType) { Integer key = entityTypeToId.get(entityType); - while (key == null) { + int tries = 0; + while (key == null && tries < 10) { + tries++; key = nextEntityTypeId; Connection conn = LogBlock.getInstance().getConnection(); try { @@ -34,8 +36,12 @@ public static int getOrAddEntityTypeId(EntityType entityType) { } else { initializeEntityTypes(conn); } - } catch (SQLException e) { + } catch (Exception e) { LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not update lb-entitytypes", e); + reinitializeEntityTypesCatchException(); + if (tries == 10) { + throw new RuntimeException(e); + } } finally { try { conn.close(); @@ -52,6 +58,21 @@ public static EntityType getEntityType(int entityTypeId) { return idToEntityType[entityTypeId]; } + private static void reinitializeEntityTypesCatchException() { + Connection conn = LogBlock.getInstance().getConnection(); + try { + initializeEntityTypes(conn); + } catch (Exception e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not reinitialize lb-entitytypes", e); + } finally { + try { + conn.close(); + } catch (Exception e) { + // ignored + } + } + } + public static void initializeEntityTypes(Connection connection) throws SQLException { Statement smt = connection.createStatement(); ResultSet rs = smt.executeQuery("SELECT id, name FROM `lb-entitytypes`"); diff --git a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java index ff89953a..8babf3dd 100644 --- a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java +++ b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java @@ -42,7 +42,9 @@ public static int getOrAddMaterialId(String blockDataString) { materialString = blockDataString.substring(0, dataPart); } Integer key = materialToID.get(materialString); - while (key == null) { + int tries = 0; + while (key == null && tries < 10) { + tries++; key = nextMaterialId; Connection conn = LogBlock.getInstance().getConnection(); try { @@ -58,8 +60,12 @@ public static int getOrAddMaterialId(String blockDataString) { } else { initializeMaterials(conn); } - } catch (SQLException e) { + } catch (Exception e) { LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not update lb-materials", e); + reinitializeMaterialsCatchException(); + if (tries == 10) { + throw new RuntimeException(e); + } } finally { try { conn.close(); @@ -79,7 +85,9 @@ public static int getOrAddBlockStateId(String blockDataString) { } String materialString = blockDataString.substring(dataPart); Integer key = blockStateToID.get(materialString); - while (key == null) { + int tries = 0; + while (key == null && tries < 10) { + tries++; key = nextBlockStateId; Connection conn = LogBlock.getInstance().getConnection(); try { @@ -95,8 +103,12 @@ public static int getOrAddBlockStateId(String blockDataString) { } else { initializeMaterials(conn); } - } catch (SQLException e) { + } catch (Exception e) { LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not update lb-blockstates", e); + reinitializeMaterialsCatchException(); + if (tries == 10) { + throw new RuntimeException(e); + } } finally { try { conn.close(); @@ -121,6 +133,21 @@ public static Material getMaterial(int materialId) { return materialKeyToMaterial.get(idToMaterial[materialId]); } + private static void reinitializeMaterialsCatchException() { + Connection conn = LogBlock.getInstance().getConnection(); + try { + initializeMaterials(conn); + } catch (Exception e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not reinitialize lb-materials", e); + } finally { + try { + conn.close(); + } catch (Exception e) { + // ignored + } + } + } + public static void initializeMaterials(Connection connection) throws SQLException { Statement smt = connection.createStatement(); ResultSet rs = smt.executeQuery("SELECT id, name FROM `lb-materials`"); From 71527530f2951cac08f7f3e96952be6338a8c3e3 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 27 Nov 2018 06:15:36 +0100 Subject: [PATCH 168/399] Reduce converter max batch size Some popular hosters have quite low memory limits.. Fixes #730 --- src/main/java/de/diddiz/LogBlock/Updater.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index df121473..73115749 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -32,7 +32,8 @@ class Updater { private final LogBlock logblock; final int UUID_CONVERT_BATCH_SIZE = 100; - final int BLOCKS_CONVERT_BATCH_SIZE = 200000; + final int BLOCKS_CONVERT_BATCH_SIZE = 100000; + final int OTHER_CONVERT_BATCH_SIZE = 20000; Updater(LogBlock logblock) { this.logblock = logblock; @@ -524,7 +525,7 @@ boolean update() { PreparedStatement insertChestData = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-chestdata` (id, item, itemremove, itemtype) VALUES (?, ?, ?, ?)"); PreparedStatement deleteChest = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-chest` WHERE id = ?"); while (true) { - rs = st.executeQuery("SELECT id, itemtype, itemamount, itemdata FROM `" + wcfg.table + "-chest` ORDER BY id ASC LIMIT " + BLOCKS_CONVERT_BATCH_SIZE); + rs = st.executeQuery("SELECT id, itemtype, itemamount, itemdata FROM `" + wcfg.table + "-chest` ORDER BY id ASC LIMIT " + OTHER_CONVERT_BATCH_SIZE); boolean anyRow = false; while (rs.next()) { anyRow = true; @@ -585,8 +586,8 @@ boolean update() { rs.close(); PreparedStatement updateWeaponStatement = conn.prepareStatement("UPDATE `" + wcfg.table + "-kills` SET weapon = ? WHERE id = ?"); - for (int start = 0;; start += BLOCKS_CONVERT_BATCH_SIZE) { - rs = st.executeQuery("SELECT id, weapon FROM `" + wcfg.table + "-kills` ORDER BY id ASC LIMIT " + start + "," + BLOCKS_CONVERT_BATCH_SIZE); + for (int start = 0;; start += OTHER_CONVERT_BATCH_SIZE) { + rs = st.executeQuery("SELECT id, weapon FROM `" + wcfg.table + "-kills` ORDER BY id ASC LIMIT " + start + "," + OTHER_CONVERT_BATCH_SIZE); boolean anyUpdate = false; boolean anyRow = false; while (rs.next()) { @@ -669,7 +670,7 @@ boolean update() { PreparedStatement insertSignState = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-state` (id, replacedState, typeState) VALUES (?, ?, ?)"); PreparedStatement deleteSign = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-sign` WHERE id = ?"); while (true) { - rs = st.executeQuery("SELECT id, signtext, replaced, type FROM `" + wcfg.table + "-sign` LEFT JOIN `" + wcfg.table + "-blocks` USING (id) ORDER BY id ASC LIMIT " + BLOCKS_CONVERT_BATCH_SIZE); + rs = st.executeQuery("SELECT id, signtext, replaced, type FROM `" + wcfg.table + "-sign` LEFT JOIN `" + wcfg.table + "-blocks` USING (id) ORDER BY id ASC LIMIT " + OTHER_CONVERT_BATCH_SIZE); boolean anyRow = false; while (rs.next()) { anyRow = true; From 9f8fd3e1caca1eb866c196809820fd8b367c488c Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 8 Dec 2018 18:04:36 +0100 Subject: [PATCH 169/399] Use constants for magic values --- src/main/java/de/diddiz/LogBlock/Consumer.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index c5e40f04..d0f1b32c 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -54,6 +54,10 @@ import de.diddiz.util.Utils; public class Consumer extends Thread { + private static final int MAX_SHUTDOWN_TIME_MILLIS = 20000; + private static final int WAIT_FOR_CONNECTION_TIME_MILLIS = 10000; + private static final int RETRIES_ON_UNKNOWN_CONNECTION_ERROR = 2; + private final Deque queue = new ArrayDeque(); private final LogBlock logblock; private final Map playerIds = new HashMap<>(); @@ -448,7 +452,7 @@ public void run() { // wait for a connection logblock.getLogger().severe("[Consumer] Could not connect to the database!"); try { - Thread.sleep(10000); + Thread.sleep(WAIT_FOR_CONNECTION_TIME_MILLIS); } catch (InterruptedException e) { // ignore } @@ -460,7 +464,7 @@ public void run() { synchronized (queue) { if (shutdown) { // Give this thread some time to process the remaining entries - if (queue.isEmpty() || System.currentTimeMillis() - shutdownInitialized > 20000) { + if (queue.isEmpty() || System.currentTimeMillis() - shutdownInitialized > MAX_SHUTDOWN_TIME_MILLIS) { if (currentRows.isEmpty()) { break; } else { @@ -505,7 +509,7 @@ public void run() { lastCommitsFailed = 0; } } catch (Exception e) { - boolean retry = lastCommitsFailed < 2; + boolean retry = lastCommitsFailed < RETRIES_ON_UNKNOWN_CONNECTION_ERROR; String state = "unknown"; if (e instanceof SQLException) { // Retry on network errors: SQLSTATE = 08S01 08001 08004 HY000 40001 From 31ef2d942b2162dd606bfd603f7af784aece3b3a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 11 Dec 2018 05:11:13 +0100 Subject: [PATCH 170/399] Return idle connection from Consumer to avoid timeout Fixes #732 --- src/main/java/de/diddiz/LogBlock/Consumer.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index d0f1b32c..afa3fe89 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -56,6 +56,7 @@ public class Consumer extends Thread { private static final int MAX_SHUTDOWN_TIME_MILLIS = 20000; private static final int WAIT_FOR_CONNECTION_TIME_MILLIS = 10000; + private static final int RETURN_IDLE_CONNECTION_TIME_MILLIS = 120000; private static final int RETRIES_ON_UNKNOWN_CONNECTION_ERROR = 2; private final Deque queue = new ArrayDeque(); @@ -434,7 +435,6 @@ public void run() { try { if (conn == null) { batchHelper.reset(); - logblock.getLogger().info("[Consumer] Connecting to the database!"); conn = logblock.getConnection(); if (conn != null) { // initialize connection @@ -476,7 +476,19 @@ public void run() { if (r == null) { try { if (currentRows.isEmpty() && !shutdown) { - queue.wait(); // nothing to do for us + // nothing to do for us + // wait some time before closing the connection + queue.wait(RETURN_IDLE_CONNECTION_TIME_MILLIS); + // if there is still nothing to do, close the connection and go to sleep + if (queue.isEmpty() && !shutdown) { + try { + conn.close(); + } catch (Exception e) { + // ignored + } + conn = null; + queue.wait(); + } } else { processBatch = true; } @@ -499,7 +511,7 @@ public void run() { r.process(conn, batchHelper); } } - if (currentRows.size() >= (processBatch ? 1 : (Config.forceToProcessAtLeast * 10))) { + if (currentRows.size() >= Math.max((processBatch ? 1 : (Config.forceToProcessAtLeast * 10)), 1)) { batchHelper.processStatements(conn); conn.commit(); currentRows.clear(); From 51f84251dc0b58234db11693c5edfcd65e1ff234 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 4 Jan 2019 18:09:12 +0100 Subject: [PATCH 171/399] Adapt to latest WorldEdit changes --- src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java index ac53acf6..dd0c4ebc 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java @@ -70,12 +70,12 @@ public void wrapForLogging(final EditSessionEvent event) { event.setExtent(new AbstractDelegateExtent(event.getExtent()) { @Override - public final boolean setBlock(BlockVector3 position, @SuppressWarnings("rawtypes") BlockStateHolder block) throws WorldEditException { + public final > boolean setBlock(BlockVector3 position, B block) throws WorldEditException { onBlockChange(position, block); return super.setBlock(position, block); } - protected void onBlockChange(BlockVector3 pt, BlockStateHolder block) { + protected > void onBlockChange(BlockVector3 pt, B block) { if (event.getStage() != EditSession.Stage.BEFORE_CHANGE) { return; From 58223b76129462f7fc5643043f7a9fde5e8e73fb Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 4 Jan 2019 18:10:11 +0100 Subject: [PATCH 172/399] Fix startup exception when running without WorldEdit Fixes #736 --- src/main/java/de/diddiz/worldedit/WorldEditHelper.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java b/src/main/java/de/diddiz/worldedit/WorldEditHelper.java index 5d7b9ecd..2df370da 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditHelper.java @@ -39,7 +39,9 @@ public static boolean hasWorldEdit() { checkedForWorldEdit = true; Plugin worldEdit = Bukkit.getPluginManager().getPlugin("WorldEdit"); hasWorldEdit = worldEdit != null; - Internal.setWorldEdit(worldEdit); + if (worldEdit != null) { + Internal.setWorldEdit(worldEdit); + } } return hasWorldEdit; } From 2e81e2be9d65e4f183fe4250205170529891c38b Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 5 Jan 2019 17:16:18 +0100 Subject: [PATCH 173/399] Catch failed ItemStack serialization This will still not serialize the problematic ItemStacks, at that is not in the scope of logblock, but it will avoid problems with logging is this problem occurs. Fixes #735 --- .../java/de/diddiz/LogBlock/Consumer.java | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index afa3fe89..34ed53d1 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -832,7 +832,13 @@ public String[] getInserts() { if (replacedState != null || typeState != null) { inserts[1] = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(" + Utils.mysqlPrepareBytesForInsertAllowNull(replacedState) + ", " + Utils.mysqlPrepareBytesForInsertAllowNull(typeState) + ", LAST_INSERT_ID());"; } else if (ca != null) { - inserts[1] = "INSERT INTO `" + table + "-chestdata` (id, item, itemremove, itemtype) values (LAST_INSERT_ID(), '" + Utils.mysqlEscapeBytes(Utils.saveItemStack(ca.itemStack)) + "', " + (ca.remove ? 1 : 0) + ", " + ca.itemType + ");"; + try { + inserts[1] = "INSERT INTO `" + table + "-chestdata` (id, item, itemremove, itemtype) values (LAST_INSERT_ID(), '" + Utils.mysqlEscapeBytes(Utils.saveItemStack(ca.itemStack)) + "', " + (ca.remove ? 1 : 0) + ", " + ca.itemType + ");"; + } catch (Exception e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not serialize ItemStack " + e.getMessage(), e); + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Problematic row: " + toString()); + return new String[0]; + } } return inserts; } @@ -844,9 +850,20 @@ public Actor[] getActors() { @Override public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + byte[] serializedItemStack = null; + if (ca != null) { + try { + serializedItemStack = Utils.saveItemStack(ca.itemStack); + } catch (Exception e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not serialize ItemStack " + e.getMessage(), e); + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Problematic row: " + toString()); + return; + } + } + final byte[] finalSerializedItemStack = serializedItemStack; int sourceActor = playerIDAsIntIncludeUncommited(actor); Location actorBlockLocation = actor.getBlockLocation(); - if(actorBlockLocation != null) { + if (actorBlockLocation != null) { Integer tempSourceActor = batchHelper.getUncommitedBlockActor(actorBlockLocation); if(tempSourceActor != null) { sourceActor = tempSourceActor; @@ -886,7 +903,7 @@ public void call(int id) throws SQLException { } if (ca != null) { ps = batchHelper.getOrPrepareStatement(conn, getWorldConfig(loc.getWorld()).insertBlockChestDataStatementString, Statement.NO_GENERATED_KEYS); - ps.setBytes(1, Utils.saveItemStack(ca.itemStack)); + ps.setBytes(1, finalSerializedItemStack); ps.setInt(2, ca.remove ? 1 : 0); ps.setInt(3, id); ps.setInt(4, ca.itemType); From 947163477bb68d0f76d881cb048eab752c920081 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 8 Jan 2019 16:38:26 +0100 Subject: [PATCH 174/399] Do not go over the maximum level for fluids --- .../java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index 18808fcf..f6fce53c 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -53,7 +53,7 @@ public void onBlockFromTo(BlockFromToEvent event) { consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData()); } else { Levelled newBlock = (Levelled) blockDataFrom.clone(); - newBlock.setLevel(levelledFrom.getLevel() + 1); + newBlock.setLevel(Math.min(levelledFrom.getMaximumLevel(), levelledFrom.getLevel() + 1)); if (BukkitUtils.isEmpty(typeTo)) { consumer.queueBlockPlace(new Actor("LavaFlow", source), to.getLocation(), newBlock); } else { @@ -70,7 +70,7 @@ public void onBlockFromTo(BlockFromToEvent event) { } else if ((typeFrom == Material.WATER) && wcfg.isLogging(Logging.WATERFLOW)) { Levelled levelledFrom = fromWaterlogged ? null : (Levelled) blockDataFrom; Levelled newBlock = (Levelled) Material.WATER.createBlockData(); - newBlock.setLevel(fromWaterlogged ? 1 : levelledFrom.getLevel() + 1); + newBlock.setLevel(fromWaterlogged ? 1 : Math.min(levelledFrom.getMaximumLevel(), levelledFrom.getLevel() + 1)); if (BukkitUtils.isEmpty(typeTo)) { consumer.queueBlockPlace(new Actor("WaterFlow", source), to.getLocation(), newBlock); } else if (BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { From dc62524d0d66bd7f9c8a1561d2f893baaa66dd9f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 9 Jan 2019 03:58:12 +0100 Subject: [PATCH 175/399] Fix logging fluids flowing down --- .../de/diddiz/LogBlock/listeners/FluidFlowLogging.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index f6fce53c..89cd1f06 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -45,6 +45,7 @@ public void onBlockFromTo(BlockFromToEvent event) { Block source = Config.logFluidFlowAsPlayerWhoTriggeredIt ? event.getBlock() : null; final Block to = event.getToBlock(); final Material typeTo = to.getType(); + boolean down = event.getFace() == BlockFace.DOWN; final boolean canFlow = BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo); if (typeFrom == Material.LAVA && wcfg.isLogging(Logging.LAVAFLOW)) { Levelled levelledFrom = (Levelled) blockDataFrom; @@ -53,7 +54,7 @@ public void onBlockFromTo(BlockFromToEvent event) { consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData()); } else { Levelled newBlock = (Levelled) blockDataFrom.clone(); - newBlock.setLevel(Math.min(levelledFrom.getMaximumLevel(), levelledFrom.getLevel() + 1)); + newBlock.setLevel(down ? 1 : levelledFrom.getLevel() + 1); if (BukkitUtils.isEmpty(typeTo)) { consumer.queueBlockPlace(new Actor("LavaFlow", source), to.getLocation(), newBlock); } else { @@ -61,7 +62,7 @@ public void onBlockFromTo(BlockFromToEvent event) { } } } else if (typeTo == Material.WATER) { - if (event.getFace() == BlockFace.DOWN) { + if (down) { consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.STONE.createBlockData()); } else { consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData()); @@ -70,7 +71,7 @@ public void onBlockFromTo(BlockFromToEvent event) { } else if ((typeFrom == Material.WATER) && wcfg.isLogging(Logging.WATERFLOW)) { Levelled levelledFrom = fromWaterlogged ? null : (Levelled) blockDataFrom; Levelled newBlock = (Levelled) Material.WATER.createBlockData(); - newBlock.setLevel(fromWaterlogged ? 1 : Math.min(levelledFrom.getMaximumLevel(), levelledFrom.getLevel() + 1)); + newBlock.setLevel(fromWaterlogged || down ? 1 : levelledFrom.getLevel() + 1); if (BukkitUtils.isEmpty(typeTo)) { consumer.queueBlockPlace(new Actor("WaterFlow", source), to.getLocation(), newBlock); } else if (BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { From 025950a8c4f93438776146728dadb11c54ab2f55 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 14 Jan 2019 03:29:07 +0100 Subject: [PATCH 176/399] Fix armor stand logging on kill in survival mode --- .../listeners/AdvancedEntityLogging.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index 7b56a97d..d4d2c187 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -34,10 +34,12 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.EntityChange; +import de.diddiz.LogBlock.EntityChange.EntityChangeType; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.EntityLogging; import de.diddiz.worldedit.WorldEditHelper; +import java.util.UUID; public class AdvancedEntityLogging extends LoggingListener { @@ -45,20 +47,26 @@ public class AdvancedEntityLogging extends LoggingListener { private Class lastSpawning; private boolean lastSpawnerEgg; + // serialize them before the death event + private UUID lastEntityDamagedForDeathUUID; + private byte[] lastEntityDamagedForDeathSerialized; + public AdvancedEntityLogging(LogBlock lb) { super(lb); new BukkitRunnable() { @Override public void run() { - resetLastSpawner(); + resetOnTick(); } }.runTaskTimer(lb, 1, 1); } - private void resetLastSpawner() { + private void resetOnTick() { lastSpawner = null; lastSpawning = null; lastSpawnerEgg = false; + lastEntityDamagedForDeathUUID = null; + lastEntityDamagedForDeathSerialized = null; } private void setLastSpawner(Player player, Class spawning, boolean spawnEgg) { @@ -145,7 +153,7 @@ public void onEntitySpawn(CreatureSpawnEvent event) { queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE); } } - resetLastSpawner(); + resetOnTick(); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -205,6 +213,10 @@ public void onEntityDamage(EntityDamageEvent event) { } } } + if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) { + lastEntityDamagedForDeathUUID = entity.getUniqueId(); + lastEntityDamagedForDeathSerialized = WorldEditHelper.serializeEntity(entity); + } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -242,7 +254,11 @@ protected void queueEntitySpawnOrKill(Entity entity, Actor actor, EntityChange.E data.set("z", location.getZ()); data.set("yaw", location.getYaw()); data.set("pitch", location.getPitch()); - data.set("worldedit", WorldEditHelper.serializeEntity(entity)); + if (changeType == EntityChangeType.KILL && entity.getUniqueId().equals(lastEntityDamagedForDeathUUID)) { + data.set("worldedit", lastEntityDamagedForDeathSerialized); + } else { + data.set("worldedit", WorldEditHelper.serializeEntity(entity)); + } consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), location, changeType, data); } } From 92de737e4e6d556ba5d1d3d06c216729a4e2e369 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 14 Feb 2019 21:24:09 +0100 Subject: [PATCH 177/399] Allow null weapons for kills Fixes #742 --- src/main/java/de/diddiz/LogBlock/Consumer.java | 3 ++- src/main/java/de/diddiz/LogBlock/Kill.java | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 34ed53d1..aa17ff90 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -280,7 +280,8 @@ public void queueKill(Entity killer, Entity victim) { weapon = ((Player) killer).getInventory().getItemInMainHand(); } if (killer instanceof Projectile) { - weapon = new ItemStack(itemIDfromProjectileEntity(killer)); + Material projectileMaterial = itemIDfromProjectileEntity(killer); + weapon = projectileMaterial == null ? null : new ItemStack(projectileMaterial); ProjectileSource ps = ((Projectile) killer).getShooter(); if (ps == null) { killerActor = Actor.actorFromEntity(killer); diff --git a/src/main/java/de/diddiz/LogBlock/Kill.java b/src/main/java/de/diddiz/LogBlock/Kill.java index 819d32bc..fc08156a 100755 --- a/src/main/java/de/diddiz/LogBlock/Kill.java +++ b/src/main/java/de/diddiz/LogBlock/Kill.java @@ -43,8 +43,10 @@ public String toString() { if (loc != null) { msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ()); } - String weaponName = prettyItemName(MaterialConverter.getMaterial(weapon)); - msg.append(" with " + weaponName); // + ("aeiou".contains(weaponName.substring(0, 1)) ? "an " : "a " ) + if (weapon != 0) { + String weaponName = prettyItemName(MaterialConverter.getMaterial(weapon)); + msg.append(" with " + weaponName); // + ("aeiou".contains(weaponName.substring(0, 1)) ? "an " : "a " ) + } return msg.toString(); } From 7dce1776e7e529bab436a3831931245d84034390 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 18 Feb 2019 21:15:42 +0100 Subject: [PATCH 178/399] Log pumpkin carving Fixes #743 --- .../java/de/diddiz/LogBlock/LogBlock.java | 3 +- .../LogBlock/listeners/InteractLogging.java | 28 ++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 34493e91..5f6afb64 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -161,7 +161,8 @@ private void registerEvents() { if (isLogging(Logging.CHESTACCESS)) { pm.registerEvents(new ChestAccessLogging(this), this); } - if (isLogging(Logging.SWITCHINTERACT) || isLogging(Logging.DOORINTERACT) || isLogging(Logging.CAKEEAT) || isLogging(Logging.DIODEINTERACT) || isLogging(Logging.COMPARATORINTERACT) || isLogging(Logging.NOTEBLOCKINTERACT) || isLogging(Logging.PRESUREPLATEINTERACT) || isLogging(Logging.TRIPWIREINTERACT) || isLogging(Logging.CROPTRAMPLE)) { + if (isLogging(Logging.BLOCKBREAK) || isLogging(Logging.BLOCKPLACE) || isLogging(Logging.SWITCHINTERACT) || isLogging(Logging.DOORINTERACT) || isLogging(Logging.CAKEEAT) || isLogging(Logging.DIODEINTERACT) || isLogging(Logging.COMPARATORINTERACT) || isLogging(Logging.NOTEBLOCKINTERACT) + || isLogging(Logging.PRESUREPLATEINTERACT) || isLogging(Logging.TRIPWIREINTERACT) || isLogging(Logging.CROPTRAMPLE)) { pm.registerEvents(new InteractLogging(this), this); } if (isLogging(Logging.CREATURECROPTRAMPLE)) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index 8de3a235..a93569b9 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -12,6 +12,7 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Directional; import org.bukkit.block.data.Openable; import org.bukkit.block.data.type.Cake; import org.bukkit.block.data.type.Comparator; @@ -27,6 +28,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; import static de.diddiz.LogBlock.config.Config.getWorldConfig; @@ -140,7 +142,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { } break; case TURTLE_EGG: - if (event.getAction() == Action.PHYSICAL) { + if (wcfg.isLogging(Logging.BLOCKBREAK) && event.getAction() == Action.PHYSICAL) { TurtleEgg turtleEggData = (TurtleEgg) blockData; int eggs = turtleEggData.getEggs(); if (eggs > 1) { @@ -152,6 +154,30 @@ public void onPlayerInteract(PlayerInteractEvent event) { } } break; + case PUMPKIN: + if ((wcfg.isLogging(Logging.BLOCKBREAK) || wcfg.isLogging(Logging.BLOCKPLACE)) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + ItemStack inHand = event.getItem(); + if (inHand.getType() == Material.SHEARS) { + BlockFace clickedFace = event.getBlockFace(); + Directional newBlockData = (Directional) Material.CARVED_PUMPKIN.createBlockData(); + if (clickedFace == BlockFace.NORTH || clickedFace == BlockFace.SOUTH || clickedFace == BlockFace.EAST || clickedFace == BlockFace.WEST) { + newBlockData.setFacing(clickedFace); + } else { + // use player distance to calculate the facing + Location playerLoc = player.getLocation(); + playerLoc.subtract(0.5, 0, 0.5); + double dx = playerLoc.getX() - loc.getX(); + double dz = playerLoc.getZ() - loc.getZ(); + if (Math.abs(dx) > Math.abs(dz)) { + newBlockData.setFacing(dx > 0 ? BlockFace.EAST : BlockFace.WEST); + } else { + newBlockData.setFacing(dz > 0 ? BlockFace.SOUTH : BlockFace.NORTH); + } + } + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } + break; default: if (BukkitUtils.isButton(type) || type == Material.LEVER) { if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { From 399cbc901f7a390d8edaca9b52e5d6cfa6265b99 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 18 Feb 2019 21:50:01 +0100 Subject: [PATCH 179/399] Null check --- src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index a93569b9..b89656a3 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -157,7 +157,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { case PUMPKIN: if ((wcfg.isLogging(Logging.BLOCKBREAK) || wcfg.isLogging(Logging.BLOCKPLACE)) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { ItemStack inHand = event.getItem(); - if (inHand.getType() == Material.SHEARS) { + if (inHand != null && inHand.getType() == Material.SHEARS) { BlockFace clickedFace = event.getBlockFace(); Directional newBlockData = (Directional) Material.CARVED_PUMPKIN.createBlockData(); if (clickedFace == BlockFace.NORTH || clickedFace == BlockFace.SOUTH || clickedFace == BlockFace.EAST || clickedFace == BlockFace.WEST) { From 34eeb52c8db334518f8b8d2d468caaf04be07f8c Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 22 Feb 2019 04:13:36 +0100 Subject: [PATCH 180/399] Use EnumSet instead of boolean array --- src/main/java/de/diddiz/LogBlock/config/Config.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index c054383b..a23961df 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -341,13 +341,17 @@ public static boolean isLoggingAnyEntities() { } class LoggingEnabledMapping { - private final boolean[] logging = new boolean[Logging.length]; + private final EnumSet logging = EnumSet.noneOf(Logging.class); public void setLogging(Logging l, boolean enabled) { - logging[l.ordinal()] = enabled; + if (enabled) { + logging.add(l); + } else { + logging.remove(l); + } } public boolean isLogging(Logging l) { - return logging[l.ordinal()]; + return logging.contains(l); } } From 8b1ee254b40a010490e51b24f909a316686f6744 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 23 Feb 2019 18:17:14 +0100 Subject: [PATCH 181/399] Fix NPE when entities die without a damager Fixes #745 --- .../LogBlock/listeners/AdvancedEntityLogging.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index d4d2c187..baa1cb4c 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -160,12 +160,16 @@ public void onEntitySpawn(CreatureSpawnEvent event) { public void onEntityDeath(EntityDeathEvent event) { LivingEntity entity = event.getEntity(); if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) { - Actor actor; + Actor actor = null; EntityDamageEvent lastDamage = entity.getLastDamageCause(); if (lastDamage instanceof EntityDamageByEntityEvent) { - actor = Actor.actorFromEntity(((EntityDamageByEntityEvent) lastDamage).getDamager()); - } else { - actor = new Actor(lastDamage.getCause().toString()); + Entity damager = ((EntityDamageByEntityEvent) lastDamage).getDamager(); + if (damager != null) { + actor = Actor.actorFromEntity(damager); + } + } + if (actor == null) { + actor = new Actor(lastDamage == null ? "UNKNOWN" : lastDamage.getCause().toString()); } queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); } From 87c09766d31f9450eff07b77e46ab5aea0031a56 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 6 Mar 2019 04:23:19 +0100 Subject: [PATCH 182/399] Allow tool use when the interact event is cancelled --- src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java index ed2239dd..9c680e75 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java @@ -31,7 +31,7 @@ public ToolListener(LogBlock logblock) { handler = logblock.getCommandsHandler(); } - @EventHandler(ignoreCancelled = true) + @EventHandler public void onPlayerInteract(PlayerInteractEvent event) { if (event.getMaterial() != null) { final Action action = event.getAction(); From d4b127244e95e617b488bc18f8ec71df108d62df Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 21 Mar 2019 01:44:33 +0100 Subject: [PATCH 183/399] Disable tool on drop: Only cancel dropping if there is space for that item --- .../LogBlock/listeners/ToolListener.java | 6 +- src/main/java/de/diddiz/util/BukkitUtils.java | 64 +++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java index 9c680e75..342eb39f 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java @@ -116,8 +116,8 @@ public void onPlayerDropItem(PlayerDropItemEvent event) { if (item == tool.item && toolData.enabled) { if (tool.dropToDisable) { toolData.enabled = false; + ItemStack stack = event.getItemDrop().getItemStack(); if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) { - ItemStack stack = event.getItemDrop().getItemStack(); if (stack.isSimilar(new ItemStack(item))) { if (stack.getAmount() > 1) { stack.setAmount(stack.getAmount() - 1); @@ -127,7 +127,9 @@ public void onPlayerDropItem(PlayerDropItemEvent event) { } } } - event.setCancelled(true); + if (BukkitUtils.hasInventoryStorageSpaceFor(player.getInventory(), stack)) { + event.setCancelled(true); + } player.sendMessage(ChatColor.GREEN + "Tool disabled."); } else if (!tool.canDrop) { player.sendMessage(ChatColor.RED + "You cannot drop this tool."); diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 5cf05aa5..baebf319 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -829,4 +829,68 @@ public static void setItemInSlot(ArmorStand stand, EquipmentSlot slot, ItemStack stand.getEquipment().setHelmet(stack); } } + + public static ItemStack[] deepCopy(ItemStack[] of) { + ItemStack[] result = new ItemStack[of.length]; + for (int i = 0; i < result.length; i++) { + result[i] = of[i] == null ? null : new ItemStack(of[i]); + } + return result; + } + + private static int getFirstPartialItemStack(ItemStack item, ItemStack[] contents, int start) { + for (int i = start; i < contents.length; i++) { + ItemStack content = contents[i]; + if (content != null && content.isSimilar(item) && content.getAmount() < content.getMaxStackSize()) { + return i; + } + } + return -1; + } + + private static int getFirstFreeItemStack(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; + } + + public static boolean hasInventoryStorageSpaceFor(Inventory inv, ItemStack... items) { + ItemStack[] contents = deepCopy(inv.getStorageContents()); + for (ItemStack item : items) { + if (item != null && item.getType() != Material.AIR) { + int remaining = item.getAmount(); + // fill partial stacks + int firstPartial = -1; + while (remaining > 0) { + firstPartial = getFirstPartialItemStack(item, contents, firstPartial + 1); + if (firstPartial < 0) { + break; + } + ItemStack content = contents[firstPartial]; + int add = Math.min(content.getMaxStackSize() - content.getAmount(), remaining); + content.setAmount(content.getAmount() + add); + remaining -= add; + } + // create new stacks + int firstFree = -1; + while (remaining > 0) { + firstFree = getFirstFreeItemStack(contents, firstFree + 1); + if (firstFree < 0) { + return false; // no free place found + } + ItemStack content = new ItemStack(item); + contents[firstFree] = content; + // max stack size might return -1, in this case assume 1 + int add = Math.min(Math.max(content.getMaxStackSize(), 1), remaining); + content.setAmount(add); + remaining -= add; + } + } + } + return true; + } } From 254c856b2ffdde3f81070e3a29656ac5efe70367 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 24 Apr 2019 17:45:34 +0200 Subject: [PATCH 184/399] Update to 1.14pre5 --- pom.xml | 4 +- .../java/de/diddiz/LogBlock/BlockChange.java | 4 +- .../java/de/diddiz/LogBlock/Consumer.java | 47 +--------- .../java/de/diddiz/LogBlock/LogBlock.java | 1 + src/main/java/de/diddiz/LogBlock/Logging.java | 2 +- .../diddiz/LogBlock/SummedBlockChanges.java | 3 +- src/main/java/de/diddiz/LogBlock/Updater.java | 92 +++++++++++++++++-- .../blockstate/BlockStateCodecSign.java | 2 +- .../LogBlock/listeners/BlockBreakLogging.java | 5 +- .../LogBlock/listeners/ExplosionLogging.java | 9 +- .../LogBlock/listeners/SignChangeLogging.java | 2 +- src/main/java/de/diddiz/util/BukkitUtils.java | 28 +++++- .../de/diddiz/util/ComparableVersion.java | 10 ++ src/main/java/de/diddiz/util/LoggingUtil.java | 12 +-- src/main/resources/blockdata.txt | 52 +++++------ src/main/resources/itemdata.txt | 20 ++-- src/main/resources/plugin.yml | 2 +- 17 files changed, 175 insertions(+), 120 deletions(-) diff --git a/pom.xml b/pom.xml index 4e304b33..9664849c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.13.2-SNAPSHOT + 1.14-SNAPSHOT jar LogBlock @@ -42,7 +42,7 @@ org.spigotmc spigot-api - 1.13.2-R0.1-SNAPSHOT + 1.14-pre5-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index d7bb2351..cf5c3986 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -15,7 +15,9 @@ import org.bukkit.block.data.type.DaylightDetector; import org.bukkit.block.data.type.NoteBlock; 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; import java.sql.ResultSet; @@ -140,7 +142,7 @@ public String toString() { msg.append("stepped on ").append(type.getMaterial().name()); } else if (type.getMaterial() == Material.TRIPWIRE) { msg.append("ran into ").append(type.getMaterial().name()); - } else if (type.getMaterial() == Material.SIGN || type.getMaterial() == Material.WALL_SIGN) { + } else if (type instanceof Sign || type instanceof WallSign) { msg.append("edited a ").append(type.getMaterial().name()).append(" to ").append(typeDetails); } else { msg.append("replaced ").append(replaced.getMaterial().name()).append(replacedDetails).append(" with ").append(type.getMaterial().name()).append(typeDetails); diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index aa17ff90..59f0313c 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -34,8 +34,9 @@ import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.BlockState; -import org.bukkit.block.Sign; import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.Sign; +import org.bukkit.block.data.type.WallSign; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -325,34 +326,6 @@ public void queueKill(Location location, Actor killer, Actor victim, ItemStack w addQueueLast(new KillRow(location, killer == null ? null : killer, victim, weapon == null ? 0 : MaterialConverter.getOrAddMaterialId(weapon.getType().getKey().toString()))); } - /** - * Logs an actor breaking a sign along with its contents - * - * @param actor - * Actor responsible for breaking the sign - * @param loc - * Location of the broken sign - * @param type - * BlockData of the sign. - * @param typeState - * Serialized text data of the sign - */ - public void queueSignBreak(Actor actor, Location loc, BlockData type, YamlConfiguration typeState) { - queueBlock(actor, loc, type, null, typeState, null, null); - } - - /** - * Logs an actor breaking a sign along with its contents - * - * @param actor - * Actor responsible for breaking the sign - * @param sign - * The sign being broken - */ - public void queueSignBreak(Actor actor, Sign sign) { - queueSignBreak(actor, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getBlockData(), BlockStateCodecs.serialize(sign)); - } - /** * Logs an actor placing a sign along with its contents * @@ -365,25 +338,13 @@ public void queueSignBreak(Actor actor, Sign sign) { * @param lines * The four lines on the sign. */ - public void queueSignPlace(Actor actor, Location loc, BlockData type, String[] lines) { - if ((type.getMaterial() != Material.SIGN && type.getMaterial() != Material.WALL_SIGN) || lines == null || lines.length != 4) { + public void queueSignChange(Actor actor, Location loc, BlockData type, String[] lines) { + if ((!(type instanceof Sign) && !(type instanceof WallSign)) || lines == null || lines.length != 4) { return; } queueBlock(actor, loc, type, type, null, BlockStateCodecSign.serialize(lines), null); } - /** - * Logs an actor placing a sign along with its contents - * - * @param actor - * Actor placing the sign - * @param sign - * The palced sign object - */ - public void queueSignPlace(Actor actor, Sign sign) { - queueSignPlace(actor, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getBlockData(), sign.getLines()); - } - public void queueChat(Actor player, String message) { if (!Config.ignoredChat.isEmpty()) { String lowerCaseMessage = message.toLowerCase(); diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 5f6afb64..e06212a9 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -88,6 +88,7 @@ public void onEnable() { conn.close(); Updater updater = new Updater(this); updater.checkTables(); + updater.updateMaterialsPost1_13(); MaterialConverter.initializeMaterials(getConnection()); MaterialConverter.getOrAddMaterialId(Material.AIR.getKey()); // AIR must be the first entry EntityTypeConverter.initializeEntityTypes(getConnection()); diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index b18a5be3..683a53d8 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -1,7 +1,7 @@ package de.diddiz.LogBlock; public enum Logging { - BLOCKPLACE(true), BLOCKBREAK(true), SIGNTEXT, TNTEXPLOSION(true), CREEPEREXPLOSION(true), + BLOCKPLACE(true), BLOCKBREAK(true), SIGNTEXT(true), TNTEXPLOSION(true), CREEPEREXPLOSION(true), GHASTFIREBALLEXPLOSION(true), ENDERDRAGON(true), MISCEXPLOSION(true), FIRE(true), LEAVESDECAY, LAVAFLOW, WATERFLOW, CHESTACCESS, KILL, CHAT, SNOWFORM, SNOWFADE, DOORINTERACT, SWITCHINTERACT, CAKEEAT, ENDERMEN, NOTEBLOCKINTERACT, DIODEINTERACT, COMPARATORINTERACT, diff --git a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java index 919949a3..c7b0584e 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java @@ -5,6 +5,7 @@ import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Objects; import static de.diddiz.util.Utils.spaces; @@ -30,6 +31,6 @@ public Location getLocation() { @Override public String getMessage() { - return created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)) + destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)) + (actor != null ? actor.getName() : MaterialConverter.getMaterial(type).toString()); + return created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)) + destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)) + (actor != null ? actor.getName() : Objects.toString(MaterialConverter.getMaterial(type))); } } diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 73115749..5afa56ca 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -27,7 +27,6 @@ import static de.diddiz.LogBlock.config.Config.isLogging; import static de.diddiz.util.BukkitUtils.friendlyWorldname; import de.diddiz.util.ComparableVersion; -import java.util.regex.Pattern; class Updater { private final LogBlock logblock; @@ -42,11 +41,6 @@ class Updater { boolean update() { final ConfigurationSection config = logblock.getConfig(); String versionString = config.getString("version"); - if (Pattern.matches("1\\.\\d{2}",versionString)) { - versionString = "1." + versionString.charAt(2) + "." + versionString.charAt(3); - config.set("version",versionString); - logblock.saveConfig(); - } ComparableVersion configVersion = new ComparableVersion(versionString); // if (configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion().replace(" (manually compiled)", ""))) >= 0) { // return false; @@ -686,8 +680,8 @@ boolean update() { Material replacedMaterial = MaterialConverter.getBlockData(replaced, -1).getMaterial(); Material typeMaterial = MaterialConverter.getBlockData(type, -1).getMaterial(); - boolean wasSign = replacedMaterial == Material.SIGN || replacedMaterial == Material.WALL_SIGN; - boolean isSign = typeMaterial == Material.SIGN || typeMaterial == Material.WALL_SIGN; + boolean wasSign = replacedMaterial == Material.OAK_SIGN || replacedMaterial == Material.OAK_WALL_SIGN; + boolean isSign = typeMaterial == Material.OAK_SIGN || typeMaterial == Material.OAK_WALL_SIGN; insertSignState.setInt(1, id); insertSignState.setBytes(2, wasSign ? bytes : null); @@ -739,6 +733,10 @@ boolean update() { config.set("version", "1.13.2"); } + if (configVersion.compareTo(new ComparableVersion("1.14.0")) < 0) { + config.set("version", "1.14.0"); + } + // this can always be checked try { final Connection conn = logblock.getConnection(); @@ -837,6 +835,84 @@ private void createTable(DatabaseMetaData dbm, Statement state, String table, St } } + /** + * Update materials that were renamed + */ + public void updateMaterialsPost1_13() { + final ConfigurationSection config = logblock.getConfig(); + String previousMinecraftVersion = config.getString("previousMinecraftVersion"); + if (previousMinecraftVersion == null) { + previousMinecraftVersion = "1.13"; + } + ComparableVersion comparablePreviousMinecraftVersion = new ComparableVersion(previousMinecraftVersion); + String currentMinecraftVersion = logblock.getServer().getVersion(); + currentMinecraftVersion = currentMinecraftVersion.substring(currentMinecraftVersion.indexOf("(MC: ") + 5); + currentMinecraftVersion = currentMinecraftVersion.substring(0, currentMinecraftVersion.indexOf(" ")); + logblock.getLogger().info("[Updater] Current Minecraft Version: '" + currentMinecraftVersion + "'"); + ComparableVersion comparableCurrentMinecraftVersion = new ComparableVersion(currentMinecraftVersion); + + if (comparablePreviousMinecraftVersion.compareTo("1.14") < 0 && comparableCurrentMinecraftVersion.compareTo("1.14") >= 0) { + logblock.getLogger().info("[Updater] Upgrading Materials to 1.14"); + renameMaterial("minecraft:sign", "minecraft:oak_sign", true); + renameMaterial("minecraft:wall_sign", "minecraft:oak_wall_sign", true); + renameMaterial("minecraft:stone_slab", "minecraft:smooth_stone_slab", false); + renameMaterial("minecraft:rose_red", "minecraft:red_dye", true); + renameMaterial("minecraft:dandelion_yellow", "minecraft:yellow_dye", true); + renameMaterial("minecraft:cactus_green", "minecraft:green_dye", true); + } + + config.set("previousMinecraftVersion", currentMinecraftVersion); + logblock.saveConfig(); + } + + private void renameMaterial(String oldName, String newName, boolean mergeOnCollision) { + logblock.getLogger().info("[Updater] Renaming " + oldName + " to " + newName); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(false); + PreparedStatement stSelectMaterial = conn.prepareStatement("SELECT id FROM `lb-materials` WHERE name = ?"); + stSelectMaterial.setString(1, oldName); + ResultSet rs = stSelectMaterial.executeQuery(); + if (!rs.next()) { + logblock.getLogger().info("[Updater] Skipped because " + oldName + " does not exist.."); + } else { + int oldId = rs.getInt(1); + stSelectMaterial.setString(1, newName); + rs = stSelectMaterial.executeQuery(); + if (rs.next()) { + int newId = rs.getInt(1); + if (!mergeOnCollision) { + logblock.getLogger().info("[Updater] Skipped because " + newName + " already exists.."); + } else { + Statement st = conn.createStatement(); + int rows = 0; + for (final WorldConfig wcfg : getLoggedWorlds()) { + rows += st.executeUpdate("UPDATE `" + wcfg.table + "-blocks` SET replaced = " + newId + " WHERE replaced = " + oldId); + rows += st.executeUpdate("UPDATE `" + wcfg.table + "-blocks` SET type = " + newId + " WHERE type = " + oldId); + rows += st.executeUpdate("UPDATE `" + wcfg.table + "-chestdata` SET itemtype = " + newId + " WHERE itemtype = " + oldId); + } + st.execute("DELETE FROM `lb-materials` WHERE id = " + oldId); + st.close(); + logblock.getLogger().info("[Updater] Successfully merged " + rows + " entries.."); + } + } else { + PreparedStatement stRenameMaterial = conn.prepareStatement("UPDATE `lb-materials` SET name = ? WHERE id = ?"); + stRenameMaterial.setString(1, newName); + stRenameMaterial.setInt(2, oldId); + if (stRenameMaterial.executeUpdate() > 0) { + logblock.getLogger().info("[Updater] Successfully renamed.."); + } + stRenameMaterial.close(); + } + } + stSelectMaterial.close(); + conn.commit(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: " + ex.getMessage(), ex); + } + } + public static class PlayerCountChecker implements Runnable { private LogBlock logblock; diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index 04e6e9de..8864de2b 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -12,7 +12,7 @@ public class BlockStateCodecSign implements BlockStateCodec { @Override public Material[] getApplicableMaterials() { - return new Material[] { Material.WALL_SIGN, Material.SIGN }; + return new Material[] { Material.ACACIA_SIGN, Material.ACACIA_WALL_SIGN, Material.BIRCH_SIGN, Material.BIRCH_WALL_SIGN, Material.DARK_OAK_SIGN, Material.DARK_OAK_WALL_SIGN, Material.JUNGLE_SIGN, Material.JUNGLE_WALL_SIGN, Material.OAK_SIGN, Material.OAK_WALL_SIGN, Material.SPRUCE_SIGN, Material.SPRUCE_WALL_SIGN }; } @Override diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java index e316fd82..1dfa94c6 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java @@ -10,7 +10,6 @@ import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.block.Sign; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Waterlogged; import org.bukkit.event.EventHandler; @@ -40,9 +39,7 @@ public void onBlockBreak(BlockBreakEvent event) { final Block origin = event.getBlock(); final Material type = origin.getType(); - if (wcfg.isLogging(Logging.SIGNTEXT) && (type == Material.SIGN || type == Material.WALL_SIGN)) { - consumer.queueSignBreak(actor, (Sign) origin.getState()); - } else if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.getContainerBlocks().contains(type)) { + if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.getContainerBlocks().contains(type)) { consumer.queueContainerBreak(actor, origin.getState()); } else if (type == Material.ICE) { // When in creative mode ice doesn't form water diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index 3098e6db..1a63d8d8 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -11,7 +11,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.block.Sign; import org.bukkit.entity.*; import org.bukkit.entity.minecart.ExplosiveMinecart; import org.bukkit.event.EventHandler; @@ -114,9 +113,7 @@ public void onEntityExplode(EntityExplodeEvent event) { } for (final Block block : event.blockList()) { final Material type = block.getType(); - if (wcfg.isLogging(Logging.SIGNTEXT) & (type == Material.SIGN || type == Material.WALL_SIGN)) { - consumer.queueSignBreak(actor, (Sign) block.getState()); - } else if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(type))) { + if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(type))) { consumer.queueContainerBreak(actor, block.getState()); } else { consumer.queueBlockBreak(actor, block.getState()); @@ -171,9 +168,7 @@ public void onBlockExplode(BlockExplodeEvent event) { } final Material type = block.getType(); - if (wcfg.isLogging(Logging.SIGNTEXT) & (type == Material.SIGN || type == Material.WALL_SIGN)) { - consumer.queueSignBreak(actor, (Sign) block.getState()); - } else if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(type))) { + if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(type))) { consumer.queueContainerBreak(actor, block.getState()); } else { consumer.queueBlockBreak(actor, block.getState()); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java index 593dbcf8..5622ce50 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java @@ -17,7 +17,7 @@ public SignChangeLogging(LogBlock lb) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSignChange(SignChangeEvent event) { if (isLogging(event.getBlock().getWorld(), Logging.SIGNTEXT)) { - consumer.queueSignPlace(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getLocation(), event.getBlock().getBlockData(), event.getLines()); + consumer.queueSignChange(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getLocation(), event.getBlock().getBlockData(), event.getLines()); } } } diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index baebf319..fea1162b 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -164,7 +164,12 @@ public class BukkitUtils { // Blocks that break when they are attached to a block relativeBreakable = EnumSet.noneOf(Material.class); - relativeBreakable.add(Material.WALL_SIGN); + relativeBreakable.add(Material.ACACIA_WALL_SIGN); + relativeBreakable.add(Material.BIRCH_WALL_SIGN); + relativeBreakable.add(Material.DARK_OAK_WALL_SIGN); + relativeBreakable.add(Material.JUNGLE_WALL_SIGN); + relativeBreakable.add(Material.OAK_WALL_SIGN); + relativeBreakable.add(Material.SPRUCE_WALL_SIGN); relativeBreakable.add(Material.LADDER); relativeBreakable.addAll(buttons); relativeBreakable.add(Material.REDSTONE_WALL_TORCH); @@ -189,7 +194,12 @@ public class BukkitUtils { relativeTopBreakable.add(Material.ACTIVATOR_RAIL); relativeTopBreakable.add(Material.RAIL); relativeTopBreakable.add(Material.REDSTONE_WIRE); - relativeTopBreakable.add(Material.SIGN); + relativeTopBreakable.add(Material.ACACIA_SIGN); + relativeTopBreakable.add(Material.BIRCH_SIGN); + relativeTopBreakable.add(Material.DARK_OAK_SIGN); + relativeTopBreakable.add(Material.JUNGLE_SIGN); + relativeTopBreakable.add(Material.OAK_SIGN); + relativeTopBreakable.add(Material.SPRUCE_SIGN); relativeTopBreakable.addAll(pressurePlates); relativeTopBreakable.add(Material.SNOW); relativeTopBreakable.add(Material.REPEATER); @@ -205,8 +215,18 @@ public class BukkitUtils { // Blocks that break falling entities fallingEntityKillers = EnumSet.noneOf(Material.class); - fallingEntityKillers.add(Material.SIGN); - fallingEntityKillers.add(Material.WALL_SIGN); + fallingEntityKillers.add(Material.ACACIA_SIGN); + fallingEntityKillers.add(Material.ACACIA_WALL_SIGN); + fallingEntityKillers.add(Material.BIRCH_SIGN); + fallingEntityKillers.add(Material.BIRCH_WALL_SIGN); + fallingEntityKillers.add(Material.DARK_OAK_SIGN); + fallingEntityKillers.add(Material.DARK_OAK_WALL_SIGN); + fallingEntityKillers.add(Material.JUNGLE_SIGN); + fallingEntityKillers.add(Material.JUNGLE_WALL_SIGN); + fallingEntityKillers.add(Material.OAK_SIGN); + fallingEntityKillers.add(Material.OAK_WALL_SIGN); + fallingEntityKillers.add(Material.SPRUCE_SIGN); + fallingEntityKillers.add(Material.SPRUCE_WALL_SIGN); fallingEntityKillers.addAll(pressurePlates); fallingEntityKillers.addAll(saplings); fallingEntityKillers.add(Material.DANDELION); diff --git a/src/main/java/de/diddiz/util/ComparableVersion.java b/src/main/java/de/diddiz/util/ComparableVersion.java index 406b0098..69a0ef71 100644 --- a/src/main/java/de/diddiz/util/ComparableVersion.java +++ b/src/main/java/de/diddiz/util/ComparableVersion.java @@ -455,11 +455,21 @@ public int compareTo( ComparableVersion o ) return items.compareTo( o.items ); } + public int compareTo( String version ) + { + return compareTo(new ComparableVersion(version)); + } + public String toString() { return value; } + public String toCanonicalString() + { + return canonical; + } + public boolean equals( Object o ) { return ( o instanceof ComparableVersion ) && canonical.equals( ( (ComparableVersion) o ).canonical ); diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index 020c7487..cec6d1e6 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -2,14 +2,12 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.Consumer; -import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; -import org.bukkit.block.Sign; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Directional; @@ -113,9 +111,7 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or Block checkBlock = origin.getRelative(BlockFace.UP); if (BukkitUtils.getRelativeTopBreakabls().contains(checkBlock.getType())) { - if (wcfg.isLogging(Logging.SIGNTEXT) && checkBlock.getType() == Material.SIGN) { - consumer.queueSignBreak(actor, (Sign) checkBlock.getState()); - } else if (checkBlock.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(checkBlock.getType())) { + if (checkBlock.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(checkBlock.getType())) { Block doorBlock = checkBlock; // If the doorBlock is the top half a door the player simply punched a door // this will be handled later. @@ -151,11 +147,7 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or BlockData blockData = block.getBlockData(); if (blockData instanceof Directional) { if (block.getRelative(((Directional) blockData).getFacing().getOppositeFace()).equals(origin)) { - if (wcfg.isLogging(Logging.SIGNTEXT) && block.getType() == Material.WALL_SIGN) { - consumer.queueSignBreak(actor, (Sign) block.getState()); - } else { - consumer.queueBlockBreak(actor, block.getState()); - } + consumer.queueBlockBreak(actor, block.getState()); } } } diff --git a/src/main/resources/blockdata.txt b/src/main/resources/blockdata.txt index 8f943138..4a6dd576 100644 --- a/src/main/resources/blockdata.txt +++ b/src/main/resources/blockdata.txt @@ -309,7 +309,7 @@ 43:13,minecraft:stone_brick_slab[type=double,waterlogged=false] 43:14,minecraft:nether_brick_slab[type=double,waterlogged=false] 43:15,minecraft:smooth_quartz -44:0,minecraft:stone_slab[type=bottom,waterlogged=false] +44:0,minecraft:smooth_stone_slab[type=bottom,waterlogged=false] 44:1,minecraft:sandstone_slab[type=bottom,waterlogged=false] 44:2,minecraft:petrified_oak_slab[type=bottom,waterlogged=false] 44:3,minecraft:cobblestone_slab[type=bottom,waterlogged=false] @@ -317,7 +317,7 @@ 44:5,minecraft:stone_brick_slab[type=bottom,waterlogged=false] 44:6,minecraft:nether_brick_slab[type=bottom,waterlogged=false] 44:7,minecraft:quartz_slab[type=bottom,waterlogged=false] -44:8,minecraft:stone_slab[type=top,waterlogged=false] +44:8,minecraft:smooth_stone_slab[type=top,waterlogged=false] 44:9,minecraft:sandstone_slab[type=top,waterlogged=false] 44:10,minecraft:petrified_oak_slab[type=top,waterlogged=false] 44:11,minecraft:cobblestone_slab[type=top,waterlogged=false] @@ -440,22 +440,22 @@ 62:10,minecraft:furnace[facing=west,lit=false] 62:11,minecraft:furnace[facing=east,lit=false] 62:15,minecraft:furnace[facing=south,lit=false] -63:0,minecraft:sign[rotation=0,waterlogged=false] -63:1,minecraft:sign[rotation=1,waterlogged=false] -63:2,minecraft:sign[rotation=2,waterlogged=false] -63:3,minecraft:sign[rotation=3,waterlogged=false] -63:4,minecraft:sign[rotation=4,waterlogged=false] -63:5,minecraft:sign[rotation=5,waterlogged=false] -63:6,minecraft:sign[rotation=6,waterlogged=false] -63:7,minecraft:sign[rotation=7,waterlogged=false] -63:8,minecraft:sign[rotation=8,waterlogged=false] -63:9,minecraft:sign[rotation=9,waterlogged=false] -63:10,minecraft:sign[rotation=10,waterlogged=false] -63:11,minecraft:sign[rotation=11,waterlogged=false] -63:12,minecraft:sign[rotation=12,waterlogged=false] -63:13,minecraft:sign[rotation=13,waterlogged=false] -63:14,minecraft:sign[rotation=14,waterlogged=false] -63:15,minecraft:sign[rotation=15,waterlogged=false] +63:0,minecraft:oak_sign[rotation=0,waterlogged=false] +63:1,minecraft:oak_sign[rotation=1,waterlogged=false] +63:2,minecraft:oak_sign[rotation=2,waterlogged=false] +63:3,minecraft:oak_sign[rotation=3,waterlogged=false] +63:4,minecraft:oak_sign[rotation=4,waterlogged=false] +63:5,minecraft:oak_sign[rotation=5,waterlogged=false] +63:6,minecraft:oak_sign[rotation=6,waterlogged=false] +63:7,minecraft:oak_sign[rotation=7,waterlogged=false] +63:8,minecraft:oak_sign[rotation=8,waterlogged=false] +63:9,minecraft:oak_sign[rotation=9,waterlogged=false] +63:10,minecraft:oak_sign[rotation=10,waterlogged=false] +63:11,minecraft:oak_sign[rotation=11,waterlogged=false] +63:12,minecraft:oak_sign[rotation=12,waterlogged=false] +63:13,minecraft:oak_sign[rotation=13,waterlogged=false] +63:14,minecraft:oak_sign[rotation=14,waterlogged=false] +63:15,minecraft:oak_sign[rotation=15,waterlogged=false] 64:0,minecraft:oak_door[facing=east,half=lower,hinge=right,open=false,powered=false] 64:1,minecraft:oak_door[facing=south,half=lower,hinge=right,open=false,powered=false] 64:2,minecraft:oak_door[facing=west,half=lower,hinge=right,open=false,powered=false] @@ -496,14 +496,14 @@ 67:13,minecraft:cobblestone_stairs[facing=west,half=top,shape=straight,waterlogged=false] 67:14,minecraft:cobblestone_stairs[facing=south,half=top,shape=straight,waterlogged=false] 67:15,minecraft:cobblestone_stairs[facing=north,half=top,shape=straight,waterlogged=false] -68:0,minecraft:wall_sign[facing=north,waterlogged=false] -68:3,minecraft:wall_sign[facing=south,waterlogged=false] -68:4,minecraft:wall_sign[facing=west,waterlogged=false] -68:5,minecraft:wall_sign[facing=east,waterlogged=false] -68:9,minecraft:wall_sign[facing=south,waterlogged=false] -68:10,minecraft:wall_sign[facing=west,waterlogged=false] -68:11,minecraft:wall_sign[facing=east,waterlogged=false] -68:15,minecraft:wall_sign[facing=south,waterlogged=false] +68:0,minecraft:oak_wall_sign[facing=north,waterlogged=false] +68:3,minecraft:oak_wall_sign[facing=south,waterlogged=false] +68:4,minecraft:oak_wall_sign[facing=west,waterlogged=false] +68:5,minecraft:oak_wall_sign[facing=east,waterlogged=false] +68:9,minecraft:oak_wall_sign[facing=south,waterlogged=false] +68:10,minecraft:oak_wall_sign[facing=west,waterlogged=false] +68:11,minecraft:oak_wall_sign[facing=east,waterlogged=false] +68:15,minecraft:oak_wall_sign[facing=south,waterlogged=false] 69:0,minecraft:lever[face=ceiling,facing=west,powered=false] 69:1,minecraft:lever[face=wall,facing=east,powered=false] 69:2,minecraft:lever[face=wall,facing=west,powered=false] diff --git a/src/main/resources/itemdata.txt b/src/main/resources/itemdata.txt index 44f83afd..01764f2c 100644 --- a/src/main/resources/itemdata.txt +++ b/src/main/resources/itemdata.txt @@ -114,7 +114,7 @@ 40:0,minecraft:red_mushroom 41:0,minecraft:gold_block 42:0,minecraft:iron_block -43:0,minecraft:stone_slab +43:0,minecraft:smooth_stone_slab 43:1,minecraft:sandstone_slab 43:2,minecraft:petrified_oak_slab 43:3,minecraft:cobblestone_slab @@ -171,16 +171,16 @@ 62:3,minecraft:furnace 62:4,minecraft:furnace 62:5,minecraft:furnace -63:0,minecraft:sign +63:0,minecraft:oak_sign 64:0,minecraft:oak_door 65:0,minecraft:ladder 66:0,minecraft:rail 67:0,minecraft:cobblestone_stairs 68:0,minecraft:air -68:2,minecraft:wall_sign -68:3,minecraft:wall_sign -68:4,minecraft:wall_sign -68:5,minecraft:wall_sign +68:2,minecraft:oak_wall_sign +68:3,minecraft:oak_wall_sign +68:4,minecraft:oak_wall_sign +68:5,minecraft:oak_wall_sign 69:0,minecraft:lever 70:0,minecraft:stone_pressure_plate 71:0,minecraft:iron_door @@ -599,7 +599,7 @@ 321:0,minecraft:painting 322:0,minecraft:golden_apple 322:1,minecraft:enchanted_golden_apple -323:0,minecraft:sign +323:0,minecraft:oak_sign 324:0,minecraft:oak_door 325:0,minecraft:bucket 326:0,minecraft:water_bucket @@ -632,8 +632,8 @@ 350:0,minecraft:cooked_cod 350:1,minecraft:cooked_salmon 351:0,minecraft:ink_sac -351:1,minecraft:rose_red -351:2,minecraft:cactus_green +351:1,minecraft:red_dye +351:2,minecraft:green_dye 351:3,minecraft:cocoa_beans 351:4,minecraft:lapis_lazuli 351:5,minecraft:purple_dye @@ -642,7 +642,7 @@ 351:8,minecraft:gray_dye 351:9,minecraft:pink_dye 351:10,minecraft:lime_dye -351:11,minecraft:dandelion_yellow +351:11,minecraft:yellow_dye 351:12,minecraft:light_blue_dye 351:13,minecraft:magenta_dye 351:14,minecraft:orange_dye diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 94b65bee..f7982088 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -6,7 +6,7 @@ website: http://dev.bukkit.org/server-mods/logblock/ main: de.diddiz.LogBlock.LogBlock description: ${project.description} softdepend: [WorldEdit] -api-version: 1.13 +api-version: 1.14 commands: lb: description: 'LogBlock plugin commands' From 82d61d5ee7b5129716ea7fa3fb17f96165536034 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 27 Apr 2019 04:53:34 +0200 Subject: [PATCH 185/399] Spigot 1.14 instead of 1.14-pre5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9664849c..347e4646 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ org.spigotmc spigot-api - 1.14-pre5-SNAPSHOT + 1.14-R0.1-SNAPSHOT provided From 503541ad4edaa709b8dd4b3480a8d703cfe30726 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 2 May 2019 21:51:16 +0200 Subject: [PATCH 186/399] Fix version parsing --- src/main/java/de/diddiz/LogBlock/Updater.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 5afa56ca..c45c596c 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -847,7 +847,12 @@ public void updateMaterialsPost1_13() { ComparableVersion comparablePreviousMinecraftVersion = new ComparableVersion(previousMinecraftVersion); String currentMinecraftVersion = logblock.getServer().getVersion(); currentMinecraftVersion = currentMinecraftVersion.substring(currentMinecraftVersion.indexOf("(MC: ") + 5); - currentMinecraftVersion = currentMinecraftVersion.substring(0, currentMinecraftVersion.indexOf(" ")); + int currentVersionEnd = currentMinecraftVersion.indexOf(" "); + int currentVersionEnd2 = currentMinecraftVersion.indexOf(")"); + if(currentVersionEnd2 >= 0 && (currentVersionEnd < 0 || currentVersionEnd2 < currentVersionEnd)) { + currentVersionEnd = currentVersionEnd2; + } + currentMinecraftVersion = currentMinecraftVersion.substring(0, currentVersionEnd); logblock.getLogger().info("[Updater] Current Minecraft Version: '" + currentMinecraftVersion + "'"); ComparableVersion comparableCurrentMinecraftVersion = new ComparableVersion(currentMinecraftVersion); From bd23c93071452b19f243f667961533bd5d4930d6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 4 May 2019 17:49:29 +0200 Subject: [PATCH 187/399] Allow logblock to load when it encounters unknown material/entity types --- .../java/de/diddiz/LogBlock/BlockChange.java | 3 +++ .../diddiz/LogBlock/EntityTypeConverter.java | 13 +++++++++--- .../de/diddiz/LogBlock/MaterialConverter.java | 20 +++++++++++++++---- .../diddiz/LogBlock/SummedBlockChanges.java | 3 ++- .../diddiz/LogBlock/SummedEntityChanges.java | 3 ++- .../java/de/diddiz/LogBlock/WorldEditor.java | 3 +++ 6 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index d7bb2351..1f772c54 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -72,6 +72,9 @@ public BlockChange(ResultSet rs, QueryParams p) throws SQLException { public String toString() { BlockData type = getBlockSet(); BlockData replaced = getBlockReplaced(); + if (type == null || replaced == null) { + return "Unknown block modification"; + } String typeDetails = null; if (BlockStateCodecs.hasCodec(type.getMaterial())) { try { diff --git a/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java b/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java index b55c6e51..88ca1ef2 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java +++ b/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java @@ -55,7 +55,7 @@ public static int getOrAddEntityTypeId(EntityType entityType) { } public static EntityType getEntityType(int entityTypeId) { - return idToEntityType[entityTypeId]; + return entityTypeId >= 0 && entityTypeId < idToEntityType.length ? idToEntityType[entityTypeId] : null; } private static void reinitializeEntityTypesCatchException() { @@ -78,8 +78,15 @@ public static void initializeEntityTypes(Connection connection) throws SQLExcept ResultSet rs = smt.executeQuery("SELECT id, name FROM `lb-entitytypes`"); while (rs.next()) { int key = rs.getInt(1); - EntityType entityType = EntityType.valueOf(rs.getString(2)); - internalAddEntityType(key, entityType); + try { + EntityType entityType = EntityType.valueOf(rs.getString(2)); + internalAddEntityType(key, entityType); + } catch (IllegalArgumentException ignored) { + // the key is used, but not available in this version + if (nextEntityTypeId <= key) { + nextEntityTypeId = key + 1; + } + } } rs.close(); smt.close(); diff --git a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java index 8babf3dd..1c90d7d3 100644 --- a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java +++ b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java @@ -122,15 +122,27 @@ public static int getOrAddBlockStateId(String blockDataString) { } public static BlockData getBlockData(int materialId, int blockStateId) { - String material = idToMaterial[materialId]; - if (blockStateId >= 0) { + String material = materialId >= 0 && materialId < idToMaterial.length ? idToMaterial[materialId] : null; + if (material == null) { + return null; + } + if (blockStateId >= 0 && blockStateId < idToBlockState.length && idToBlockState[blockStateId] != null) { material = material + idToBlockState[blockStateId]; } - return Bukkit.createBlockData(material); + try { + return Bukkit.createBlockData(material); + } catch (IllegalArgumentException ignored) { + // fall back to create the default block data for the material + try { + return Bukkit.createBlockData(idToMaterial[materialId]); + } catch (IllegalArgumentException ignored2) { + return null; + } + } } public static Material getMaterial(int materialId) { - return materialKeyToMaterial.get(idToMaterial[materialId]); + return materialId >= 0 && materialId < idToMaterial.length ? materialKeyToMaterial.get(idToMaterial[materialId]) : null; } private static void reinitializeMaterialsCatchException() { diff --git a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java index 919949a3..c7b0584e 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java @@ -5,6 +5,7 @@ import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Objects; import static de.diddiz.util.Utils.spaces; @@ -30,6 +31,6 @@ public Location getLocation() { @Override public String getMessage() { - return created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)) + destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)) + (actor != null ? actor.getName() : MaterialConverter.getMaterial(type).toString()); + return created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)) + destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)) + (actor != null ? actor.getName() : Objects.toString(MaterialConverter.getMaterial(type))); } } diff --git a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java index c47ab8c0..5b1fd454 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java @@ -5,6 +5,7 @@ import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Objects; import static de.diddiz.util.Utils.spaces; @@ -30,6 +31,6 @@ public Location getLocation() { @Override public String getMessage() { - return created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)) + destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)) + (actor != null ? actor.getName() : EntityTypeConverter.getEntityType(type).toString()); + return created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)) + destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)) + (actor != null ? actor.getName() : Objects.toString(EntityTypeConverter.getEntityType(type))); } } diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index b54b4015..668a4a37 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -226,6 +226,9 @@ public long getTime() { @Override public PerformResult perform() throws WorldEditorException { + if (type == null) { + throw new WorldEditorException("Unkown entity type for entity " + entityUUID, loc); + } if (changeType == (rollback ? EntityChangeType.KILL : EntityChangeType.CREATE)) { // spawn entity UUID uuid = getReplacedUUID(entityId, entityUUID); From 33c18a9e62eeaf1e20adbf2212ce4e482c5d14b0 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 5 May 2019 05:55:47 +0200 Subject: [PATCH 188/399] Improve compatibility when running 1.13 and 1.14 servers on the same logblock database Old materials are no longer renamed, instead new materials are added and the old entries are modified --- .../java/de/diddiz/LogBlock/LogBlock.java | 1 - src/main/java/de/diddiz/LogBlock/Updater.java | 63 ++++++++----------- 2 files changed, 26 insertions(+), 38 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index e06212a9..5f6afb64 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -88,7 +88,6 @@ public void onEnable() { conn.close(); Updater updater = new Updater(this); updater.checkTables(); - updater.updateMaterialsPost1_13(); MaterialConverter.initializeMaterials(getConnection()); MaterialConverter.getOrAddMaterialId(Material.AIR.getKey()); // AIR must be the first entry EntityTypeConverter.initializeEntityTypes(getConnection()); diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index c45c596c..6ed87992 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -756,6 +756,8 @@ boolean update() { return false; } + updateMaterialsPost1_13(); + logblock.saveConfig(); return true; } @@ -838,7 +840,7 @@ private void createTable(DatabaseMetaData dbm, Statement state, String table, St /** * Update materials that were renamed */ - public void updateMaterialsPost1_13() { + private void updateMaterialsPost1_13() { final ConfigurationSection config = logblock.getConfig(); String previousMinecraftVersion = config.getString("previousMinecraftVersion"); if (previousMinecraftVersion == null) { @@ -858,56 +860,43 @@ public void updateMaterialsPost1_13() { if (comparablePreviousMinecraftVersion.compareTo("1.14") < 0 && comparableCurrentMinecraftVersion.compareTo("1.14") >= 0) { logblock.getLogger().info("[Updater] Upgrading Materials to 1.14"); - renameMaterial("minecraft:sign", "minecraft:oak_sign", true); - renameMaterial("minecraft:wall_sign", "minecraft:oak_wall_sign", true); - renameMaterial("minecraft:stone_slab", "minecraft:smooth_stone_slab", false); - renameMaterial("minecraft:rose_red", "minecraft:red_dye", true); - renameMaterial("minecraft:dandelion_yellow", "minecraft:yellow_dye", true); - renameMaterial("minecraft:cactus_green", "minecraft:green_dye", true); + renameMaterial("minecraft:sign", "minecraft:oak_sign"); + renameMaterial("minecraft:wall_sign", "minecraft:oak_wall_sign"); + renameMaterial("minecraft:stone_slab", "minecraft:smooth_stone_slab"); + renameMaterial("minecraft:rose_red", "minecraft:red_dye"); + renameMaterial("minecraft:dandelion_yellow", "minecraft:yellow_dye"); + renameMaterial("minecraft:cactus_green", "minecraft:green_dye"); } config.set("previousMinecraftVersion", currentMinecraftVersion); logblock.saveConfig(); } - private void renameMaterial(String oldName, String newName, boolean mergeOnCollision) { - logblock.getLogger().info("[Updater] Renaming " + oldName + " to " + newName); + private void renameMaterial(String oldName, String newName) { final Connection conn = logblock.getConnection(); try { conn.setAutoCommit(false); PreparedStatement stSelectMaterial = conn.prepareStatement("SELECT id FROM `lb-materials` WHERE name = ?"); stSelectMaterial.setString(1, oldName); ResultSet rs = stSelectMaterial.executeQuery(); - if (!rs.next()) { - logblock.getLogger().info("[Updater] Skipped because " + oldName + " does not exist.."); - } else { + if (rs.next()) { + logblock.getLogger().info("[Updater] Updating " + oldName + " to " + newName); int oldId = rs.getInt(1); - stSelectMaterial.setString(1, newName); - rs = stSelectMaterial.executeQuery(); - if (rs.next()) { - int newId = rs.getInt(1); - if (!mergeOnCollision) { - logblock.getLogger().info("[Updater] Skipped because " + newName + " already exists.."); - } else { - Statement st = conn.createStatement(); - int rows = 0; - for (final WorldConfig wcfg : getLoggedWorlds()) { - rows += st.executeUpdate("UPDATE `" + wcfg.table + "-blocks` SET replaced = " + newId + " WHERE replaced = " + oldId); - rows += st.executeUpdate("UPDATE `" + wcfg.table + "-blocks` SET type = " + newId + " WHERE type = " + oldId); - rows += st.executeUpdate("UPDATE `" + wcfg.table + "-chestdata` SET itemtype = " + newId + " WHERE itemtype = " + oldId); - } - st.execute("DELETE FROM `lb-materials` WHERE id = " + oldId); - st.close(); - logblock.getLogger().info("[Updater] Successfully merged " + rows + " entries.."); - } - } else { - PreparedStatement stRenameMaterial = conn.prepareStatement("UPDATE `lb-materials` SET name = ? WHERE id = ?"); - stRenameMaterial.setString(1, newName); - stRenameMaterial.setInt(2, oldId); - if (stRenameMaterial.executeUpdate() > 0) { - logblock.getLogger().info("[Updater] Successfully renamed.."); + int newId = MaterialConverter.getOrAddMaterialId(newName); + + Statement st = conn.createStatement(); + int rows = 0; + for (final WorldConfig wcfg : getLoggedWorlds()) { + rows += st.executeUpdate("UPDATE `" + wcfg.table + "-blocks` SET replaced = " + newId + " WHERE replaced = " + oldId); + rows += st.executeUpdate("UPDATE `" + wcfg.table + "-blocks` SET type = " + newId + " WHERE type = " + oldId); + rows += st.executeUpdate("UPDATE `" + wcfg.table + "-chestdata` SET itemtype = " + newId + " WHERE itemtype = " + oldId); + if (wcfg.isLogging(Logging.KILL)) { + rows += st.executeUpdate("UPDATE `" + wcfg.table + "-kills` SET weapon = " + newId + " WHERE weapon = " + oldId); } - stRenameMaterial.close(); + } + st.close(); + if (rows > 0) { + logblock.getLogger().info("[Updater] Successfully updated " + rows + " entries.."); } } stSelectMaterial.close(); From 1602fdb03a8db0fc20e150a3719a845c1410a37d Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 14 May 2019 17:54:33 +0200 Subject: [PATCH 189/399] Configuration option to require SSL on the database connection --- src/main/java/de/diddiz/LogBlock/LogBlock.java | 2 +- src/main/java/de/diddiz/LogBlock/config/Config.java | 3 +++ src/main/java/de/diddiz/util/MySQLConnectionPool.java | 6 +++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 5f6afb64..e57afe4a 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -72,7 +72,7 @@ public void onEnable() { } try { getLogger().info("Connecting to " + user + "@" + url + "..."); - pool = new MySQLConnectionPool(url, user, password); + pool = new MySQLConnectionPool(url, user, password, mysqlRequireSSL); final Connection conn = getConnection(true); if (conn == null) { noDb = true; diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index a23961df..9fae8eec 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -25,6 +25,7 @@ public class Config { private static LoggingEnabledMapping superWorldConfig; private static Map worldConfigs; public static String url, user, password; + public static boolean mysqlRequireSSL; public static int delayBetweenRuns, forceToProcessAtLeast, timePerRun; public static boolean fireCustomEvents; public static boolean useBukkitScheduler; @@ -79,6 +80,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("mysql.database", "minecraft"); def.put("mysql.user", "username"); def.put("mysql.password", "pass"); + def.put("mysql.requireSSL", false); def.put("consumer.delayBetweenRuns", 2); def.put("consumer.forceToProcessAtLeast", 200); def.put("consumer.timePerRun", 1000); @@ -163,6 +165,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database"); user = getStringIncludingInts(config, "mysql.user"); password = getStringIncludingInts(config, "mysql.password"); + mysqlRequireSSL = config.getBoolean("mysql.requireSSL", false); delayBetweenRuns = config.getInt("consumer.delayBetweenRuns", 2); forceToProcessAtLeast = config.getInt("consumer.forceToProcessAtLeast", 0); timePerRun = config.getInt("consumer.timePerRun", 1000); diff --git a/src/main/java/de/diddiz/util/MySQLConnectionPool.java b/src/main/java/de/diddiz/util/MySQLConnectionPool.java index 3727cd9a..bf9d6930 100644 --- a/src/main/java/de/diddiz/util/MySQLConnectionPool.java +++ b/src/main/java/de/diddiz/util/MySQLConnectionPool.java @@ -11,7 +11,7 @@ public class MySQLConnectionPool implements Closeable { private final HikariDataSource ds; - public MySQLConnectionPool(String url, String user, String password) { + public MySQLConnectionPool(String url, String user, String password, boolean requireSSL) { this.ds = new HikariDataSource(); ds.setJdbcUrl(url); ds.setUsername(user); @@ -29,6 +29,10 @@ public MySQLConnectionPool(String url, String user, String password) { ds.addDataSourceProperty("prepStmtCacheSize", "250"); ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); ds.addDataSourceProperty("useServerPrepStmts", "true"); + + ds.addDataSourceProperty("useSSL", "true"); + ds.addDataSourceProperty("requireSSL", Boolean.toString(requireSSL)); + ds.addDataSourceProperty("verifyServerCertificate", "false"); } @Override From ac233a392076bfa12c6a562530b1690dc97bc74a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 14 May 2019 17:59:30 +0200 Subject: [PATCH 190/399] Spigot 1.14.1 --- pom.xml | 4 ++-- src/main/java/de/diddiz/LogBlock/Updater.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 347e4646..7d37a400 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.14-SNAPSHOT + 1.14.1-SNAPSHOT jar LogBlock @@ -42,7 +42,7 @@ org.spigotmc spigot-api - 1.14-R0.1-SNAPSHOT + 1.14.1-R0.1-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 6ed87992..dabf4035 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -733,8 +733,8 @@ boolean update() { config.set("version", "1.13.2"); } - if (configVersion.compareTo(new ComparableVersion("1.14.0")) < 0) { - config.set("version", "1.14.0"); + if (configVersion.compareTo(new ComparableVersion("1.14.1")) < 0) { + config.set("version", "1.14.1"); } // this can always be checked From f6522b73f49b1032873fa846c11cca8e79556ce5 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 16 May 2019 01:35:46 +0200 Subject: [PATCH 191/399] create chat table without fulltext index if the database does not support it. --- src/main/java/de/diddiz/LogBlock/Updater.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index dabf4035..54b5e2d2 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -807,7 +807,11 @@ void checkTables() throws SQLException { state.execute("INSERT IGNORE INTO `lb-players` (UUID,playername) VALUES ('log_dummy_record','dummy_record')"); } if (isLogging(Logging.CHAT)) { - createTable(dbm, 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); + try { + createTable(dbm, 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(dbm, 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(dbm, state, "lb-materials", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); createTable(dbm, state, "lb-blockstates", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); From 8f429afbeb0bbab86129ed2b98bcf50c87ea1996 Mon Sep 17 00:00:00 2001 From: Wyatt Childers Date: Mon, 1 Sep 2014 22:35:22 -0400 Subject: [PATCH 192/399] Made LogBlock's messages far more visual appealing --- .../java/de/diddiz/LogBlock/BlockChange.java | 98 +++++++++---------- .../java/de/diddiz/LogBlock/ChatMessage.java | 5 +- .../de/diddiz/LogBlock/CommandsHandler.java | 11 ++- src/main/java/de/diddiz/LogBlock/Kill.java | 18 ++-- .../diddiz/LogBlock/SummedBlockChanges.java | 10 +- .../java/de/diddiz/LogBlock/SummedKills.java | 10 +- src/main/java/de/diddiz/util/ActionColor.java | 24 +++++ src/main/java/de/diddiz/util/BukkitUtils.java | 17 ++-- .../java/de/diddiz/util/MessagingUtil.java | 66 +++++++++++++ src/main/java/de/diddiz/util/TypeColor.java | 29 ++++++ 10 files changed, 217 insertions(+), 71 deletions(-) create mode 100644 src/main/java/de/diddiz/util/ActionColor.java create mode 100644 src/main/java/de/diddiz/util/MessagingUtil.java create mode 100644 src/main/java/de/diddiz/util/TypeColor.java diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index ecd5a0c9..a66d1d2d 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -1,7 +1,6 @@ package de.diddiz.LogBlock; import de.diddiz.LogBlock.blockstate.BlockStateCodecs; -import de.diddiz.LogBlock.config.Config; import de.diddiz.util.BukkitUtils; import de.diddiz.util.Utils; @@ -11,19 +10,16 @@ import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Openable; import org.bukkit.block.data.Powerable; -import org.bukkit.block.data.type.Comparator; -import org.bukkit.block.data.type.DaylightDetector; -import org.bukkit.block.data.type.NoteBlock; -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.block.data.type.*; import org.bukkit.inventory.ItemStack; import java.sql.ResultSet; import java.sql.SQLException; import java.util.logging.Level; +import static de.diddiz.util.ActionColor.*; +import static de.diddiz.util.MessagingUtil.*; + public class BlockChange implements LookupCacheElement { public final long id, date; public final Location loc; @@ -70,14 +66,9 @@ public BlockChange(ResultSet rs, QueryParams p) throws SQLException { ca = catemp; } - @Override - public String toString() { - BlockData type = getBlockSet(); - BlockData replaced = getBlockReplaced(); - if (type == null || replaced == null) { - return "Unknown block modification"; - } + private String getTypeDetails(BlockData type, byte[] typeState) { String typeDetails = null; + if (BlockStateCodecs.hasCodec(type.getMaterial())) { try { typeDetails = BlockStateCodecs.toString(type.getMaterial(), Utils.deserializeYamlConfiguration(typeState)); @@ -85,80 +76,85 @@ public String toString() { LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + type.getMaterial(), e); } } + if (typeDetails == null) { - typeDetails = ""; + return ""; } else { - typeDetails = " " + typeDetails; - } - String replacedDetails = null; - if (BlockStateCodecs.hasCodec(replaced.getMaterial())) { - try { - replacedDetails = BlockStateCodecs.toString(replaced.getMaterial(), Utils.deserializeYamlConfiguration(replacedState)); - } catch (Exception e) { - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + replaced.getMaterial(), e); - } + return " " + typeDetails; } - if (replacedDetails == null) { - replacedDetails = ""; - } else { - replacedDetails = " " + replacedDetails; + } + + @Override + public String toString() { + BlockData type = getBlockSet(); + BlockData replaced = getBlockReplaced(); + if (type == null || replaced == null) { + return "Unknown block modification"; } + + // Process type details once for later use. + String typeDetails = getTypeDetails(type, typeState); + String replacedDetails = getTypeDetails(replaced, replacedState); + final StringBuilder msg = new StringBuilder(); + if (date > 0) { - msg.append(Config.formatter.format(date)).append(" "); + msg.append(brackets(prettyDate(date), BracketType.STANDARD)).append(' '); } + if (actor != null) { msg.append(actor.getName()).append(" "); } + if (type.getMaterial().equals(replaced.getMaterial())) { if (BukkitUtils.isEmpty(type.getMaterial())) { - msg.append("did an unspecified action"); + msg.append(INTERACT).append("did an unspecified action"); } else if (ca != null) { if (ca.itemStack == null) { - msg.append("looked inside ").append(type.getMaterial().name()); + msg.append(INTERACT).append("looked inside ").append(prettyMaterial(type.getMaterial())); } else if (ca.remove) { - msg.append("took ").append(BukkitUtils.toString(ca.itemStack)).append(" from ").append(type.getMaterial().name()); + msg.append(DESTROY).append("took ").append(BukkitUtils.toString(ca.itemStack)).append(" from ").append(prettyMaterial(type.getMaterial())); } else { - msg.append("put ").append(BukkitUtils.toString(ca.itemStack)).append(" into ").append(type.getMaterial().name()); + msg.append(CREATE).append("put ").append(BukkitUtils.toString(ca.itemStack)).append(" into ").append(prettyMaterial(type.getMaterial())); } } else if (BukkitUtils.getContainerBlocks().contains(type.getMaterial())) { - msg.append("opened ").append(type.getMaterial().name()); + msg.append(INTERACT).append("opened ").append(prettyMaterial(type.getMaterial())); } else if (type instanceof Openable) { // Door, Trapdoor, Fence gate - msg.append(((Openable)type).isOpen() ? "opened" : "closed").append(" ").append(type.getMaterial().name()); + msg.append(INTERACT).append(((Openable)type).isOpen() ? "opened" : "closed").append(" ").append(prettyMaterial(type.getMaterial())); } else if (type.getMaterial() == Material.LEVER) { - msg.append("switched ").append(type.getMaterial().name()).append(" ").append(((Switch) type).isPowered() ? "on" : "off"); + msg.append(INTERACT).append("switched ").append(prettyMaterial(type.getMaterial())).append(" ").append(prettyState(((Switch) type).isPowered() ? "on" : "off")); } else if (type instanceof Switch) { - msg.append("pressed ").append(type.getMaterial().name()); + msg.append(INTERACT).append("pressed ").append(prettyMaterial(type.getMaterial())); } else if (type.getMaterial() == Material.CAKE) { - msg.append("ate a piece of ").append(type.getMaterial().name()); + msg.append(DESTROY).append("ate a piece of ").append(prettyMaterial(type.getMaterial())); } else if (type.getMaterial() == Material.NOTE_BLOCK) { Note note = ((NoteBlock) type).getNote(); - msg.append("set ").append(type.getMaterial().name()).append(" to ").append(note.getTone().name()).append(note.isSharped() ? "#" : ""); + msg.append(INTERACT).append("set ").append(prettyMaterial(type.getMaterial())).append(" to ").append(prettyState(note.getTone().name() + (note.isSharped() ? "#" : ""))); } else if (type.getMaterial() == Material.REPEATER) { - msg.append("set ").append(type.getMaterial().name()).append(" to ").append(((Repeater) type).getDelay()).append(" ticks delay"); + msg.append(INTERACT).append("set ").append(prettyMaterial(type.getMaterial())).append(" to ").append(prettyState(((Repeater) type).getDelay())).append(" ticks delay"); } else if (type.getMaterial() == Material.COMPARATOR) { - msg.append("set ").append(type.getMaterial().name()).append(" to ").append(((Comparator) type).getMode()); + msg.append(INTERACT).append("set ").append(prettyMaterial(type.getMaterial())).append(" to ").append(prettyState(((Comparator) type).getMode())); } else if (type.getMaterial() == Material.DAYLIGHT_DETECTOR) { - msg.append("set ").append(type.getMaterial().name()).append(" to ").append(((DaylightDetector) type).isInverted() ? "inverted" : "normal"); + msg.append(INTERACT).append("set ").append(prettyMaterial(type.getMaterial())).append(" to ").append(prettyState(((DaylightDetector) type).isInverted() ? "inverted" : "normal")); } else if (type instanceof Powerable) { - msg.append("stepped on ").append(type.getMaterial().name()); + msg.append(INTERACT).append("stepped on ").append(prettyMaterial(type.getMaterial())); } else if (type.getMaterial() == Material.TRIPWIRE) { - msg.append("ran into ").append(type.getMaterial().name()); + msg.append(INTERACT).append("ran into ").append(prettyMaterial(type.getMaterial())); } else if (type instanceof Sign || type instanceof WallSign) { - msg.append("edited a ").append(type.getMaterial().name()).append(" to ").append(typeDetails); + msg.append(DESTROY).append("edited a ").append(prettyMaterial(type.getMaterial())).append(CREATE).append(" to ").append(prettyState(typeDetails)); } else { - msg.append("replaced ").append(replaced.getMaterial().name()).append(replacedDetails).append(" with ").append(type.getMaterial().name()).append(typeDetails); + msg.append(DESTROY).append("replaced ").append(prettyMaterial(replaced.getMaterial())).append(prettyState(replacedDetails)).append(CREATE).append(" with ").append(prettyMaterial(type.getMaterial())).append(prettyState(typeDetails)); } } else if (BukkitUtils.isEmpty(type.getMaterial())) { - msg.append("destroyed ").append(replaced.getMaterial().name()).append(replacedDetails); + msg.append(DESTROY).append("destroyed ").append(prettyMaterial(replaced.getMaterial())).append(prettyState(replacedDetails)); } else if (BukkitUtils.isEmpty(replaced.getMaterial())) { - msg.append("created ").append(type.getMaterial().name()).append(typeDetails); + msg.append(CREATE).append("created ").append(prettyMaterial(type.getMaterial())).append(prettyState(typeDetails)); } else { - msg.append("replaced ").append(replaced.getMaterial().name()).append(replacedDetails).append(" with ").append(type.getMaterial().name()).append(typeDetails); + msg.append(DESTROY).append("replaced ").append(prettyMaterial(replaced.getMaterial())).append(prettyState(replacedDetails)).append(CREATE).append(" with ").append(type.getMaterial().name()).append(typeDetails); } if (loc != null) { - msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ()); + msg.append(" at: ").append(prettyLocation(loc)); } return msg.toString(); } diff --git a/src/main/java/de/diddiz/LogBlock/ChatMessage.java b/src/main/java/de/diddiz/LogBlock/ChatMessage.java index 097f56bb..499e45ed 100644 --- a/src/main/java/de/diddiz/LogBlock/ChatMessage.java +++ b/src/main/java/de/diddiz/LogBlock/ChatMessage.java @@ -1,10 +1,13 @@ package de.diddiz.LogBlock; +import org.bukkit.ChatColor; import org.bukkit.Location; import java.sql.ResultSet; import java.sql.SQLException; +import static de.diddiz.util.ActionColor.CREATE; +import static de.diddiz.util.MessagingUtil.*; import static de.diddiz.util.LoggingUtil.checkText; public class ChatMessage implements LookupCacheElement { @@ -35,6 +38,6 @@ public Location getLocation() { @Override public String getMessage() { - return (player != null ? "<" + player.getName() + "> " : "") + (message != null ? message : ""); + return (playerName != null ? brackets(ChatColor.WHITE + playerName, BracketType.ANGLE) + ' ' : "") + (message != null ? CREATE + message : ""); } } diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index c19f5651..32df41c0 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -37,6 +37,9 @@ import static de.diddiz.LogBlock.config.Config.*; import static de.diddiz.util.BukkitUtils.giveTool; import static de.diddiz.util.BukkitUtils.saveSpawnHeight; +import static de.diddiz.util.TypeColor.DEFAULT; +import static de.diddiz.util.TypeColor.ERROR; +import static de.diddiz.util.TypeColor.HEADER; import static de.diddiz.util.Utils.isInt; import static de.diddiz.util.Utils.listing; @@ -382,19 +385,19 @@ private static void showPage(CommandSender sender, int page, LookupCacheElement[ final int stoppos = startpos + linesPerPage >= lookupElements.length ? lookupElements.length - 1 : startpos + linesPerPage - 1; final int numberOfPages = (int) Math.ceil(lookupElements.length / (double) linesPerPage); if (numberOfPages != 1) { - sender.sendMessage(ChatColor.DARK_AQUA + "Page " + page + "/" + numberOfPages); + sender.sendMessage(HEADER + "Page " + page + "/" + numberOfPages); } for (int i = startpos; i <= stoppos; i++) { - sender.sendMessage(ChatColor.GOLD + (lookupElements[i].getLocation() != null ? "(" + (i + 1) + ") " : "") + lookupElements[i].getMessage()); + sender.sendMessage(DEFAULT + (lookupElements[i].getLocation() != null ? "(" + (i + 1) + ") " : "") + lookupElements[i].getMessage()); } if (setSessionPage) { getSession(sender).page = page; } } else { - sender.sendMessage(ChatColor.RED + "There isn't a page '" + page + "'"); + sender.sendMessage(ERROR + "There isn't a page '" + page + "'"); } } else { - sender.sendMessage(ChatColor.RED + "No blocks in lookup cache"); + sender.sendMessage(ERROR + "No blocks in lookup cache"); } } diff --git a/src/main/java/de/diddiz/LogBlock/Kill.java b/src/main/java/de/diddiz/LogBlock/Kill.java index fc08156a..53a058ca 100755 --- a/src/main/java/de/diddiz/LogBlock/Kill.java +++ b/src/main/java/de/diddiz/LogBlock/Kill.java @@ -1,14 +1,18 @@ package de.diddiz.LogBlock; -import de.diddiz.LogBlock.config.Config; import de.diddiz.util.BukkitUtils; +import de.diddiz.util.TypeColor; import org.bukkit.Location; import org.bukkit.Material; import java.sql.ResultSet; import java.sql.SQLException; +import static de.diddiz.util.ActionColor.DESTROY; +import static de.diddiz.util.MessagingUtil.*; +import static de.diddiz.util.TypeColor.DEFAULT; + public class Kill implements LookupCacheElement { final long id, date; public final Location loc; @@ -37,15 +41,15 @@ public Kill(ResultSet rs, QueryParams p) throws SQLException { public String toString() { final StringBuilder msg = new StringBuilder(); if (date > 0) { - msg.append(Config.formatter.format(date)).append(" "); + msg.append(brackets(prettyDate(date), BracketType.STANDARD)).append(' '); } - msg.append(killerName).append(" killed ").append(victimName); + msg.append(killerName).append(DESTROY).append(" killed ").append(DEFAULT).append(victimName); if (loc != null) { - msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ()); + msg.append(" at ").append(prettyLocation(loc)); } if (weapon != 0) { String weaponName = prettyItemName(MaterialConverter.getMaterial(weapon)); - msg.append(" with " + weaponName); // + ("aeiou".contains(weaponName.substring(0, 1)) ? "an " : "a " ) + msg.append(" with ").append(weaponName); // + ("aeiou".contains(weaponName.substring(0, 1)) ? "an " : "a " ) } return msg.toString(); } @@ -62,8 +66,8 @@ public String getMessage() { public String prettyItemName(Material t) { if (t == null || BukkitUtils.isEmpty(t)) { - return "fist"; + return prettyMaterial("fist"); } - return t.toString().replace('_', ' ').toLowerCase(); + return prettyMaterial(t.toString().replace('_', ' ')); } } diff --git a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java index c7b0584e..c2e9e6b3 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java @@ -7,6 +7,10 @@ import java.sql.SQLException; import java.util.Objects; +import static de.diddiz.util.ActionColor.CREATE; +import static de.diddiz.util.ActionColor.DESTROY; +import static de.diddiz.util.MessagingUtil.prettyMaterial; +import static de.diddiz.util.TypeColor.DEFAULT; import static de.diddiz.util.Utils.spaces; public class SummedBlockChanges implements LookupCacheElement { @@ -31,6 +35,10 @@ public Location getLocation() { @Override public String getMessage() { - return created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)) + destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)) + (actor != null ? actor.getName() : Objects.toString(MaterialConverter.getMaterial(type))); + StringBuilder builder = new StringBuilder(); + builder.append(CREATE).append(created).append(spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor))); + builder.append(DESTROY).append(destroyed).append(spaces((int)((10 - String.valueOf(destroyed).length()) / spaceFactor))); + builder.append(actor != null ? DEFAULT + actor.getName() : prettyMaterial(Objects.toString(MaterialConverter.getMaterial(type)))); + return builder.toString(); } } diff --git a/src/main/java/de/diddiz/LogBlock/SummedKills.java b/src/main/java/de/diddiz/LogBlock/SummedKills.java index 3db77814..8e2db8dd 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedKills.java +++ b/src/main/java/de/diddiz/LogBlock/SummedKills.java @@ -5,6 +5,9 @@ import java.sql.ResultSet; import java.sql.SQLException; +import static de.diddiz.util.ActionColor.CREATE; +import static de.diddiz.util.ActionColor.DESTROY; +import static de.diddiz.util.TypeColor.DEFAULT; import static de.diddiz.util.Utils.spaces; public class SummedKills implements LookupCacheElement { @@ -26,6 +29,11 @@ public Location getLocation() { @Override public String getMessage() { - return kills + spaces((int) ((6 - String.valueOf(kills).length()) / spaceFactor)) + killed + spaces((int) ((7 - String.valueOf(killed).length()) / spaceFactor)) + player.getName(); + StringBuilder builder = new StringBuilder(); + builder.append(CREATE).append(kills).append(spaces((int)((6 - String.valueOf(kills).length()) / spaceFactor))); + builder.append(DESTROY).append(killed).append(spaces((int)((7 - String.valueOf(killed).length()) / spaceFactor))); + builder.append(DEFAULT).append(player.getName()); + return builder.toString(); + } } diff --git a/src/main/java/de/diddiz/util/ActionColor.java b/src/main/java/de/diddiz/util/ActionColor.java new file mode 100644 index 00000000..f3761d23 --- /dev/null +++ b/src/main/java/de/diddiz/util/ActionColor.java @@ -0,0 +1,24 @@ +package de.diddiz.util; + +import org.bukkit.ChatColor; + +public enum ActionColor { + DESTROY(ChatColor.RED), + CREATE(ChatColor.DARK_GREEN), + INTERACT(ChatColor.GRAY); + + private final ChatColor color; + + ActionColor(ChatColor color) { + this.color = color; + } + + public ChatColor getColor() { + return color; + } + + @Override + public String toString() { + return color.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index fea1162b..d63e0f15 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -28,6 +28,9 @@ import java.util.*; import java.util.Map.Entry; +import static de.diddiz.util.MessagingUtil.prettyMaterial; +import static de.diddiz.util.TypeColor.DEFAULT; + public class BukkitUtils { private static final Set> blockEquivalents; private static final Set relativeBreakable; @@ -642,10 +645,11 @@ public static boolean isEmpty(Material m) { public static String toString(ItemStack stack) { if (stack == null || stack.getAmount() == 0 || isEmpty(stack.getType())) { - return "nothing"; + return prettyMaterial("nothing"); } StringBuilder sb = new StringBuilder(); - sb.append(stack.getAmount()).append("x ").append(stack.getType().name()); + sb.append(stack.getAmount()).append("x ").append(prettyMaterial(stack.getType())); + sb.append(TypeColor.STATE); ItemMeta meta = stack.getItemMeta(); boolean metaStarted = false; if (meta.hasEnchants()) { @@ -659,8 +663,8 @@ public static String toString(ItemStack stack) { sb.append(", "); } sb.append(formatMinecraftKey(e.getKey().getKey().getKey())); - if (e.getValue().intValue() > 1) { - sb.append(" ").append(maybeToRoman(e.getValue().intValue() - 1)); + if (e.getValue() > 1) { + sb.append(" ").append(maybeToRoman(e.getValue() - 1)); } } } @@ -678,8 +682,8 @@ public static String toString(ItemStack stack) { sb.append(", "); } sb.append(formatMinecraftKey(e.getKey().getKey().getKey())); - if (e.getValue().intValue() > 1) { - sb.append(" ").append(maybeToRoman(e.getValue().intValue() - 1)); + if (e.getValue() > 1) { + sb.append(" ").append(maybeToRoman(e.getValue() - 1)); } } } @@ -688,6 +692,7 @@ public static String toString(ItemStack stack) { if (metaStarted) { sb.append("]"); } + sb.append(DEFAULT); return sb.toString(); } diff --git a/src/main/java/de/diddiz/util/MessagingUtil.java b/src/main/java/de/diddiz/util/MessagingUtil.java new file mode 100644 index 00000000..b3270821 --- /dev/null +++ b/src/main/java/de/diddiz/util/MessagingUtil.java @@ -0,0 +1,66 @@ +package de.diddiz.util; + +import de.diddiz.LogBlock.config.Config; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; + +import static de.diddiz.util.TypeColor.DEFAULT; + +public class MessagingUtil { + public static String brackets(String string, BracketType type) { + return TypeColor.BRACKETS + String.valueOf(type.getStarting()) + string + TypeColor.BRACKETS + type.getEnding() + DEFAULT; + } + + public static String prettyDate(long date) { + return TypeColor.DATE + Config.formatter.format(date) + DEFAULT; + } + + public static String prettyState(String stateName) { + return TypeColor.STATE + stateName.toUpperCase() + DEFAULT; + } + + public static String prettyState(int stateValue) { + return prettyState(Integer.toString(stateValue)); + } + + public static > String prettyState(E enumerator) { + return prettyState(enumerator.toString()); + } + + public static String prettyMaterial(String materialName) { + return TypeColor.MATERIAL + materialName.toUpperCase() + DEFAULT; + } + + public static String prettyMaterial(Material material) { + return prettyMaterial(material.name()); + } + + public static String prettyLocation(Location loc) { + return prettyLocation(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + } + + public static String prettyLocation(Number x, Number y, Number z) { + return DEFAULT + "X: " + TypeColor.COORDINATE + x.intValue() + DEFAULT + ", Y: " + TypeColor.COORDINATE + y.intValue() + DEFAULT + ", Z: " + TypeColor.COORDINATE + z.intValue() + DEFAULT; + } + + public enum BracketType { + STANDARD('[', ']'), + ANGLE('<', '>'); + + private char starting, ending; + + BracketType(char starting, char ending) { + this.starting = starting; + this.ending = ending; + } + + public char getStarting() { + return starting; + } + + public char getEnding() { + return ending; + } + } +} diff --git a/src/main/java/de/diddiz/util/TypeColor.java b/src/main/java/de/diddiz/util/TypeColor.java new file mode 100644 index 00000000..a35216aa --- /dev/null +++ b/src/main/java/de/diddiz/util/TypeColor.java @@ -0,0 +1,29 @@ +package de.diddiz.util; + +import org.bukkit.ChatColor; + +public enum TypeColor { + DEFAULT(ChatColor.YELLOW), + MATERIAL(ChatColor.BLUE), + STATE(ChatColor.BLUE), + DATE(ChatColor.DARK_AQUA), + BRACKETS(ChatColor.DARK_GRAY), + COORDINATE(ChatColor.WHITE), + HEADER(ChatColor.GOLD), + ERROR(ChatColor.RED); + + private final ChatColor color; + + TypeColor(ChatColor color) { + this.color = color; + } + + public ChatColor getColor() { + return color; + } + + @Override + public String toString() { + return color.toString(); + } +} From 4fda020dfcc773b8a493437f03a4d2806786c556 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 27 May 2019 22:46:32 +0200 Subject: [PATCH 193/399] Log sign base color change --- .../blockstate/BlockStateCodecSign.java | 28 ++++++-- .../LogBlock/listeners/InteractLogging.java | 66 +++++++++++++++---- src/main/java/de/diddiz/util/BukkitUtils.java | 27 ++++++++ 3 files changed, 104 insertions(+), 17 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index 8864de2b..9df3cfd7 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -3,7 +3,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; - +import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; @@ -27,9 +27,18 @@ public YamlConfiguration serialize(BlockState state) { break; } } - if (hasText) { + DyeColor signColor = sign.getColor(); + if (signColor == null) { + signColor = DyeColor.BLACK; + } + if (hasText || signColor != DyeColor.BLACK) { YamlConfiguration conf = new YamlConfiguration(); - conf.set("lines", Arrays.asList(lines)); + if (hasText) { + conf.set("lines", Arrays.asList(lines)); + } + if (signColor != DyeColor.BLACK) { + conf.set("color", signColor.name()); + } return conf; } } @@ -49,14 +58,25 @@ public static YamlConfiguration serialize(String[] lines) { public void deserialize(BlockState state, YamlConfiguration conf) { if (state instanceof Sign) { Sign sign = (Sign) state; + DyeColor signColor = DyeColor.BLACK; List lines = Collections.emptyList(); if (conf != null) { - lines = conf.getStringList("lines"); + if (conf.contains("lines")) { + lines = conf.getStringList("lines"); + } + if (conf.contains("color")) { + try { + signColor = DyeColor.valueOf(conf.getString("color")); + } catch (IllegalArgumentException | NullPointerException e) { + // ignored + } + } } for (int i = 0; i < 4; i++) { String line = lines.size() > i && lines.get(i) != null ? lines.get(i) : ""; sign.setLine(i, line); } + sign.setColor(signColor); } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index b89656a3..743c39ec 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -5,12 +5,15 @@ import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.util.BukkitUtils; +import org.bukkit.DyeColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Note; import org.bukkit.Note.Tone; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.block.Sign; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Directional; import org.bukkit.block.data.Openable; @@ -178,23 +181,60 @@ public void onPlayerInteract(PlayerInteractEvent event) { } } break; - default: - if (BukkitUtils.isButton(type) || type == Material.LEVER) { - if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Switch newBlockData = (Switch) blockData.clone(); - if (!newBlockData.isPowered() || type == Material.LEVER) { - newBlockData.setPowered(!newBlockData.isPowered()); - } - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + case OAK_DOOR: + case SPRUCE_DOOR: + case BIRCH_DOOR: + case JUNGLE_DOOR: + case ACACIA_DOOR: + case DARK_OAK_DOOR: + if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Door newBlockData = (Door) blockData.clone(); + newBlockData.setOpen(!newBlockData.isOpen()); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + break; + case STONE_BUTTON: + case OAK_BUTTON: + case SPRUCE_BUTTON: + case BIRCH_BUTTON: + case JUNGLE_BUTTON: + case ACACIA_BUTTON: + case DARK_OAK_BUTTON: + case LEVER: + if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Switch newBlockData = (Switch) blockData.clone(); + if (!newBlockData.isPowered() || type == Material.LEVER) { + newBlockData.setPowered(!newBlockData.isPowered()); } + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); } - if (BukkitUtils.isWoodenDoor(type)) { - if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Door newBlockData = (Door) blockData.clone(); - newBlockData.setOpen(!newBlockData.isOpen()); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + break; + case OAK_SIGN: + case SPRUCE_SIGN: + case BIRCH_SIGN: + case JUNGLE_SIGN: + case ACACIA_SIGN: + case DARK_OAK_SIGN: + case OAK_WALL_SIGN: + case SPRUCE_WALL_SIGN: + case BIRCH_WALL_SIGN: + case JUNGLE_WALL_SIGN: + case ACACIA_WALL_SIGN: + case DARK_OAK_WALL_SIGN: + ItemStack stack = event.getItem(); + if (stack != null && BukkitUtils.isDye(stack.getType())) { + final BlockState before = event.getClickedBlock().getState(); + if (before instanceof Sign) { + DyeColor newColor = BukkitUtils.dyeToDyeColor(stack.getType()); + Sign signBefore = (Sign) before; + if (newColor != null && signBefore.getColor() != newColor) { + final Sign signAfter = (Sign) event.getClickedBlock().getState(); + signAfter.setColor(newColor); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } } } + default: } } } diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index fea1162b..651dc9d6 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -50,6 +50,7 @@ public class BukkitUtils { private static final EnumSet woodenDoors; private static final EnumSet slabs; private static final EnumSet concreteBlocks; + private static final EnumMap dyes; static { pressurePlates = EnumSet.noneOf(Material.class); @@ -393,6 +394,24 @@ public class BukkitUtils { concreteBlocks.add(Material.RED_CONCRETE); concreteBlocks.add(Material.WHITE_CONCRETE); concreteBlocks.add(Material.YELLOW_CONCRETE); + + dyes = new EnumMap<>(Material.class); + dyes.put(Material.BLACK_DYE, DyeColor.BLACK); + dyes.put(Material.BLUE_DYE, DyeColor.BLUE); + dyes.put(Material.LIGHT_GRAY_DYE, DyeColor.LIGHT_GRAY); + dyes.put(Material.BROWN_DYE, DyeColor.BROWN); + dyes.put(Material.CYAN_DYE, DyeColor.CYAN); + dyes.put(Material.GRAY_DYE, DyeColor.GRAY); + dyes.put(Material.GREEN_DYE, DyeColor.GREEN); + dyes.put(Material.LIGHT_BLUE_DYE, DyeColor.LIGHT_BLUE); + dyes.put(Material.MAGENTA_DYE, DyeColor.MAGENTA); + dyes.put(Material.LIME_DYE, DyeColor.LIME); + dyes.put(Material.ORANGE_DYE, DyeColor.ORANGE); + dyes.put(Material.PINK_DYE, DyeColor.PINK); + dyes.put(Material.PURPLE_DYE, DyeColor.PURPLE); + dyes.put(Material.RED_DYE, DyeColor.RED); + dyes.put(Material.WHITE_DYE, DyeColor.WHITE); + dyes.put(Material.YELLOW_DYE, DyeColor.YELLOW); } private static final BlockFace[] relativeBlockFaces = new BlockFace[]{ @@ -727,6 +746,14 @@ public static boolean isBed(Material type) { return bedBlocks.contains(type); } + public static boolean isDye(Material type) { + return dyes.containsKey(type); + } + + public static DyeColor dyeToDyeColor(Material type) { + return dyes.get(type); + } + public static Block getConnectedChest(Block chestBlock) { // is this a chest? BlockData blockData = chestBlock.getBlockData(); From 424ef3b02bf0af190836def8ad7187783a8500eb Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 27 May 2019 23:53:50 +0200 Subject: [PATCH 194/399] Only log sign base color changes when we log SIGNTEXT for this world --- .../LogBlock/listeners/InteractLogging.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index 743c39ec..e3dacc12 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -221,16 +221,18 @@ public void onPlayerInteract(PlayerInteractEvent event) { case JUNGLE_WALL_SIGN: case ACACIA_WALL_SIGN: case DARK_OAK_WALL_SIGN: - ItemStack stack = event.getItem(); - if (stack != null && BukkitUtils.isDye(stack.getType())) { - final BlockState before = event.getClickedBlock().getState(); - if (before instanceof Sign) { - DyeColor newColor = BukkitUtils.dyeToDyeColor(stack.getType()); - Sign signBefore = (Sign) before; - if (newColor != null && signBefore.getColor() != newColor) { - final Sign signAfter = (Sign) event.getClickedBlock().getState(); - signAfter.setColor(newColor); - consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + if (wcfg.isLogging(Logging.SIGNTEXT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + ItemStack stack = event.getItem(); + if (stack != null && BukkitUtils.isDye(stack.getType())) { + final BlockState before = event.getClickedBlock().getState(); + if (before instanceof Sign) { + DyeColor newColor = BukkitUtils.dyeToDyeColor(stack.getType()); + Sign signBefore = (Sign) before; + if (newColor != null && signBefore.getColor() != newColor) { + final Sign signAfter = (Sign) event.getClickedBlock().getState(); + signAfter.setColor(newColor); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } } } } From da692ed01a05bb5ef3aad503b33e58861798f863 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 28 May 2019 05:25:25 +0200 Subject: [PATCH 195/399] Log lectern book change --- .../java/de/diddiz/LogBlock/BlockChange.java | 3 ++ .../java/de/diddiz/LogBlock/LogBlock.java | 3 ++ src/main/java/de/diddiz/LogBlock/Logging.java | 3 +- .../blockstate/BlockStateCodecLectern.java | 50 +++++++++++++++++++ .../LogBlock/blockstate/BlockStateCodecs.java | 1 + .../LogBlock/listeners/BlockPlaceLogging.java | 4 +- .../LogBlock/listeners/LecternLogging.java | 30 +++++++++++ 7 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java create mode 100644 src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index ecd5a0c9..16b2a7e1 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -13,6 +13,7 @@ import org.bukkit.block.data.Powerable; import org.bukkit.block.data.type.Comparator; import org.bukkit.block.data.type.DaylightDetector; +import org.bukkit.block.data.type.Lectern; import org.bukkit.block.data.type.NoteBlock; import org.bukkit.block.data.type.Repeater; import org.bukkit.block.data.type.Sign; @@ -141,6 +142,8 @@ public String toString() { msg.append("set ").append(type.getMaterial().name()).append(" to ").append(((Comparator) type).getMode()); } else if (type.getMaterial() == Material.DAYLIGHT_DETECTOR) { msg.append("set ").append(type.getMaterial().name()).append(" to ").append(((DaylightDetector) type).isInverted() ? "inverted" : "normal"); + } else if (type instanceof Lectern) { + msg.append("changed the book on a ").append(type.getMaterial().name()).append(" to").append(replacedDetails.length() == 0 ? "empty" : replacedDetails); } else if (type instanceof Powerable) { msg.append("stepped on ").append(type.getMaterial().name()); } else if (type.getMaterial() == Material.TRIPWIRE) { diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index e57afe4a..4f3fbaac 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -189,6 +189,9 @@ private void registerEvents() { if (isLogging(Logging.DRAGONEGGTELEPORT)) { pm.registerEvents(new DragonEggLogging(this), this); } + if (isLogging(Logging.LECTERNBOOKCHANGE)) { + pm.registerEvents(new LecternLogging(this), this); + } if (Config.isLoggingAnyEntities()) { if (!WorldEditHelper.hasFullWorldEdit()) { getLogger().severe("No compatible WorldEdit found, entity logging will not work!"); diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index 683a53d8..6259fe38 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -8,7 +8,8 @@ public enum Logging { PRESUREPLATEINTERACT, TRIPWIREINTERACT, CREATURECROPTRAMPLE, CROPTRAMPLE, NATURALSTRUCTUREGROW, GRASSGROWTH, MYCELIUMSPREAD, VINEGROWTH, MUSHROOMSPREAD, WITHER(true), WITHER_SKULL(true), BONEMEALSTRUCTUREGROW, WORLDEDIT, TNTMINECARTEXPLOSION(true), - ENDERCRYSTALEXPLOSION(true), BEDEXPLOSION(true), DRAGONEGGTELEPORT(true), DAYLIGHTDETECTORINTERACT; + ENDERCRYSTALEXPLOSION(true), BEDEXPLOSION(true), DRAGONEGGTELEPORT(true), DAYLIGHTDETECTORINTERACT, + LECTERNBOOKCHANGE(true); public static final int length = Logging.values().length; private final boolean defaultEnabled; diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java new file mode 100644 index 00000000..14e2a956 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java @@ -0,0 +1,50 @@ +package de.diddiz.LogBlock.blockstate; + +import org.bukkit.Material; +import org.bukkit.block.BlockState; +import org.bukkit.block.Lectern; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemStack; + +public class BlockStateCodecLectern implements BlockStateCodec { + @Override + public Material[] getApplicableMaterials() { + return new Material[] { Material.LECTERN }; + } + + @Override + public YamlConfiguration serialize(BlockState state) { + if (state instanceof Lectern) { + Lectern lectern = (Lectern) state; + ItemStack book = lectern.getSnapshotInventory().getItem(0); + if (book != null && book.getType() != Material.AIR) { + YamlConfiguration conf = new YamlConfiguration(); + conf.set("book", book); + return conf; + } + } + return null; + } + + @Override + public void deserialize(BlockState state, YamlConfiguration conf) { + if (state instanceof Lectern) { + Lectern lectern = (Lectern) state; + ItemStack book = null; + if (conf != null) { + book = conf.getItemStack("book"); + } + lectern.getSnapshotInventory().setItem(0, book); + } + } + + @Override + public String toString(YamlConfiguration conf) { + if (conf != null) { + StringBuilder sb = new StringBuilder(); + sb.append("[").append("book").append("]"); + return sb.toString(); + } + return null; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java index de446938..403d8d19 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java @@ -25,6 +25,7 @@ public static void registerCodec(BlockStateCodec codec) { registerCodec(new BlockStateCodecSkull()); registerCodec(new BlockStateCodecBanner()); registerCodec(new BlockStateCodecSpawner()); + registerCodec(new BlockStateCodecLectern()); } public static boolean hasCodec(Material material) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java index 24b90a21..cf1bd4bb 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java @@ -29,7 +29,9 @@ public void onBlockPlace(BlockPlaceEvent event) { final BlockState before = event.getBlockReplacedState(); final BlockState after = event.getBlockPlaced().getState(); final Actor actor = Actor.actorFromEntity(event.getPlayer()); - + if (before.getType() == Material.LECTERN && after.getType() == Material.LECTERN && !Config.isLogging(event.getBlock().getWorld(), Logging.LECTERNBOOKCHANGE)) { + return; + } LoggingUtil.smartLogBlockPlace(consumer, actor, before, after); } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java new file mode 100644 index 00000000..491d4b28 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java @@ -0,0 +1,30 @@ +package de.diddiz.LogBlock.listeners; + +import static de.diddiz.LogBlock.config.Config.getWorldConfig; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.WorldConfig; +import org.bukkit.block.Lectern; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerTakeLecternBookEvent; + +public class LecternLogging extends LoggingListener { + public LecternLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerTakeLecternBook(PlayerTakeLecternBookEvent event) { + final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld()); + if (wcfg != null && wcfg.isLogging(Logging.LECTERNBOOKCHANGE)) { + Lectern oldState = event.getLectern(); + Lectern newState = (Lectern) oldState.getBlock().getState(); + newState.getSnapshotInventory().setItem(0, null); + + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), oldState, newState); + } + } +} From 9eef03aa9038a21eca0e6598be8fa02e846c9cc0 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 28 May 2019 06:07:57 +0200 Subject: [PATCH 196/399] Fix lectern logging --- .../java/de/diddiz/LogBlock/BlockChange.java | 2 +- .../LogBlock/listeners/BlockPlaceLogging.java | 2 +- .../LogBlock/listeners/LecternLogging.java | 27 ++++++++++++++++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 16b2a7e1..450f7fdd 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -143,7 +143,7 @@ public String toString() { } else if (type.getMaterial() == Material.DAYLIGHT_DETECTOR) { msg.append("set ").append(type.getMaterial().name()).append(" to ").append(((DaylightDetector) type).isInverted() ? "inverted" : "normal"); } else if (type instanceof Lectern) { - msg.append("changed the book on a ").append(type.getMaterial().name()).append(" to").append(replacedDetails.length() == 0 ? "empty" : replacedDetails); + msg.append("changed the book on a ").append(type.getMaterial().name()).append(" to").append(typeDetails.length() == 0 ? " empty" : typeDetails); } else if (type instanceof Powerable) { msg.append("stepped on ").append(type.getMaterial().name()); } else if (type.getMaterial() == Material.TRIPWIRE) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java index cf1bd4bb..9912f907 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java @@ -29,7 +29,7 @@ public void onBlockPlace(BlockPlaceEvent event) { final BlockState before = event.getBlockReplacedState(); final BlockState after = event.getBlockPlaced().getState(); final Actor actor = Actor.actorFromEntity(event.getPlayer()); - if (before.getType() == Material.LECTERN && after.getType() == Material.LECTERN && !Config.isLogging(event.getBlock().getWorld(), Logging.LECTERNBOOKCHANGE)) { + if (before.getType() == Material.LECTERN && after.getType() == Material.LECTERN) { return; } LoggingUtil.smartLogBlockPlace(consumer, actor, before, after); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java index 491d4b28..e6b367c6 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java @@ -6,16 +6,37 @@ import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; +import org.bukkit.Material; +import org.bukkit.block.BlockState; import org.bukkit.block.Lectern; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerTakeLecternBookEvent; +import org.bukkit.inventory.ItemStack; public class LecternLogging extends LoggingListener { public LecternLogging(LogBlock lb) { super(lb); } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + 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); + lecternBefore.getSnapshotInventory().setItem(0, null); + lecternBefore.setBlockData(before.getBlockData()); + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), lecternBefore, after); + lecternBefore.getSnapshotInventory().setItem(0, book); + } + } + } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerTakeLecternBook(PlayerTakeLecternBookEvent event) { final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld()); @@ -23,7 +44,11 @@ public void onPlayerTakeLecternBook(PlayerTakeLecternBookEvent event) { Lectern oldState = event.getLectern(); Lectern newState = (Lectern) oldState.getBlock().getState(); newState.getSnapshotInventory().setItem(0, null); - + org.bukkit.block.data.type.Lectern oldBlockData = (org.bukkit.block.data.type.Lectern) oldState.getBlockData(); + org.bukkit.block.data.type.Lectern blockData = (org.bukkit.block.data.type.Lectern) Material.LECTERN.createBlockData(); + blockData.setFacing(oldBlockData.getFacing()); + blockData.setPowered(oldBlockData.isPowered()); + newState.setBlockData(blockData); consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), oldState, newState); } } From 72fc78b3c075973b1956f85f75769ef76ea79322 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 28 May 2019 07:30:56 +0200 Subject: [PATCH 197/399] Add missing break --- src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index e3dacc12..acfbceb9 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -236,6 +236,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { } } } + break; default: } } From 05d7652bccc967d0a08c758376d398cede4b19c8 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 31 May 2019 18:00:55 +0200 Subject: [PATCH 198/399] Improve log messages when the block/entity type is unknown --- .../java/de/diddiz/LogBlock/BlockChange.java | 17 +++--- .../java/de/diddiz/LogBlock/EntityChange.java | 52 ++++++++++--------- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 450f7fdd..64b4d531 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -73,10 +73,18 @@ public BlockChange(ResultSet rs, QueryParams p) throws SQLException { @Override public String toString() { + final StringBuilder msg = new StringBuilder(); + if (date > 0) { + msg.append(Config.formatter.format(date)).append(" "); + } + if (actor != null) { + msg.append(actor.getName()).append(" "); + } BlockData type = getBlockSet(); BlockData replaced = getBlockReplaced(); if (type == null || replaced == null) { - return "Unknown block modification"; + msg.append("did an unknown block modification"); + return msg.toString(); } String typeDetails = null; if (BlockStateCodecs.hasCodec(type.getMaterial())) { @@ -104,13 +112,6 @@ public String toString() { } else { replacedDetails = " " + replacedDetails; } - final StringBuilder msg = new StringBuilder(); - if (date > 0) { - msg.append(Config.formatter.format(date)).append(" "); - } - if (actor != null) { - msg.append(actor.getName()).append(" "); - } if (type.getMaterial().equals(replaced.getMaterial())) { if (BukkitUtils.isEmpty(type.getMaterial())) { msg.append("did an unspecified action"); diff --git a/src/main/java/de/diddiz/LogBlock/EntityChange.java b/src/main/java/de/diddiz/LogBlock/EntityChange.java index 90c389b3..b0056928 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityChange.java +++ b/src/main/java/de/diddiz/LogBlock/EntityChange.java @@ -71,32 +71,36 @@ public String toString() { if (actor != null) { msg.append(actor.getName()).append(" "); } - if (type != null) { - boolean living = LivingEntity.class.isAssignableFrom(type.getEntityClass()) && !ArmorStand.class.isAssignableFrom(type.getDeclaringClass()); - if (changeType == EntityChangeType.CREATE) { - msg.append("created "); - } else if (changeType == EntityChangeType.KILL) { - msg.append(living ? "killed " : "destroyed "); - } else if (changeType == EntityChangeType.ADDEQUIP) { - YamlConfiguration conf = Utils.deserializeYamlConfiguration(data); - ItemStack stack = conf == null ? null : conf.getItemStack("item"); - if (stack == null) { - msg.append("added an item to "); - } else { - msg.append("added " + stack.getType() + " to "); - } - } else if (changeType == EntityChangeType.REMOVEEQUIP) { - YamlConfiguration conf = Utils.deserializeYamlConfiguration(data); - ItemStack stack = conf == null ? null : conf.getItemStack("item"); - if (stack == null) { - msg.append("removed an item from "); - } else { - msg.append("removed " + stack.getType() + " from "); - } - } else if (changeType == EntityChangeType.MODIFY) { - msg.append("modified "); + if (changeType == EntityChangeType.CREATE) { + msg.append("created "); + } else if (changeType == EntityChangeType.KILL) { + boolean living = type != null && LivingEntity.class.isAssignableFrom(type.getEntityClass()) && !ArmorStand.class.isAssignableFrom(type.getDeclaringClass()); + msg.append(living ? "killed " : "destroyed "); + } else if (changeType == EntityChangeType.ADDEQUIP) { + YamlConfiguration conf = Utils.deserializeYamlConfiguration(data); + ItemStack stack = conf == null ? null : conf.getItemStack("item"); + if (stack == null) { + msg.append("added an item to "); + } else { + msg.append("added " + stack.getType() + " to "); + } + } else if (changeType == EntityChangeType.REMOVEEQUIP) { + YamlConfiguration conf = Utils.deserializeYamlConfiguration(data); + ItemStack stack = conf == null ? null : conf.getItemStack("item"); + if (stack == null) { + msg.append("removed an item from "); + } else { + msg.append("removed " + stack.getType() + " from "); } + } else if (changeType == EntityChangeType.MODIFY) { + msg.append("modified "); + } else { + msg.append("did an unknown action to "); + } + if (type != null) { msg.append(type.name()); + } else { + msg.append("an unknown entity"); } if (loc != null) { msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ()); From 3efd92d9dfae7ffe6583a3bce0f62a4ad85309c6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 20 Jun 2019 05:37:55 +0200 Subject: [PATCH 199/399] loadChunk will keep chunks loaded forever, so do not use that --- src/main/java/de/diddiz/LogBlock/WorldEditor.java | 3 --- src/main/java/de/diddiz/util/BukkitUtils.java | 5 +---- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 668a4a37..67df99bf 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -348,9 +348,6 @@ public PerformResult perform() throws WorldEditorException { return PerformResult.BLACKLISTED; } final Block block = loc.getBlock(); - if (!world.isChunkLoaded(block.getChunk())) { - world.loadChunk(block.getChunk()); - } if (BukkitUtils.isEmpty(replacedBlock.getMaterial()) && BukkitUtils.isEmpty(block.getType())) { return PerformResult.NO_ACTION; } diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 651dc9d6..2891dec4 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -589,9 +589,6 @@ public static void giveTool(Player player, Material type) { public static int saveSpawnHeight(Location loc) { final World world = loc.getWorld(); final Chunk chunk = world.getChunkAt(loc); - if (!world.isChunkLoaded(chunk)) { - world.loadChunk(chunk); - } final int x = loc.getBlockX(), z = loc.getBlockZ(); int y = loc.getBlockY(); boolean lower = world.getBlockAt(x, y, z).isEmpty(), upper = world.getBlockAt(x, y + 1, z).isEmpty(); @@ -814,7 +811,7 @@ public static Entity loadEntityAround(Chunk chunk, UUID uuid) { int x = i < 3 ? chunkx - 1 : (i < 5 ? chunkx : chunkx + 1); int z = i == 0 || i == 3 || i == 5 ? chunkz - 1 : (i == 1 || i == 6 ? chunkz : chunkz + 1); if (!chunk.getWorld().isChunkLoaded(x, z)) { - chunk.getWorld().loadChunk(x, z); + chunk.getWorld().getChunkAt(x, z); e = Bukkit.getEntity(uuid); if (e != null) { return e; From e6b0108bc5546736bb716d950c45a7314e496326 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 20 Jun 2019 06:08:59 +0200 Subject: [PATCH 200/399] Chunk.load is just as World.loadChunk --- src/main/java/de/diddiz/util/BukkitUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 2891dec4..e1baa87b 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -799,7 +799,7 @@ public static Entity loadEntityAround(Chunk chunk, UUID uuid) { return e; } if (!chunk.isLoaded()) { - chunk.load(); + chunk.getWorld().getChunkAt(chunk.getX(), chunk.getZ()); e = Bukkit.getEntity(uuid); if (e != null) { return e; From 9b5e0c9025ac1b85e1eebcd792cf22b16c70646f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 23 Jun 2019 05:22:18 +0200 Subject: [PATCH 201/399] WorldEdit logging should only log modified blocks Fixes #757 --- .../worldedit/WorldEditLoggingHook.java | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java index dd0c4ebc..1a9ab285 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java @@ -74,26 +74,30 @@ public final > boolean setBlock(BlockVector3 posit onBlockChange(position, block); return super.setBlock(position, block); } - + protected > void onBlockChange(BlockVector3 pt, B block) { if (event.getStage() != EditSession.Stage.BEFORE_CHANGE) { return; } - Location location = new Location(world, pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - Block origin = location.getBlock(); - Material typeBefore = origin.getType(); - - // Check to see if we've broken a sign - if (BlockStateCodecs.hasCodec(typeBefore)) { - plugin.getConsumer().queueBlockBreak(lbActor, origin.getState()); - } else if (!origin.isEmpty()) { - plugin.getConsumer().queueBlockBreak(lbActor, location, origin.getBlockData()); - } - BlockData newBlock = BukkitAdapter.adapt(block); - if (newBlock != null && !BukkitUtils.isEmpty(newBlock.getMaterial())) { - plugin.getConsumer().queueBlockPlace(lbActor, location, newBlock); + Location location = BukkitAdapter.adapt(world, pt); + Block blockBefore = location.getBlock(); + BlockData blockDataBefore = blockBefore.getBlockData(); + Material typeBefore = blockDataBefore.getMaterial(); + + BlockData blockDataNew = BukkitAdapter.adapt(block); + + if (!blockDataBefore.equals(blockDataNew)) { + // Check to see if we've broken a sign + if (BlockStateCodecs.hasCodec(typeBefore)) { + plugin.getConsumer().queueBlockBreak(lbActor, blockBefore.getState()); + } else if (!BukkitUtils.isEmpty(typeBefore)) { + plugin.getConsumer().queueBlockBreak(lbActor, location, blockDataBefore); + } + if (!BukkitUtils.isEmpty(blockDataNew.getMaterial())) { + plugin.getConsumer().queueBlockPlace(lbActor, location, blockDataNew); + } } } }); From 76f7f8701d413f11261af4474b49a6777e890251 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 23 Jun 2019 05:23:31 +0200 Subject: [PATCH 202/399] Improve logging of 1.14 blocks --- src/main/java/de/diddiz/util/BukkitUtils.java | 21 ++++++-- src/main/java/de/diddiz/util/LoggingUtil.java | 49 ++++++++++++++++--- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index e1baa87b..35acdbac 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -144,6 +144,10 @@ public class BukkitUtils { singleBlockPlants.add(Material.OXEYE_DAISY); singleBlockPlants.add(Material.BROWN_MUSHROOM); singleBlockPlants.add(Material.RED_MUSHROOM); + singleBlockPlants.add(Material.SWEET_BERRY_BUSH); + singleBlockPlants.add(Material.LILY_OF_THE_VALLEY); + singleBlockPlants.add(Material.CORNFLOWER); + singleBlockPlants.add(Material.WITHER_ROSE); doublePlants = EnumSet.noneOf(Material.class); doublePlants.add(Material.TALL_GRASS); @@ -178,6 +182,7 @@ public class BukkitUtils { relativeBreakable.add(Material.WALL_TORCH); relativeBreakable.add(Material.TRIPWIRE_HOOK); relativeBreakable.add(Material.COCOA); + relativeBreakable.add(Material.BELL); // Blocks that break when they are on top of a block relativeTopBreakable = EnumSet.noneOf(Material.class); @@ -206,13 +211,18 @@ public class BukkitUtils { relativeTopBreakable.add(Material.REPEATER); relativeTopBreakable.add(Material.COMPARATOR); relativeTopBreakable.add(Material.TORCH); - relativeTopBreakable.add(Material.WALL_TORCH); relativeTopBreakable.add(Material.REDSTONE_TORCH); - relativeTopBreakable.add(Material.REDSTONE_WALL_TORCH); relativeTopBreakable.addAll(woodenDoors); relativeTopBreakable.add(Material.IRON_DOOR); relativeTopBreakable.addAll(carpets); relativeTopBreakable.addAll(doublePlants); + relativeTopBreakable.add(Material.BAMBOO); + relativeTopBreakable.add(Material.BAMBOO_SAPLING); + for(Material m : Material.values()) { + if(m.name().startsWith("POTTED_")) { + relativeTopBreakable.add(m); + } + } // Blocks that break falling entities fallingEntityKillers = EnumSet.noneOf(Material.class); @@ -314,6 +324,10 @@ public class BukkitUtils { containerBlocks.add(Material.RED_SHULKER_BOX); containerBlocks.add(Material.WHITE_SHULKER_BOX); containerBlocks.add(Material.YELLOW_SHULKER_BOX); + containerBlocks.add(Material.BARREL); + containerBlocks.add(Material.BLAST_FURNACE); + containerBlocks.add(Material.SMOKER); + containerBlocks.add(Material.LECTERN); // Doesn't actually have a block inventory // containerBlocks.add(Material.ENDER_CHEST); @@ -329,6 +343,7 @@ public class BukkitUtils { projectileItems.put(EntityType.SPLASH_POTION, Material.SPLASH_POTION); projectileItems.put(EntityType.THROWN_EXP_BOTTLE, Material.EXPERIENCE_BOTTLE); projectileItems.put(EntityType.WITHER_SKULL, Material.WITHER_SKELETON_SKULL); + projectileItems.put(EntityType.FIREWORK, Material.FIREWORK_ROCKET); nonFluidProofBlocks = EnumSet.noneOf(Material.class); nonFluidProofBlocks.addAll(singleBlockPlants); @@ -588,7 +603,7 @@ public static void giveTool(Player player, Material type) { public static int saveSpawnHeight(Location loc) { final World world = loc.getWorld(); - final Chunk chunk = world.getChunkAt(loc); + world.getChunkAt(loc); final int x = loc.getBlockX(), z = loc.getBlockZ(); int y = loc.getBlockY(); boolean lower = world.getBlockAt(x, y, z).isEmpty(), upper = world.getBlockAt(x, y + 1, z).isEmpty(); diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index cec6d1e6..1e269fa6 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -10,7 +10,9 @@ import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Directional; - +import org.bukkit.block.data.type.Bell; +import org.bukkit.block.data.type.Bell.Attachment; +import org.bukkit.block.data.type.Lantern; import java.util.List; import static de.diddiz.LogBlock.config.Config.getWorldConfig; @@ -110,8 +112,9 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or } Block checkBlock = origin.getRelative(BlockFace.UP); - if (BukkitUtils.getRelativeTopBreakabls().contains(checkBlock.getType())) { - if (checkBlock.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(checkBlock.getType())) { + Material typeAbove = checkBlock.getType(); + if (BukkitUtils.getRelativeTopBreakabls().contains(typeAbove)) { + if (typeAbove == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(typeAbove)) { Block doorBlock = checkBlock; // If the doorBlock is the top half a door the player simply punched a door // this will be handled later. @@ -123,7 +126,7 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or } consumer.queueBlockBreak(actor, checkBlock.getState()); } - } else if (BukkitUtils.isDoublePlant(checkBlock.getType())) { + } else if (BukkitUtils.isDoublePlant(typeAbove)) { Block plantBlock = checkBlock; // If the plantBlock is the top half of a double plant the player simply // punched the plant this will be handled later. @@ -138,16 +141,48 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or } else { consumer.queueBlockBreak(actor, checkBlock.getState()); } + } else if(typeAbove == Material.LANTERN) { + Lantern lantern = (Lantern) checkBlock.getBlockData(); + if(!lantern.isHanging()) { + consumer.queueBlockBreak(actor, checkBlock.getState()); + } + }else if(typeAbove == Material.BELL) { + Bell bell = (Bell) checkBlock.getBlockData(); + if(bell.getAttachment() == Attachment.FLOOR) { + consumer.queueBlockBreak(actor, checkBlock.getState()); + } } - + + checkBlock = origin.getRelative(BlockFace.DOWN); + Material typeBelow = checkBlock.getType(); + if(typeBelow == Material.LANTERN) { + Lantern lantern = (Lantern) checkBlock.getBlockData(); + if(lantern.isHanging()) { + consumer.queueBlockBreak(actor, checkBlock.getState()); + } + } else if(typeBelow == Material.BELL) { + Bell bell = (Bell) checkBlock.getBlockData(); + if(bell.getAttachment() == Attachment.CEILING) { + consumer.queueBlockBreak(actor, checkBlock.getState()); + } + } + List relativeBreakables = BukkitUtils.getBlocksNearby(origin, BukkitUtils.getRelativeBreakables()); if (relativeBreakables.size() != 0) { for (Location location : relativeBreakables) { Block block = location.getBlock(); BlockData blockData = block.getBlockData(); if (blockData instanceof Directional) { - if (block.getRelative(((Directional) blockData).getFacing().getOppositeFace()).equals(origin)) { - consumer.queueBlockBreak(actor, block.getState()); + if (blockData.getMaterial() == Material.BELL) { + if (((Bell) blockData).getAttachment() == Attachment.SINGLE_WALL) { + if (block.getRelative(((Bell) blockData).getFacing()).equals(origin)) { + consumer.queueBlockBreak(actor, block.getState()); + } + } + } else { + if (block.getRelative(((Directional) blockData).getFacing().getOppositeFace()).equals(origin)) { + consumer.queueBlockBreak(actor, block.getState()); + } } } } From 1525d7682ff2541bddccb6653c037480e9e146e1 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 23 Jun 2019 16:45:14 +0200 Subject: [PATCH 203/399] Reformat --- .../java/de/diddiz/LogBlock/BlockChange.java | 4 +- .../de/diddiz/LogBlock/CommandsHandler.java | 16 +- .../java/de/diddiz/LogBlock/Consumer.java | 4 +- .../java/de/diddiz/LogBlock/LogBlock.java | 4 +- src/main/java/de/diddiz/LogBlock/Logging.java | 50 ++- .../de/diddiz/LogBlock/MaterialConverter.java | 2 +- .../java/de/diddiz/LogBlock/QueryParams.java | 46 ++- .../java/de/diddiz/LogBlock/ToolBehavior.java | 4 +- .../java/de/diddiz/LogBlock/ToolMode.java | 6 +- src/main/java/de/diddiz/LogBlock/Updater.java | 13 +- .../java/de/diddiz/LogBlock/WorldEditor.java | 8 +- .../LogBlock/WorldEditorEditFactory.java | 2 +- .../de/diddiz/LogBlock/config/Config.java | 10 +- .../LogBlock/listeners/BlockBurnLogging.java | 8 +- .../listeners/CreatureInteractLogging.java | 1 - .../LogBlock/listeners/ExplosionLogging.java | 2 +- .../LogBlock/listeners/FluidFlowLogging.java | 2 +- .../LogBlock/listeners/KillLogging.java | 1 - .../LogBlock/listeners/SnowFormLogging.java | 6 - src/main/java/de/diddiz/util/BukkitUtils.java | 26 +- .../de/diddiz/util/ComparableVersion.java | 291 +++++++----------- src/main/java/de/diddiz/util/LoggingUtil.java | 24 +- .../de/diddiz/util/MySQLConnectionPool.java | 2 +- .../de/diddiz/worldedit/CuboidRegion.java | 12 +- .../de/diddiz/LogBlock/QueryParsingTest.java | 1 - 25 files changed, 260 insertions(+), 285 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 64b4d531..e28e7786 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -127,7 +127,7 @@ public String toString() { msg.append("opened ").append(type.getMaterial().name()); } else if (type instanceof Openable) { // Door, Trapdoor, Fence gate - msg.append(((Openable)type).isOpen() ? "opened" : "closed").append(" ").append(type.getMaterial().name()); + msg.append(((Openable) type).isOpen() ? "opened" : "closed").append(" ").append(type.getMaterial().name()); } else if (type.getMaterial() == Material.LEVER) { msg.append("switched ").append(type.getMaterial().name()).append(" ").append(((Switch) type).isPowered() ? "on" : "off"); } else if (type instanceof Switch) { @@ -152,7 +152,7 @@ public String toString() { } else if (type instanceof Sign || type instanceof WallSign) { msg.append("edited a ").append(type.getMaterial().name()).append(" to ").append(typeDetails); } else { - msg.append("replaced ").append(replaced.getMaterial().name()).append(replacedDetails).append(" with ").append(type.getMaterial().name()).append(typeDetails); + msg.append("replaced ").append(replaced.getMaterial().name()).append(replacedDetails).append(" with ").append(type.getMaterial().name()).append(typeDetails); } } else if (BukkitUtils.isEmpty(type.getMaterial())) { msg.append("destroyed ").append(replaced.getMaterial().name()).append(replacedDetails); diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index c19f5651..0321ffb7 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -102,7 +102,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, sender.sendMessage(ChatColor.GOLD + "silent -- Displays lesser messages"); } else if (command.equals("permissions")) { sender.sendMessage(ChatColor.DARK_AQUA + "You've got the following permissions:"); - for (final String permission : new String[]{"me", "lookup", "tp", "rollback", "clearlog", "hide", "ignoreRestrictions", "spawnTools"}) { + for (final String permission : new String[] { "me", "lookup", "tp", "rollback", "clearlog", "hide", "ignoreRestrictions", "spawnTools" }) { if (logblock.hasPermission(sender, "logblock." + permission)) { sender.sendMessage(ChatColor.GOLD + "logblock." + permission); } @@ -659,15 +659,15 @@ public CommandRollback(CommandSender sender, QueryParams params, boolean async) @Override public void run() { try { - if(params.bct == BlockChangeType.CHAT) { + if (params.bct == BlockChangeType.CHAT) { sender.sendMessage(ChatColor.RED + "Chat cannot be rolled back"); return; } - if(params.bct == BlockChangeType.KILLS) { + if (params.bct == BlockChangeType.KILLS) { sender.sendMessage(ChatColor.RED + "Kills cannot be rolled back"); return; } - if(params.sum != SummarizationMode.NONE) { + if (params.sum != SummarizationMode.NONE) { sender.sendMessage(ChatColor.RED + "Cannot rollback summarized changes"); return; } @@ -749,15 +749,15 @@ public CommandRedo(CommandSender sender, QueryParams params, boolean async) thro @Override public void run() { try { - if(params.bct == BlockChangeType.CHAT) { + if (params.bct == BlockChangeType.CHAT) { sender.sendMessage(ChatColor.RED + "Chat cannot be redone"); return; } - if(params.bct == BlockChangeType.KILLS) { + if (params.bct == BlockChangeType.KILLS) { sender.sendMessage(ChatColor.RED + "Kills cannot be redone"); return; } - if(params.sum != SummarizationMode.NONE) { + if (params.sum != SummarizationMode.NONE) { sender.sendMessage(ChatColor.RED + "Cannot redo summarized changes"); return; } @@ -914,7 +914,7 @@ public void run() { sb.append(rs.getInt("z")); sb.append(");\n"); } else if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) { - + } else { sb.append("INSERT INTO `").append(tableBase).append("-blocks` (`id`, `date`, `playerid`, `replaced`, `replacedData`, `type`, `typeData`, `x`, `y`, `z`) VALUES ("); sb.append(rs.getInt("id")).append(", FROM_UNIXTIME("); diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 59f0313c..02f35bf2 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -357,7 +357,7 @@ public void queueChat(Actor player, String message) { if (hiddenPlayers.contains(player.getName().toLowerCase())) { return; } - while(message.length() > 256) { + while (message.length() > 256) { addQueueLast(new ChatRow(player, message.substring(0, 256))); message = message.substring(256); } @@ -827,7 +827,7 @@ public void process(Connection conn, BatchHelper batchHelper) throws SQLExceptio Location actorBlockLocation = actor.getBlockLocation(); if (actorBlockLocation != null) { Integer tempSourceActor = batchHelper.getUncommitedBlockActor(actorBlockLocation); - if(tempSourceActor != null) { + if (tempSourceActor != null) { sourceActor = tempSourceActor; } else { PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, selectActorIdStatementString, Statement.NO_GENERATED_KEYS); diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 4f3fbaac..df659173 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -325,12 +325,12 @@ public int getCount(QueryParams params) throws SQLException { conn.close(); } } - + @Override public File getFile() { return super.getFile(); } - + public Questioner getQuestioner() { return questioner; } diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index 6259fe38..4357201e 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -1,14 +1,48 @@ package de.diddiz.LogBlock; public enum Logging { - BLOCKPLACE(true), BLOCKBREAK(true), SIGNTEXT(true), TNTEXPLOSION(true), CREEPEREXPLOSION(true), - GHASTFIREBALLEXPLOSION(true), ENDERDRAGON(true), MISCEXPLOSION(true), FIRE(true), LEAVESDECAY, - LAVAFLOW, WATERFLOW, CHESTACCESS, KILL, CHAT, SNOWFORM, SNOWFADE, DOORINTERACT, - SWITCHINTERACT, CAKEEAT, ENDERMEN, NOTEBLOCKINTERACT, DIODEINTERACT, COMPARATORINTERACT, - PRESUREPLATEINTERACT, TRIPWIREINTERACT, CREATURECROPTRAMPLE, CROPTRAMPLE, - NATURALSTRUCTUREGROW, GRASSGROWTH, MYCELIUMSPREAD, VINEGROWTH, MUSHROOMSPREAD, - WITHER(true), WITHER_SKULL(true), BONEMEALSTRUCTUREGROW, WORLDEDIT, TNTMINECARTEXPLOSION(true), - ENDERCRYSTALEXPLOSION(true), BEDEXPLOSION(true), DRAGONEGGTELEPORT(true), DAYLIGHTDETECTORINTERACT, + BLOCKPLACE(true), + BLOCKBREAK(true), + SIGNTEXT(true), + TNTEXPLOSION(true), + CREEPEREXPLOSION(true), + GHASTFIREBALLEXPLOSION(true), + ENDERDRAGON(true), + MISCEXPLOSION(true), + FIRE(true), + LEAVESDECAY, + LAVAFLOW, + WATERFLOW, + CHESTACCESS, + KILL, + CHAT, + SNOWFORM, + SNOWFADE, + DOORINTERACT, + SWITCHINTERACT, + CAKEEAT, + ENDERMEN, + NOTEBLOCKINTERACT, + DIODEINTERACT, + COMPARATORINTERACT, + PRESUREPLATEINTERACT, + TRIPWIREINTERACT, + CREATURECROPTRAMPLE, + CROPTRAMPLE, + NATURALSTRUCTUREGROW, + GRASSGROWTH, + MYCELIUMSPREAD, + VINEGROWTH, + MUSHROOMSPREAD, + WITHER(true), + WITHER_SKULL(true), + BONEMEALSTRUCTUREGROW, + WORLDEDIT, + TNTMINECARTEXPLOSION(true), + ENDERCRYSTALEXPLOSION(true), + BEDEXPLOSION(true), + DRAGONEGGTELEPORT(true), + DAYLIGHTDETECTORINTERACT, LECTERNBOOKCHANGE(true); public static final int length = Logging.values().length; diff --git a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java index 1c90d7d3..c462a25a 100644 --- a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java +++ b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java @@ -22,7 +22,7 @@ public class MaterialConverter { private static String[] idToBlockState = new String[10]; private static HashMap blockStateToID = new HashMap<>(); private static int nextBlockStateId; - + private static HashMap materialKeyToMaterial = new HashMap<>(); static { diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 0d7ad206..7fa8ade2 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -273,7 +273,7 @@ public String getFields() { if (needType) { select += "entitytypeid, action, "; } - if(needData) { + if (needData) { select += "entityid, entityuuid, data, "; } } @@ -291,21 +291,26 @@ public String getQuery() { } if (bct == BlockChangeType.KILLS) { if (sum == SummarizationMode.PLAYERS) { - return "SELECT playername, UUID, SUM(kills) AS kills, SUM(killed) AS killed FROM ((SELECT killer AS playerid, count(*) AS kills, 0 as killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY killer) UNION (SELECT victim AS playerid, 0 as kills, count(*) AS killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY victim)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(kills) + SUM(killed) " + order + " " + getLimit(); + return "SELECT playername, UUID, SUM(kills) AS kills, SUM(killed) AS killed FROM ((SELECT killer AS playerid, count(*) AS kills, 0 as killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY killer) UNION (SELECT victim AS playerid, 0 as kills, count(*) AS killed FROM `" + getTable() + + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY victim)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(kills) + SUM(killed) " + order + " " + getLimit(); } throw new IllegalStateException("Invalid summarization for kills"); } if (bct == BlockChangeType.ENTITIES || bct == BlockChangeType.ENTITIES_CREATED || bct == BlockChangeType.ENTITIES_KILLED) { if (sum == SummarizationMode.TYPES) { - return "SELECT entitytypeid, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT entitytypeid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-entities` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.ENTITIES_CREATED) + "GROUP BY entitytypeid) UNION (SELECT entitytypeid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-entities` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.ENTITIES_KILLED) + "GROUP BY entitytypeid)) AS t GROUP BY entitytypeid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); + return "SELECT entitytypeid, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT entitytypeid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-entities` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.ENTITIES_CREATED) + "GROUP BY entitytypeid) UNION (SELECT entitytypeid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-entities` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.ENTITIES_KILLED) + + "GROUP BY entitytypeid)) AS t GROUP BY entitytypeid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); } else { - return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-entities` " + getWhere(BlockChangeType.ENTITIES_CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-entities` " + getWhere(BlockChangeType.ENTITIES_KILLED) + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); + return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-entities` " + getWhere(BlockChangeType.ENTITIES_CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-entities` " + getWhere(BlockChangeType.ENTITIES_KILLED) + + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); } } if (sum == SummarizationMode.TYPES) { - return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.CREATED) + "GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); + return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.CREATED) + "GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.DESTROYED) + + "GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); } else { - return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); + return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "-blocks` " + getWhere(BlockChangeType.DESTROYED) + + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); } } @@ -574,22 +579,20 @@ public String getWhere(BlockChangeType blockChangeType) { break; } } - if(blockChangeType != BlockChangeType.CHAT) { + if (blockChangeType != BlockChangeType.CHAT) { if (loc != null) { if (radius == 0) { compileLocationQuery( where, loc.getBlockX(), loc.getBlockX(), loc.getBlockY(), loc.getBlockY(), - loc.getBlockZ(), loc.getBlockZ() - ); + loc.getBlockZ(), loc.getBlockZ()); } else if (radius > 0) { compileLocationQuery( where, loc.getBlockX() - radius + 1, loc.getBlockX() + radius - 1, loc.getBlockY() - radius + 1, loc.getBlockY() + radius - 1, - loc.getBlockZ() - radius + 1, loc.getBlockZ() + radius - 1 - ); + loc.getBlockZ() - radius + 1, loc.getBlockZ() + radius - 1); } } else if (sel != null) { @@ -597,8 +600,7 @@ public String getWhere(BlockChangeType blockChangeType) { where, sel.getMinimumPoint().getBlockX(), sel.getMaximumPoint().getBlockX(), sel.getMinimumPoint().getBlockY(), sel.getMaximumPoint().getBlockY(), - sel.getMinimumPoint().getBlockZ(), sel.getMaximumPoint().getBlockZ() - ); + sel.getMinimumPoint().getBlockZ(), sel.getMaximumPoint().getBlockZ()); } } if (!players.isEmpty() && sum != SummarizationMode.PLAYERS && blockChangeType != BlockChangeType.KILLS) { @@ -1028,14 +1030,26 @@ public void merge(QueryParams p) { } public static enum BlockChangeType { - ALL, BOTH, CHESTACCESS, CREATED, DESTROYED, CHAT, KILLS, ENTITIES, ENTITIES_CREATED, ENTITIES_KILLED, + ALL, + BOTH, + CHESTACCESS, + CREATED, + DESTROYED, + CHAT, + KILLS, + ENTITIES, + ENTITIES_CREATED, + ENTITIES_KILLED, } public static enum Order { - ASC, DESC + ASC, + DESC } public static enum SummarizationMode { - NONE, PLAYERS, TYPES + NONE, + PLAYERS, + TYPES } } diff --git a/src/main/java/de/diddiz/LogBlock/ToolBehavior.java b/src/main/java/de/diddiz/LogBlock/ToolBehavior.java index e51e7b51..bbeac793 100644 --- a/src/main/java/de/diddiz/LogBlock/ToolBehavior.java +++ b/src/main/java/de/diddiz/LogBlock/ToolBehavior.java @@ -1,5 +1,7 @@ package de.diddiz.LogBlock; public enum ToolBehavior { - TOOL, BLOCK, NONE + TOOL, + BLOCK, + NONE } diff --git a/src/main/java/de/diddiz/LogBlock/ToolMode.java b/src/main/java/de/diddiz/LogBlock/ToolMode.java index bea69c0a..25fc2496 100644 --- a/src/main/java/de/diddiz/LogBlock/ToolMode.java +++ b/src/main/java/de/diddiz/LogBlock/ToolMode.java @@ -1,7 +1,11 @@ package de.diddiz.LogBlock; public enum ToolMode { - CLEARLOG("logblock.clearlog"), LOOKUP("logblock.lookup"), REDO("logblock.rollback"), ROLLBACK("logblock.rollback"), WRITELOGFILE("logblock.rollback"); + CLEARLOG("logblock.clearlog"), + LOOKUP("logblock.lookup"), + REDO("logblock.rollback"), + ROLLBACK("logblock.rollback"), + WRITELOGFILE("logblock.rollback"); private final String permission; private ToolMode(String permission) { diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 54b5e2d2..2bf2b58e 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -431,7 +431,7 @@ boolean update() { logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table); } rs.close(); - + PreparedStatement deleteStatement = conn.prepareStatement("DELETE FROM `" + wcfg.table + "` WHERE id = ?"); PreparedStatement insertStatement = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-blocks` (id, date, playerid, replaced, replacedData, type, typeData, x, y, z) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); @@ -515,7 +515,7 @@ boolean update() { logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-chest"); } rs.close(); - + PreparedStatement insertChestData = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-chestdata` (id, item, itemremove, itemtype) VALUES (?, ?, ?, ?)"); PreparedStatement deleteChest = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-chest` WHERE id = ?"); while (true) { @@ -532,13 +532,13 @@ boolean update() { weaponMaterial = Material.AIR; } @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.setInt(1, id); insertChestData.setBytes(2, Utils.saveItemStack(stack)); insertChestData.setInt(3, amount >= 0 ? 0 : 1); insertChestData.setInt(4, MaterialConverter.getOrAddMaterialId(weaponMaterial.getKey())); insertChestData.addBatch(); - + deleteChest.setInt(1, id); deleteChest.addBatch(); done++; @@ -578,7 +578,7 @@ boolean update() { logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-kills"); } rs.close(); - + PreparedStatement updateWeaponStatement = conn.prepareStatement("UPDATE `" + wcfg.table + "-kills` SET weapon = ? WHERE id = ?"); for (int start = 0;; start += OTHER_CONVERT_BATCH_SIZE) { rs = st.executeQuery("SELECT id, weapon FROM `" + wcfg.table + "-kills` ORDER BY id ASC LIMIT " + start + "," + OTHER_CONVERT_BATCH_SIZE); @@ -855,7 +855,7 @@ private void updateMaterialsPost1_13() { currentMinecraftVersion = currentMinecraftVersion.substring(currentMinecraftVersion.indexOf("(MC: ") + 5); int currentVersionEnd = currentMinecraftVersion.indexOf(" "); int currentVersionEnd2 = currentMinecraftVersion.indexOf(")"); - if(currentVersionEnd2 >= 0 && (currentVersionEnd < 0 || currentVersionEnd2 < currentVersionEnd)) { + if (currentVersionEnd2 >= 0 && (currentVersionEnd < 0 || currentVersionEnd2 < currentVersionEnd)) { currentVersionEnd = currentVersionEnd2; } currentMinecraftVersion = currentMinecraftVersion.substring(0, currentVersionEnd); @@ -944,6 +944,7 @@ public void run() { public static class MaterialUpdater1_13 { BlockData[][] blockDataMapping; Material[][] itemMapping = new Material[10][]; + public MaterialUpdater1_13(LogBlock plugin) throws IOException { blockDataMapping = new BlockData[256][16]; try (JarFile file = new JarFile(plugin.getFile())) { diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 67df99bf..81889ed8 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -91,7 +91,6 @@ public int getBlacklistCollisions() { return blacklistCollisions; } - public void setSender(CommandSender sender) { this.sender = sender; } @@ -202,12 +201,14 @@ protected UUID getReplacedUUID(int entityid, UUID unreplaced) { } public static enum PerformResult { - SUCCESS, BLACKLISTED, NO_ACTION + SUCCESS, + BLACKLISTED, + NO_ACTION } public interface Edit { PerformResult perform() throws WorldEditorException; - + public long getTime(); } @@ -440,6 +441,7 @@ public PerformResult perform() throws WorldEditorException { public static class EditComparator implements Comparator { private final int mult; + public EditComparator(QueryParams.Order order) { mult = order == Order.DESC ? 1 : -1; } diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java b/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java index 80728cce..efec5087 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java @@ -21,7 +21,7 @@ public WorldEditorEditFactory(WorldEditor editor, QueryParams params, boolean ro public void processRow(ResultSet rs) throws SQLException { if (params.bct == BlockChangeType.ENTITIES) { - editor.queueEntityEdit(rs, params, rollback); + editor.queueEntityEdit(rs, params, rollback); return; } ChestAccess chestaccess = null; diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 9fae8eec..a2f760ae 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -58,7 +58,9 @@ public class Config { public static boolean mb4 = false; public static enum LogKillsLevel { - PLAYERS, MONSTERS, ANIMALS; + PLAYERS, + MONSTERS, + ANIMALS; } public static void load(LogBlock logblock) throws DataFormatException, IOException { @@ -158,10 +160,10 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti } } logblock.saveConfig(); - + ComparableVersion configVersion = new ComparableVersion(config.getString("version")); boolean oldConfig = configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion().replace(" (manually compiled)", ""))) < 0; - + url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database"); user = getStringIncludingInts(config, "mysql.user"); password = getStringIncludingInts(config, "mysql.password"); @@ -246,7 +248,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti final ToolBehavior leftClickBehavior = ToolBehavior.valueOf(tSec.getString("leftClickBehavior").toUpperCase()); final ToolBehavior rightClickBehavior = ToolBehavior.valueOf(tSec.getString("rightClickBehavior").toUpperCase()); final boolean defaultEnabled = tSec.getBoolean("defaultEnabled", false); - final Material item = Material.matchMaterial(tSec.getString("item","OAK_LOG")); + final Material item = Material.matchMaterial(tSec.getString("item", "OAK_LOG")); final boolean canDrop = tSec.getBoolean("canDrop", false); final boolean removeOnDisable = tSec.getBoolean("removeOnDisable", true); final boolean dropToDisable = tSec.getBoolean("dropToDisable", false); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java index 4d4ebc86..090b7bb4 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java @@ -43,13 +43,13 @@ public void onBlockIgnite(BlockIgniteEvent event) { } else { actor = new Actor("Dispenser"); } - } else if(event.getCause() == IgniteCause.LIGHTNING) { + } else if (event.getCause() == IgniteCause.LIGHTNING) { actor = new Actor("Lightning"); - } else if(event.getCause() == IgniteCause.EXPLOSION) { + } else if (event.getCause() == IgniteCause.EXPLOSION) { actor = new Actor("Explosion"); - } else if(event.getCause() == IgniteCause.LAVA) { + } else if (event.getCause() == IgniteCause.LAVA) { actor = new Actor("Lava"); - } else if(event.getCause() == IgniteCause.ENDER_CRYSTAL) { + } else if (event.getCause() == IgniteCause.ENDER_CRYSTAL) { actor = new Actor("EnderCrystal"); } if (isLogging(event.getBlock().getWorld(), Logging.FIRE)) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java index 7eb97fc5..f831d841 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java @@ -65,4 +65,3 @@ public void onEntityInteract(EntityInteractEvent event) { } } } - diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index 1a63d8d8..af5e285d 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -100,7 +100,7 @@ public void onEntityExplode(EntityExplodeEvent event) { } actor = Actor.actorFromEntity(source); - } else if (source instanceof EnderCrystal){ + } else if (source instanceof EnderCrystal) { if (!wcfg.isLogging(Logging.ENDERCRYSTALEXPLOSION)) { return; } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index 89cd1f06..51fe14d5 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -40,7 +40,7 @@ public void onBlockFromTo(BlockFromToEvent event) { if (typeFrom == Material.SEAGRASS || typeFrom == Material.KELP_PLANT || typeFrom == Material.KELP) { typeFrom = Material.WATER; fromWaterlogged = true; - } + } Block source = Config.logFluidFlowAsPlayerWhoTriggeredIt ? event.getBlock() : null; final Block to = event.getToBlock(); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java index 49c8c76e..d70a740d 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java @@ -16,7 +16,6 @@ import static de.diddiz.LogBlock.config.Config.*; - public class KillLogging extends LoggingListener { public KillLogging(LogBlock lb) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java index d9abcef4..b269f029 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java @@ -16,12 +16,6 @@ public SnowFormLogging(LogBlock lb) { super(lb); } -// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) -// public void onLeavesDecay(LeavesDecayEvent event) { -// if (isLogging(event.getBlock().getWorld(), Logging.SNOWFORM)) -// consumer.queueBlockBreak("LeavesDecay", event.getBlock().getState()); -// } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockForm(BlockFormEvent event) { if (isLogging(event.getBlock().getWorld(), Logging.SNOWFORM)) { diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 35acdbac..2758c3b4 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -141,14 +141,14 @@ public class BukkitUtils { singleBlockPlants.add(Material.WHITE_TULIP); singleBlockPlants.add(Material.PINK_TULIP); singleBlockPlants.add(Material.RED_TULIP); - singleBlockPlants.add(Material.OXEYE_DAISY); + singleBlockPlants.add(Material.OXEYE_DAISY); singleBlockPlants.add(Material.BROWN_MUSHROOM); singleBlockPlants.add(Material.RED_MUSHROOM); singleBlockPlants.add(Material.SWEET_BERRY_BUSH); singleBlockPlants.add(Material.LILY_OF_THE_VALLEY); singleBlockPlants.add(Material.CORNFLOWER); singleBlockPlants.add(Material.WITHER_ROSE); - + doublePlants = EnumSet.noneOf(Material.class); doublePlants.add(Material.TALL_GRASS); doublePlants.add(Material.LARGE_FERN); @@ -157,7 +157,7 @@ public class BukkitUtils { doublePlants.add(Material.LILAC); doublePlants.add(Material.SUNFLOWER); doublePlants.add(Material.PEONY); - + blockEquivalents = new HashSet>(7); blockEquivalents.add(new HashSet(Arrays.asList(2, 3, 60))); blockEquivalents.add(new HashSet(Arrays.asList(8, 9, 79))); @@ -218,9 +218,9 @@ public class BukkitUtils { relativeTopBreakable.addAll(doublePlants); relativeTopBreakable.add(Material.BAMBOO); relativeTopBreakable.add(Material.BAMBOO_SAPLING); - for(Material m : Material.values()) { - if(m.name().startsWith("POTTED_")) { - relativeTopBreakable.add(m); + for (Material m : Material.values()) { + if (m.name().startsWith("POTTED_")) { + relativeTopBreakable.add(m); } } @@ -249,7 +249,7 @@ public class BukkitUtils { fallingEntityKillers.add(Material.WHITE_TULIP); fallingEntityKillers.add(Material.PINK_TULIP); fallingEntityKillers.add(Material.RED_TULIP); - fallingEntityKillers.add(Material.OXEYE_DAISY); + fallingEntityKillers.add(Material.OXEYE_DAISY); fallingEntityKillers.add(Material.BROWN_MUSHROOM); fallingEntityKillers.add(Material.RED_MUSHROOM); fallingEntityKillers.addAll(doublePlants); @@ -336,8 +336,8 @@ public class BukkitUtils { projectileItems.put(EntityType.ARROW, Material.ARROW); projectileItems.put(EntityType.EGG, Material.EGG); 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.SMALL_FIREBALL, Material.FIRE_CHARGE); // Fire charge + projectileItems.put(EntityType.FIREBALL, Material.FIRE_CHARGE); // Fire charge projectileItems.put(EntityType.FISHING_HOOK, Material.FISHING_ROD); projectileItems.put(EntityType.SNOWBALL, Material.SNOWBALL); projectileItems.put(EntityType.SPLASH_POTION, Material.SPLASH_POTION); @@ -429,7 +429,7 @@ public class BukkitUtils { dyes.put(Material.YELLOW_DYE, DyeColor.YELLOW); } - private static final BlockFace[] relativeBlockFaces = new BlockFace[]{ + private static final BlockFace[] relativeBlockFaces = new BlockFace[] { BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN }; @@ -556,7 +556,7 @@ public static Set getRelativeTopBreakabls() { public static Set getFallingEntityKillers() { return fallingEntityKillers; } - + public static Set getNonFluidProofBlocks() { return nonFluidProofBlocks; } @@ -654,7 +654,7 @@ public static boolean canDirectlyFallIn(Material m) { public static Material itemIDfromProjectileEntity(Entity e) { return projectileItems.get(e.getType()); } - + public static boolean isDoublePlant(Material m) { return doublePlants.contains(m); } @@ -799,7 +799,7 @@ public static Block getConnectedChest(Block chestBlock) { if (face.getType() == chestBlock.getType()) { // check is the neighbour connects to this chest org.bukkit.block.data.type.Chest otherChestData = (org.bukkit.block.data.type.Chest) face.getBlockData(); - if(otherChestData.getType() != wantedChestType || otherChestData.getFacing() != chestFace) { + if (otherChestData.getType() != wantedChestType || otherChestData.getFacing() != chestFace) { return null; } return face; diff --git a/src/main/java/de/diddiz/util/ComparableVersion.java b/src/main/java/de/diddiz/util/ComparableVersion.java index 69a0ef71..46b6922b 100644 --- a/src/main/java/de/diddiz/util/ComparableVersion.java +++ b/src/main/java/de/diddiz/util/ComparableVersion.java @@ -61,22 +61,19 @@ * @author Kenney Westerhof * @author Hervé Boutemy */ -public class ComparableVersion - implements Comparable -{ +public class ComparableVersion implements Comparable { private String value; private String canonical; private ListItem items; - private interface Item - { + private interface Item { int INTEGER_ITEM = 0; int STRING_ITEM = 1; int LIST_ITEM = 2; - int compareTo( Item item ); + int compareTo(Item item); int getType(); @@ -86,46 +83,37 @@ private interface Item /** * Represents a numeric item in the version item list. */ - private static class IntegerItem - implements Item - { - private static final BigInteger BIG_INTEGER_ZERO = new BigInteger( "0" ); + private static class IntegerItem implements Item { + private static final BigInteger BIG_INTEGER_ZERO = new BigInteger("0"); private final BigInteger value; public static final IntegerItem ZERO = new IntegerItem(); - private IntegerItem() - { + private IntegerItem() { this.value = BIG_INTEGER_ZERO; } - public IntegerItem( String str ) - { - this.value = new BigInteger( str ); + public IntegerItem(String str) { + this.value = new BigInteger(str); } - public int getType() - { + public int getType() { return INTEGER_ITEM; } - public boolean isNull() - { - return BIG_INTEGER_ZERO.equals( value ); + public boolean isNull() { + return BIG_INTEGER_ZERO.equals(value); } - public int compareTo( Item item ) - { - if ( item == null ) - { - return BIG_INTEGER_ZERO.equals( value ) ? 0 : 1; // 1.0 == 1, 1.1 > 1 + public int compareTo(Item item) { + if (item == null) { + return BIG_INTEGER_ZERO.equals(value) ? 0 : 1; // 1.0 == 1, 1.1 > 1 } - switch ( item.getType() ) - { + switch (item.getType()) { case INTEGER_ITEM: - return value.compareTo( ( (IntegerItem) item ).value ); + return value.compareTo(((IntegerItem) item).value); case STRING_ITEM: return 1; // 1.1 > 1-sp @@ -134,12 +122,11 @@ public int compareTo( Item item ) return 1; // 1.1 > 1-1 default: - throw new RuntimeException( "invalid item: " + item.getClass() ); + throw new RuntimeException("invalid item: " + item.getClass()); } } - public String toString() - { + public String toString() { return value.toString(); } } @@ -147,36 +134,30 @@ public String toString() /** * Represents a string in the version item list, usually a qualifier. */ - private static class StringItem - implements Item - { + private static class StringItem implements Item { private static final String[] QUALIFIERS = { "alpha", "beta", "milestone", "rc", "snapshot", "", "sp" }; - private static final List _QUALIFIERS = Arrays.asList( QUALIFIERS ); + private static final List _QUALIFIERS = Arrays.asList(QUALIFIERS); private static final Properties ALIASES = new Properties(); - static - { - ALIASES.put( "ga", "" ); - ALIASES.put( "final", "" ); - ALIASES.put( "cr", "rc" ); + static { + ALIASES.put("ga", ""); + ALIASES.put("final", ""); + ALIASES.put("cr", "rc"); } /** * A comparable value for the empty-string qualifier. This one is used to determine if a given qualifier makes * the version older than one without a qualifier, or more recent. */ - private static final String RELEASE_VERSION_INDEX = String.valueOf( _QUALIFIERS.indexOf( "" ) ); + private static final String RELEASE_VERSION_INDEX = String.valueOf(_QUALIFIERS.indexOf("")); private String value; - public StringItem( String value, boolean followedByDigit ) - { - if ( followedByDigit && value.length() == 1 ) - { + public StringItem(String value, boolean followedByDigit) { + if (followedByDigit && value.length() == 1) { // a1 = alpha-1, b1 = beta-1, m1 = milestone-1 - switch ( value.charAt( 0 ) ) - { + switch (value.charAt(0)) { case 'a': value = "alpha"; break; @@ -188,17 +169,15 @@ public StringItem( String value, boolean followedByDigit ) break; } } - this.value = ALIASES.getProperty( value , value ); + this.value = ALIASES.getProperty(value, value); } - public int getType() - { + public int getType() { return STRING_ITEM; } - public boolean isNull() - { - return ( comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX ) == 0 ); + public boolean isNull() { + return (comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX) == 0); } /** @@ -213,38 +192,33 @@ public boolean isNull() * @param qualifier * @return an equivalent value that can be used with lexical comparison */ - public static String comparableQualifier( String qualifier ) - { - int i = _QUALIFIERS.indexOf( qualifier ); + public static String comparableQualifier(String qualifier) { + int i = _QUALIFIERS.indexOf(qualifier); - return i == -1 ? ( _QUALIFIERS.size() + "-" + qualifier ) : String.valueOf( i ); + return i == -1 ? (_QUALIFIERS.size() + "-" + qualifier) : String.valueOf(i); } - public int compareTo( Item item ) - { - if ( item == null ) - { + public int compareTo(Item item) { + if (item == null) { // 1-rc < 1, 1-ga > 1 - return comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX ); + return comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX); } - switch ( item.getType() ) - { + switch (item.getType()) { case INTEGER_ITEM: return -1; // 1.any < 1.1 ? case STRING_ITEM: - return comparableQualifier( value ).compareTo( comparableQualifier( ( (StringItem) item ).value ) ); + return comparableQualifier(value).compareTo(comparableQualifier(((StringItem) item).value)); case LIST_ITEM: return -1; // 1.any < 1-1 default: - throw new RuntimeException( "invalid item: " + item.getClass() ); + throw new RuntimeException("invalid item: " + item.getClass()); } } - public String toString() - { + public String toString() { return value; } } @@ -253,51 +227,37 @@ public String toString() * Represents a version list item. This class is used both for the global item list and for sub-lists (which start * with '-(number)' in the version specification). */ - private static class ListItem - extends ArrayList - implements Item - { + private static class ListItem extends ArrayList implements Item { private static final long serialVersionUID = 5914575811857700009L; - public int getType() - { + public int getType() { return LIST_ITEM; } - public boolean isNull() - { - return ( size() == 0 ); + public boolean isNull() { + return (size() == 0); } - void normalize() - { - for ( ListIterator iterator = listIterator( size() ); iterator.hasPrevious(); ) - { + void normalize() { + for (ListIterator iterator = listIterator(size()); iterator.hasPrevious();) { Item item = iterator.previous(); - if ( item.isNull() ) - { + if (item.isNull()) { iterator.remove(); // remove null trailing items: 0, "", empty list - } - else - { + } else { break; } } } - public int compareTo( Item item ) - { - if ( item == null ) - { - if ( size() == 0 ) - { + public int compareTo(Item item) { + if (item == null) { + if (size() == 0) { return 0; // 1-0 = 1- (normalize) = 1 } - Item first = get( 0 ); - return first.compareTo( null ); + Item first = get(0); + return first.compareTo(null); } - switch ( item.getType() ) - { + switch (item.getType()) { case INTEGER_ITEM: return -1; // 1-1 < 1.0.x @@ -306,18 +266,16 @@ public int compareTo( Item item ) case LIST_ITEM: Iterator left = iterator(); - Iterator right = ( (ListItem) item ).iterator(); + Iterator right = ((ListItem) item).iterator(); - while ( left.hasNext() || right.hasNext() ) - { + while (left.hasNext() || right.hasNext()) { Item l = left.hasNext() ? left.next() : null; Item r = right.hasNext() ? right.next() : null; // if this is shorter, then invert the compare and mul with -1 - int result = l == null ? ( r == null ? 0 : -1 * r.compareTo( l ) ) : l.compareTo( r ); + int result = l == null ? (r == null ? 0 : -1 * r.compareTo(l)) : l.compareTo(r); - if ( result != 0 ) - { + if (result != 0) { return result; } } @@ -325,105 +283,82 @@ public int compareTo( Item item ) return 0; default: - throw new RuntimeException( "invalid item: " + item.getClass() ); + throw new RuntimeException("invalid item: " + item.getClass()); } } - public String toString() - { - StringBuilder buffer = new StringBuilder( "(" ); - for ( Iterator iter = iterator(); iter.hasNext(); ) - { - buffer.append( iter.next() ); - if ( iter.hasNext() ) - { - buffer.append( ',' ); + public String toString() { + StringBuilder buffer = new StringBuilder("("); + for (Iterator iter = iterator(); iter.hasNext();) { + buffer.append(iter.next()); + if (iter.hasNext()) { + buffer.append(','); } } - buffer.append( ')' ); + buffer.append(')'); return buffer.toString(); } } - public ComparableVersion( String version ) - { - parseVersion( version ); + public ComparableVersion(String version) { + parseVersion(version); } - public final void parseVersion( String version ) - { + public final void parseVersion(String version) { this.value = version; items = new ListItem(); - version = version.toLowerCase( Locale.ENGLISH ); + version = version.toLowerCase(Locale.ENGLISH); ListItem list = items; Stack stack = new Stack(); - stack.push( list ); + stack.push(list); boolean isDigit = false; int startIndex = 0; - for ( int i = 0; i < version.length(); i++ ) - { - char c = version.charAt( i ); + for (int i = 0; i < version.length(); i++) { + char c = version.charAt(i); - if ( c == '.' ) - { - if ( i == startIndex ) - { - list.add( IntegerItem.ZERO ); - } - else - { - list.add( parseItem( isDigit, version.substring( startIndex, i ) ) ); + if (c == '.') { + if (i == startIndex) { + list.add(IntegerItem.ZERO); + } else { + list.add(parseItem(isDigit, version.substring(startIndex, i))); } startIndex = i + 1; - } - else if ( c == '-' ) - { - if ( i == startIndex ) - { - list.add( IntegerItem.ZERO ); - } - else - { - list.add( parseItem( isDigit, version.substring( startIndex, i ) ) ); + } else if (c == '-') { + if (i == startIndex) { + list.add(IntegerItem.ZERO); + } else { + list.add(parseItem(isDigit, version.substring(startIndex, i))); } startIndex = i + 1; - if ( isDigit ) - { + if (isDigit) { list.normalize(); // 1.0-* = 1-* - if ( ( i + 1 < version.length() ) && Character.isDigit( version.charAt( i + 1 ) ) ) - { + if ((i + 1 < version.length()) && Character.isDigit(version.charAt(i + 1))) { // new ListItem only if previous were digits and new char is a digit, // ie need to differentiate only 1.1 from 1-1 - list.add( list = new ListItem() ); + list.add(list = new ListItem()); - stack.push( list ); + stack.push(list); } } - } - else if ( Character.isDigit( c ) ) - { - if ( !isDigit && i > startIndex ) - { - list.add( new StringItem( version.substring( startIndex, i ), true ) ); + } else if (Character.isDigit(c)) { + if (!isDigit && i > startIndex) { + list.add(new StringItem(version.substring(startIndex, i), true)); startIndex = i; } isDigit = true; - } - else - { - if ( isDigit && i > startIndex ) - { - list.add( parseItem( true, version.substring( startIndex, i ) ) ); + } else { + if (isDigit && i > startIndex) { + list.add(parseItem(true, version.substring(startIndex, i))); startIndex = i; } @@ -431,13 +366,11 @@ else if ( Character.isDigit( c ) ) } } - if ( version.length() > startIndex ) - { - list.add( parseItem( isDigit, version.substring( startIndex ) ) ); + if (version.length() > startIndex) { + list.add(parseItem(isDigit, version.substring(startIndex))); } - while ( !stack.isEmpty() ) - { + while (!stack.isEmpty()) { list = (ListItem) stack.pop(); list.normalize(); } @@ -445,39 +378,31 @@ else if ( Character.isDigit( c ) ) canonical = items.toString(); } - private static Item parseItem( boolean isDigit, String buf ) - { - return isDigit ? new IntegerItem( buf ) : new StringItem( buf, false ); + private static Item parseItem(boolean isDigit, String buf) { + return isDigit ? new IntegerItem(buf) : new StringItem(buf, false); } - public int compareTo( ComparableVersion o ) - { - return items.compareTo( o.items ); + public int compareTo(ComparableVersion o) { + return items.compareTo(o.items); } - public int compareTo( String version ) - { + public int compareTo(String version) { return compareTo(new ComparableVersion(version)); } - public String toString() - { + public String toString() { return value; } - public String toCanonicalString() - { + public String toCanonicalString() { return canonical; } - public boolean equals( Object o ) - { - return ( o instanceof ComparableVersion ) && canonical.equals( ( (ComparableVersion) o ).canonical ); + public boolean equals(Object o) { + return (o instanceof ComparableVersion) && canonical.equals(((ComparableVersion) o).canonical); } - public int hashCode() - { + public int hashCode() { return canonical.hashCode(); } } - diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index 1e269fa6..97bb5693 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -20,7 +20,7 @@ public class LoggingUtil { - public static void smartLogBlockPlace(Consumer consumer, Actor actor, BlockState replaced, BlockState placed) { + public static void smartLogBlockPlace(Consumer consumer, Actor actor, BlockState replaced, BlockState placed) { Location loc = replaced.getLocation(); if (!placed.getType().hasGravity() || !BukkitUtils.canDirectlyFallIn(replaced.getBlock().getRelative(BlockFace.DOWN).getType())) { if (BukkitUtils.isEmpty(replaced.getType())) { @@ -141,32 +141,32 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or } else { consumer.queueBlockBreak(actor, checkBlock.getState()); } - } else if(typeAbove == Material.LANTERN) { + } else if (typeAbove == Material.LANTERN) { Lantern lantern = (Lantern) checkBlock.getBlockData(); - if(!lantern.isHanging()) { + if (!lantern.isHanging()) { consumer.queueBlockBreak(actor, checkBlock.getState()); } - }else if(typeAbove == Material.BELL) { + } else if (typeAbove == Material.BELL) { Bell bell = (Bell) checkBlock.getBlockData(); - if(bell.getAttachment() == Attachment.FLOOR) { + if (bell.getAttachment() == Attachment.FLOOR) { consumer.queueBlockBreak(actor, checkBlock.getState()); } } - + checkBlock = origin.getRelative(BlockFace.DOWN); Material typeBelow = checkBlock.getType(); - if(typeBelow == Material.LANTERN) { + if (typeBelow == Material.LANTERN) { Lantern lantern = (Lantern) checkBlock.getBlockData(); - if(lantern.isHanging()) { + if (lantern.isHanging()) { consumer.queueBlockBreak(actor, checkBlock.getState()); } - } else if(typeBelow == Material.BELL) { + } else if (typeBelow == Material.BELL) { Bell bell = (Bell) checkBlock.getBlockData(); - if(bell.getAttachment() == Attachment.CEILING) { - consumer.queueBlockBreak(actor, checkBlock.getState()); + if (bell.getAttachment() == Attachment.CEILING) { + consumer.queueBlockBreak(actor, checkBlock.getState()); } } - + List relativeBreakables = BukkitUtils.getBlocksNearby(origin, BukkitUtils.getRelativeBreakables()); if (relativeBreakables.size() != 0) { for (Location location : relativeBreakables) { diff --git a/src/main/java/de/diddiz/util/MySQLConnectionPool.java b/src/main/java/de/diddiz/util/MySQLConnectionPool.java index bf9d6930..1b3d8715 100644 --- a/src/main/java/de/diddiz/util/MySQLConnectionPool.java +++ b/src/main/java/de/diddiz/util/MySQLConnectionPool.java @@ -29,7 +29,7 @@ public MySQLConnectionPool(String url, String user, String password, boolean req ds.addDataSourceProperty("prepStmtCacheSize", "250"); ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); ds.addDataSourceProperty("useServerPrepStmts", "true"); - + ds.addDataSourceProperty("useSSL", "true"); ds.addDataSourceProperty("requireSSL", Boolean.toString(requireSSL)); ds.addDataSourceProperty("verifyServerCertificate", "false"); diff --git a/src/main/java/de/diddiz/worldedit/CuboidRegion.java b/src/main/java/de/diddiz/worldedit/CuboidRegion.java index 7b094298..15dc1ccd 100644 --- a/src/main/java/de/diddiz/worldedit/CuboidRegion.java +++ b/src/main/java/de/diddiz/worldedit/CuboidRegion.java @@ -21,12 +21,12 @@ public class CuboidRegion implements Cloneable { public CuboidRegion(World world, BlockVector first, BlockVector second) { this.world = world; - this.min.setX(Math.min(first.getBlockX(),second.getBlockX())); - this.min.setY(Math.min(first.getBlockY(),second.getBlockY())); - this.min.setZ(Math.min(first.getBlockZ(),second.getBlockZ())); - this.max.setX(Math.max(first.getBlockX(),second.getBlockX())); - this.max.setY(Math.max(first.getBlockY(),second.getBlockY())); - this.max.setZ(Math.max(first.getBlockZ(),second.getBlockZ())); + this.min.setX(Math.min(first.getBlockX(), second.getBlockX())); + this.min.setY(Math.min(first.getBlockY(), second.getBlockY())); + this.min.setZ(Math.min(first.getBlockZ(), second.getBlockZ())); + this.max.setX(Math.max(first.getBlockX(), second.getBlockX())); + this.max.setY(Math.max(first.getBlockY(), second.getBlockY())); + this.max.setZ(Math.max(first.getBlockZ(), second.getBlockZ())); } public static CuboidRegion fromPlayerSelection(Player player) { diff --git a/src/test/java/de/diddiz/LogBlock/QueryParsingTest.java b/src/test/java/de/diddiz/LogBlock/QueryParsingTest.java index 30e8ee60..9e7d828d 100644 --- a/src/test/java/de/diddiz/LogBlock/QueryParsingTest.java +++ b/src/test/java/de/diddiz/LogBlock/QueryParsingTest.java @@ -1,6 +1,5 @@ package de.diddiz.LogBlock; - import de.diddiz.util.Utils; import org.junit.Assert; import org.junit.Test; From e8aaadf37bea53f769d9dee77e38034e25309dd4 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 23 Jun 2019 17:14:17 +0200 Subject: [PATCH 204/399] Code style --- src/main/java/de/diddiz/LogBlock/Actor.java | 5 ++-- .../de/diddiz/LogBlock/CommandsHandler.java | 8 +++--- .../java/de/diddiz/LogBlock/Consumer.java | 12 ++++---- .../java/de/diddiz/LogBlock/LogBlock.java | 2 +- .../java/de/diddiz/LogBlock/QueryParams.java | 28 +++++++++---------- src/main/java/de/diddiz/LogBlock/Session.java | 4 +-- src/main/java/de/diddiz/LogBlock/Updater.java | 4 +-- .../java/de/diddiz/LogBlock/WorldEditor.java | 3 +- .../blockstate/BlockStateCodecSign.java | 3 +- .../de/diddiz/LogBlock/config/Config.java | 24 ++++++++-------- .../diddiz/LogBlock/config/WorldConfig.java | 2 +- .../events/BlockChangePreLogEvent.java | 13 ++------- .../diddiz/LogBlock/events/PreLogEvent.java | 8 ++---- .../LogBlock/listeners/BlockBurnLogging.java | 2 +- .../listeners/ChestAccessLogging.java | 2 +- .../LogBlock/questioner/Questioner.java | 3 +- src/main/java/de/diddiz/util/BukkitUtils.java | 24 ++++++++-------- .../de/diddiz/util/ComparableVersion.java | 22 +++++++++++++-- src/main/java/de/diddiz/util/UUIDFetcher.java | 2 +- src/main/java/de/diddiz/util/Utils.java | 2 +- 20 files changed, 92 insertions(+), 81 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index 1fde0725..4ed73aff 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -122,13 +122,14 @@ public static Actor actorFromProjectileSource(ProjectileSource psource) { * or {@link #actorFromEntity(org.bukkit.entity.EntityType) } methods *

* If you know something is a server effect (like gravity) use {@link #Actor(java.lang.String)} - * + * * @deprecated Only use this if you have a String of unknown origin - * + * * @param actorName * String of unknown origin * @return */ + @Deprecated public static Actor actorFromString(String actorName) { Collection players = Bukkit.getServer().getOnlinePlayers(); for (Player p : players) { diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 0321ffb7..addbcde9 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -124,7 +124,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, final WorldConfig wcfg = getWorldConfig(world.getName()); if (wcfg != null) { sender.sendMessage(ChatColor.DARK_AQUA + "Currently logging in " + world.getName() + ":"); - final List logging = new ArrayList(); + final List logging = new ArrayList<>(); for (final Logging l : Logging.values()) { if (wcfg.isLogging(l)) { logging.add(l.toString()); @@ -343,7 +343,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, } } else if (command.equals("lookup") || QueryParams.isKeyWord(args[0])) { if (logblock.hasPermission(sender, "logblock.lookup")) { - final List argsList = new ArrayList(Arrays.asList(args)); + final List argsList = new ArrayList<>(Arrays.asList(args)); if (command.equals("lookup")) { argsList.remove(0); } @@ -486,7 +486,7 @@ public void run() { sender.sendMessage(ChatColor.DARK_AQUA + params.getTitle() + ":"); if (rs.next()) { rs.beforeFirst(); - final List blockchanges = new ArrayList(); + final List blockchanges = new ArrayList<>(); final LookupCacheElementFactory factory = new LookupCacheElementFactory(params, sender instanceof Player ? 2 / 3f : 1); while (rs.next()) { blockchanges.add(factory.getLookupCacheElement(rs)); @@ -989,7 +989,7 @@ private ResultSet executeQuery(Statement state, String query) throws SQLExceptio } private static List argsToList(String[] arr, int offset) { - final List list = new ArrayList(Arrays.asList(arr)); + final List list = new ArrayList<>(Arrays.asList(arr)); for (int i = 0; i < offset; i++) { list.remove(0); } diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 02f35bf2..c9e45512 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -60,7 +60,7 @@ public class Consumer extends Thread { private static final int RETURN_IDLE_CONNECTION_TIME_MILLIS = 120000; private static final int RETRIES_ON_UNKNOWN_CONNECTION_ERROR = 2; - private final Deque queue = new ArrayDeque(); + private final Deque queue = new ArrayDeque<>(); private final LogBlock logblock; private final Map playerIds = new HashMap<>(); private final Map uncommitedPlayerIds = new HashMap<>(); @@ -534,7 +534,7 @@ public void run() { public void writeToFile() throws FileNotFoundException { final long time = System.currentTimeMillis(); - final Set insertedPlayers = new HashSet(); + final Set insertedPlayers = new HashSet<>(); int counter = 0; new File("plugins/LogBlock/import/").mkdirs(); PrintWriter writer = new PrintWriter(new File("plugins/LogBlock/import/queue-" + time + "-0.sql")); @@ -734,7 +734,7 @@ public void queueEntityModification(Actor actor, UUID entityId, EntityType entit /** * Change the UUID that is stored for an entity in the database. This is needed when an entity is respawned * and now has a different UUID. - * + * * @param world the world that contains the entity * @param entityId the database id of the entity * @param entityUUID the new UUID of the entity @@ -1128,10 +1128,12 @@ public void process(Connection conn, BatchHelper batchHelper) throws SQLExceptio private int safeY(Location loc) { int safeY = loc.getBlockY(); - if (safeY < 0) + if (safeY < 0) { safeY = 0; - if (safeY > 65535) + } + if (safeY > 65535) { safeY = 65535; + } return safeY; } diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index df659173..09185ef7 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -287,7 +287,7 @@ public List getBlockChanges(QueryParams params) throws SQLException try { state = conn.createStatement(); final ResultSet rs = state.executeQuery(params.getQuery()); - final List blockchanges = new ArrayList(); + final List blockchanges = new ArrayList<>(); while (rs.next()) { blockchanges.add(new BlockChange(rs, params)); } diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 7fa8ade2..4af9a46b 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -62,17 +62,17 @@ public final class QueryParams implements Cloneable { public int limit = -1, before = 0, since = 0, radius = -1; public Location loc = null; public Order order = Order.DESC; - public List players = new ArrayList(); - public List killers = new ArrayList(); - public List victims = new ArrayList(); + public List players = new ArrayList<>(); + public List killers = new ArrayList<>(); + public List victims = new ArrayList<>(); public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, excludeBlocksEntitiesMode = false, prepareToolQuery = false, silent = false, noForcedLimit = false; public boolean forceReplace = false, noCache = false; public CuboidRegion sel = null; public SummarizationMode sum = SummarizationMode.NONE; - public List types = new ArrayList(); - public List typeIds = new ArrayList(); - public List entityTypes = new ArrayList(); - public List entityTypeIds = new ArrayList(); + public List types = new ArrayList<>(); + public List typeIds = new ArrayList<>(); + public List entityTypes = new ArrayList<>(); + public List entityTypeIds = new ArrayList<>(); public World world = null; public String match = null; public boolean needCount = false, needId = false, needDate = false, needType = false, needData = false, needPlayerId = false, needPlayer = false, needCoords = false, needChestAccess = false, needMessage = false, needKiller = false, needVictim = false, needWeapon = false; @@ -961,13 +961,13 @@ public void setPlayer(String playerName) { public QueryParams clone() { try { final QueryParams params = (QueryParams) super.clone(); - params.players = new ArrayList(players); - params.killers = new ArrayList(killers); - params.victims = new ArrayList(victims); - params.typeIds = new ArrayList(typeIds); - params.types = new ArrayList(types); - params.entityTypeIds = new ArrayList(entityTypeIds); - params.entityTypes = new ArrayList(entityTypes); + params.players = new ArrayList<>(players); + params.killers = new ArrayList<>(killers); + params.victims = new ArrayList<>(victims); + params.typeIds = new ArrayList<>(typeIds); + params.types = new ArrayList<>(types); + params.entityTypeIds = new ArrayList<>(entityTypeIds); + params.entityTypes = new ArrayList<>(entityTypes); params.loc = loc == null ? null : loc.clone(); params.sel = sel == null ? null : sel.clone(); return params; diff --git a/src/main/java/de/diddiz/LogBlock/Session.java b/src/main/java/de/diddiz/LogBlock/Session.java index 3e533557..d13ff785 100644 --- a/src/main/java/de/diddiz/LogBlock/Session.java +++ b/src/main/java/de/diddiz/LogBlock/Session.java @@ -10,14 +10,14 @@ import static org.bukkit.Bukkit.getServer; public class Session { - private static final Map sessions = new HashMap(); + private static final Map sessions = new HashMap<>(); public QueryParams lastQuery = null; public LookupCacheElement[] lookupCache = null; public int page = 1; public Map toolData; private Session(Player player) { - toolData = new HashMap(); + toolData = new HashMap<>(); final LogBlock logblock = LogBlock.getInstance(); if (player != null) { for (final Tool tool : toolsByType.values()) { diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 2bf2b58e..de93eb4c 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -290,8 +290,8 @@ boolean update() { int done = 0; conn.setAutoCommit(false); - Map players = new HashMap(); - List names = new ArrayList(UUID_CONVERT_BATCH_SIZE); + Map players = new HashMap<>(); + List names = new ArrayList<>(UUID_CONVERT_BATCH_SIZE); Map response; rs = st.executeQuery("SELECT playerid,playername FROM `lb-players` WHERE LENGTH(UUID)=0 LIMIT " + Integer.toString(UUID_CONVERT_BATCH_SIZE)); while (rs.next()) { diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 81889ed8..4e377471 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -147,7 +147,7 @@ synchronized public void start() throws Exception { @Override public synchronized void run() { - final List errorList = new ArrayList(); + final List errorList = new ArrayList<>(); int counter = 0; float size = edits.size(); while (!edits.isEmpty() && counter < 100) { @@ -337,6 +337,7 @@ public long getTime() { return date; } + @Override public PerformResult perform() throws WorldEditorException { BlockData replacedBlock = getBlockReplaced(); BlockData setBlock = getBlockSet(); diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index 9df3cfd7..5f3a6e60 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -85,8 +85,9 @@ public String toString(YamlConfiguration conf) { if (conf != null) { StringBuilder sb = new StringBuilder(); for (String line : conf.getStringList("lines")) { - if (sb.length() > 0) + if (sb.length() > 0) { sb.append(" "); + } sb.append("[").append(line).append("]"); } return sb.toString(); diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index a2f760ae..e91a9064 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -65,9 +65,9 @@ public static enum LogKillsLevel { public static void load(LogBlock logblock) throws DataFormatException, IOException { final ConfigurationSection config = logblock.getConfig(); - final Map def = new HashMap(); + final Map def = new HashMap<>(); def.put("version", logblock.getDescription().getVersion()); - final List worldNames = new ArrayList(); + final List worldNames = new ArrayList<>(); for (final World world : getWorlds()) { worldNames.add(world.getName()); } @@ -91,7 +91,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("consumer.queueWarningSize", 1000); def.put("clearlog.dumpDeletedLog", false); def.put("clearlog.enableAutoClearLog", false); - final List autoClearlog = new ArrayList(); + final List autoClearlog = new ArrayList<>(); for (final String world : worldNames) { autoClearlog.add("world \"" + world + "\" before 365 days all"); autoClearlog.add("world \"" + world + "\" player lavaflow waterflow leavesdecay before 7 days all"); @@ -189,11 +189,11 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti throw new DataFormatException("logging.logKillsLevel doesn't appear to be a valid log level. Allowed are 'PLAYERS', 'MONSTERS' and 'ANIMALS'"); } logEnvironmentalKills = config.getBoolean("logging.logEnvironmentalKills", false); - hiddenPlayers = new HashSet(); + hiddenPlayers = new HashSet<>(); for (final String playerName : config.getStringList("logging.hiddenPlayers")) { hiddenPlayers.add(playerName.toLowerCase().trim()); } - hiddenBlocks = new HashSet(); + hiddenBlocks = new HashSet<>(); for (final String blocktype : config.getStringList("logging.hiddenBlocks")) { final Material mat = Material.matchMaterial(blocktype); if (mat != null) { @@ -202,11 +202,11 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti throw new DataFormatException("Not a valid material in hiddenBlocks: '" + blocktype + "'"); } } - ignoredChat = new ArrayList(); + ignoredChat = new ArrayList<>(); for (String chatCommand : config.getStringList("logging.ignoredChat")) { ignoredChat.add(chatCommand.toLowerCase()); } - dontRollback = new HashSet(); + dontRollback = new HashSet<>(); for (String e : config.getStringList("rollback.dontRollback")) { Material mat = Material.matchMaterial(e); if (mat != null) { @@ -215,7 +215,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti throw new DataFormatException("Not a valid material in dontRollback: '" + e + "'"); } } - replaceAnyway = new HashSet(); + replaceAnyway = new HashSet<>(); for (String e : config.getStringList("rollback.replaceAnyway")) { Material mat = Material.matchMaterial(e); if (mat != null) { @@ -239,7 +239,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti safetyIdCheck = config.getBoolean("safety.id.check", true); debug = config.getBoolean("debug", false); banPermission = config.getString("questioner.banPermission"); - final List tools = new ArrayList(); + final List tools = new ArrayList<>(); final ConfigurationSection toolsSec = config.getConfigurationSection("tools"); for (final String toolName : toolsSec.getKeys(false)) { try { @@ -262,8 +262,8 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti getLogger().log(Level.WARNING, "Error at parsing tool '" + toolName + "': ", ex); } } - toolsByName = new HashMap(); - toolsByType = new HashMap(); + toolsByName = new HashMap<>(); + toolsByType = new HashMap<>(); for (final Tool tool : tools) { toolsByType.put(tool.item, tool); toolsByName.put(tool.name.toLowerCase(), tool); @@ -272,7 +272,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti } } final List loggedWorlds = config.getStringList("loggedWorlds"); - worldConfigs = new HashMap(); + worldConfigs = new HashMap<>(); if (loggedWorlds.isEmpty()) { throw new DataFormatException("No worlds configured"); } diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index e4aea94d..19230bd4 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -38,7 +38,7 @@ public class WorldConfig extends LoggingEnabledMapping { public WorldConfig(String world, File file) throws IOException { this.world = world; - final Map def = new HashMap(); + final Map def = new HashMap<>(); // "Before MySQL 5.1.6, database and table names cannot contain "/", "\", ".", or characters that are not permitted in file names" - MySQL manual // They _can_ contain spaces, but replace them as well def.put("table", "lb-" + file.getName().substring(0, file.getName().length() - 4).replaceAll("[ ./\\\\]", "_")); diff --git a/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java b/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java index fdb25dad..efdf0266 100644 --- a/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java +++ b/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java @@ -19,9 +19,7 @@ public class BlockChangePreLogEvent extends PreLogEvent { private YamlConfiguration stateBefore; private YamlConfiguration stateAfter; - public BlockChangePreLogEvent(Actor owner, Location location, BlockData typeBefore, BlockData typeAfter, - YamlConfiguration stateBefore, YamlConfiguration stateAfter, ChestAccess chestAccess) { - + public BlockChangePreLogEvent(Actor owner, Location location, BlockData typeBefore, BlockData typeAfter, YamlConfiguration stateBefore, YamlConfiguration stateAfter, ChestAccess chestAccess) { super(owner); this.location = location; this.typeBefore = typeBefore; @@ -32,17 +30,14 @@ public BlockChangePreLogEvent(Actor owner, Location location, BlockData typeBefo } public Location getLocation() { - return location; } public void setLocation(Location location) { - this.location = location; } public BlockData getTypeBefore() { - return typeBefore; } @@ -54,7 +49,6 @@ public void setTypeBefore(BlockData typeBefore) { } public BlockData getTypeAfter() { - return typeAfter; } @@ -82,22 +76,19 @@ public void setStateAfter(YamlConfiguration stateAfter) { } public ChestAccess getChestAccess() { - return chestAccess; } public void setChestAccess(ChestAccess chestAccess) { - this.chestAccess = chestAccess; } + @Override public HandlerList getHandlers() { - return handlers; } public static HandlerList getHandlerList() { - return handlers; } } diff --git a/src/main/java/de/diddiz/LogBlock/events/PreLogEvent.java b/src/main/java/de/diddiz/LogBlock/events/PreLogEvent.java index 51a7a228..109aed59 100644 --- a/src/main/java/de/diddiz/LogBlock/events/PreLogEvent.java +++ b/src/main/java/de/diddiz/LogBlock/events/PreLogEvent.java @@ -10,7 +10,6 @@ public abstract class PreLogEvent extends Event implements Cancellable { protected Actor owner; public PreLogEvent(Actor owner) { - this.owner = owner; } @@ -21,8 +20,8 @@ public PreLogEvent(Actor owner) { * @deprecated {@link #getOwnerActor() } returns an object encapsulating * name and uuid. Names are not guaranteed to be unique. */ + @Deprecated public String getOwner() { - return owner.getName(); } @@ -41,17 +40,16 @@ public Actor getOwnerActor() { * @param owner The player/monster/cause who is involved in this event */ public void setOwner(Actor owner) { - this.owner = owner; } + @Override public boolean isCancelled() { - return cancelled; } + @Override public void setCancelled(boolean cancelled) { - this.cancelled = cancelled; } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java index 090b7bb4..e329ccf0 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java @@ -39,7 +39,7 @@ public void onBlockIgnite(BlockIgniteEvent event) { Actor actor = new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null); if (event.getCause() == IgniteCause.FLINT_AND_STEEL) { if (event.getIgnitingEntity() != null) { - return; // handled in block place + return; // handled in block place } else { actor = new Actor("Dispenser"); } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index dba45d62..0b8422bd 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -22,7 +22,7 @@ import static de.diddiz.util.BukkitUtils.*; public class ChestAccessLogging extends LoggingListener { - private final Map containers = new HashMap(); + private final Map containers = new HashMap<>(); public ChestAccessLogging(LogBlock lb) { super(lb); diff --git a/src/main/java/de/diddiz/LogBlock/questioner/Questioner.java b/src/main/java/de/diddiz/LogBlock/questioner/Questioner.java index f4746ec2..399f3589 100644 --- a/src/main/java/de/diddiz/LogBlock/questioner/Questioner.java +++ b/src/main/java/de/diddiz/LogBlock/questioner/Questioner.java @@ -15,7 +15,7 @@ public class Questioner { private final LogBlock logBlock; - private final ConcurrentHashMap questions = new ConcurrentHashMap(); + private final ConcurrentHashMap questions = new ConcurrentHashMap<>(); public Questioner(LogBlock logBlock) { this.logBlock = logBlock; @@ -42,6 +42,7 @@ public String ask(Player respondent, String questionMessage, String... answers) } private class QuestionsReaper implements Runnable { + @Override public void run() { if (questions.isEmpty()) { return; diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 2758c3b4..ec62af3f 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -158,14 +158,14 @@ public class BukkitUtils { doublePlants.add(Material.SUNFLOWER); doublePlants.add(Material.PEONY); - blockEquivalents = new HashSet>(7); - blockEquivalents.add(new HashSet(Arrays.asList(2, 3, 60))); - blockEquivalents.add(new HashSet(Arrays.asList(8, 9, 79))); - blockEquivalents.add(new HashSet(Arrays.asList(10, 11))); - blockEquivalents.add(new HashSet(Arrays.asList(61, 62))); - blockEquivalents.add(new HashSet(Arrays.asList(73, 74))); - blockEquivalents.add(new HashSet(Arrays.asList(75, 76))); - blockEquivalents.add(new HashSet(Arrays.asList(93, 94))); + blockEquivalents = new HashSet<>(7); + blockEquivalents.add(new HashSet<>(Arrays.asList(2, 3, 60))); + blockEquivalents.add(new HashSet<>(Arrays.asList(8, 9, 79))); + blockEquivalents.add(new HashSet<>(Arrays.asList(10, 11))); + blockEquivalents.add(new HashSet<>(Arrays.asList(61, 62))); + blockEquivalents.add(new HashSet<>(Arrays.asList(73, 74))); + blockEquivalents.add(new HashSet<>(Arrays.asList(75, 76))); + blockEquivalents.add(new HashSet<>(Arrays.asList(93, 94))); // Blocks that break when they are attached to a block relativeBreakable = EnumSet.noneOf(Material.class); @@ -332,7 +332,7 @@ public class BukkitUtils { // containerBlocks.add(Material.ENDER_CHEST); // It doesn't seem like you could injure people with some of these, but they exist, so.... - projectileItems = new EnumMap(EntityType.class); + projectileItems = new EnumMap<>(EntityType.class); projectileItems.put(EntityType.ARROW, Material.ARROW); projectileItems.put(EntityType.EGG, Material.EGG); projectileItems.put(EntityType.ENDER_PEARL, Material.ENDER_PEARL); @@ -441,7 +441,7 @@ public class BukkitUtils { * @return List of block locations around the block that are of the type specified by the integer list parameter */ public static List getBlocksNearby(org.bukkit.block.Block block, Set type) { - ArrayList blocks = new ArrayList(); + ArrayList blocks = new ArrayList<>(); for (BlockFace blockFace : relativeBlockFaces) { if (type.contains(block.getRelative(blockFace).getType())) { blocks.add(block.getRelative(blockFace).getLocation()); @@ -478,7 +478,7 @@ public static Location getInventoryHolderLocation(InventoryHolder holder) { } public static ItemStack[] compareInventories(ItemStack[] items1, ItemStack[] items2) { - final ArrayList diff = new ArrayList(); + final ArrayList diff = new ArrayList<>(); for (ItemStack current : items2) { diff.add(new ItemStack(current)); } @@ -506,7 +506,7 @@ public static ItemStack[] compareInventories(ItemStack[] items1, ItemStack[] ite } public static ItemStack[] compressInventory(ItemStack[] items) { - final ArrayList compressed = new ArrayList(); + final ArrayList compressed = new ArrayList<>(); for (final ItemStack item : items) { if (item != null) { boolean found = false; diff --git a/src/main/java/de/diddiz/util/ComparableVersion.java b/src/main/java/de/diddiz/util/ComparableVersion.java index 46b6922b..95aba246 100644 --- a/src/main/java/de/diddiz/util/ComparableVersion.java +++ b/src/main/java/de/diddiz/util/ComparableVersion.java @@ -1,6 +1,6 @@ package de.diddiz.util; -// Taken from maven-artifact at +// Taken from maven-artifact at // http://grepcode.com/file_/repo1.maven.org/maven2/org.apache.maven/maven-artifact/3.2.3/org/apache/maven/artifact/versioning/ComparableVersion.java/?v=source /* @@ -34,7 +34,7 @@ /** * Generic implementation of version comparison. - * + * *

Features: *

    *
  • mixing of '-' (dash) and '.' (dot) separators,
  • @@ -98,14 +98,17 @@ public IntegerItem(String str) { this.value = new BigInteger(str); } + @Override public int getType() { return INTEGER_ITEM; } + @Override public boolean isNull() { return BIG_INTEGER_ZERO.equals(value); } + @Override public int compareTo(Item item) { if (item == null) { return BIG_INTEGER_ZERO.equals(value) ? 0 : 1; // 1.0 == 1, 1.1 > 1 @@ -126,6 +129,7 @@ public int compareTo(Item item) { } } + @Override public String toString() { return value.toString(); } @@ -172,10 +176,12 @@ public StringItem(String value, boolean followedByDigit) { this.value = ALIASES.getProperty(value, value); } + @Override public int getType() { return STRING_ITEM; } + @Override public boolean isNull() { return (comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX) == 0); } @@ -198,6 +204,7 @@ public static String comparableQualifier(String qualifier) { return i == -1 ? (_QUALIFIERS.size() + "-" + qualifier) : String.valueOf(i); } + @Override public int compareTo(Item item) { if (item == null) { // 1-rc < 1, 1-ga > 1 @@ -218,6 +225,7 @@ public int compareTo(Item item) { } } + @Override public String toString() { return value; } @@ -230,10 +238,12 @@ public String toString() { private static class ListItem extends ArrayList implements Item { private static final long serialVersionUID = 5914575811857700009L; + @Override public int getType() { return LIST_ITEM; } + @Override public boolean isNull() { return (size() == 0); } @@ -249,6 +259,7 @@ void normalize() { } } + @Override public int compareTo(Item item) { if (item == null) { if (size() == 0) { @@ -287,6 +298,7 @@ public int compareTo(Item item) { } } + @Override public String toString() { StringBuilder buffer = new StringBuilder("("); for (Iterator iter = iterator(); iter.hasNext();) { @@ -313,7 +325,7 @@ public final void parseVersion(String version) { ListItem list = items; - Stack stack = new Stack(); + Stack stack = new Stack<>(); stack.push(list); boolean isDigit = false; @@ -382,6 +394,7 @@ private static Item parseItem(boolean isDigit, String buf) { return isDigit ? new IntegerItem(buf) : new StringItem(buf, false); } + @Override public int compareTo(ComparableVersion o) { return items.compareTo(o.items); } @@ -390,6 +403,7 @@ public int compareTo(String version) { return compareTo(new ComparableVersion(version)); } + @Override public String toString() { return value; } @@ -398,10 +412,12 @@ public String toCanonicalString() { return canonical; } + @Override public boolean equals(Object o) { return (o instanceof ComparableVersion) && canonical.equals(((ComparableVersion) o).canonical); } + @Override public int hashCode() { return canonical.hashCode(); } diff --git a/src/main/java/de/diddiz/util/UUIDFetcher.java b/src/main/java/de/diddiz/util/UUIDFetcher.java index 2b4d66a8..54a86fbe 100644 --- a/src/main/java/de/diddiz/util/UUIDFetcher.java +++ b/src/main/java/de/diddiz/util/UUIDFetcher.java @@ -22,7 +22,7 @@ public class UUIDFetcher { private static final JSONParser jsonParser = new JSONParser(); public static Map getUUIDs(List names) throws Exception { - Map uuidMap = new HashMap(); + Map uuidMap = new HashMap<>(); HttpURLConnection connection = createConnection(); String body = JSONArray.toJSONString(names); writeBody(connection, body); diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index c4ea0f90..3e38a3b1 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -181,7 +181,7 @@ public static String join(String[] s, String delimiter) { * @return A new list with the quoted arguments parsed to single values */ public static List parseQuotes(List args) { - List newArguments = new ArrayList(); + List newArguments = new ArrayList<>(); String subjectString = join(args.toArray(new String[args.size()]), " "); Pattern regex = Pattern.compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'"); From d829005c7ecbf9ecdca8eb2c6db085d5e00bed29 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 23 Jun 2019 21:56:36 +0200 Subject: [PATCH 205/399] Apply new message formatting to entity changes --- .../java/de/diddiz/LogBlock/EntityChange.java | 39 +++++++++++-------- .../java/de/diddiz/util/MessagingUtil.java | 5 +++ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/EntityChange.java b/src/main/java/de/diddiz/LogBlock/EntityChange.java index b0056928..71e91898 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityChange.java +++ b/src/main/java/de/diddiz/LogBlock/EntityChange.java @@ -1,9 +1,19 @@ package de.diddiz.LogBlock; +import static de.diddiz.util.ActionColor.CREATE; +import static de.diddiz.util.ActionColor.DESTROY; +import static de.diddiz.util.ActionColor.INTERACT; +import static de.diddiz.util.MessagingUtil.brackets; +import static de.diddiz.util.MessagingUtil.prettyDate; +import static de.diddiz.util.MessagingUtil.prettyEntityType; +import static de.diddiz.util.MessagingUtil.prettyLocation; +import static de.diddiz.util.MessagingUtil.prettyMaterial; + +import de.diddiz.util.MessagingUtil.BracketType; +import de.diddiz.util.Utils; import java.sql.ResultSet; import java.sql.SQLException; import java.util.UUID; - import org.bukkit.Location; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.ArmorStand; @@ -11,9 +21,6 @@ import org.bukkit.entity.LivingEntity; import org.bukkit.inventory.ItemStack; -import de.diddiz.LogBlock.config.Config; -import de.diddiz.util.Utils; - public class EntityChange implements LookupCacheElement { public static enum EntityChangeType { CREATE, @@ -66,44 +73,44 @@ public EntityChange(ResultSet rs, QueryParams p) throws SQLException { public String toString() { final StringBuilder msg = new StringBuilder(); if (date > 0) { - msg.append(Config.formatter.format(date)).append(" "); + msg.append(brackets(prettyDate(date), BracketType.STANDARD)).append(' '); } if (actor != null) { msg.append(actor.getName()).append(" "); } if (changeType == EntityChangeType.CREATE) { - msg.append("created "); + msg.append(CREATE).append("created "); } else if (changeType == EntityChangeType.KILL) { boolean living = type != null && LivingEntity.class.isAssignableFrom(type.getEntityClass()) && !ArmorStand.class.isAssignableFrom(type.getDeclaringClass()); - msg.append(living ? "killed " : "destroyed "); + msg.append(DESTROY).append(living ? "killed " : "destroyed "); } else if (changeType == EntityChangeType.ADDEQUIP) { YamlConfiguration conf = Utils.deserializeYamlConfiguration(data); ItemStack stack = conf == null ? null : conf.getItemStack("item"); if (stack == null) { - msg.append("added an item to "); + msg.append(CREATE).append("added an item to "); } else { - msg.append("added " + stack.getType() + " to "); + msg.append(CREATE).append("added ").append(prettyMaterial(stack.getType())).append(" to "); } } else if (changeType == EntityChangeType.REMOVEEQUIP) { YamlConfiguration conf = Utils.deserializeYamlConfiguration(data); ItemStack stack = conf == null ? null : conf.getItemStack("item"); if (stack == null) { - msg.append("removed an item from "); + msg.append(DESTROY).append("removed an item from "); } else { - msg.append("removed " + stack.getType() + " from "); + msg.append(DESTROY).append("removed ").append(prettyMaterial(stack.getType())).append(" from "); } } else if (changeType == EntityChangeType.MODIFY) { - msg.append("modified "); + msg.append(INTERACT).append("modified "); } else { - msg.append("did an unknown action to "); + msg.append(INTERACT).append("did an unknown action to "); } if (type != null) { - msg.append(type.name()); + msg.append(prettyEntityType(type)); } else { - msg.append("an unknown entity"); + msg.append(prettyMaterial("an unknown entity")); } if (loc != null) { - msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ()); + msg.append(" at: ").append(prettyLocation(loc)); } return msg.toString(); } diff --git a/src/main/java/de/diddiz/util/MessagingUtil.java b/src/main/java/de/diddiz/util/MessagingUtil.java index 336b3c55..83765efe 100644 --- a/src/main/java/de/diddiz/util/MessagingUtil.java +++ b/src/main/java/de/diddiz/util/MessagingUtil.java @@ -5,6 +5,7 @@ import de.diddiz.LogBlock.config.Config; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.entity.EntityType; public class MessagingUtil { public static String brackets(String string, BracketType type) { @@ -35,6 +36,10 @@ public static String prettyMaterial(Material material) { return prettyMaterial(material.name()); } + public static String prettyEntityType(EntityType type) { + return prettyMaterial(type.name()); + } + public static String prettyLocation(Location loc) { return prettyLocation(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); } From e9d78bffb12355fb0beecb78aa4b49f0805fa83d Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 23 Jun 2019 21:59:07 +0200 Subject: [PATCH 206/399] Change action type for some entries --- src/main/java/de/diddiz/LogBlock/BlockChange.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 3fd274ff..613c9d3f 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -154,16 +154,16 @@ public String toString() { } else if (type.getMaterial() == Material.TRIPWIRE) { msg.append(INTERACT).append("ran into ").append(prettyMaterial(type.getMaterial())); } else if (type instanceof Sign || type instanceof WallSign) { - msg.append(DESTROY).append("edited a ").append(prettyMaterial(type.getMaterial())).append(CREATE).append(" to ").append(prettyState(typeDetails)); + msg.append(CREATE).append("edited a ").append(prettyMaterial(type.getMaterial())).append(CREATE).append(" to ").append(prettyState(typeDetails)); } else { - msg.append(DESTROY).append("replaced ").append(prettyMaterial(replaced.getMaterial())).append(prettyState(replacedDetails)).append(CREATE).append(" with ").append(prettyMaterial(type.getMaterial())).append(prettyState(typeDetails)); + msg.append(CREATE).append("replaced ").append(prettyMaterial(replaced.getMaterial())).append(prettyState(replacedDetails)).append(CREATE).append(" with ").append(prettyMaterial(type.getMaterial())).append(prettyState(typeDetails)); } } else if (BukkitUtils.isEmpty(type.getMaterial())) { msg.append(DESTROY).append("destroyed ").append(prettyMaterial(replaced.getMaterial())).append(prettyState(replacedDetails)); } else if (BukkitUtils.isEmpty(replaced.getMaterial())) { msg.append(CREATE).append("created ").append(prettyMaterial(type.getMaterial())).append(prettyState(typeDetails)); } else { - msg.append(DESTROY).append("replaced ").append(prettyMaterial(replaced.getMaterial())).append(prettyState(replacedDetails)).append(CREATE).append(" with ").append(type.getMaterial().name()).append(typeDetails); + msg.append(CREATE).append("replaced ").append(prettyMaterial(replaced.getMaterial())).append(prettyState(replacedDetails)).append(CREATE).append(" with ").append(type.getMaterial().name()).append(typeDetails); } if (loc != null) { msg.append(" at: ").append(prettyLocation(loc)); From d03bbe68ba4d708d56f1d05634705dd3b74e131c Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 24 Jun 2019 04:14:52 +0200 Subject: [PATCH 207/399] Add missing newline --- src/main/java/de/diddiz/util/ActionColor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/util/ActionColor.java b/src/main/java/de/diddiz/util/ActionColor.java index f3761d23..5573ba3f 100644 --- a/src/main/java/de/diddiz/util/ActionColor.java +++ b/src/main/java/de/diddiz/util/ActionColor.java @@ -21,4 +21,4 @@ public ChatColor getColor() { public String toString() { return color.toString(); } -} \ No newline at end of file +} From 6f4ce7e6d052d28acc81b25a080649ce1bd51b9a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 9 Jul 2019 03:42:33 +0200 Subject: [PATCH 208/399] Fix lectern logging Fixes #761 --- .../blockstate/BlockStateCodecLectern.java | 6 +++++- .../LogBlock/listeners/LecternLogging.java | 18 +++++++++++++++--- src/main/java/de/diddiz/util/BukkitUtils.java | 1 - 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java index 14e2a956..ec450803 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java @@ -34,7 +34,11 @@ public void deserialize(BlockState state, YamlConfiguration conf) { if (conf != null) { book = conf.getItemStack("book"); } - lectern.getSnapshotInventory().setItem(0, book); + try { + lectern.getSnapshotInventory().setItem(0, book); + } catch (NullPointerException e) { + //ignored + } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java index e6b367c6..16e7627b 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java @@ -29,10 +29,18 @@ public void onBlockPlace(BlockPlaceEvent event) { if (before.getType() == Material.LECTERN && after.getType() == Material.LECTERN) { Lectern lecternBefore = (Lectern) before.getBlock().getState(); ItemStack book = lecternBefore.getSnapshotInventory().getItem(0); - lecternBefore.getSnapshotInventory().setItem(0, null); + try { + lecternBefore.getSnapshotInventory().setItem(0, null); + } catch (NullPointerException e) { + //ignored + } lecternBefore.setBlockData(before.getBlockData()); consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), lecternBefore, after); - lecternBefore.getSnapshotInventory().setItem(0, book); + try { + lecternBefore.getSnapshotInventory().setItem(0, book); + } catch (NullPointerException e) { + //ignored + } } } } @@ -43,7 +51,11 @@ public void onPlayerTakeLecternBook(PlayerTakeLecternBookEvent event) { if (wcfg != null && wcfg.isLogging(Logging.LECTERNBOOKCHANGE)) { Lectern oldState = event.getLectern(); Lectern newState = (Lectern) oldState.getBlock().getState(); - newState.getSnapshotInventory().setItem(0, null); + try { + newState.getSnapshotInventory().setItem(0, null); + } catch (NullPointerException e) { + //ignored + } org.bukkit.block.data.type.Lectern oldBlockData = (org.bukkit.block.data.type.Lectern) oldState.getBlockData(); org.bukkit.block.data.type.Lectern blockData = (org.bukkit.block.data.type.Lectern) Material.LECTERN.createBlockData(); blockData.setFacing(oldBlockData.getFacing()); diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index ec62af3f..4cb5dd2a 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -327,7 +327,6 @@ public class BukkitUtils { containerBlocks.add(Material.BARREL); containerBlocks.add(Material.BLAST_FURNACE); containerBlocks.add(Material.SMOKER); - containerBlocks.add(Material.LECTERN); // Doesn't actually have a block inventory // containerBlocks.add(Material.ENDER_CHEST); From 06f24bf632c7d1ef3b1bebd1172a78f42f588eb3 Mon Sep 17 00:00:00 2001 From: Paul-Maxime Date: Sat, 10 Aug 2019 00:24:27 +0200 Subject: [PATCH 209/399] Add public to the ChestAccess variables --- src/main/java/de/diddiz/LogBlock/ChestAccess.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/ChestAccess.java b/src/main/java/de/diddiz/LogBlock/ChestAccess.java index 312dc05f..c9d78828 100644 --- a/src/main/java/de/diddiz/LogBlock/ChestAccess.java +++ b/src/main/java/de/diddiz/LogBlock/ChestAccess.java @@ -3,9 +3,9 @@ import org.bukkit.inventory.ItemStack; public class ChestAccess { - final ItemStack itemStack; - final boolean remove; - final int itemType; + public final ItemStack itemStack; + public final boolean remove; + public final int itemType; public ChestAccess(ItemStack itemStack, boolean remove, int itemType) { this.itemStack = itemStack; From 07bf9421ddde5309f4d323c81a0a7430435b0c46 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 10 Aug 2019 04:24:03 +0200 Subject: [PATCH 210/399] Switch to openjdk8 in travis builds --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a20cdb5a..b2270fd7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: java jdk: - - oraclejdk8 + - openjdk8 notifications: email: false From 2f92fd3426956a96940e1ce7bb226163d6cd5d6e Mon Sep 17 00:00:00 2001 From: Paul-Maxime Date: Sat, 10 Aug 2019 19:11:58 +0200 Subject: [PATCH 211/399] Fix beacon logging, they are not a container --- src/main/java/de/diddiz/util/BukkitUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 4cb5dd2a..36183284 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -306,7 +306,6 @@ public class BukkitUtils { containerBlocks.add(Material.HOPPER); containerBlocks.add(Material.BREWING_STAND); containerBlocks.add(Material.FURNACE); - containerBlocks.add(Material.BEACON); containerBlocks.add(Material.SHULKER_BOX); containerBlocks.add(Material.BLACK_SHULKER_BOX); containerBlocks.add(Material.BLUE_SHULKER_BOX); From a7967e9b1ef7816f1082e0f7191a063844cf45e6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 27 Aug 2019 20:10:12 +0200 Subject: [PATCH 212/399] Do not require WorldEdit for CuboidRegion --- .../java/de/diddiz/LogBlock/QueryParams.java | 8 +--- .../LogBlock/listeners/ToolListener.java | 2 +- .../{worldedit => util}/CuboidRegion.java | 36 +--------------- .../de/diddiz/worldedit/WorldEditHelper.java | 43 ++++++++++++++++++- 4 files changed, 45 insertions(+), 44 deletions(-) rename src/main/java/de/diddiz/{worldedit => util}/CuboidRegion.java (51%) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 4af9a46b..5c1c46af 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -2,8 +2,8 @@ import de.diddiz.LogBlock.config.Config; import de.diddiz.util.BukkitUtils; +import de.diddiz.util.CuboidRegion; import de.diddiz.util.Utils; -import de.diddiz.worldedit.CuboidRegion; import de.diddiz.worldedit.WorldEditHelper; import org.bukkit.Location; @@ -792,11 +792,7 @@ public void parseArgs(CommandSender sender, List args, boolean validate) if (player == null) { throw new IllegalArgumentException("You have to be a player to use selection"); } - if (WorldEditHelper.hasWorldEdit()) { - setSelection(CuboidRegion.fromPlayerSelection(player)); - } else { - throw new IllegalArgumentException("WorldEdit not found!"); - } + setSelection(WorldEditHelper.getSelectedRegion(player)); } else if (param.equals("time") || param.equals("since")) { since = values.length > 0 ? parseTimeSpec(values) : defaultTime; if (since == -1) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java index 342eb39f..df889d76 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java @@ -2,7 +2,7 @@ import de.diddiz.LogBlock.*; import de.diddiz.util.BukkitUtils; -import de.diddiz.worldedit.CuboidRegion; +import de.diddiz.util.CuboidRegion; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.block.Block; diff --git a/src/main/java/de/diddiz/worldedit/CuboidRegion.java b/src/main/java/de/diddiz/util/CuboidRegion.java similarity index 51% rename from src/main/java/de/diddiz/worldedit/CuboidRegion.java rename to src/main/java/de/diddiz/util/CuboidRegion.java index 15dc1ccd..a7046096 100644 --- a/src/main/java/de/diddiz/worldedit/CuboidRegion.java +++ b/src/main/java/de/diddiz/util/CuboidRegion.java @@ -1,16 +1,7 @@ -package de.diddiz.worldedit; - -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; +package de.diddiz.util; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; import org.bukkit.util.BlockVector; public class CuboidRegion implements Cloneable { @@ -29,31 +20,6 @@ public CuboidRegion(World world, BlockVector first, BlockVector second) { this.max.setZ(Math.max(first.getBlockZ(), second.getBlockZ())); } - public static CuboidRegion fromPlayerSelection(Player player) { - Plugin worldEditPlugin = player.getServer().getPluginManager().getPlugin("WorldEdit"); - LocalSession session = ((WorldEditPlugin) worldEditPlugin).getSession(player); - World world = player.getWorld(); - com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(world); - if (!weWorld.equals(session.getSelectionWorld())) { - throw new IllegalArgumentException("No selection defined"); - } - Region selection; - try { - selection = session.getSelection(weWorld); - } catch (IncompleteRegionException e) { - throw new IllegalArgumentException("No selection defined"); - } - if (selection == null) { - throw new IllegalArgumentException("No selection defined"); - } - if (!(selection instanceof com.sk89q.worldedit.regions.CuboidRegion)) { - throw new IllegalArgumentException("You have to define a cuboid selection"); - } - BlockVector3 min = selection.getMinimumPoint(); - BlockVector3 max = selection.getMaximumPoint(); - return new CuboidRegion(world, new BlockVector(min.getBlockX(), min.getBlockY(), min.getBlockZ()), new BlockVector(max.getBlockX(), max.getBlockY(), max.getBlockZ())); - } - public static CuboidRegion fromCorners(World world, Location first, Location second) { return new CuboidRegion(world, new BlockVector(first.getBlockX(), first.getBlockY(), first.getBlockZ()), new BlockVector(second.getBlockX(), second.getBlockY(), second.getBlockZ())); } diff --git a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java b/src/main/java/de/diddiz/worldedit/WorldEditHelper.java index 2df370da..b3cf56f4 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditHelper.java @@ -11,10 +11,12 @@ import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; - +import org.bukkit.util.BlockVector; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.DoubleTag; import com.sk89q.jnbt.FloatTag; @@ -24,11 +26,15 @@ 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; 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 de.diddiz.LogBlock.LogBlock; +import de.diddiz.util.CuboidRegion; public class WorldEditHelper { private static boolean checkedForWorldEdit; @@ -58,9 +64,19 @@ public static byte[] serializeEntity(Entity entity) { } public static Entity restoreEntity(Location location, EntityType type, byte[] serialized) { + if (!hasWorldEdit()) { + return null; + } return Internal.restoreEntity(location, type, serialized); } + public static CuboidRegion getSelectedRegion(Player player) throws IllegalArgumentException { + if (!hasWorldEdit()) { + throw new IllegalArgumentException("WorldEdit not found!"); + } + return Internal.getSelectedRegion(player); + } + private static class Internal { private static WorldEditPlugin worldEdit; private static Method getBukkitImplAdapter; @@ -133,5 +149,28 @@ public static byte[] serializeEntity(Entity entity) { return null; } + public static CuboidRegion getSelectedRegion(Player player) throws IllegalArgumentException { + LocalSession session = worldEdit.getSession(player); + World world = player.getWorld(); + com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(world); + if (!weWorld.equals(session.getSelectionWorld())) { + throw new IllegalArgumentException("No selection defined"); + } + Region selection; + try { + selection = session.getSelection(weWorld); + } catch (IncompleteRegionException e) { + throw new IllegalArgumentException("No selection defined"); + } + if (selection == null) { + throw new IllegalArgumentException("No selection defined"); + } + if (!(selection instanceof com.sk89q.worldedit.regions.CuboidRegion)) { + throw new IllegalArgumentException("You have to define a cuboid selection"); + } + BlockVector3 min = selection.getMinimumPoint(); + BlockVector3 max = selection.getMaximumPoint(); + return new CuboidRegion(world, new BlockVector(min.getBlockX(), min.getBlockY(), min.getBlockZ()), new BlockVector(max.getBlockX(), max.getBlockY(), max.getBlockZ())); + } } } From cd38ac986685f7af6085a6163083d13618c61578 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 27 Aug 2019 22:30:37 +0200 Subject: [PATCH 213/399] Remove unused methods --- src/main/java/de/diddiz/util/UUIDFetcher.java | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/main/java/de/diddiz/util/UUIDFetcher.java b/src/main/java/de/diddiz/util/UUIDFetcher.java index 54a86fbe..1368dc3d 100644 --- a/src/main/java/de/diddiz/util/UUIDFetcher.java +++ b/src/main/java/de/diddiz/util/UUIDFetcher.java @@ -8,7 +8,6 @@ import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; -import java.nio.ByteBuffer; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,7 +30,7 @@ public static Map getUUIDs(List names) throws Exception { JSONObject jsonProfile = (JSONObject) profile; String id = (String) jsonProfile.get("id"); String name = (String) jsonProfile.get("name"); - UUID uuid = UUIDFetcher.getUUID(id); + UUID uuid = getUUID(id); uuidMap.put(name, uuid); } return uuidMap; @@ -58,22 +57,4 @@ private static HttpURLConnection createConnection() throws Exception { private static UUID getUUID(String id) { return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" + id.substring(20, 32)); } - - public static byte[] toBytes(UUID uuid) { - ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]); - byteBuffer.putLong(uuid.getMostSignificantBits()); - byteBuffer.putLong(uuid.getLeastSignificantBits()); - return byteBuffer.array(); - } - - public static UUID fromBytes(byte[] array) { - if (array.length != 16) { - throw new IllegalArgumentException("Illegal byte array length: " + array.length); - } - ByteBuffer byteBuffer = ByteBuffer.wrap(array); - long mostSignificant = byteBuffer.getLong(); - long leastSignificant = byteBuffer.getLong(); - return new UUID(mostSignificant, leastSignificant); - } - } From 921df872d14df240bb6252b0f0b81039963cd210 Mon Sep 17 00:00:00 2001 From: TheMolkaPL Date: Fri, 27 Sep 2019 02:17:54 +0200 Subject: [PATCH 214/399] Expose useSSL flag to config --- src/main/java/de/diddiz/LogBlock/LogBlock.java | 2 +- src/main/java/de/diddiz/LogBlock/config/Config.java | 3 +++ src/main/java/de/diddiz/util/MySQLConnectionPool.java | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 09185ef7..91acee30 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -72,7 +72,7 @@ public void onEnable() { } try { getLogger().info("Connecting to " + user + "@" + url + "..."); - pool = new MySQLConnectionPool(url, user, password, mysqlRequireSSL); + pool = new MySQLConnectionPool(url, user, password, mysqlUseSSL, mysqlRequireSSL); final Connection conn = getConnection(true); if (conn == null) { noDb = true; diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index e91a9064..103f349d 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -25,6 +25,7 @@ public class Config { private static LoggingEnabledMapping superWorldConfig; private static Map worldConfigs; public static String url, user, password; + public static boolean mysqlUseSSL; public static boolean mysqlRequireSSL; public static int delayBetweenRuns, forceToProcessAtLeast, timePerRun; public static boolean fireCustomEvents; @@ -82,6 +83,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("mysql.database", "minecraft"); def.put("mysql.user", "username"); def.put("mysql.password", "pass"); + def.put("mysql.useSSL", true); def.put("mysql.requireSSL", false); def.put("consumer.delayBetweenRuns", 2); def.put("consumer.forceToProcessAtLeast", 200); @@ -167,6 +169,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database"); user = getStringIncludingInts(config, "mysql.user"); password = getStringIncludingInts(config, "mysql.password"); + mysqlUseSSL = config.getBoolean("mysql.useSSL", true); mysqlRequireSSL = config.getBoolean("mysql.requireSSL", false); delayBetweenRuns = config.getInt("consumer.delayBetweenRuns", 2); forceToProcessAtLeast = config.getInt("consumer.forceToProcessAtLeast", 0); diff --git a/src/main/java/de/diddiz/util/MySQLConnectionPool.java b/src/main/java/de/diddiz/util/MySQLConnectionPool.java index 1b3d8715..b064d708 100644 --- a/src/main/java/de/diddiz/util/MySQLConnectionPool.java +++ b/src/main/java/de/diddiz/util/MySQLConnectionPool.java @@ -11,7 +11,7 @@ public class MySQLConnectionPool implements Closeable { private final HikariDataSource ds; - public MySQLConnectionPool(String url, String user, String password, boolean requireSSL) { + public MySQLConnectionPool(String url, String user, String password, boolean useSSL, boolean requireSSL) { this.ds = new HikariDataSource(); ds.setJdbcUrl(url); ds.setUsername(user); @@ -30,7 +30,7 @@ public MySQLConnectionPool(String url, String user, String password, boolean req ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); ds.addDataSourceProperty("useServerPrepStmts", "true"); - ds.addDataSourceProperty("useSSL", "true"); + ds.addDataSourceProperty("useSSL", Boolean.toString(useSSL)); ds.addDataSourceProperty("requireSSL", Boolean.toString(requireSSL)); ds.addDataSourceProperty("verifyServerCertificate", "false"); } From d98d46d0c92e0f042c9bb690fbaafdcc44253665 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 16 Oct 2019 00:52:29 +0200 Subject: [PATCH 215/399] Fix logging when waterlogging waterlogged blocks --- src/main/java/de/diddiz/LogBlock/BlockChange.java | 13 ++++++++++--- .../LogBlock/listeners/BlockPlaceLogging.java | 9 ++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index e28e7786..51cac262 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -11,6 +11,7 @@ import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Openable; import org.bukkit.block.data.Powerable; +import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.Comparator; import org.bukkit.block.data.type.DaylightDetector; import org.bukkit.block.data.type.Lectern; @@ -123,14 +124,20 @@ public String toString() { } else { msg.append("put ").append(BukkitUtils.toString(ca.itemStack)).append(" into ").append(type.getMaterial().name()); } + } else if (type instanceof Waterlogged && ((Waterlogged) type).isWaterlogged() != ((Waterlogged) replaced).isWaterlogged()) { + if (((Waterlogged) type).isWaterlogged()) { + msg.append("waterlogged ").append(type.getMaterial().name()); + } else { + msg.append("dried ").append(type.getMaterial().name()); + } } else if (BukkitUtils.getContainerBlocks().contains(type.getMaterial())) { msg.append("opened ").append(type.getMaterial().name()); - } else if (type instanceof Openable) { + } else if (type instanceof Openable && ((Openable) type).isOpen() != ((Openable) replaced).isOpen()) { // Door, Trapdoor, Fence gate msg.append(((Openable) type).isOpen() ? "opened" : "closed").append(" ").append(type.getMaterial().name()); - } else if (type.getMaterial() == Material.LEVER) { + } else if (type.getMaterial() == Material.LEVER && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) { msg.append("switched ").append(type.getMaterial().name()).append(" ").append(((Switch) type).isPowered() ? "on" : "off"); - } else if (type instanceof Switch) { + } else if (type instanceof Switch && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) { msg.append("pressed ").append(type.getMaterial().name()); } else if (type.getMaterial() == Material.CAKE) { msg.append("ate a piece of ").append(type.getMaterial().name()); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java index 9912f907..58ce7a27 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java @@ -54,7 +54,14 @@ public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) { if (placedAt.isEmpty()) { consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedMaterial.createBlockData()); } else { - consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedAt.getBlockData(), placedMaterial.createBlockData()); + BlockData placedAtBlock = placedAt.getBlockData(); + if (placedAtBlock instanceof Waterlogged && !(((Waterlogged) placedAtBlock).isWaterlogged())) { + Waterlogged clickedWaterloggedWithWater = (Waterlogged) placedAtBlock.clone(); + clickedWaterloggedWithWater.setWaterlogged(true); + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedAtBlock, clickedWaterloggedWithWater); + } else { + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedAtBlock, placedMaterial.createBlockData()); + } } } } From 078fe7f423fb8a6a098e5b83b5741adb695390b4 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 16 Oct 2019 02:37:07 +0200 Subject: [PATCH 216/399] missing diff for log formatting --- src/main/java/de/diddiz/LogBlock/BlockChange.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 480e86e1..821fd0c1 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -130,9 +130,9 @@ public String toString() { } } else if (type instanceof Waterlogged && ((Waterlogged) type).isWaterlogged() != ((Waterlogged) replaced).isWaterlogged()) { if (((Waterlogged) type).isWaterlogged()) { - msg.append(CREATE).append("waterlogged ").append(type.getMaterial().name()); + msg.append(CREATE).append("waterlogged ").append(prettyMaterial(type.getMaterial())); } else { - msg.append(DESTROY).append("dried ").append(type.getMaterial().name()); + msg.append(DESTROY).append("dried ").append(prettyMaterial(type.getMaterial())); } } else if (BukkitUtils.getContainerBlocks().contains(type.getMaterial())) { msg.append(INTERACT).append("opened ").append(prettyMaterial(type.getMaterial())); From 8192aa4fb889be824cb7a71097f752c4807d1184 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 17 Nov 2019 03:17:32 +0100 Subject: [PATCH 217/399] Allow block tags in querys "block #signs" and similar: https://minecraft.gamepedia.com/Tag#List_of_tags --- .../java/de/diddiz/LogBlock/QueryParams.java | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 5c1c46af..98d89aa9 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -5,9 +5,10 @@ import de.diddiz.util.CuboidRegion; import de.diddiz.util.Utils; import de.diddiz.worldedit.WorldEditHelper; - import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.entity.EntityType; @@ -70,6 +71,7 @@ public final class QueryParams implements Cloneable { public CuboidRegion sel = null; public SummarizationMode sum = SummarizationMode.NONE; public List types = new ArrayList<>(); + public List> typeTags = new ArrayList<>(); public List typeIds = new ArrayList<>(); public List entityTypes = new ArrayList<>(); public List entityTypeIds = new ArrayList<>(); @@ -340,14 +342,17 @@ public String getTitle() { title.append("entity changes "); } } else { - if (!types.isEmpty()) { + if (!types.isEmpty() || !typeTags.isEmpty()) { if (excludeBlocksEntitiesMode) { title.append("all blocks except "); } - final String[] blocknames = new String[types.size()]; + final String[] blocknames = new String[types.size() + typeTags.size()]; for (int i = 0; i < types.size(); i++) { blocknames[i] = types.get(i).name(); } + for (int i = 0; i < typeTags.size(); i++) { + blocknames[i + types.size()] = "#" + typeTags.get(i).getKey().getKey().toUpperCase(); + } title.append(listing(blocknames, ", ", " and ")).append(" "); } else { title.append("block "); @@ -762,13 +767,27 @@ public void parseArgs(CommandSender sender, List args, boolean validate) excludeBlocksEntitiesMode = true; blockName = blockName.substring(1); } - - final Material mat = Material.matchMaterial(blockName); - if (mat == null) { - throw new IllegalArgumentException("No material matching: '" + blockName + "'"); + if (blockName.startsWith("#")) { + String tagName = blockName.substring(1).toLowerCase(); + Tag tag = logblock.getServer().getTag(Tag.REGISTRY_BLOCKS, NamespacedKey.minecraft(tagName), Material.class); + if (tag == null || tag.getValues().isEmpty()) { + tag = logblock.getServer().getTag(Tag.REGISTRY_ITEMS, NamespacedKey.minecraft(tagName), Material.class); + if (tag == null || tag.getValues().isEmpty()) { + throw new IllegalArgumentException("No block tag matching: '" + blockName + "'"); + } + } + for (Material mat : tag.getValues()) { + typeIds.add(MaterialConverter.getOrAddMaterialId(mat.getKey())); + } + typeTags.add(tag); + } else { + final Material mat = Material.matchMaterial(blockName); + if (mat == null) { + throw new IllegalArgumentException("No material matching: '" + blockName + "'"); + } + types.add(mat); + typeIds.add(MaterialConverter.getOrAddMaterialId(mat.getKey())); } - types.add(mat); - typeIds.add(MaterialConverter.getOrAddMaterialId(mat.getKey())); } } else if (param.equals("area")) { if (player == null && !prepareToolQuery && loc == null) { @@ -962,6 +981,7 @@ public QueryParams clone() { params.victims = new ArrayList<>(victims); params.typeIds = new ArrayList<>(typeIds); params.types = new ArrayList<>(types); + params.typeTags = new ArrayList<>(typeTags); params.entityTypeIds = new ArrayList<>(entityTypeIds); params.entityTypes = new ArrayList<>(entityTypes); params.loc = loc == null ? null : loc.clone(); @@ -1008,6 +1028,7 @@ public void merge(QueryParams p) { excludePlayersMode = p.excludePlayersMode; typeIds.addAll(p.typeIds); types.addAll(p.types); + typeTags.addAll(p.typeTags); entityTypeIds.addAll(p.entityTypeIds); entityTypes.addAll(p.entityTypes); loc = p.loc == null ? null : p.loc.clone(); From 241a7adc484f224b865ed03395b53361644e2cfa Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 17 Nov 2019 04:00:34 +0100 Subject: [PATCH 218/399] Wildcard block names in querys For example "*_slab" to match any slab --- .../java/de/diddiz/LogBlock/QueryParams.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 98d89aa9..dd5ad506 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -15,6 +15,7 @@ import org.bukkit.entity.Player; import java.util.*; +import java.util.regex.Pattern; import static de.diddiz.LogBlock.Session.getSession; import static de.diddiz.LogBlock.config.Config.*; @@ -780,6 +781,34 @@ public void parseArgs(CommandSender sender, List args, boolean validate) typeIds.add(MaterialConverter.getOrAddMaterialId(mat.getKey())); } typeTags.add(tag); + } else if (blockName.contains("*")) { + StringBuilder sb = new StringBuilder(); + for (int ci = 0; ci < blockName.length(); ci++) { + char c = blockName.charAt(ci); + if (!Character.isAlphabetic(c)) { + if (c == '*') { + sb.append('.'); + } else { + sb.append('\\'); + } + } + sb.append(c); + } + String blockNamePattern = sb.toString(); + Pattern pattern = Pattern.compile(blockNamePattern, Pattern.CASE_INSENSITIVE); + ArrayList matched = new ArrayList<>(); + for (Material mat : Material.values()) { + if (pattern.matcher(mat.name()).matches()) { + matched.add(mat); + } + } + if (matched.isEmpty()) { + throw new IllegalArgumentException("No material matching: '" + blockName + "'"); + } + for (Material mat : matched) { + types.add(mat); + typeIds.add(MaterialConverter.getOrAddMaterialId(mat.getKey())); + } } else { final Material mat = Material.matchMaterial(blockName); if (mat == null) { From 8214e7d177bbc7faa63c7bb0b09cd77b1f52663e Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 24 Nov 2019 05:46:51 +0100 Subject: [PATCH 219/399] Log falling scaffoldings --- .../java/de/diddiz/LogBlock/LogBlock.java | 3 + src/main/java/de/diddiz/LogBlock/Logging.java | 3 +- .../listeners/ScaffoldingLogging.java | 170 ++++++++++++++++++ 3 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 src/main/java/de/diddiz/LogBlock/listeners/ScaffoldingLogging.java diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 91acee30..cb7706b5 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -152,6 +152,9 @@ private void registerEvents() { if (isLogging(Logging.SNOWFADE)) { pm.registerEvents(new SnowFadeLogging(this), this); } + if (isLogging(Logging.SCAFFOLDING)) { + pm.registerEvents(new ScaffoldingLogging(this), this); + } if (isLogging(Logging.CREEPEREXPLOSION) || isLogging(Logging.TNTEXPLOSION) || isLogging(Logging.GHASTFIREBALLEXPLOSION) || isLogging(Logging.ENDERDRAGON) || isLogging(Logging.MISCEXPLOSION)) { pm.registerEvents(new ExplosionLogging(this), this); } diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index 4357201e..40a4e16f 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -43,7 +43,8 @@ public enum Logging { BEDEXPLOSION(true), DRAGONEGGTELEPORT(true), DAYLIGHTDETECTORINTERACT, - LECTERNBOOKCHANGE(true); + LECTERNBOOKCHANGE(true), + SCAFFOLDING(true); public static final int length = Logging.values().length; private final boolean defaultEnabled; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ScaffoldingLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ScaffoldingLogging.java new file mode 100644 index 00000000..ba44e8f9 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/listeners/ScaffoldingLogging.java @@ -0,0 +1,170 @@ +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import java.util.ArrayDeque; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockFadeEvent; +import org.bukkit.event.block.BlockPlaceEvent; + +import static de.diddiz.LogBlock.config.Config.isLogging; + +public class ScaffoldingLogging extends LoggingListener { + private final static long MAX_SCAFFOLDING_LOG_TIME_MS = 2000; + private final static EnumSet NEIGHBOURS_SIDES_AND_UP = EnumSet.of(BlockFace.UP, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST); + private final static EnumSet NEIGHBOURS_SIDES_AND_BELOW = EnumSet.of(BlockFace.DOWN, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST); + + private final ArrayDeque scaffoldingBreakersList = new ArrayDeque<>(); + private final HashMap scaffoldingBreakersByLocation = new HashMap<>(); + private final HashMap scaffoldingPlacersByLocation = new HashMap<>(); + + public ScaffoldingLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockFade(BlockFadeEvent event) { + Block block = event.getBlock(); + if (isLogging(block.getWorld(), Logging.SCAFFOLDING)) { + final Material type = block.getType(); + if (type == Material.SCAFFOLDING) { + Player placer = scaffoldingPlacersByLocation.get(block.getLocation()); + cleanupScaffoldingBreakers(); + if (placer != null) { + consumer.queueBlockReplace(Actor.actorFromEntity(placer), block.getState(), event.getNewState()); + return; + } + Player breaker = getScaffoldingBreaker(block); + if (breaker != null) { + for (BlockFace dir : NEIGHBOURS_SIDES_AND_UP) { + Block otherBlock = block.getRelative(dir); + if (otherBlock.getType() == Material.SCAFFOLDING) { + addScaffoldingBreaker(breaker, otherBlock); + } + } + } + consumer.queueBlockReplace(breaker == null ? new Actor("ScaffoldingFall") : Actor.actorFromEntity(breaker), block.getState(), event.getNewState()); + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockBreak(BlockBreakEvent event) { + Block block = event.getBlock(); + if (isLogging(block.getWorld(), Logging.SCAFFOLDING)) { + cleanupScaffoldingBreakers(); + Block otherBlock; + if (block.getType() == Material.SCAFFOLDING) { + for (BlockFace dir : NEIGHBOURS_SIDES_AND_UP) { + otherBlock = block.getRelative(dir); + if (otherBlock.getType() == Material.SCAFFOLDING) { + addScaffoldingBreaker(event.getPlayer(), otherBlock); + } + } + } else if ((otherBlock = block.getRelative(BlockFace.UP)).getType() == Material.SCAFFOLDING) { + addScaffoldingBreaker(event.getPlayer(), otherBlock); + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent event) { + Block block = event.getBlock(); + if (isLogging(block.getWorld(), Logging.SCAFFOLDING)) { + cleanupScaffoldingBreakers(); + if (block.getType() == Material.SCAFFOLDING) { + scaffoldingPlacersByLocation.put(block.getLocation(), event.getPlayer()); + } + } + } + + private void addScaffoldingBreaker(Player player, Block block) { + ScaffoldingBreaker breaker = new ScaffoldingBreaker(player, block.getLocation()); + scaffoldingBreakersList.addLast(breaker); + scaffoldingBreakersByLocation.put(breaker.getLocation(), breaker); + + } + + private void cleanupScaffoldingBreakers() { + if (!scaffoldingPlacersByLocation.isEmpty()) { + scaffoldingPlacersByLocation.clear(); + } + if (!scaffoldingBreakersList.isEmpty()) { + long time = System.currentTimeMillis() - MAX_SCAFFOLDING_LOG_TIME_MS; + while (!scaffoldingBreakersList.isEmpty() && scaffoldingBreakersList.getFirst().getTime() < time) { + ScaffoldingBreaker breaker = scaffoldingBreakersList.removeFirst(); + scaffoldingBreakersByLocation.remove(breaker.getLocation(), breaker); + } + } + } + + private Player getScaffoldingBreaker(Block block) { + if (scaffoldingBreakersList.isEmpty()) { + return null; + } + + ScaffoldingBreaker breaker = scaffoldingBreakersByLocation.get(block.getLocation()); + if (breaker != null) { + return breaker.getBreaker(); + } + + // Search all connected scaffoldings + ArrayDeque front = new ArrayDeque<>(); + HashSet frontAndDone = new HashSet<>(); + front.addLast(block); + frontAndDone.add(block); + while (!front.isEmpty()) { + Block current = front.removeFirst(); + Location loc = current.getLocation(); + + breaker = scaffoldingBreakersByLocation.get(loc); + if (breaker != null) { + return breaker.getBreaker(); + } + + for (BlockFace dir : NEIGHBOURS_SIDES_AND_BELOW) { + Block otherBlock = current.getRelative(dir); + if (!frontAndDone.contains(otherBlock) && otherBlock.getType() == Material.SCAFFOLDING) { + front.addLast(otherBlock); + frontAndDone.add(otherBlock); + } + } + } + return null; + } + + class ScaffoldingBreaker { + protected final Player breaker; + protected final long time; + protected final Location location; + + public ScaffoldingBreaker(Player breaker, Location location) { + this.breaker = breaker; + this.location = location; + this.time = System.currentTimeMillis(); + } + + public Player getBreaker() { + return breaker; + } + + public Location getLocation() { + return location; + } + + public long getTime() { + return time; + } + } +} From 59d0794c3daa8e884db405931a0931a125b94a35 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 24 Nov 2019 06:16:07 +0100 Subject: [PATCH 220/399] Improve scaffolding logging with fallable blocks - Log fallable blocks above scaffoldings - Log scaffolding breaking because blocks below are falling down --- .../java/de/diddiz/LogBlock/Consumer.java | 4 ++ .../java/de/diddiz/LogBlock/LogBlock.java | 7 ++- .../listeners/ScaffoldingLogging.java | 55 ++++++++++--------- src/main/java/de/diddiz/util/LoggingUtil.java | 4 ++ 4 files changed, 42 insertions(+), 28 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index c9e45512..4be454a6 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -78,6 +78,10 @@ public class Consumer extends Thread { setName("Logblock-Consumer"); } + public LogBlock getLogblock() { + return logblock; + } + /** * Logs any block change. Don't try to combine broken and placed blocks. Queue two block changes or use the queueBLockReplace methods. * diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index cb7706b5..6078aa1d 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -36,6 +36,7 @@ public class LogBlock extends JavaPlugin { private CommandsHandler commandsHandler; private boolean noDb = false, connected = true; private PlayerInfoLogging playerInfoLogging; + private ScaffoldingLogging scaffoldingLogging; private Questioner questioner; private volatile boolean isCompletelyEnabled; @@ -153,7 +154,7 @@ private void registerEvents() { pm.registerEvents(new SnowFadeLogging(this), this); } if (isLogging(Logging.SCAFFOLDING)) { - pm.registerEvents(new ScaffoldingLogging(this), this); + pm.registerEvents(scaffoldingLogging = new ScaffoldingLogging(this), this); } if (isLogging(Logging.CREEPEREXPLOSION) || isLogging(Logging.TNTEXPLOSION) || isLogging(Logging.GHASTFIREBALLEXPLOSION) || isLogging(Logging.ENDERDRAGON) || isLogging(Logging.MISCEXPLOSION)) { pm.registerEvents(new ExplosionLogging(this), this); @@ -337,4 +338,8 @@ public File getFile() { public Questioner getQuestioner() { return questioner; } + + public ScaffoldingLogging getScaffoldingLogging() { + return scaffoldingLogging; + } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ScaffoldingLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ScaffoldingLogging.java index ba44e8f9..cf7e1f38 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ScaffoldingLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ScaffoldingLogging.java @@ -11,7 +11,6 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockBreakEvent; @@ -19,6 +18,7 @@ import org.bukkit.event.block.BlockPlaceEvent; import static de.diddiz.LogBlock.config.Config.isLogging; +import static de.diddiz.util.LoggingUtil.smartLogFallables; public class ScaffoldingLogging extends LoggingListener { private final static long MAX_SCAFFOLDING_LOG_TIME_MS = 2000; @@ -27,7 +27,7 @@ public class ScaffoldingLogging extends LoggingListener { private final ArrayDeque scaffoldingBreakersList = new ArrayDeque<>(); private final HashMap scaffoldingBreakersByLocation = new HashMap<>(); - private final HashMap scaffoldingPlacersByLocation = new HashMap<>(); + private final HashMap scaffoldingPlacersByLocation = new HashMap<>(); public ScaffoldingLogging(LogBlock lb) { super(lb); @@ -39,22 +39,23 @@ public void onBlockFade(BlockFadeEvent event) { if (isLogging(block.getWorld(), Logging.SCAFFOLDING)) { final Material type = block.getType(); if (type == Material.SCAFFOLDING) { - Player placer = scaffoldingPlacersByLocation.get(block.getLocation()); + Actor actor = scaffoldingPlacersByLocation.get(block.getLocation()); // get placer before cleanupScaffoldingBreakers cleanupScaffoldingBreakers(); - if (placer != null) { - consumer.queueBlockReplace(Actor.actorFromEntity(placer), block.getState(), event.getNewState()); - return; - } - Player breaker = getScaffoldingBreaker(block); - if (breaker != null) { - for (BlockFace dir : NEIGHBOURS_SIDES_AND_UP) { - Block otherBlock = block.getRelative(dir); - if (otherBlock.getType() == Material.SCAFFOLDING) { - addScaffoldingBreaker(breaker, otherBlock); + if (actor == null) { + actor = getScaffoldingBreaker(block); + if (actor != null) { + for (BlockFace dir : NEIGHBOURS_SIDES_AND_UP) { + Block otherBlock = block.getRelative(dir); + if (otherBlock.getType() == Material.SCAFFOLDING) { + addScaffoldingBreaker(actor, otherBlock); + } } + } else { + actor = new Actor("ScaffoldingFall"); } } - consumer.queueBlockReplace(breaker == null ? new Actor("ScaffoldingFall") : Actor.actorFromEntity(breaker), block.getState(), event.getNewState()); + consumer.queueBlockReplace(actor, block.getState(), event.getNewState()); + smartLogFallables(consumer, actor, block); } } } @@ -69,11 +70,11 @@ public void onBlockBreak(BlockBreakEvent event) { for (BlockFace dir : NEIGHBOURS_SIDES_AND_UP) { otherBlock = block.getRelative(dir); if (otherBlock.getType() == Material.SCAFFOLDING) { - addScaffoldingBreaker(event.getPlayer(), otherBlock); + addScaffoldingBreaker(Actor.actorFromEntity(event.getPlayer()), otherBlock); } } } else if ((otherBlock = block.getRelative(BlockFace.UP)).getType() == Material.SCAFFOLDING) { - addScaffoldingBreaker(event.getPlayer(), otherBlock); + addScaffoldingBreaker(Actor.actorFromEntity(event.getPlayer()), otherBlock); } } } @@ -84,13 +85,13 @@ public void onBlockPlace(BlockPlaceEvent event) { if (isLogging(block.getWorld(), Logging.SCAFFOLDING)) { cleanupScaffoldingBreakers(); if (block.getType() == Material.SCAFFOLDING) { - scaffoldingPlacersByLocation.put(block.getLocation(), event.getPlayer()); + scaffoldingPlacersByLocation.put(block.getLocation(), Actor.actorFromEntity(event.getPlayer())); } } } - private void addScaffoldingBreaker(Player player, Block block) { - ScaffoldingBreaker breaker = new ScaffoldingBreaker(player, block.getLocation()); + public void addScaffoldingBreaker(Actor actor, Block block) { + ScaffoldingBreaker breaker = new ScaffoldingBreaker(actor, block.getLocation()); scaffoldingBreakersList.addLast(breaker); scaffoldingBreakersByLocation.put(breaker.getLocation(), breaker); @@ -109,14 +110,14 @@ private void cleanupScaffoldingBreakers() { } } - private Player getScaffoldingBreaker(Block block) { + private Actor getScaffoldingBreaker(Block block) { if (scaffoldingBreakersList.isEmpty()) { return null; } ScaffoldingBreaker breaker = scaffoldingBreakersByLocation.get(block.getLocation()); if (breaker != null) { - return breaker.getBreaker(); + return breaker.getActor(); } // Search all connected scaffoldings @@ -130,7 +131,7 @@ private Player getScaffoldingBreaker(Block block) { breaker = scaffoldingBreakersByLocation.get(loc); if (breaker != null) { - return breaker.getBreaker(); + return breaker.getActor(); } for (BlockFace dir : NEIGHBOURS_SIDES_AND_BELOW) { @@ -145,18 +146,18 @@ private Player getScaffoldingBreaker(Block block) { } class ScaffoldingBreaker { - protected final Player breaker; + protected final Actor actor; protected final long time; protected final Location location; - public ScaffoldingBreaker(Player breaker, Location location) { - this.breaker = breaker; + public ScaffoldingBreaker(Actor actor, Location location) { + this.actor = actor; this.location = location; this.time = System.currentTimeMillis(); } - public Player getBreaker() { - return breaker; + public Actor getActor() { + return actor; } public Location getLocation() { diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index 97bb5693..477a4849 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -2,6 +2,7 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.Consumer; +import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; import org.bukkit.Location; import org.bukkit.Material; @@ -98,6 +99,9 @@ public static void smartLogFallables(Consumer consumer, Actor actor, Block origi } checkBlock = checkBlock.getRelative(BlockFace.UP); } + if (wcfg.isLogging(Logging.SCAFFOLDING) && checkBlock.getType() == Material.SCAFFOLDING && consumer.getLogblock().getScaffoldingLogging() != null) { + consumer.getLogblock().getScaffoldingLogging().addScaffoldingBreaker(actor, checkBlock); + } } public static void smartLogBlockBreak(Consumer consumer, Actor actor, Block origin) { From 60a771224becb7e87c7135236f0bd08a3cd675f6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 1 Dec 2019 05:14:10 +0100 Subject: [PATCH 221/399] improve logging of entitiy damaged by projectiles or tnt --- .../listeners/AdvancedEntityLogging.java | 9 ++++++--- src/main/java/de/diddiz/util/LoggingUtil.java | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index baa1cb4c..684d3a83 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -38,6 +38,7 @@ import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.EntityLogging; +import de.diddiz.util.LoggingUtil; import de.diddiz.worldedit.WorldEditHelper; import java.util.UUID; @@ -163,7 +164,7 @@ public void onEntityDeath(EntityDeathEvent event) { Actor actor = null; EntityDamageEvent lastDamage = entity.getLastDamageCause(); if (lastDamage instanceof EntityDamageByEntityEvent) { - Entity damager = ((EntityDamageByEntityEvent) lastDamage).getDamager(); + Entity damager = LoggingUtil.getRealDamager(((EntityDamageByEntityEvent) lastDamage).getDamager()); if (damager != null) { actor = Actor.actorFromEntity(damager); } @@ -190,7 +191,8 @@ public void onHangingBreak(HangingBreakEvent event) { if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) { Actor actor; if (event instanceof HangingBreakByEntityEvent) { - actor = Actor.actorFromEntity(((HangingBreakByEntityEvent) event).getRemover()); + Entity damager = LoggingUtil.getRealDamager(((HangingBreakByEntityEvent) event).getRemover()); + actor = Actor.actorFromEntity(damager); } else { actor = new Actor(event.getCause().toString()); } @@ -207,7 +209,8 @@ public void onEntityDamage(EntityDamageEvent event) { if (Config.isLogging(entity.getWorld(), EntityLogging.MODIFY, entity)) { Actor actor; if (event instanceof EntityDamageByEntityEvent) { - actor = Actor.actorFromEntity(((EntityDamageByEntityEvent) event).getDamager()); + Entity damager = LoggingUtil.getRealDamager(((EntityDamageByEntityEvent) event).getDamager()); + actor = Actor.actorFromEntity(damager); } else { actor = new Actor(event.getCause().toString()); } diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index 477a4849..a78f02ce 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -14,6 +14,10 @@ import org.bukkit.block.data.type.Bell; import org.bukkit.block.data.type.Bell.Attachment; import org.bukkit.block.data.type.Lantern; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.projectiles.ProjectileSource; import java.util.List; import static de.diddiz.LogBlock.config.Config.getWorldConfig; @@ -238,4 +242,20 @@ public static String checkText(String text) { } return text.replaceAll("[^\\u0000-\\uFFFF]", "?"); } + + public static Entity getRealDamager(Entity damager) { + if (damager instanceof Projectile) { + ProjectileSource realDamager = ((Projectile) damager).getShooter(); + if (realDamager instanceof Entity) { + damager = (Entity) realDamager; + } + } + if (damager instanceof TNTPrimed) { + Entity realRemover = ((TNTPrimed) damager).getSource(); + if (realRemover != null) { + damager = realRemover; + } + } + return damager; + } } From 169328e159e1b5dd71a00fdae9398f60888a814d Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 18 Dec 2019 01:33:40 +0100 Subject: [PATCH 222/399] Use ChatComponent API for log messages --- .../java/de/diddiz/LogBlock/BlockChange.java | 129 +++++++++++++----- .../java/de/diddiz/LogBlock/ChatMessage.java | 24 +++- .../de/diddiz/LogBlock/CommandsHandler.java | 14 +- .../java/de/diddiz/LogBlock/EntityChange.java | 52 ++++--- src/main/java/de/diddiz/LogBlock/Kill.java | 42 +++--- .../diddiz/LogBlock/LookupCacheElement.java | 3 +- .../diddiz/LogBlock/SummedBlockChanges.java | 16 +-- .../diddiz/LogBlock/SummedEntityChanges.java | 9 +- .../java/de/diddiz/LogBlock/SummedKills.java | 17 +-- .../java/de/diddiz/LogBlock/WorldEditor.java | 9 +- src/main/java/de/diddiz/util/ActionColor.java | 2 +- src/main/java/de/diddiz/util/BukkitUtils.java | 37 +++-- .../java/de/diddiz/util/MessagingUtil.java | 71 +++++++--- src/main/java/de/diddiz/util/TypeColor.java | 2 +- 14 files changed, 270 insertions(+), 157 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 821fd0c1..997926a5 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -3,7 +3,8 @@ import static de.diddiz.util.ActionColor.CREATE; import static de.diddiz.util.ActionColor.DESTROY; import static de.diddiz.util.ActionColor.INTERACT; -import static de.diddiz.util.MessagingUtil.brackets; +import static de.diddiz.util.TypeColor.DEFAULT; +import static de.diddiz.util.MessagingUtil.createTextComponentWithColor; import static de.diddiz.util.MessagingUtil.prettyDate; import static de.diddiz.util.MessagingUtil.prettyLocation; import static de.diddiz.util.MessagingUtil.prettyMaterial; @@ -11,11 +12,12 @@ import de.diddiz.LogBlock.blockstate.BlockStateCodecs; import de.diddiz.util.BukkitUtils; -import de.diddiz.util.MessagingUtil.BracketType; import de.diddiz.util.Utils; import java.sql.ResultSet; import java.sql.SQLException; import java.util.logging.Level; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Note; @@ -99,18 +101,25 @@ private String getTypeDetails(BlockData type, byte[] typeState) { @Override public String toString() { - final StringBuilder msg = new StringBuilder(); + return BaseComponent.toPlainText(getLogMessage()); + } + + @Override + public BaseComponent[] getLogMessage() { + TextComponent msg = new TextComponent(); if (date > 0) { - msg.append(brackets(prettyDate(date), BracketType.STANDARD)).append(' '); + msg.addExtra(prettyDate(date)); + msg.addExtra(" "); } if (actor != null) { - msg.append(actor.getName()).append(" "); + msg.addExtra(actor.getName()); + msg.addExtra(" "); } BlockData type = getBlockSet(); BlockData replaced = getBlockReplaced(); if (type == null || replaced == null) { - msg.append("did an unknown block modification"); - return msg.toString(); + msg.addExtra("did an unknown block modification"); + return new BaseComponent[] { msg }; } // Process type details once for later use. @@ -119,63 +128,114 @@ public String toString() { if (type.getMaterial().equals(replaced.getMaterial())) { if (BukkitUtils.isEmpty(type.getMaterial())) { - msg.append(INTERACT).append("did an unspecified action"); + msg.addExtra(createTextComponentWithColor("did an unspecified action", INTERACT.getColor())); } else if (ca != null) { if (ca.itemStack == null) { - msg.append(INTERACT).append("looked inside ").append(prettyMaterial(type.getMaterial())); + msg.addExtra(createTextComponentWithColor("looked inside ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); } else if (ca.remove) { - msg.append(DESTROY).append("took ").append(BukkitUtils.toString(ca.itemStack)).append(" from ").append(prettyMaterial(type.getMaterial())); + msg.addExtra(createTextComponentWithColor("took ", DESTROY.getColor())); + msg.addExtra(BukkitUtils.toString(ca.itemStack)); + msg.addExtra(createTextComponentWithColor(" from ", DESTROY.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); } else { - msg.append(CREATE).append("put ").append(BukkitUtils.toString(ca.itemStack)).append(" into ").append(prettyMaterial(type.getMaterial())); + msg.addExtra(createTextComponentWithColor("put ", CREATE.getColor())); + msg.addExtra(BukkitUtils.toString(ca.itemStack)); + msg.addExtra(createTextComponentWithColor(" into ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); } } else if (type instanceof Waterlogged && ((Waterlogged) type).isWaterlogged() != ((Waterlogged) replaced).isWaterlogged()) { if (((Waterlogged) type).isWaterlogged()) { - msg.append(CREATE).append("waterlogged ").append(prettyMaterial(type.getMaterial())); + msg.addExtra(createTextComponentWithColor("waterlogged ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); } else { - msg.append(DESTROY).append("dried ").append(prettyMaterial(type.getMaterial())); + msg.addExtra(createTextComponentWithColor("dried ", DESTROY.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); } } else if (BukkitUtils.getContainerBlocks().contains(type.getMaterial())) { - msg.append(INTERACT).append("opened ").append(prettyMaterial(type.getMaterial())); + msg.addExtra(createTextComponentWithColor("opened ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); } else if (type instanceof Openable && ((Openable) type).isOpen() != ((Openable) replaced).isOpen()) { // Door, Trapdoor, Fence gate - msg.append(INTERACT).append(((Openable) type).isOpen() ? "opened" : "closed").append(" ").append(prettyMaterial(type.getMaterial())); + msg.addExtra(createTextComponentWithColor(((Openable) type).isOpen() ? "opened " : "closed ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); } else if (type.getMaterial() == Material.LEVER && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) { - msg.append(INTERACT).append("switched ").append(prettyMaterial(type.getMaterial())).append(" ").append(prettyState(((Switch) type).isPowered() ? "on" : "off")); + msg.addExtra(createTextComponentWithColor("switched ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyState(((Switch) type).isPowered() ? " on" : " off")); } else if (type instanceof Switch && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) { - msg.append(INTERACT).append("pressed ").append(prettyMaterial(type.getMaterial())); + msg.addExtra(createTextComponentWithColor("pressed ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); } else if (type.getMaterial() == Material.CAKE) { - msg.append(DESTROY).append("ate a piece of ").append(prettyMaterial(type.getMaterial())); + msg.addExtra(createTextComponentWithColor("ate a piece of ", DESTROY.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); } else if (type.getMaterial() == Material.NOTE_BLOCK) { Note note = ((NoteBlock) type).getNote(); - msg.append(INTERACT).append("set ").append(prettyMaterial(type.getMaterial())).append(" to ").append(prettyState(note.getTone().name() + (note.isSharped() ? "#" : ""))); + msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(" to "); + msg.addExtra(prettyState(note.getTone().name() + (note.isSharped() ? "#" : ""))); } else if (type.getMaterial() == Material.REPEATER) { - msg.append(INTERACT).append("set ").append(prettyMaterial(type.getMaterial())).append(" to ").append(prettyState(((Repeater) type).getDelay())).append(" ticks delay"); + msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(" to "); + msg.addExtra(prettyState(((Repeater) type).getDelay())); + msg.addExtra(createTextComponentWithColor(" ticks delay", DEFAULT.getColor())); } else if (type.getMaterial() == Material.COMPARATOR) { - msg.append(INTERACT).append("set ").append(prettyMaterial(type.getMaterial())).append(" to ").append(prettyState(((Comparator) type).getMode())); + msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(" to "); + msg.addExtra(prettyState(((Comparator) type).getMode())); } else if (type.getMaterial() == Material.DAYLIGHT_DETECTOR) { - msg.append(INTERACT).append("set ").append(prettyMaterial(type.getMaterial())).append(" to ").append(prettyState(((DaylightDetector) type).isInverted() ? "inverted" : "normal")); + msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(" to "); + msg.addExtra(prettyState(((DaylightDetector) type).isInverted() ? "inverted" : "normal")); } else if (type instanceof Lectern) { - msg.append(INTERACT).append("changed the book on a ").append(prettyMaterial(type.getMaterial())).append(" to").append(prettyState(typeDetails.length() == 0 ? " empty" : typeDetails)); + msg.addExtra(createTextComponentWithColor("changed the book on a ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(" to"); + msg.addExtra(prettyState(typeDetails.length() == 0 ? " empty" : typeDetails)); } else if (type instanceof Powerable) { - msg.append(INTERACT).append("stepped on ").append(prettyMaterial(type.getMaterial())); + msg.addExtra(createTextComponentWithColor("stepped on ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); } else if (type.getMaterial() == Material.TRIPWIRE) { - msg.append(INTERACT).append("ran into ").append(prettyMaterial(type.getMaterial())); + msg.addExtra(createTextComponentWithColor("ran into ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); } else if (type instanceof Sign || type instanceof WallSign) { - msg.append(CREATE).append("edited a ").append(prettyMaterial(type.getMaterial())).append(CREATE).append(" to ").append(prettyState(typeDetails)); + msg.addExtra(createTextComponentWithColor("edited a ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(createTextComponentWithColor(" to ", CREATE.getColor())); + msg.addExtra(prettyState(typeDetails)); } else { - msg.append(CREATE).append("replaced ").append(prettyMaterial(replaced.getMaterial())).append(prettyState(replacedDetails)).append(CREATE).append(" with ").append(prettyMaterial(type.getMaterial())).append(prettyState(typeDetails)); + msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor())); + msg.addExtra(prettyMaterial(replaced.getMaterial())); + msg.addExtra(prettyState(replacedDetails)); + msg.addExtra(createTextComponentWithColor(" with ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyState(typeDetails)); } } else if (BukkitUtils.isEmpty(type.getMaterial())) { - msg.append(DESTROY).append("destroyed ").append(prettyMaterial(replaced.getMaterial())).append(prettyState(replacedDetails)); + msg.addExtra(createTextComponentWithColor("destroyed ", DESTROY.getColor())); + msg.addExtra(prettyMaterial(replaced.getMaterial())); + msg.addExtra(prettyState(replacedDetails)); } else if (BukkitUtils.isEmpty(replaced.getMaterial())) { - msg.append(CREATE).append("created ").append(prettyMaterial(type.getMaterial())).append(prettyState(typeDetails)); + msg.addExtra(createTextComponentWithColor("created ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyState(typeDetails)); } else { - msg.append(CREATE).append("replaced ").append(prettyMaterial(replaced.getMaterial())).append(prettyState(replacedDetails)).append(CREATE).append(" with ").append(type.getMaterial().name()).append(typeDetails); + msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor())); + msg.addExtra(prettyMaterial(replaced.getMaterial())); + msg.addExtra(prettyState(replacedDetails)); + msg.addExtra(createTextComponentWithColor(" with ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyState(typeDetails)); } if (loc != null) { - msg.append(" at: ").append(prettyLocation(loc)); + msg.addExtra(" at "); + msg.addExtra(prettyLocation(loc)); } - return msg.toString(); + return new BaseComponent[] { msg }; } public BlockData getBlockReplaced() { @@ -190,9 +250,4 @@ public BlockData getBlockSet() { public Location getLocation() { return loc; } - - @Override - public String getMessage() { - return toString(); - } } diff --git a/src/main/java/de/diddiz/LogBlock/ChatMessage.java b/src/main/java/de/diddiz/LogBlock/ChatMessage.java index 256a2f83..9c632628 100644 --- a/src/main/java/de/diddiz/LogBlock/ChatMessage.java +++ b/src/main/java/de/diddiz/LogBlock/ChatMessage.java @@ -1,13 +1,15 @@ package de.diddiz.LogBlock; -import static de.diddiz.util.ActionColor.CREATE; import static de.diddiz.util.LoggingUtil.checkText; import static de.diddiz.util.MessagingUtil.brackets; +import static de.diddiz.util.MessagingUtil.prettyDate; +import de.diddiz.util.MessagingUtil; import de.diddiz.util.MessagingUtil.BracketType; import java.sql.ResultSet; import java.sql.SQLException; -import org.bukkit.ChatColor; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Location; public class ChatMessage implements LookupCacheElement { @@ -37,7 +39,21 @@ public Location getLocation() { } @Override - public String getMessage() { - return (playerName != null ? brackets(ChatColor.WHITE + playerName, BracketType.ANGLE) + ' ' : "") + (message != null ? CREATE + message : ""); + public BaseComponent[] getLogMessage() { + TextComponent msg = new TextComponent(); + if (date > 0) { + msg.addExtra(prettyDate(date)); + msg.addExtra(" "); + } + if (playerName != null) { + msg.addExtra(brackets(BracketType.ANGLE, MessagingUtil.createTextComponentWithColor(playerName, net.md_5.bungee.api.ChatColor.WHITE))); + msg.addExtra(" "); + } + if (message != null) { + for (BaseComponent messageComponent : TextComponent.fromLegacyText(message)) { + msg.addExtra(messageComponent); + } + } + return new BaseComponent[] { msg }; } } diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 7b381351..c309289f 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -43,6 +43,8 @@ import java.util.Arrays; import java.util.List; import java.util.logging.Level; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.World; @@ -398,7 +400,15 @@ private static void showPage(CommandSender sender, int page, LookupCacheElement[ sender.sendMessage(HEADER + "Page " + page + "/" + numberOfPages); } for (int i = startpos; i <= stoppos; i++) { - sender.sendMessage(DEFAULT + (lookupElements[i].getLocation() != null ? "(" + (i + 1) + ") " : "") + lookupElements[i].getMessage()); + TextComponent message = new TextComponent(); + message.setColor(DEFAULT.getColor()); + if (lookupElements[i].getLocation() != null) { + message.addExtra(new TextComponent("(" + (i + 1) + ") ")); + } + for (BaseComponent component : lookupElements[i].getLogMessage()) { + message.addExtra(component); + } + sender.spigot().sendMessage(message); } if (setSessionPage) { getSession(sender).page = page; @@ -586,7 +596,7 @@ public void run() { } final LookupCacheElementFactory factory = new LookupCacheElementFactory(params, sender instanceof Player ? 2 / 3f : 1); while (rs.next()) { - writer.write(factory.getLookupCacheElement(rs).getMessage() + newline); + writer.write(BaseComponent.toPlainText(factory.getLookupCacheElement(rs).getLogMessage()) + newline); counter++; } writer.close(); diff --git a/src/main/java/de/diddiz/LogBlock/EntityChange.java b/src/main/java/de/diddiz/LogBlock/EntityChange.java index 71e91898..5f04cdbf 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityChange.java +++ b/src/main/java/de/diddiz/LogBlock/EntityChange.java @@ -3,17 +3,18 @@ import static de.diddiz.util.ActionColor.CREATE; import static de.diddiz.util.ActionColor.DESTROY; import static de.diddiz.util.ActionColor.INTERACT; -import static de.diddiz.util.MessagingUtil.brackets; +import static de.diddiz.util.MessagingUtil.createTextComponentWithColor; import static de.diddiz.util.MessagingUtil.prettyDate; import static de.diddiz.util.MessagingUtil.prettyEntityType; import static de.diddiz.util.MessagingUtil.prettyLocation; import static de.diddiz.util.MessagingUtil.prettyMaterial; -import de.diddiz.util.MessagingUtil.BracketType; import de.diddiz.util.Utils; import java.sql.ResultSet; import java.sql.SQLException; import java.util.UUID; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Location; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.ArmorStand; @@ -71,57 +72,64 @@ public EntityChange(ResultSet rs, QueryParams p) throws SQLException { @Override public String toString() { - final StringBuilder msg = new StringBuilder(); + return BaseComponent.toPlainText(getLogMessage()); + } + + @Override + public BaseComponent[] getLogMessage() { + TextComponent msg = new TextComponent(); if (date > 0) { - msg.append(brackets(prettyDate(date), BracketType.STANDARD)).append(' '); + msg.addExtra(prettyDate(date)); + msg.addExtra(" "); } if (actor != null) { - msg.append(actor.getName()).append(" "); + msg.addExtra(actor.getName()); + msg.addExtra(" "); } if (changeType == EntityChangeType.CREATE) { - msg.append(CREATE).append("created "); + msg.addExtra(createTextComponentWithColor("created ", CREATE.getColor())); } else if (changeType == EntityChangeType.KILL) { boolean living = type != null && LivingEntity.class.isAssignableFrom(type.getEntityClass()) && !ArmorStand.class.isAssignableFrom(type.getDeclaringClass()); - msg.append(DESTROY).append(living ? "killed " : "destroyed "); + msg.addExtra(createTextComponentWithColor(living ? "killed " : "destroyed ", DESTROY.getColor())); } else if (changeType == EntityChangeType.ADDEQUIP) { YamlConfiguration conf = Utils.deserializeYamlConfiguration(data); ItemStack stack = conf == null ? null : conf.getItemStack("item"); if (stack == null) { - msg.append(CREATE).append("added an item to "); + msg.addExtra(createTextComponentWithColor("added an item to ", CREATE.getColor())); } else { - msg.append(CREATE).append("added ").append(prettyMaterial(stack.getType())).append(" to "); + msg.addExtra(createTextComponentWithColor("added ", CREATE.getColor())); + msg.addExtra(prettyMaterial(stack.getType())); + msg.addExtra(" to "); } } else if (changeType == EntityChangeType.REMOVEEQUIP) { YamlConfiguration conf = Utils.deserializeYamlConfiguration(data); ItemStack stack = conf == null ? null : conf.getItemStack("item"); if (stack == null) { - msg.append(DESTROY).append("removed an item from "); + msg.addExtra(createTextComponentWithColor("removed an item from ", DESTROY.getColor())); } else { - msg.append(DESTROY).append("removed ").append(prettyMaterial(stack.getType())).append(" from "); + msg.addExtra(createTextComponentWithColor("removed ", DESTROY.getColor())); + msg.addExtra(prettyMaterial(stack.getType())); + msg.addExtra(" from "); } } else if (changeType == EntityChangeType.MODIFY) { - msg.append(INTERACT).append("modified "); + msg.addExtra(createTextComponentWithColor("modified ", INTERACT.getColor())); } else { - msg.append(INTERACT).append("did an unknown action to "); + msg.addExtra(createTextComponentWithColor("did an unknown action to ", INTERACT.getColor())); } if (type != null) { - msg.append(prettyEntityType(type)); + msg.addExtra(prettyEntityType(type)); } else { - msg.append(prettyMaterial("an unknown entity")); + msg.addExtra(prettyMaterial("an unknown entity")); } if (loc != null) { - msg.append(" at: ").append(prettyLocation(loc)); + msg.addExtra(" at "); + msg.addExtra(prettyLocation(loc)); } - return msg.toString(); + return new BaseComponent[] { msg }; } @Override public Location getLocation() { return loc; } - - @Override - public String getMessage() { - return toString(); - } } diff --git a/src/main/java/de/diddiz/LogBlock/Kill.java b/src/main/java/de/diddiz/LogBlock/Kill.java index 549dadfe..f052b473 100755 --- a/src/main/java/de/diddiz/LogBlock/Kill.java +++ b/src/main/java/de/diddiz/LogBlock/Kill.java @@ -1,16 +1,15 @@ package de.diddiz.LogBlock; import static de.diddiz.util.ActionColor.DESTROY; -import static de.diddiz.util.MessagingUtil.brackets; import static de.diddiz.util.MessagingUtil.prettyDate; import static de.diddiz.util.MessagingUtil.prettyLocation; import static de.diddiz.util.MessagingUtil.prettyMaterial; -import static de.diddiz.util.TypeColor.DEFAULT; - import de.diddiz.util.BukkitUtils; -import de.diddiz.util.MessagingUtil.BracketType; +import de.diddiz.util.MessagingUtil; import java.sql.ResultSet; import java.sql.SQLException; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Location; import org.bukkit.Material; @@ -40,19 +39,7 @@ public Kill(ResultSet rs, QueryParams p) throws SQLException { @Override public String toString() { - final StringBuilder msg = new StringBuilder(); - if (date > 0) { - msg.append(brackets(prettyDate(date), BracketType.STANDARD)).append(' '); - } - msg.append(killerName).append(DESTROY).append(" killed ").append(DEFAULT).append(victimName); - if (loc != null) { - msg.append(" at ").append(prettyLocation(loc)); - } - if (weapon != 0) { - String weaponName = prettyItemName(MaterialConverter.getMaterial(weapon)); - msg.append(" with ").append(weaponName); // + ("aeiou".contains(weaponName.substring(0, 1)) ? "an " : "a " ) - } - return msg.toString(); + return BaseComponent.toPlainText(getLogMessage()); } @Override @@ -61,11 +48,26 @@ public Location getLocation() { } @Override - public String getMessage() { - return toString(); + public BaseComponent[] getLogMessage() { + TextComponent msg = new TextComponent(); + if (date > 0) { + msg.addExtra(prettyDate(date)); + msg.addExtra(" "); + } + msg.addExtra(MessagingUtil.createTextComponentWithColor(killerName + " killed ", DESTROY.getColor())); + msg.addExtra(new TextComponent(victimName)); + if (loc != null) { + msg.addExtra(" at "); + msg.addExtra(prettyLocation(loc)); + } + if (weapon != 0) { + msg.addExtra(" with "); + msg.addExtra(prettyItemName(MaterialConverter.getMaterial(weapon))); + } + return new BaseComponent[] { msg }; } - public String prettyItemName(Material t) { + public TextComponent prettyItemName(Material t) { if (t == null || BukkitUtils.isEmpty(t)) { return prettyMaterial("fist"); } diff --git a/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java b/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java index 595a2e39..ea63ce4e 100644 --- a/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java +++ b/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java @@ -1,9 +1,10 @@ package de.diddiz.LogBlock; +import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.Location; public interface LookupCacheElement { public Location getLocation(); - public String getMessage(); + public BaseComponent[] getLogMessage(); } diff --git a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java index 183159ee..7b07339b 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java @@ -1,15 +1,13 @@ package de.diddiz.LogBlock; -import static de.diddiz.util.ActionColor.CREATE; -import static de.diddiz.util.ActionColor.DESTROY; import static de.diddiz.util.MessagingUtil.prettyMaterial; -import static de.diddiz.util.TypeColor.DEFAULT; -import static de.diddiz.util.Utils.spaces; - import de.diddiz.LogBlock.QueryParams.SummarizationMode; +import de.diddiz.util.MessagingUtil; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Objects; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Location; public class SummedBlockChanges implements LookupCacheElement { @@ -33,11 +31,7 @@ public Location getLocation() { } @Override - public String getMessage() { - StringBuilder builder = new StringBuilder(); - builder.append(CREATE).append(created).append(spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor))); - builder.append(DESTROY).append(destroyed).append(spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor))); - builder.append(actor != null ? DEFAULT + actor.getName() : prettyMaterial(Objects.toString(MaterialConverter.getMaterial(type)))); - return builder.toString(); + public BaseComponent[] getLogMessage() { + return MessagingUtil.formatSummarizedChanges(created, destroyed, actor != null ? new TextComponent(actor.getName()) : prettyMaterial(Objects.toString(MaterialConverter.getMaterial(type))), 10, 10, spaceFactor); } } diff --git a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java index 5b1fd454..3b697845 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java @@ -1,13 +1,16 @@ package de.diddiz.LogBlock; import de.diddiz.LogBlock.QueryParams.SummarizationMode; +import de.diddiz.util.MessagingUtil; import org.bukkit.Location; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Objects; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; -import static de.diddiz.util.Utils.spaces; +import static de.diddiz.util.MessagingUtil.prettyMaterial; public class SummedEntityChanges implements LookupCacheElement { private final int type; @@ -30,7 +33,7 @@ public Location getLocation() { } @Override - public String getMessage() { - return created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)) + destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)) + (actor != null ? actor.getName() : Objects.toString(EntityTypeConverter.getEntityType(type))); + public BaseComponent[] getLogMessage() { + return MessagingUtil.formatSummarizedChanges(created, destroyed, actor != null ? new TextComponent(actor.getName()) : prettyMaterial(Objects.toString(EntityTypeConverter.getEntityType(type))), 10, 10, spaceFactor); } } diff --git a/src/main/java/de/diddiz/LogBlock/SummedKills.java b/src/main/java/de/diddiz/LogBlock/SummedKills.java index 35945521..e0ea69a4 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedKills.java +++ b/src/main/java/de/diddiz/LogBlock/SummedKills.java @@ -1,12 +1,10 @@ package de.diddiz.LogBlock; -import static de.diddiz.util.ActionColor.CREATE; -import static de.diddiz.util.ActionColor.DESTROY; -import static de.diddiz.util.TypeColor.DEFAULT; -import static de.diddiz.util.Utils.spaces; - +import de.diddiz.util.MessagingUtil; import java.sql.ResultSet; import java.sql.SQLException; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Location; public class SummedKills implements LookupCacheElement { @@ -27,12 +25,7 @@ public Location getLocation() { } @Override - public String getMessage() { - StringBuilder builder = new StringBuilder(); - builder.append(CREATE).append(kills).append(spaces((int) ((6 - String.valueOf(kills).length()) / spaceFactor))); - builder.append(DESTROY).append(killed).append(spaces((int) ((7 - String.valueOf(killed).length()) / spaceFactor))); - builder.append(DEFAULT).append(player.getName()); - return builder.toString(); - + public BaseComponent[] getLogMessage() { + return MessagingUtil.formatSummarizedChanges(kills, killed, new TextComponent(player.getName()), 6, 7, spaceFactor); } } diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 4e377471..972d11c5 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -43,6 +43,8 @@ import java.util.List; import java.util.UUID; import java.util.logging.Level; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import static de.diddiz.LogBlock.config.Config.dontRollback; import static de.diddiz.LogBlock.config.Config.replaceAnyway; @@ -184,7 +186,7 @@ public synchronized void run() { file.getParentFile().mkdirs(); final PrintWriter writer = new PrintWriter(file); for (final LookupCacheElement err : errorList) { - writer.println(err.getMessage()); + writer.println(BaseComponent.toPlainText(err.getLogMessage())); } writer.close(); } catch (final Exception ex) { @@ -472,5 +474,10 @@ public WorldEditorException(String msg, Location loc) { public Location getLocation() { return loc; } + + @Override + public BaseComponent[] getLogMessage() { + return TextComponent.fromLegacyText(getMessage()); + } } } diff --git a/src/main/java/de/diddiz/util/ActionColor.java b/src/main/java/de/diddiz/util/ActionColor.java index 5573ba3f..e336ba02 100644 --- a/src/main/java/de/diddiz/util/ActionColor.java +++ b/src/main/java/de/diddiz/util/ActionColor.java @@ -1,6 +1,6 @@ package de.diddiz.util; -import org.bukkit.ChatColor; +import net.md_5.bungee.api.ChatColor; public enum ActionColor { DESTROY(ChatColor.RED), diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index d9903a8c..d1bbc0a4 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -1,8 +1,6 @@ package de.diddiz.util; import static de.diddiz.util.MessagingUtil.prettyMaterial; -import static de.diddiz.util.TypeColor.DEFAULT; - import java.io.File; import java.util.ArrayList; import java.util.Arrays; @@ -15,6 +13,10 @@ import java.util.Map.Entry; import java.util.Set; import java.util.UUID; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.HoverEvent.Action; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Chunk; @@ -686,29 +688,26 @@ public static boolean isEmpty(Material m) { return m == Material.AIR || m == Material.CAVE_AIR || m == Material.VOID_AIR; } - public static String toString(ItemStack stack) { + public static TextComponent toString(ItemStack stack) { if (stack == null || stack.getAmount() == 0 || isEmpty(stack.getType())) { return prettyMaterial("nothing"); } - StringBuilder sb = new StringBuilder(); - sb.append(stack.getAmount()).append("x ").append(prettyMaterial(stack.getType())); - sb.append(TypeColor.STATE); + TextComponent msg = MessagingUtil.createTextComponentWithColor(stack.getAmount() + "x ", TypeColor.DEFAULT.getColor()); + msg.addExtra(prettyMaterial(stack.getType())); + ItemMeta meta = stack.getItemMeta(); + TextComponent hover = MessagingUtil.createTextComponentWithColor("", TypeColor.STATE.getColor()); boolean metaStarted = false; if (meta.hasEnchants()) { Map enchants = meta.getEnchants(); if (!enchants.isEmpty()) { for (Entry e : enchants.entrySet()) { if (!metaStarted) { - sb.append(" ["); metaStarted = true; } else { - sb.append(", "); - } - sb.append(formatMinecraftKey(e.getKey().getKey().getKey())); - if (e.getValue() > 1) { - sb.append(" ").append(maybeToRoman(e.getValue() - 1)); + hover.addExtra("\n"); } + hover.addExtra(formatMinecraftKey(e.getKey().getKey().getKey()) + ((e.getKey().getMaxLevel() != 1 || e.getValue() != 1) ? " " + maybeToRoman(e.getValue()) : "")); } } } @@ -719,24 +718,20 @@ public static String toString(ItemStack stack) { if (!enchants.isEmpty()) { for (Entry e : enchants.entrySet()) { if (!metaStarted) { - sb.append(" ["); metaStarted = true; } else { - sb.append(", "); - } - sb.append(formatMinecraftKey(e.getKey().getKey().getKey())); - if (e.getValue() > 1) { - sb.append(" ").append(maybeToRoman(e.getValue() - 1)); + hover.addExtra("\n"); } + hover.addExtra(formatMinecraftKey(e.getKey().getKey().getKey()) + ((e.getKey().getMaxLevel() != 1 || e.getValue() != 1) ? " " + maybeToRoman(e.getValue()) : "")); } } } } if (metaStarted) { - sb.append("]"); + msg.setHoverEvent(new HoverEvent(Action.SHOW_TEXT, new BaseComponent[] { hover })); } - sb.append(DEFAULT); - return sb.toString(); + + return msg; } private static final String[] romanNumbers = new String[] { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "XI", "X" }; diff --git a/src/main/java/de/diddiz/util/MessagingUtil.java b/src/main/java/de/diddiz/util/MessagingUtil.java index 83765efe..a8d66637 100644 --- a/src/main/java/de/diddiz/util/MessagingUtil.java +++ b/src/main/java/de/diddiz/util/MessagingUtil.java @@ -1,69 +1,98 @@ package de.diddiz.util; +import static de.diddiz.util.ActionColor.CREATE; +import static de.diddiz.util.ActionColor.DESTROY; import static de.diddiz.util.TypeColor.DEFAULT; +import static de.diddiz.util.Utils.spaces; import de.diddiz.LogBlock.config.Config; +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.EntityType; public class MessagingUtil { - public static String brackets(String string, BracketType type) { - return TypeColor.BRACKETS + String.valueOf(type.getStarting()) + string + TypeColor.BRACKETS + type.getEnding() + DEFAULT; + 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()); + return new BaseComponent[] { textCreated, textDestroyed, actor }; } - public static String prettyDate(long date) { - return TypeColor.DATE + Config.formatter.format(date) + DEFAULT; + public static TextComponent createTextComponentWithColor(String text, ChatColor color) { + TextComponent tc = new TextComponent(text); + tc.setColor(color); + return tc; } - public static String prettyState(String stateName) { - return TypeColor.STATE + stateName.toUpperCase() + DEFAULT; + public static TextComponent brackets(BracketType type, BaseComponent... content) { + TextComponent tc = createTextComponentWithColor(type.getStarting(), TypeColor.BRACKETS.getColor()); + for (BaseComponent c : content) { + tc.addExtra(c); + } + tc.addExtra(new TextComponent(type.getEnding())); + return tc; + } + + public static TextComponent prettyDate(long date) { + return brackets(BracketType.STANDARD, createTextComponentWithColor(Config.formatter.format(date), TypeColor.DATE.getColor())); + } + + public static TextComponent prettyState(String stateName) { + return createTextComponentWithColor(stateName, TypeColor.STATE.getColor()); } - public static String prettyState(int stateValue) { + public static TextComponent prettyState(int stateValue) { return prettyState(Integer.toString(stateValue)); } - public static > String prettyState(E enumerator) { + public static > TextComponent prettyState(E enumerator) { return prettyState(enumerator.toString()); } - public static String prettyMaterial(String materialName) { - return TypeColor.MATERIAL + materialName.toUpperCase() + DEFAULT; + public static TextComponent prettyMaterial(String materialName) { + return createTextComponentWithColor(materialName.toUpperCase(), TypeColor.MATERIAL.getColor()); } - public static String prettyMaterial(Material material) { + public static TextComponent prettyMaterial(Material material) { return prettyMaterial(material.name()); } - public static String prettyEntityType(EntityType type) { + public static TextComponent prettyEntityType(EntityType type) { return prettyMaterial(type.name()); } - public static String prettyLocation(Location loc) { + public static TextComponent prettyLocation(Location loc) { return prettyLocation(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); } - public static String prettyLocation(Number x, Number y, Number z) { - return DEFAULT + "X: " + TypeColor.COORDINATE + x.intValue() + DEFAULT + ", Y: " + TypeColor.COORDINATE + y.intValue() + DEFAULT + ", Z: " + TypeColor.COORDINATE + z.intValue() + DEFAULT; + public static TextComponent prettyLocation(Number x, Number y, Number z) { + TextComponent tc = createTextComponentWithColor("X: ", DEFAULT.getColor()); + tc.addExtra(createTextComponentWithColor(Integer.toString(x.intValue()), TypeColor.COORDINATE.getColor())); + tc.addExtra(createTextComponentWithColor(", Y: ", DEFAULT.getColor())); + tc.addExtra(createTextComponentWithColor(Integer.toString(y.intValue()), TypeColor.COORDINATE.getColor())); + tc.addExtra(createTextComponentWithColor(", Z: ", DEFAULT.getColor())); + tc.addExtra(createTextComponentWithColor(Integer.toString(z.intValue()), TypeColor.COORDINATE.getColor())); + return tc; } public enum BracketType { - STANDARD('[', ']'), - ANGLE('<', '>'); + STANDARD("[", "]"), + ANGLE("<", ">"); - private char starting, ending; + private String starting, ending; - BracketType(char starting, char ending) { + BracketType(String starting, String ending) { this.starting = starting; this.ending = ending; } - public char getStarting() { + public String getStarting() { return starting; } - public char getEnding() { + public String getEnding() { return ending; } } diff --git a/src/main/java/de/diddiz/util/TypeColor.java b/src/main/java/de/diddiz/util/TypeColor.java index a35216aa..00904d02 100644 --- a/src/main/java/de/diddiz/util/TypeColor.java +++ b/src/main/java/de/diddiz/util/TypeColor.java @@ -1,6 +1,6 @@ package de.diddiz.util; -import org.bukkit.ChatColor; +import net.md_5.bungee.api.ChatColor; public enum TypeColor { DEFAULT(ChatColor.YELLOW), From 31428d60e4cebdcfddf908a88d56f9e876dfab9e Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 20 Dec 2019 05:15:45 +0100 Subject: [PATCH 223/399] Add some hover texts and clickable coords --- .../java/de/diddiz/LogBlock/BlockChange.java | 54 +++++++++---------- .../java/de/diddiz/LogBlock/ChatMessage.java | 2 +- .../de/diddiz/LogBlock/CommandsHandler.java | 2 +- .../java/de/diddiz/LogBlock/EntityChange.java | 4 +- src/main/java/de/diddiz/LogBlock/Kill.java | 4 +- .../diddiz/LogBlock/LookupCacheElement.java | 6 ++- .../diddiz/LogBlock/SummedBlockChanges.java | 2 +- .../diddiz/LogBlock/SummedEntityChanges.java | 2 +- .../java/de/diddiz/LogBlock/SummedKills.java | 2 +- .../java/de/diddiz/LogBlock/WorldEditor.java | 2 +- .../de/diddiz/LogBlock/config/Config.java | 11 +++- .../java/de/diddiz/util/MessagingUtil.java | 44 +++++++++++---- 12 files changed, 85 insertions(+), 50 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 997926a5..55b396a5 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -101,11 +101,11 @@ private String getTypeDetails(BlockData type, byte[] typeState) { @Override public String toString() { - return BaseComponent.toPlainText(getLogMessage()); + return BaseComponent.toPlainText(getLogMessage(-1)); } @Override - public BaseComponent[] getLogMessage() { + public BaseComponent[] getLogMessage(int entry) { TextComponent msg = new TextComponent(); if (date > 0) { msg.addExtra(prettyDate(date)); @@ -132,108 +132,108 @@ public BaseComponent[] getLogMessage() { } else if (ca != null) { if (ca.itemStack == null) { msg.addExtra(createTextComponentWithColor("looked inside ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); } else if (ca.remove) { msg.addExtra(createTextComponentWithColor("took ", DESTROY.getColor())); msg.addExtra(BukkitUtils.toString(ca.itemStack)); msg.addExtra(createTextComponentWithColor(" from ", DESTROY.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); } else { msg.addExtra(createTextComponentWithColor("put ", CREATE.getColor())); msg.addExtra(BukkitUtils.toString(ca.itemStack)); msg.addExtra(createTextComponentWithColor(" into ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); } } else if (type instanceof Waterlogged && ((Waterlogged) type).isWaterlogged() != ((Waterlogged) replaced).isWaterlogged()) { if (((Waterlogged) type).isWaterlogged()) { msg.addExtra(createTextComponentWithColor("waterlogged ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); } else { msg.addExtra(createTextComponentWithColor("dried ", DESTROY.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); } } else if (BukkitUtils.getContainerBlocks().contains(type.getMaterial())) { msg.addExtra(createTextComponentWithColor("opened ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); } else if (type instanceof Openable && ((Openable) type).isOpen() != ((Openable) replaced).isOpen()) { // Door, Trapdoor, Fence gate msg.addExtra(createTextComponentWithColor(((Openable) type).isOpen() ? "opened " : "closed ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); } else if (type.getMaterial() == Material.LEVER && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) { msg.addExtra(createTextComponentWithColor("switched ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); msg.addExtra(prettyState(((Switch) type).isPowered() ? " on" : " off")); } else if (type instanceof Switch && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) { msg.addExtra(createTextComponentWithColor("pressed ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); } else if (type.getMaterial() == Material.CAKE) { msg.addExtra(createTextComponentWithColor("ate a piece of ", DESTROY.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); } else if (type.getMaterial() == Material.NOTE_BLOCK) { Note note = ((NoteBlock) type).getNote(); msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); msg.addExtra(" to "); msg.addExtra(prettyState(note.getTone().name() + (note.isSharped() ? "#" : ""))); } else if (type.getMaterial() == Material.REPEATER) { msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); msg.addExtra(" to "); msg.addExtra(prettyState(((Repeater) type).getDelay())); msg.addExtra(createTextComponentWithColor(" ticks delay", DEFAULT.getColor())); } else if (type.getMaterial() == Material.COMPARATOR) { msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); msg.addExtra(" to "); msg.addExtra(prettyState(((Comparator) type).getMode())); } else if (type.getMaterial() == Material.DAYLIGHT_DETECTOR) { msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); msg.addExtra(" to "); msg.addExtra(prettyState(((DaylightDetector) type).isInverted() ? "inverted" : "normal")); } else if (type instanceof Lectern) { msg.addExtra(createTextComponentWithColor("changed the book on a ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); msg.addExtra(" to"); msg.addExtra(prettyState(typeDetails.length() == 0 ? " empty" : typeDetails)); } else if (type instanceof Powerable) { msg.addExtra(createTextComponentWithColor("stepped on ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); } else if (type.getMaterial() == Material.TRIPWIRE) { msg.addExtra(createTextComponentWithColor("ran into ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); } else if (type instanceof Sign || type instanceof WallSign) { msg.addExtra(createTextComponentWithColor("edited a ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); msg.addExtra(createTextComponentWithColor(" to ", CREATE.getColor())); msg.addExtra(prettyState(typeDetails)); } else { msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor())); - msg.addExtra(prettyMaterial(replaced.getMaterial())); + msg.addExtra(prettyMaterial(replaced)); msg.addExtra(prettyState(replacedDetails)); msg.addExtra(createTextComponentWithColor(" with ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); msg.addExtra(prettyState(typeDetails)); } } else if (BukkitUtils.isEmpty(type.getMaterial())) { msg.addExtra(createTextComponentWithColor("destroyed ", DESTROY.getColor())); - msg.addExtra(prettyMaterial(replaced.getMaterial())); + msg.addExtra(prettyMaterial(replaced)); msg.addExtra(prettyState(replacedDetails)); } else if (BukkitUtils.isEmpty(replaced.getMaterial())) { msg.addExtra(createTextComponentWithColor("created ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); msg.addExtra(prettyState(typeDetails)); } else { msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor())); - msg.addExtra(prettyMaterial(replaced.getMaterial())); + msg.addExtra(prettyMaterial(replaced)); msg.addExtra(prettyState(replacedDetails)); msg.addExtra(createTextComponentWithColor(" with ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type.getMaterial())); + msg.addExtra(prettyMaterial(type)); msg.addExtra(prettyState(typeDetails)); } if (loc != null) { msg.addExtra(" at "); - msg.addExtra(prettyLocation(loc)); + msg.addExtra(prettyLocation(loc, entry)); } return new BaseComponent[] { msg }; } diff --git a/src/main/java/de/diddiz/LogBlock/ChatMessage.java b/src/main/java/de/diddiz/LogBlock/ChatMessage.java index 9c632628..1f55dd2a 100644 --- a/src/main/java/de/diddiz/LogBlock/ChatMessage.java +++ b/src/main/java/de/diddiz/LogBlock/ChatMessage.java @@ -39,7 +39,7 @@ public Location getLocation() { } @Override - public BaseComponent[] getLogMessage() { + public BaseComponent[] getLogMessage(int entry) { TextComponent msg = new TextComponent(); if (date > 0) { msg.addExtra(prettyDate(date)); diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index c309289f..71f22a7d 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -405,7 +405,7 @@ private static void showPage(CommandSender sender, int page, LookupCacheElement[ if (lookupElements[i].getLocation() != null) { message.addExtra(new TextComponent("(" + (i + 1) + ") ")); } - for (BaseComponent component : lookupElements[i].getLogMessage()) { + for (BaseComponent component : lookupElements[i].getLogMessage(i + 1)) { message.addExtra(component); } sender.spigot().sendMessage(message); diff --git a/src/main/java/de/diddiz/LogBlock/EntityChange.java b/src/main/java/de/diddiz/LogBlock/EntityChange.java index 5f04cdbf..a7e0e582 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityChange.java +++ b/src/main/java/de/diddiz/LogBlock/EntityChange.java @@ -76,7 +76,7 @@ public String toString() { } @Override - public BaseComponent[] getLogMessage() { + public BaseComponent[] getLogMessage(int entry) { TextComponent msg = new TextComponent(); if (date > 0) { msg.addExtra(prettyDate(date)); @@ -123,7 +123,7 @@ public BaseComponent[] getLogMessage() { } if (loc != null) { msg.addExtra(" at "); - msg.addExtra(prettyLocation(loc)); + msg.addExtra(prettyLocation(loc, entry)); } return new BaseComponent[] { msg }; } diff --git a/src/main/java/de/diddiz/LogBlock/Kill.java b/src/main/java/de/diddiz/LogBlock/Kill.java index f052b473..bec4f18f 100755 --- a/src/main/java/de/diddiz/LogBlock/Kill.java +++ b/src/main/java/de/diddiz/LogBlock/Kill.java @@ -48,7 +48,7 @@ public Location getLocation() { } @Override - public BaseComponent[] getLogMessage() { + public BaseComponent[] getLogMessage(int entry) { TextComponent msg = new TextComponent(); if (date > 0) { msg.addExtra(prettyDate(date)); @@ -58,7 +58,7 @@ public BaseComponent[] getLogMessage() { msg.addExtra(new TextComponent(victimName)); if (loc != null) { msg.addExtra(" at "); - msg.addExtra(prettyLocation(loc)); + msg.addExtra(prettyLocation(loc, entry)); } if (weapon != 0) { msg.addExtra(" with "); diff --git a/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java b/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java index ea63ce4e..402ec8a4 100644 --- a/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java +++ b/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java @@ -6,5 +6,9 @@ public interface LookupCacheElement { public Location getLocation(); - public BaseComponent[] getLogMessage(); + public default BaseComponent[] getLogMessage() { + return getLogMessage(-1); + } + + public BaseComponent[] getLogMessage(int entry); } diff --git a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java index 7b07339b..c9eceae5 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java @@ -31,7 +31,7 @@ public Location getLocation() { } @Override - public BaseComponent[] getLogMessage() { + 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); } } diff --git a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java index 3b697845..5677cb01 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java @@ -33,7 +33,7 @@ public Location getLocation() { } @Override - public BaseComponent[] getLogMessage() { + 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); } } diff --git a/src/main/java/de/diddiz/LogBlock/SummedKills.java b/src/main/java/de/diddiz/LogBlock/SummedKills.java index e0ea69a4..6151a737 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedKills.java +++ b/src/main/java/de/diddiz/LogBlock/SummedKills.java @@ -25,7 +25,7 @@ public Location getLocation() { } @Override - public BaseComponent[] getLogMessage() { + public BaseComponent[] getLogMessage(int entry) { return MessagingUtil.formatSummarizedChanges(kills, killed, new TextComponent(player.getName()), 6, 7, spaceFactor); } } diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 972d11c5..662d4beb 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -476,7 +476,7 @@ public Location getLocation() { } @Override - public BaseComponent[] getLogMessage() { + public BaseComponent[] getLogMessage(int entry) { return TextComponent.fromLegacyText(getMessage()); } } diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 103f349d..3f1a61d0 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -52,6 +52,7 @@ public class Config { public static Set hiddenPlayers; public static List ignoredChat; public static SimpleDateFormat formatter; + public static SimpleDateFormat formatterShort; public static boolean safetyIdCheck; public static boolean debug; public static boolean logEnvironmentalKills; @@ -121,11 +122,17 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("lookup.linesLimit", 1500); def.put("lookup.hardLinesLimit", 100000); try { - formatter = new SimpleDateFormat(config.getString("lookup.dateFormat", "MM-dd HH:mm:ss")); + formatter = new SimpleDateFormat(config.getString("lookup.dateFormat", "yyyy-MM-dd HH:mm:ss")); } catch (IllegalArgumentException e) { throw new DataFormatException("Invalid specification for date format, please see http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html : " + e.getMessage()); } - def.put("lookup.dateFormat", "MM-dd HH:mm:ss"); + def.put("lookup.dateFormat", "yyyy-MM-dd HH:mm:ss"); + try { + formatterShort = new SimpleDateFormat(config.getString("lookup.dateFormatShort", "MM-dd HH:mm")); + } catch (IllegalArgumentException e) { + throw new DataFormatException("Invalid specification for date format, please see http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html : " + e.getMessage()); + } + def.put("lookup.dateFormatShort", "MM-dd HH:mm"); def.put("questioner.askRollbacks", true); def.put("questioner.askRedos", true); def.put("questioner.askClearLogs", true); diff --git a/src/main/java/de/diddiz/util/MessagingUtil.java b/src/main/java/de/diddiz/util/MessagingUtil.java index a8d66637..f1c81288 100644 --- a/src/main/java/de/diddiz/util/MessagingUtil.java +++ b/src/main/java/de/diddiz/util/MessagingUtil.java @@ -8,9 +8,13 @@ import de.diddiz.LogBlock.config.Config; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.data.BlockData; import org.bukkit.entity.EntityType; public class MessagingUtil { @@ -36,7 +40,9 @@ public static TextComponent brackets(BracketType type, BaseComponent... content) } public static TextComponent prettyDate(long date) { - return brackets(BracketType.STANDARD, createTextComponentWithColor(Config.formatter.format(date), TypeColor.DATE.getColor())); + TextComponent tc = brackets(BracketType.STANDARD, createTextComponentWithColor(Config.formatterShort.format(date), TypeColor.DATE.getColor())); + tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(Config.formatter.format(date)).create())); + return tc; } public static TextComponent prettyState(String stateName) { @@ -59,21 +65,39 @@ public static TextComponent prettyMaterial(Material material) { return prettyMaterial(material.name()); } + public static TextComponent prettyMaterial(BlockData material) { + TextComponent tc = prettyMaterial(material.getMaterial()); + String bdString = material.getAsString(); + int bracket = bdString.indexOf("["); + if (bracket >= 0) { + int bracket2 = bdString.indexOf("]", bracket); + if (bracket2 >= 0) { + String state = bdString.substring(bracket + 1, bracket2).replace(',', '\n'); + tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(state).create())); + } + } + return tc; + } + public static TextComponent prettyEntityType(EntityType type) { return prettyMaterial(type.name()); } - public static TextComponent prettyLocation(Location loc) { - return prettyLocation(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + public static TextComponent prettyLocation(Location loc, int entryId) { + return prettyLocation(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), entryId); } - public static TextComponent prettyLocation(Number x, Number y, Number z) { - TextComponent tc = createTextComponentWithColor("X: ", DEFAULT.getColor()); - tc.addExtra(createTextComponentWithColor(Integer.toString(x.intValue()), TypeColor.COORDINATE.getColor())); - tc.addExtra(createTextComponentWithColor(", Y: ", DEFAULT.getColor())); - tc.addExtra(createTextComponentWithColor(Integer.toString(y.intValue()), TypeColor.COORDINATE.getColor())); - tc.addExtra(createTextComponentWithColor(", Z: ", DEFAULT.getColor())); - tc.addExtra(createTextComponentWithColor(Integer.toString(z.intValue()), TypeColor.COORDINATE.getColor())); + public static TextComponent prettyLocation(int x, int y, int z, int entryId) { + TextComponent tc = createTextComponentWithColor("", DEFAULT.getColor()); + tc.addExtra(createTextComponentWithColor(Integer.toString(x), TypeColor.COORDINATE.getColor())); + tc.addExtra(createTextComponentWithColor(", ", DEFAULT.getColor())); + tc.addExtra(createTextComponentWithColor(Integer.toString(y), TypeColor.COORDINATE.getColor())); + tc.addExtra(createTextComponentWithColor(", ", DEFAULT.getColor())); + tc.addExtra(createTextComponentWithColor(Integer.toString(z), TypeColor.COORDINATE.getColor())); + if (entryId > 0) { + tc.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/lb tp " + entryId)); + tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("Teleport here").create())); + } return tc; } From 793df218e54a94d2a97f877ec098f67a3386bcbc Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 20 Dec 2019 05:27:24 +0100 Subject: [PATCH 224/399] Bump version to 1.15.1, update dependencies --- pom.xml | 18 ++++-------------- src/main/java/de/diddiz/LogBlock/Updater.java | 4 ++++ 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/pom.xml b/pom.xml index 7d37a400..f0bf3501 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.14.1-SNAPSHOT + 1.15.1-SNAPSHOT jar LogBlock @@ -42,24 +42,14 @@ org.spigotmc spigot-api - 1.14.1-R0.1-SNAPSHOT + 1.15.1-R0.1-SNAPSHOT provided com.sk89q.worldedit worldedit-bukkit - 7.0.0-SNAPSHOT + 7.1.0-SNAPSHOT provided - - - org.bstats - bstats-bukkit - - - io.papermc - paperlib - - junit @@ -70,7 +60,7 @@ com.zaxxer HikariCP - 3.2.0 + 3.4.1 compile diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index de93eb4c..77ecd0ab 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -737,6 +737,10 @@ boolean update() { config.set("version", "1.14.1"); } + if (configVersion.compareTo(new ComparableVersion("1.15.1")) < 0) { + config.set("version", "1.15.1"); + } + // this can always be checked try { final Connection conn = logblock.getConnection(); From 8e948e857f8a62352d1a1624cea6f0d445fd4c9c Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 20 Dec 2019 05:27:55 +0100 Subject: [PATCH 225/399] Release 1.15.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f0bf3501..4cae5cad 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.15.1-SNAPSHOT + 1.15.1 jar LogBlock From cdee5b36096c2c796bf0f32d42b2eeb798f840f3 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 20 Dec 2019 05:37:55 +0100 Subject: [PATCH 226/399] Back to snapshots --- pom.xml | 2 +- src/main/java/de/diddiz/LogBlock/Updater.java | 12 ++---------- src/main/java/de/diddiz/LogBlock/config/Config.java | 4 +++- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index 4cae5cad..b1f55e3d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.15.1 + 1.15.1.1-SNAPSHOT jar LogBlock diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 77ecd0ab..42ff25a9 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -729,16 +729,8 @@ boolean update() { config.set("version", "1.13.1"); } - if (configVersion.compareTo(new ComparableVersion("1.13.2")) < 0) { - config.set("version", "1.13.2"); - } - - if (configVersion.compareTo(new ComparableVersion("1.14.1")) < 0) { - config.set("version", "1.14.1"); - } - - if (configVersion.compareTo(new ComparableVersion("1.15.1")) < 0) { - config.set("version", "1.15.1"); + if (configVersion.compareTo(new ComparableVersion(Config.CURRENT_CONFIG_VERSION)) < 0) { + config.set("version", Config.CURRENT_CONFIG_VERSION); } // this can always be checked diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 3f1a61d0..86f73a2b 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -59,6 +59,8 @@ public class Config { // Not loaded from config - checked at runtime public static boolean mb4 = false; + public static final String CURRENT_CONFIG_VERSION = "1.15.1"; + public static enum LogKillsLevel { PLAYERS, MONSTERS, @@ -68,7 +70,7 @@ public static enum LogKillsLevel { public static void load(LogBlock logblock) throws DataFormatException, IOException { final ConfigurationSection config = logblock.getConfig(); final Map def = new HashMap<>(); - def.put("version", logblock.getDescription().getVersion()); + def.put("version", CURRENT_CONFIG_VERSION); final List worldNames = new ArrayList<>(); for (final World world : getWorlds()) { worldNames.add(world.getName()); From cdf6c1df042a2885fdd2151114d7099cd91d464a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 27 Dec 2019 18:04:41 +0100 Subject: [PATCH 227/399] Fix conversion to roman numbers Fixes #779 --- src/main/java/de/diddiz/util/BukkitUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index d1bbc0a4..90c3eabb 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -738,7 +738,7 @@ public static TextComponent toString(ItemStack stack) { private static String maybeToRoman(int value) { if (value > 0 && value <= 10) { - return romanNumbers[value]; + return romanNumbers[value - 1]; } return Integer.toString(value); } From 5b0e2d9adb53bfc7440a138182457dc08aca3c96 Mon Sep 17 00:00:00 2001 From: TheMolkaPL Date: Tue, 21 Jan 2020 17:44:56 +0100 Subject: [PATCH 228/399] Call ToolUseEvent when a tool is about to be used --- .../diddiz/LogBlock/events/ToolUseEvent.java | 59 +++++++++++++++++++ .../LogBlock/listeners/ToolListener.java | 9 +++ 2 files changed, 68 insertions(+) create mode 100644 src/main/java/de/diddiz/LogBlock/events/ToolUseEvent.java diff --git a/src/main/java/de/diddiz/LogBlock/events/ToolUseEvent.java b/src/main/java/de/diddiz/LogBlock/events/ToolUseEvent.java new file mode 100644 index 00000000..cb6c0833 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/events/ToolUseEvent.java @@ -0,0 +1,59 @@ +package de.diddiz.LogBlock.events; + +import de.diddiz.LogBlock.QueryParams; +import de.diddiz.LogBlock.Tool; +import de.diddiz.LogBlock.ToolBehavior; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; + +/** + * Fired whether a tool is about to be used by a player. + */ +public class ToolUseEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + private boolean cancel; + private final Tool tool; + private final ToolBehavior behavior; + private final QueryParams params; + + public ToolUseEvent(Player who, Tool tool, ToolBehavior behavior, QueryParams params) { + super(who); + this.tool = tool; + this.behavior = behavior; + this.params = params; + } + + @Override + public boolean isCancelled() { + return cancel; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + public Tool getTool() { + return tool; + } + + public ToolBehavior getBehavior() { + return behavior; + } + + public QueryParams getParams() { + return params; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java index df889d76..e20b1c46 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java @@ -1,6 +1,7 @@ package de.diddiz.LogBlock.listeners; import de.diddiz.LogBlock.*; +import de.diddiz.LogBlock.events.ToolUseEvent; import de.diddiz.util.BukkitUtils; import de.diddiz.util.CuboidRegion; import org.bukkit.ChatColor; @@ -65,6 +66,9 @@ public void onPlayerInteract(PlayerInteractEvent event) { } try { params.validate(); + if (this.callToolUseEvent(new ToolUseEvent(player, tool, behavior, params))) { + return; + } if (toolData.mode == ToolMode.ROLLBACK) { handler.new CommandRollback(player, params, true); } else if (toolData.mode == ToolMode.REDO) { @@ -85,6 +89,11 @@ public void onPlayerInteract(PlayerInteractEvent event) { } } + private boolean callToolUseEvent(ToolUseEvent event) { + this.logblock.getServer().getPluginManager().callEvent(event); + return event.isCancelled(); + } + @EventHandler public void onPlayerChangedWorld(PlayerChangedWorldEvent event) { final Player player = event.getPlayer(); From 8b34e397978017d8b6bbb491e8dbbffe098fc46e Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 24 Jan 2020 04:23:59 +0100 Subject: [PATCH 229/399] Log getting stung by bees Fixes #780 --- src/main/java/de/diddiz/LogBlock/EntityChange.java | 5 ++++- src/main/java/de/diddiz/LogBlock/WorldEditor.java | 7 +++++++ .../LogBlock/listeners/AdvancedEntityLogging.java | 12 ++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/EntityChange.java b/src/main/java/de/diddiz/LogBlock/EntityChange.java index a7e0e582..77a1d230 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityChange.java +++ b/src/main/java/de/diddiz/LogBlock/EntityChange.java @@ -28,7 +28,8 @@ public static enum EntityChangeType { KILL, MODIFY, ADDEQUIP, - REMOVEEQUIP; + REMOVEEQUIP, + GET_STUNG; private static EntityChangeType[] values = values(); @@ -113,6 +114,8 @@ public BaseComponent[] getLogMessage(int entry) { } } else if (changeType == EntityChangeType.MODIFY) { msg.addExtra(createTextComponentWithColor("modified ", INTERACT.getColor())); + } else if (changeType == EntityChangeType.GET_STUNG) { + msg.addExtra(createTextComponentWithColor("got stung by ", DESTROY.getColor())); } else { msg.addExtra(createTextComponentWithColor("did an unknown action to ", INTERACT.getColor())); } diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 662d4beb..4530bc2c 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -20,6 +20,7 @@ import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Bee; import org.bukkit.entity.Entity; import org.bukkit.entity.ItemFrame; import org.bukkit.inventory.EquipmentSlot; @@ -324,6 +325,12 @@ public PerformResult perform() throws WorldEditorException { } } return PerformResult.NO_ACTION; // the entity is not there, or equip does not match + } else if (changeType == EntityChangeType.GET_STUNG) { + UUID uuid = getReplacedUUID(entityId, entityUUID); + Entity existing = BukkitUtils.loadEntityAround(loc.getChunk(), uuid); + if (existing != null && existing instanceof Bee) { + ((Bee) existing).setHasStung(!rollback); + } } return PerformResult.NO_ACTION; } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index 684d3a83..4867f692 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -5,6 +5,7 @@ import org.bukkit.block.BlockFace; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Bee; import org.bukkit.entity.Entity; import org.bukkit.entity.Hanging; import org.bukkit.entity.IronGolem; @@ -226,6 +227,17 @@ public void onEntityDamage(EntityDamageEvent event) { } } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { + Entity damager = event.getDamager(); + if (damager instanceof Bee && !((Bee) damager).hasStung()) { + if (Config.isLogging(damager.getWorld(), EntityLogging.MODIFY, damager)) { + Actor actor = Actor.actorFromEntity(event.getEntity()); + consumer.queueEntityModification(actor, damager.getUniqueId(), damager.getType(), damager.getLocation(), EntityChange.EntityChangeType.GET_STUNG, null); + } + } + } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerArmorStandManipulate(PlayerArmorStandManipulateEvent event) { ArmorStand entity = event.getRightClicked(); From b9513df20e635cde8f3bf695a7470b261860b3d5 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 24 Jan 2020 04:52:13 +0100 Subject: [PATCH 230/399] Log bamboo growth (new world logging option) Fixes #769 --- src/main/java/de/diddiz/LogBlock/Logging.java | 1 + .../LogBlock/listeners/BlockSpreadLogging.java | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index 40a4e16f..9fcc7104 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -34,6 +34,7 @@ public enum Logging { MYCELIUMSPREAD, VINEGROWTH, MUSHROOMSPREAD, + BAMBOOGROWTH, WITHER(true), WITHER_SKULL(true), BONEMEALSTRUCTUREGROW, diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java index 02937180..22f29a58 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java @@ -51,6 +51,18 @@ public void onBlockSpread(BlockSpreadEvent event) { } name = "MushroomSpread"; break; + case BAMBOO: + case BAMBOO_SAPLING: { + if (!isLogging(world, Logging.BAMBOOGROWTH)) { + return; + } + name = "BambooGrowth"; + if (type == Material.BAMBOO_SAPLING) { + // bamboo sapling gets replaced by bamboo + consumer.queueBlockReplace(new Actor(name), event.getSource().getState(), Material.BAMBOO.createBlockData()); + } + break; + } default: return; } From 6dec1b6c37e661d79bc6afbb502d2888c2cbeed8 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 24 Jan 2020 05:06:48 +0100 Subject: [PATCH 231/399] Improve rollback ability by accepting similar blocks to the expected one For example grass_block instead of dirt --- .../java/de/diddiz/LogBlock/WorldEditor.java | 2 +- src/main/java/de/diddiz/util/BukkitUtils.java | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 4530bc2c..d5624793 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -380,7 +380,7 @@ public PerformResult perform() throws WorldEditorException { return PerformResult.NO_ACTION; } } - if (!forceReplace && block.getType() != setBlock.getMaterial() && !block.isEmpty() && !replaceAnyway.contains(block.getType())) { + if (!forceReplace && !BukkitUtils.isSimilarForRollback(setBlock.getMaterial(), block.getType()) && !block.isEmpty() && !replaceAnyway.contains(block.getType())) { return PerformResult.NO_ACTION; } if (state instanceof Container && replacedBlock.getMaterial() != block.getType()) { diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 90c3eabb..7bb8b516 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -964,4 +964,32 @@ public static boolean hasInventoryStorageSpaceFor(Inventory inv, ItemStack... it } return true; } + + public static boolean isSimilarForRollback(Material expected, Material found) { + if (expected == found) { + return true; + } + switch (expected) { + case DIRT: + case MYCELIUM: + case FARMLAND: + case GRASS_BLOCK: + case PODZOL: + case GRASS_PATH: + return found == Material.DIRT || found == Material.MYCELIUM || found == Material.FARMLAND || found == Material.GRASS_BLOCK || found == Material.PODZOL || found == Material.GRASS_PATH; + case BAMBOO: + case BAMBOO_SAPLING: + return found == Material.BAMBOO || found == Material.BAMBOO_SAPLING; + case SPONGE: + case WET_SPONGE: + return found == Material.SPONGE || found == Material.WET_SPONGE; + case MELON_STEM: + case ATTACHED_MELON_STEM: + return found == Material.MELON_STEM || found == Material.ATTACHED_MELON_STEM; + case PUMPKIN_STEM: + case ATTACHED_PUMPKIN_STEM: + return found == Material.PUMPKIN_STEM || found == Material.ATTACHED_PUMPKIN_STEM; + } + return false; + } } From 6b71a3c30d76511be99d31e0587661bd34e586b8 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 24 Jan 2020 05:17:33 +0100 Subject: [PATCH 232/399] smart log breaking ice --- .../java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java index 1dfa94c6..17d3c292 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java @@ -20,6 +20,7 @@ import static de.diddiz.LogBlock.config.Config.getWorldConfig; import static de.diddiz.LogBlock.config.Config.isLogging; import static de.diddiz.util.LoggingUtil.smartLogBlockBreak; +import static de.diddiz.util.LoggingUtil.smartLogBlockReplace; import static de.diddiz.util.LoggingUtil.smartLogFallables; public class BlockBreakLogging extends LoggingListener { @@ -44,9 +45,9 @@ public void onBlockBreak(BlockBreakEvent event) { } else if (type == Material.ICE) { // When in creative mode ice doesn't form water if (event.getPlayer().getGameMode().equals(GameMode.CREATIVE)) { - consumer.queueBlockBreak(actor, origin.getState()); + smartLogBlockBreak(consumer, actor, origin); } else { - consumer.queueBlockReplace(actor, origin.getState(), Bukkit.createBlockData(Material.WATER)); + smartLogBlockReplace(consumer, actor, origin, Bukkit.createBlockData(Material.WATER)); } } else { smartLogBlockBreak(consumer, actor, origin); From 068ac898196b09ac7f10c4359c4b77c1300be111 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 24 Jan 2020 05:51:18 +0100 Subject: [PATCH 233/399] Add optional logging of shulker box contents Fixes #781 --- src/main/java/de/diddiz/LogBlock/Logging.java | 3 +- .../blockstate/BlockStateCodecShulkerBox.java | 85 +++++++++++++++++++ .../LogBlock/blockstate/BlockStateCodecs.java | 1 + .../LogBlock/listeners/BlockBreakLogging.java | 2 +- .../LogBlock/listeners/ExplosionLogging.java | 4 +- src/main/java/de/diddiz/util/BukkitUtils.java | 43 ++++++---- 6 files changed, 117 insertions(+), 21 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index 9fcc7104..79e8e4ae 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -45,7 +45,8 @@ public enum Logging { DRAGONEGGTELEPORT(true), DAYLIGHTDETECTORINTERACT, LECTERNBOOKCHANGE(true), - SCAFFOLDING(true); + SCAFFOLDING(true), + SHULKER_BOX_CONTENT; public static final int length = Logging.values().length; private final boolean defaultEnabled; diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java new file mode 100644 index 00000000..ac59c276 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java @@ -0,0 +1,85 @@ +package de.diddiz.LogBlock.blockstate; + +import static de.diddiz.LogBlock.config.Config.getWorldConfig; + +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.WorldConfig; +import de.diddiz.util.BukkitUtils; +import org.bukkit.Material; +import org.bukkit.block.BlockState; +import org.bukkit.block.ShulkerBox; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemStack; + +public class BlockStateCodecShulkerBox implements BlockStateCodec { + @Override + public Material[] getApplicableMaterials() { + return BukkitUtils.getShulkerBoxBlocks().toArray(new Material[BukkitUtils.getShulkerBoxBlocks().size()]); + } + + @Override + public YamlConfiguration serialize(BlockState state) { + WorldConfig wcfg = getWorldConfig(state.getWorld()); + if (wcfg == null || !wcfg.isLogging(Logging.SHULKER_BOX_CONTENT)) { + return null; + } + if (state instanceof ShulkerBox) { + ShulkerBox shulkerBox = (ShulkerBox) state; + ItemStack[] content = shulkerBox.getSnapshotInventory().getStorageContents(); + YamlConfiguration conf = new YamlConfiguration(); + boolean anySlot = false; + for (int i = 0; i < content.length; i++) { + ItemStack stack = content[i]; + if (stack != null && stack.getType() != Material.AIR) { + conf.set("slot" + i, stack); + anySlot = true; + } + } + if (anySlot) { + return conf; + } + } + return null; + } + + @Override + public void deserialize(BlockState state, YamlConfiguration conf) { + if (state instanceof ShulkerBox) { + ShulkerBox shulkerBox = (ShulkerBox) state; + if (conf != null) { + ItemStack[] content = shulkerBox.getSnapshotInventory().getStorageContents(); + for (int i = 0; i < content.length; i++) { + ItemStack stack = conf.getItemStack("slot" + i); + if (stack != null && stack.getType() != Material.AIR) { + content[i] = stack; + } + } + shulkerBox.getSnapshotInventory().setContents(content); + } + } + } + + @Override + public String toString(YamlConfiguration conf) { + if (conf != null) { + StringBuilder sb = new StringBuilder(); + sb.append("["); + boolean anySlot = false; + for (String key : conf.getKeys(false)) { + if (key.startsWith("slot")) { + ItemStack stack = conf.getItemStack(key); + if (stack != null && stack.getType() != Material.AIR) { + if (anySlot) { + sb.append(","); + } + anySlot = true; + sb.append(stack.getAmount()).append("x").append(stack.getType()); + } + } + } + sb.append("]"); + return anySlot ? sb.toString() : null; + } + return null; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java index 403d8d19..b610fa38 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java @@ -26,6 +26,7 @@ public static void registerCodec(BlockStateCodec codec) { registerCodec(new BlockStateCodecBanner()); registerCodec(new BlockStateCodecSpawner()); registerCodec(new BlockStateCodecLectern()); + registerCodec(new BlockStateCodecShulkerBox()); } public static boolean hasCodec(Material material) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java index 17d3c292..9f1d11c5 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java @@ -40,7 +40,7 @@ public void onBlockBreak(BlockBreakEvent event) { final Block origin = event.getBlock(); final Material type = origin.getType(); - if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.getContainerBlocks().contains(type)) { + if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) { consumer.queueContainerBreak(actor, origin.getState()); } else if (type == Material.ICE) { // When in creative mode ice doesn't form water diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index af5e285d..237c5d1a 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -113,7 +113,7 @@ public void onEntityExplode(EntityExplodeEvent event) { } for (final Block block : event.blockList()) { final Material type = block.getType(); - if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(type))) { + if (wcfg.isLogging(Logging.CHESTACCESS) && getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) { consumer.queueContainerBreak(actor, block.getState()); } else { consumer.queueBlockBreak(actor, block.getState()); @@ -168,7 +168,7 @@ public void onBlockExplode(BlockExplodeEvent event) { } final Material type = block.getType(); - if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(type))) { + if (wcfg.isLogging(Logging.CHESTACCESS) && getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) { consumer.queueContainerBreak(actor, block.getState()); } else { consumer.queueBlockBreak(actor, block.getState()); diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 7bb8b516..c69c2b4c 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -55,6 +55,7 @@ public class BukkitUtils { private static final Set cropBlocks; private static final Set containerBlocks; + private static final Set shulkerBoxBlocks; private static final Set singleBlockPlants; private static final Set doublePlants; @@ -316,6 +317,26 @@ public class BukkitUtils { cropBlocks.add(Material.POTATO); cropBlocks.add(Material.BEETROOT); + // Shulker Boxes + shulkerBoxBlocks = EnumSet.noneOf(Material.class); + shulkerBoxBlocks.add(Material.SHULKER_BOX); + shulkerBoxBlocks.add(Material.BLACK_SHULKER_BOX); + shulkerBoxBlocks.add(Material.BLUE_SHULKER_BOX); + shulkerBoxBlocks.add(Material.LIGHT_GRAY_SHULKER_BOX); + shulkerBoxBlocks.add(Material.BROWN_SHULKER_BOX); + shulkerBoxBlocks.add(Material.CYAN_SHULKER_BOX); + shulkerBoxBlocks.add(Material.GRAY_SHULKER_BOX); + shulkerBoxBlocks.add(Material.GREEN_SHULKER_BOX); + shulkerBoxBlocks.add(Material.LIGHT_BLUE_SHULKER_BOX); + shulkerBoxBlocks.add(Material.MAGENTA_SHULKER_BOX); + shulkerBoxBlocks.add(Material.LIME_SHULKER_BOX); + shulkerBoxBlocks.add(Material.ORANGE_SHULKER_BOX); + shulkerBoxBlocks.add(Material.PINK_SHULKER_BOX); + shulkerBoxBlocks.add(Material.PURPLE_SHULKER_BOX); + shulkerBoxBlocks.add(Material.RED_SHULKER_BOX); + shulkerBoxBlocks.add(Material.WHITE_SHULKER_BOX); + shulkerBoxBlocks.add(Material.YELLOW_SHULKER_BOX); + // Container Blocks containerBlocks = EnumSet.noneOf(Material.class); containerBlocks.add(Material.CHEST); @@ -325,23 +346,7 @@ public class BukkitUtils { containerBlocks.add(Material.HOPPER); containerBlocks.add(Material.BREWING_STAND); containerBlocks.add(Material.FURNACE); - containerBlocks.add(Material.SHULKER_BOX); - containerBlocks.add(Material.BLACK_SHULKER_BOX); - containerBlocks.add(Material.BLUE_SHULKER_BOX); - containerBlocks.add(Material.LIGHT_GRAY_SHULKER_BOX); - containerBlocks.add(Material.BROWN_SHULKER_BOX); - containerBlocks.add(Material.CYAN_SHULKER_BOX); - containerBlocks.add(Material.GRAY_SHULKER_BOX); - containerBlocks.add(Material.GREEN_SHULKER_BOX); - containerBlocks.add(Material.LIGHT_BLUE_SHULKER_BOX); - containerBlocks.add(Material.MAGENTA_SHULKER_BOX); - containerBlocks.add(Material.LIME_SHULKER_BOX); - containerBlocks.add(Material.ORANGE_SHULKER_BOX); - containerBlocks.add(Material.PINK_SHULKER_BOX); - containerBlocks.add(Material.PURPLE_SHULKER_BOX); - containerBlocks.add(Material.RED_SHULKER_BOX); - containerBlocks.add(Material.WHITE_SHULKER_BOX); - containerBlocks.add(Material.YELLOW_SHULKER_BOX); + containerBlocks.addAll(shulkerBoxBlocks); containerBlocks.add(Material.BARREL); containerBlocks.add(Material.BLAST_FURNACE); containerBlocks.add(Material.SMOKER); @@ -586,6 +591,10 @@ public static Set getContainerBlocks() { return containerBlocks; } + public static Set getShulkerBoxBlocks() { + return shulkerBoxBlocks; + } + public static boolean isConcreteBlock(Material m) { return concreteBlocks.contains(m); } From 8eb93411ec6e83a7661f1e4a8c3c7adf4734b203 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 26 Jan 2020 03:21:12 +0100 Subject: [PATCH 234/399] Configurable command logging --- src/main/java/de/diddiz/LogBlock/Logging.java | 5 +++- .../LogBlock/listeners/ChatLogging.java | 25 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index 79e8e4ae..ba6d7c04 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -46,7 +46,10 @@ public enum Logging { DAYLIGHTDETECTORINTERACT, LECTERNBOOKCHANGE(true), SCAFFOLDING(true), - SHULKER_BOX_CONTENT; + SHULKER_BOX_CONTENT, + PLAYER_COMMANDS, + COMMANDBLOCK_COMMANDS, + CONSOLE_COMMANDS; public static final int length = Logging.values().length; private final boolean defaultEnabled; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChatLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChatLogging.java index e8985f20..baafe636 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChatLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChatLogging.java @@ -3,6 +3,9 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; +import org.bukkit.command.BlockCommandSender; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.minecart.CommandMinecart; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.player.AsyncPlayerChatEvent; @@ -18,7 +21,7 @@ public ChatLogging(LogBlock lb) { @EventHandler(priority = EventPriority.MONITOR) public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { - if (isLogging(event.getPlayer().getWorld(), Logging.CHAT)) { + if (isLogging(event.getPlayer().getWorld(), Logging.PLAYER_COMMANDS)) { consumer.queueChat(Actor.actorFromEntity(event.getPlayer()), event.getMessage()); } } @@ -32,6 +35,24 @@ public void onPlayerChat(AsyncPlayerChatEvent event) { @EventHandler(priority = EventPriority.MONITOR) public void onServerCommand(ServerCommandEvent event) { - consumer.queueChat(new Actor("Console"), "/" + event.getCommand()); + CommandSender sender = event.getSender(); + Actor actor; + if (sender instanceof BlockCommandSender) { + if (!isLogging(((BlockCommandSender) sender).getBlock().getWorld(), Logging.COMMANDBLOCK_COMMANDS)) { + return; + } + actor = new Actor("CommandBlock"); + } else if (sender instanceof CommandMinecart) { + if (!isLogging(((CommandMinecart) sender).getWorld(), Logging.COMMANDBLOCK_COMMANDS)) { + return; + } + actor = new Actor("CommandMinecart"); + } else { + if (!isLogging(Logging.CONSOLE_COMMANDS)) { + return; + } + actor = new Actor("Console"); + } + consumer.queueChat(actor, "/" + event.getCommand()); } } From 1dba9f20f124324e624bb0d77a58d22267389f21 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 26 Jan 2020 06:27:09 +0100 Subject: [PATCH 235/399] create tables and register events if logging commands --- src/main/java/de/diddiz/LogBlock/LogBlock.java | 2 +- src/main/java/de/diddiz/LogBlock/QueryParams.java | 2 +- src/main/java/de/diddiz/LogBlock/Updater.java | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 6078aa1d..613162b1 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -175,7 +175,7 @@ private void registerEvents() { if (isLogging(Logging.KILL)) { pm.registerEvents(new KillLogging(this), this); } - if (isLogging(Logging.CHAT)) { + 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.ENDERMEN)) { diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index dd5ad506..feb9d272 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -975,7 +975,7 @@ public void validate() { } } if (bct == BlockChangeType.CHAT) { - if (!Config.isLogging(Logging.CHAT)) { + if (!(isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS))) { throw new IllegalArgumentException("Chat is not logged"); } if (sum != SummarizationMode.NONE) { diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 42ff25a9..dcdfec3b 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -47,7 +47,7 @@ boolean update() { // } if (configVersion.compareTo(new ComparableVersion("1.2.7")) < 0) { logblock.getLogger().info("Updating tables to 1.2.7 ..."); - if (isLogging(Logging.CHAT)) { + if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { final Connection conn = logblock.getConnection(); try { conn.setAutoCommit(true); @@ -376,7 +376,7 @@ boolean update() { conn.setAutoCommit(true); final Statement st = conn.createStatement(); checkCharset("lb-players", "name", st, false); - if (isLogging(Logging.CHAT)) { + if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { checkCharset("lb-chat", "message", st, false); } for (final WorldConfig wcfg : getLoggedWorlds()) { @@ -395,7 +395,7 @@ boolean update() { if (configVersion.compareTo(new ComparableVersion("1.12.0")) < 0) { logblock.getLogger().info("Updating tables to 1.12.0 ..."); - if (isLogging(Logging.CHAT)) { + if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { final Connection conn = logblock.getConnection(); try { conn.setAutoCommit(true); @@ -739,7 +739,7 @@ boolean update() { conn.setAutoCommit(true); final Statement st = conn.createStatement(); checkCharset("lb-players", "name", st, true); - if (isLogging(Logging.CHAT)) { + if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { checkCharset("lb-chat", "message", st, true); } createIndexIfDoesNotExist("lb-materials", "name", "UNIQUE KEY `name` (`name`(150))", st, true); @@ -802,7 +802,7 @@ void checkTables() throws SQLException { if (!rs.next()) { state.execute("INSERT IGNORE INTO `lb-players` (UUID,playername) VALUES ('log_dummy_record','dummy_record')"); } - if (isLogging(Logging.CHAT)) { + if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { try { createTable(dbm, 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) { From fc1cd5ef2c5a93846a5d57a141353e0fcd568ab8 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 8 Feb 2020 17:33:39 +0100 Subject: [PATCH 236/399] Fix oldConfig check --- src/main/java/de/diddiz/LogBlock/config/Config.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 86f73a2b..eba25d64 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -173,7 +173,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti logblock.saveConfig(); ComparableVersion configVersion = new ComparableVersion(config.getString("version")); - boolean oldConfig = configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion().replace(" (manually compiled)", ""))) < 0; + boolean oldConfig = configVersion.compareTo(new ComparableVersion(CURRENT_CONFIG_VERSION)) < 0; url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database"); user = getStringIncludingInts(config, "mysql.user"); From e1064dd0b184c01bc4025fc964b25af114d4cf38 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 13 Feb 2020 04:17:01 +0100 Subject: [PATCH 237/399] Load mysql driver on startup Fixes #784 --- src/main/java/de/diddiz/LogBlock/LogBlock.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 613162b1..98ad84ce 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -73,6 +73,7 @@ public void onEnable() { } try { getLogger().info("Connecting to " + user + "@" + url + "..."); + Class.forName("com.mysql.jdbc.Driver"); pool = new MySQLConnectionPool(url, user, password, mysqlUseSSL, mysqlRequireSSL); final Connection conn = getConnection(true); if (conn == null) { From 39f58a6bd450a08f566dd4b7a91379b219f9e060 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 13 Feb 2020 05:05:21 +0100 Subject: [PATCH 238/399] Release 1.15.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b1f55e3d..df40158a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.15.1.1-SNAPSHOT + 1.15.2 jar LogBlock From a96f82efae379e3973f66ca7a60a30d335b0c554 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 13 Feb 2020 05:09:27 +0100 Subject: [PATCH 239/399] Back to snapshots --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index df40158a..eca56a05 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.15.2 + 1.15.2.1-SNAPSHOT jar LogBlock From 04b5d9e7ed9d604f524e707abd274b93a2d7f555 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 27 Jun 2020 22:39:29 +0200 Subject: [PATCH 240/399] Snapshots for 1.16.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index eca56a05..4708d017 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.15.2.1-SNAPSHOT + 1.16.1.0-SNAPSHOT jar LogBlock @@ -42,7 +42,7 @@ org.spigotmc spigot-api - 1.15.1-R0.1-SNAPSHOT + 1.16.1-R0.1-SNAPSHOT provided From 3bfb19cdfacea639ab6e5f9a3a6fd28260e61dd6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 27 Jun 2020 22:40:08 +0200 Subject: [PATCH 241/399] Correctly log 1.16 blocks --- src/main/java/de/diddiz/util/BukkitUtils.java | 13 +++++ src/main/java/de/diddiz/util/LoggingUtil.java | 50 +++++++++++++++++-- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index c69c2b4c..b45ac7ad 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -168,6 +168,11 @@ public class BukkitUtils { singleBlockPlants.add(Material.LILY_OF_THE_VALLEY); singleBlockPlants.add(Material.CORNFLOWER); singleBlockPlants.add(Material.WITHER_ROSE); + singleBlockPlants.add(Material.CRIMSON_FUNGUS); + singleBlockPlants.add(Material.WARPED_FUNGUS); + singleBlockPlants.add(Material.CRIMSON_ROOTS); + singleBlockPlants.add(Material.WARPED_ROOTS); + singleBlockPlants.add(Material.NETHER_SPROUTS); doublePlants = EnumSet.noneOf(Material.class); doublePlants.add(Material.TALL_GRASS); @@ -238,6 +243,8 @@ public class BukkitUtils { relativeTopBreakable.addAll(doublePlants); relativeTopBreakable.add(Material.BAMBOO); relativeTopBreakable.add(Material.BAMBOO_SAPLING); + relativeTopBreakable.add(Material.TWISTING_VINES); + relativeTopBreakable.add(Material.TWISTING_VINES_PLANT); for (Material m : Material.values()) { if (m.name().startsWith("POTTED_")) { relativeTopBreakable.add(m); @@ -998,6 +1005,12 @@ public static boolean isSimilarForRollback(Material expected, Material found) { case PUMPKIN_STEM: case ATTACHED_PUMPKIN_STEM: return found == Material.PUMPKIN_STEM || found == Material.ATTACHED_PUMPKIN_STEM; + case TWISTING_VINES: + case TWISTING_VINES_PLANT: + return found == Material.TWISTING_VINES || found == Material.TWISTING_VINES_PLANT; + case WEEPING_VINES: + case WEEPING_VINES_PLANT: + return found == Material.WEEPING_VINES || found == Material.WEEPING_VINES_PLANT; } return false; } diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index a78f02ce..8764c67c 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -27,7 +27,20 @@ public class LoggingUtil { public static void smartLogBlockPlace(Consumer consumer, Actor actor, BlockState replaced, BlockState placed) { Location loc = replaced.getLocation(); - if (!placed.getType().hasGravity() || !BukkitUtils.canDirectlyFallIn(replaced.getBlock().getRelative(BlockFace.DOWN).getType())) { + Material placedType = placed.getType(); + if (!placedType.hasGravity() || !BukkitUtils.canDirectlyFallIn(replaced.getBlock().getRelative(BlockFace.DOWN).getType())) { + if (placedType == Material.TWISTING_VINES) { + Block below = placed.getBlock().getRelative(BlockFace.DOWN); + if (below.getType() == Material.TWISTING_VINES) { + consumer.queueBlockReplace(actor, below.getState(), Material.TWISTING_VINES_PLANT.createBlockData()); + } + } + if (placedType == Material.WEEPING_VINES) { + Block above = placed.getBlock().getRelative(BlockFace.UP); + if (above.getType() == Material.WEEPING_VINES) { + consumer.queueBlockReplace(actor, above.getState(), Material.WEEPING_VINES_PLANT.createBlockData()); + } + } if (BukkitUtils.isEmpty(replaced.getType())) { consumer.queueBlockPlace(actor, placed); } else { @@ -118,6 +131,19 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or if (wcfg == null) { return; } + Material replacedType = origin.getType(); + if (replacedType == Material.TWISTING_VINES || replacedType == Material.TWISTING_VINES_PLANT) { + Block below = origin.getRelative(BlockFace.DOWN); + if (below.getType() == Material.TWISTING_VINES_PLANT) { + consumer.queueBlockReplace(actor, below.getState(), Material.TWISTING_VINES.createBlockData()); + } + } + if (replacedType == Material.WEEPING_VINES || replacedType == Material.WEEPING_VINES_PLANT) { + Block above = origin.getRelative(BlockFace.UP); + if (above.getType() == Material.WEEPING_VINES_PLANT) { + consumer.queueBlockReplace(actor, above.getState(), Material.WEEPING_VINES.createBlockData()); + } + } Block checkBlock = origin.getRelative(BlockFace.UP); Material typeAbove = checkBlock.getType(); @@ -148,6 +174,14 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or } } else { consumer.queueBlockBreak(actor, checkBlock.getState()); + // check next blocks above + checkBlock = checkBlock.getRelative(BlockFace.UP); + typeAbove = checkBlock.getType(); + while (BukkitUtils.getRelativeTopBreakabls().contains(typeAbove)) { + consumer.queueBlockBreak(actor, checkBlock.getState()); + checkBlock = checkBlock.getRelative(BlockFace.UP); + typeAbove = checkBlock.getType(); + } } } else if (typeAbove == Material.LANTERN) { Lantern lantern = (Lantern) checkBlock.getBlockData(); @@ -173,6 +207,16 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or if (bell.getAttachment() == Attachment.CEILING) { consumer.queueBlockBreak(actor, checkBlock.getState()); } + } else if (typeBelow == Material.WEEPING_VINES || typeBelow == Material.WEEPING_VINES_PLANT) { + consumer.queueBlockBreak(actor, checkBlock.getState()); + // check next blocks above + checkBlock = checkBlock.getRelative(BlockFace.DOWN); + typeBelow = checkBlock.getType(); + while (typeBelow == Material.WEEPING_VINES || typeBelow == Material.WEEPING_VINES_PLANT) { + consumer.queueBlockBreak(actor, checkBlock.getState()); + checkBlock = checkBlock.getRelative(BlockFace.DOWN); + typeBelow = checkBlock.getType(); + } } List relativeBreakables = BukkitUtils.getBlocksNearby(origin, BukkitUtils.getRelativeBreakables()); @@ -197,7 +241,7 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or } // Special door check - if (origin.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(origin.getType())) { + if (replacedType == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(replacedType)) { Block doorBlock = origin; // Up or down? @@ -210,7 +254,7 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or if (doorBlock.getType() == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(doorBlock.getType())) { consumer.queueBlockBreak(actor, doorBlock.getState()); } - } else if (BukkitUtils.isDoublePlant(origin.getType())) { // Special double plant check + } else if (BukkitUtils.isDoublePlant(replacedType)) { // Special double plant check Block plantBlock = origin; // Up or down? From 788d8fd4d51162555e153e8c8da8dc0dac3d6f88 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 27 Jun 2020 22:43:33 +0200 Subject: [PATCH 242/399] Release 1.16.1.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4708d017..f24dc8c7 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.16.1.0-SNAPSHOT + 1.16.1.0 jar LogBlock From 1ef7c78c0dc7e95d6a9bd19f1753f52dbca7b958 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 27 Jun 2020 22:45:20 +0200 Subject: [PATCH 243/399] Snapshots for 1.16.1.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f24dc8c7..08a17253 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.16.1.0 + 1.16.1.1-SNAPSHOT jar LogBlock From aba6e4d9c8d736c8d80ebad917136c417d767182 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 2 Jul 2020 04:33:18 +0200 Subject: [PATCH 244/399] Add some missing special block handlings for 1.16 --- .../blockstate/BlockStateCodecSign.java | 3 +- .../LogBlock/listeners/InteractLogging.java | 14 +++ src/main/java/de/diddiz/util/BukkitUtils.java | 91 +++++++++++-------- 3 files changed, 71 insertions(+), 37 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index 5f3a6e60..ee883028 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock.blockstate; +import de.diddiz.util.BukkitUtils; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -12,7 +13,7 @@ public class BlockStateCodecSign implements BlockStateCodec { @Override public Material[] getApplicableMaterials() { - return new Material[] { Material.ACACIA_SIGN, Material.ACACIA_WALL_SIGN, Material.BIRCH_SIGN, Material.BIRCH_WALL_SIGN, Material.DARK_OAK_SIGN, Material.DARK_OAK_WALL_SIGN, Material.JUNGLE_SIGN, Material.JUNGLE_WALL_SIGN, Material.OAK_SIGN, Material.OAK_WALL_SIGN, Material.SPRUCE_SIGN, Material.SPRUCE_WALL_SIGN }; + return BukkitUtils.getAllSignsArray(); } @Override diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index acfbceb9..350c4312 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -60,12 +60,16 @@ public void onPlayerInteract(PlayerInteractEvent event) { case JUNGLE_FENCE_GATE: case ACACIA_FENCE_GATE: case DARK_OAK_FENCE_GATE: + case WARPED_FENCE_GATE: + case CRIMSON_FENCE_GATE: case OAK_TRAPDOOR: case SPRUCE_TRAPDOOR: case BIRCH_TRAPDOOR: case JUNGLE_TRAPDOOR: case ACACIA_TRAPDOOR: case DARK_OAK_TRAPDOOR: + case WARPED_TRAPDOOR: + case CRIMSON_TRAPDOOR: if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { Openable newBlockData = (Openable) blockData.clone(); newBlockData.setOpen(!newBlockData.isOpen()); @@ -121,6 +125,8 @@ public void onPlayerInteract(PlayerInteractEvent event) { case JUNGLE_PRESSURE_PLATE: case ACACIA_PRESSURE_PLATE: case DARK_OAK_PRESSURE_PLATE: + case WARPED_PRESSURE_PLATE: + case CRIMSON_PRESSURE_PLATE: case STONE_PRESSURE_PLATE: case HEAVY_WEIGHTED_PRESSURE_PLATE: case LIGHT_WEIGHTED_PRESSURE_PLATE: @@ -187,6 +193,8 @@ public void onPlayerInteract(PlayerInteractEvent event) { case JUNGLE_DOOR: case ACACIA_DOOR: case DARK_OAK_DOOR: + case WARPED_DOOR: + case CRIMSON_DOOR: if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { Door newBlockData = (Door) blockData.clone(); newBlockData.setOpen(!newBlockData.isOpen()); @@ -200,6 +208,8 @@ public void onPlayerInteract(PlayerInteractEvent event) { case JUNGLE_BUTTON: case ACACIA_BUTTON: case DARK_OAK_BUTTON: + case WARPED_BUTTON: + case CRIMSON_BUTTON: case LEVER: if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { Switch newBlockData = (Switch) blockData.clone(); @@ -215,12 +225,16 @@ public void onPlayerInteract(PlayerInteractEvent event) { case JUNGLE_SIGN: case ACACIA_SIGN: case DARK_OAK_SIGN: + case WARPED_SIGN: + case CRIMSON_SIGN: case OAK_WALL_SIGN: case SPRUCE_WALL_SIGN: case BIRCH_WALL_SIGN: case JUNGLE_WALL_SIGN: case ACACIA_WALL_SIGN: case DARK_OAK_WALL_SIGN: + case WARPED_WALL_SIGN: + case CRIMSON_WALL_SIGN: if (wcfg.isLogging(Logging.SIGNTEXT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { ItemStack stack = event.getItem(); if (stack != null && BukkitUtils.isDye(stack.getType())) { diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index b45ac7ad..d75c520a 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -65,6 +65,9 @@ public class BukkitUtils { private static final Set bedBlocks; private static final Map projectileItems; + private static final EnumSet signs; + private static final EnumSet wallSigns; + private static final EnumSet allSigns; private static final EnumSet buttons; private static final EnumSet pressurePlates; private static final EnumSet woodenDoors; @@ -80,6 +83,8 @@ public class BukkitUtils { pressurePlates.add(Material.JUNGLE_PRESSURE_PLATE); pressurePlates.add(Material.ACACIA_PRESSURE_PLATE); pressurePlates.add(Material.DARK_OAK_PRESSURE_PLATE); + pressurePlates.add(Material.WARPED_PRESSURE_PLATE); + pressurePlates.add(Material.CRIMSON_PRESSURE_PLATE); pressurePlates.add(Material.STONE_PRESSURE_PLATE); pressurePlates.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); pressurePlates.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); @@ -91,6 +96,8 @@ public class BukkitUtils { woodenDoors.add(Material.JUNGLE_DOOR); woodenDoors.add(Material.ACACIA_DOOR); woodenDoors.add(Material.DARK_OAK_DOOR); + woodenDoors.add(Material.WARPED_DOOR); + woodenDoors.add(Material.CRIMSON_DOOR); EnumSet saplings = EnumSet.noneOf(Material.class); saplings.add(Material.OAK_SAPLING); @@ -99,6 +106,8 @@ public class BukkitUtils { saplings.add(Material.JUNGLE_SAPLING); saplings.add(Material.ACACIA_SAPLING); saplings.add(Material.DARK_OAK_SAPLING); + saplings.add(Material.WARPED_FUNGUS); + saplings.add(Material.CRIMSON_FUNGUS); EnumSet carpets = EnumSet.noneOf(Material.class); carpets.add(Material.BLACK_CARPET); @@ -125,6 +134,8 @@ public class BukkitUtils { slabs.add(Material.JUNGLE_SLAB); slabs.add(Material.ACACIA_SLAB); slabs.add(Material.DARK_OAK_SLAB); + slabs.add(Material.WARPED_SLAB); + slabs.add(Material.CRIMSON_SLAB); slabs.add(Material.STONE_SLAB); slabs.add(Material.STONE_BRICK_SLAB); slabs.add(Material.COBBLESTONE_SLAB); @@ -138,6 +149,8 @@ public class BukkitUtils { slabs.add(Material.PRISMARINE_SLAB); slabs.add(Material.DARK_PRISMARINE_SLAB); slabs.add(Material.PRISMARINE_BRICK_SLAB); + slabs.add(Material.BLACKSTONE_SLAB); + slabs.add(Material.POLISHED_BLACKSTONE_SLAB); buttons = EnumSet.noneOf(Material.class); buttons.add(Material.STONE_BUTTON); @@ -147,6 +160,32 @@ public class BukkitUtils { buttons.add(Material.JUNGLE_BUTTON); buttons.add(Material.ACACIA_BUTTON); buttons.add(Material.DARK_OAK_BUTTON); + buttons.add(Material.WARPED_BUTTON); + buttons.add(Material.CRIMSON_BUTTON); + + signs = EnumSet.noneOf(Material.class); + signs.add(Material.OAK_SIGN); + signs.add(Material.SPRUCE_SIGN); + signs.add(Material.BIRCH_SIGN); + signs.add(Material.JUNGLE_SIGN); + signs.add(Material.DARK_OAK_SIGN); + signs.add(Material.ACACIA_SIGN); + signs.add(Material.WARPED_SIGN); + signs.add(Material.CRIMSON_SIGN); + + wallSigns = EnumSet.noneOf(Material.class); + wallSigns.add(Material.OAK_WALL_SIGN); + wallSigns.add(Material.SPRUCE_WALL_SIGN); + wallSigns.add(Material.BIRCH_WALL_SIGN); + wallSigns.add(Material.JUNGLE_WALL_SIGN); + wallSigns.add(Material.DARK_OAK_WALL_SIGN); + wallSigns.add(Material.ACACIA_WALL_SIGN); + wallSigns.add(Material.WARPED_WALL_SIGN); + wallSigns.add(Material.CRIMSON_WALL_SIGN); + + allSigns = EnumSet.noneOf(Material.class); + allSigns.addAll(signs); + allSigns.addAll(wallSigns); singleBlockPlants = EnumSet.noneOf(Material.class); singleBlockPlants.add(Material.GRASS); @@ -194,12 +233,7 @@ public class BukkitUtils { // Blocks that break when they are attached to a block relativeBreakable = EnumSet.noneOf(Material.class); - relativeBreakable.add(Material.ACACIA_WALL_SIGN); - relativeBreakable.add(Material.BIRCH_WALL_SIGN); - relativeBreakable.add(Material.DARK_OAK_WALL_SIGN); - relativeBreakable.add(Material.JUNGLE_WALL_SIGN); - relativeBreakable.add(Material.OAK_WALL_SIGN); - relativeBreakable.add(Material.SPRUCE_WALL_SIGN); + relativeBreakable.addAll(wallSigns); relativeBreakable.add(Material.LADDER); relativeBreakable.addAll(buttons); relativeBreakable.add(Material.REDSTONE_WALL_TORCH); @@ -225,17 +259,13 @@ public class BukkitUtils { relativeTopBreakable.add(Material.ACTIVATOR_RAIL); relativeTopBreakable.add(Material.RAIL); relativeTopBreakable.add(Material.REDSTONE_WIRE); - relativeTopBreakable.add(Material.ACACIA_SIGN); - relativeTopBreakable.add(Material.BIRCH_SIGN); - relativeTopBreakable.add(Material.DARK_OAK_SIGN); - relativeTopBreakable.add(Material.JUNGLE_SIGN); - relativeTopBreakable.add(Material.OAK_SIGN); - relativeTopBreakable.add(Material.SPRUCE_SIGN); + relativeTopBreakable.addAll(signs); relativeTopBreakable.addAll(pressurePlates); relativeTopBreakable.add(Material.SNOW); relativeTopBreakable.add(Material.REPEATER); relativeTopBreakable.add(Material.COMPARATOR); relativeTopBreakable.add(Material.TORCH); + relativeTopBreakable.add(Material.SOUL_TORCH); relativeTopBreakable.add(Material.REDSTONE_TORCH); relativeTopBreakable.addAll(woodenDoors); relativeTopBreakable.add(Material.IRON_DOOR); @@ -253,32 +283,13 @@ public class BukkitUtils { // Blocks that break falling entities fallingEntityKillers = EnumSet.noneOf(Material.class); - fallingEntityKillers.add(Material.ACACIA_SIGN); - fallingEntityKillers.add(Material.ACACIA_WALL_SIGN); - fallingEntityKillers.add(Material.BIRCH_SIGN); - fallingEntityKillers.add(Material.BIRCH_WALL_SIGN); - fallingEntityKillers.add(Material.DARK_OAK_SIGN); - fallingEntityKillers.add(Material.DARK_OAK_WALL_SIGN); - fallingEntityKillers.add(Material.JUNGLE_SIGN); - fallingEntityKillers.add(Material.JUNGLE_WALL_SIGN); - fallingEntityKillers.add(Material.OAK_SIGN); - fallingEntityKillers.add(Material.OAK_WALL_SIGN); - fallingEntityKillers.add(Material.SPRUCE_SIGN); - fallingEntityKillers.add(Material.SPRUCE_WALL_SIGN); + fallingEntityKillers.addAll(signs); + fallingEntityKillers.addAll(wallSigns); fallingEntityKillers.addAll(pressurePlates); fallingEntityKillers.addAll(saplings); - fallingEntityKillers.add(Material.DANDELION); - fallingEntityKillers.add(Material.POPPY); - fallingEntityKillers.add(Material.BLUE_ORCHID); - fallingEntityKillers.add(Material.ALLIUM); - fallingEntityKillers.add(Material.AZURE_BLUET); - fallingEntityKillers.add(Material.ORANGE_TULIP); - fallingEntityKillers.add(Material.WHITE_TULIP); - fallingEntityKillers.add(Material.PINK_TULIP); - fallingEntityKillers.add(Material.RED_TULIP); - fallingEntityKillers.add(Material.OXEYE_DAISY); - fallingEntityKillers.add(Material.BROWN_MUSHROOM); - fallingEntityKillers.add(Material.RED_MUSHROOM); + fallingEntityKillers.addAll(singleBlockPlants); + fallingEntityKillers.remove(Material.GRASS); + fallingEntityKillers.remove(Material.NETHER_SPROUTS); fallingEntityKillers.addAll(doublePlants); fallingEntityKillers.add(Material.WHEAT); fallingEntityKillers.add(Material.CARROT); @@ -289,6 +300,8 @@ public class BukkitUtils { fallingEntityKillers.addAll(slabs); fallingEntityKillers.add(Material.TORCH); fallingEntityKillers.add(Material.WALL_TORCH); + fallingEntityKillers.add(Material.SOUL_TORCH); + fallingEntityKillers.add(Material.SOUL_WALL_TORCH); fallingEntityKillers.add(Material.FLOWER_POT); fallingEntityKillers.add(Material.POWERED_RAIL); fallingEntityKillers.add(Material.DETECTOR_RAIL); @@ -380,6 +393,7 @@ public class BukkitUtils { nonFluidProofBlocks.add(Material.REDSTONE_WALL_TORCH); nonFluidProofBlocks.add(Material.LEVER); nonFluidProofBlocks.add(Material.WALL_TORCH); + nonFluidProofBlocks.add(Material.SOUL_WALL_TORCH); nonFluidProofBlocks.add(Material.TRIPWIRE_HOOK); nonFluidProofBlocks.add(Material.COCOA); nonFluidProofBlocks.addAll(pressurePlates); @@ -390,6 +404,7 @@ public class BukkitUtils { nonFluidProofBlocks.add(Material.BEETROOT); nonFluidProofBlocks.add(Material.NETHER_WART); nonFluidProofBlocks.add(Material.TORCH); + nonFluidProofBlocks.add(Material.SOUL_TORCH); nonFluidProofBlocks.add(Material.FLOWER_POT); nonFluidProofBlocks.add(Material.POWERED_RAIL); nonFluidProofBlocks.add(Material.DETECTOR_RAIL); @@ -1014,4 +1029,8 @@ public static boolean isSimilarForRollback(Material expected, Material found) { } return false; } + + public static Material[] getAllSignsArray() { + return allSigns.toArray(new Material[allSigns.size()]); + } } From 1562bbacea94d36f59de96d9cf0d1cc5669204f4 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 11 Jul 2020 05:43:54 +0200 Subject: [PATCH 245/399] Release 1.16.1.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 08a17253..184ece48 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.16.1.1-SNAPSHOT + 1.16.1.1 jar LogBlock From a63c97bd70c0c5b8849b06eaa22ef2f5ab98bff2 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 11 Jul 2020 05:45:35 +0200 Subject: [PATCH 246/399] Back to snapshots --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 184ece48..78d6c6d8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.16.1.1 + 1.16.1.2-SNAPSHOT jar LogBlock From 5c22beb2e52d72dcd0e45e681100b26e39a6e4a8 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 20 Jul 2020 06:02:23 +0200 Subject: [PATCH 247/399] Make MaterialConverter type safe --- .../java/de/diddiz/LogBlock/Consumer.java | 14 +++++------- .../java/de/diddiz/LogBlock/LogBlock.java | 2 +- .../de/diddiz/LogBlock/MaterialConverter.java | 20 +++++++++-------- .../java/de/diddiz/LogBlock/QueryParams.java | 8 +++---- src/main/java/de/diddiz/LogBlock/Updater.java | 22 +++++++++---------- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 4be454a6..572fcb56 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -230,7 +230,7 @@ public void queueChestAccess(Actor actor, BlockState container, ItemStack itemSt * true if the item was removed */ 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().getKey()))); + queueBlock(actor, loc, type, type, null, null, new ChestAccess(itemStack, remove, MaterialConverter.getOrAddMaterialId(itemStack.getType()))); } /** @@ -327,7 +327,7 @@ public void queueKill(Location location, Actor killer, Actor victim, ItemStack w if (victim == null || !isLogged(location.getWorld())) { return; } - addQueueLast(new KillRow(location, killer == null ? null : killer, victim, weapon == null ? 0 : MaterialConverter.getOrAddMaterialId(weapon.getType().getKey().toString()))); + addQueueLast(new KillRow(location, killer == null ? null : killer, victim, weapon == null ? 0 : MaterialConverter.getOrAddMaterialId(weapon.getType()))); } /** @@ -718,12 +718,10 @@ private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDa return; } - String replacedString = typeBefore.getAsString(); - int replacedMaterialId = MaterialConverter.getOrAddMaterialId(replacedString); - int replacedStateId = MaterialConverter.getOrAddBlockStateId(replacedString); - String typeString = typeAfter.getAsString(); - int typeMaterialId = MaterialConverter.getOrAddMaterialId(typeString); - int typeStateId = MaterialConverter.getOrAddBlockStateId(typeString); + int replacedMaterialId = MaterialConverter.getOrAddMaterialId(typeBefore); + int replacedStateId = MaterialConverter.getOrAddBlockStateId(typeBefore); + int typeMaterialId = MaterialConverter.getOrAddMaterialId(typeAfter); + int typeStateId = MaterialConverter.getOrAddBlockStateId(typeAfter); addQueueLast(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, Utils.serializeYamlConfiguration(stateBefore), typeMaterialId, typeStateId, Utils.serializeYamlConfiguration(stateAfter), ca)); } diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 98ad84ce..36a849ef 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -91,7 +91,7 @@ public void onEnable() { Updater updater = new Updater(this); updater.checkTables(); MaterialConverter.initializeMaterials(getConnection()); - MaterialConverter.getOrAddMaterialId(Material.AIR.getKey()); // AIR must be the first entry + MaterialConverter.getOrAddMaterialId(Material.AIR); // AIR must be the first entry EntityTypeConverter.initializeEntityTypes(getConnection()); if (updater.update()) { load(this); diff --git a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java index c462a25a..dbafc514 100644 --- a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java +++ b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java @@ -11,7 +11,6 @@ import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.NamespacedKey; import org.bukkit.block.data.BlockData; public class MaterialConverter { @@ -31,16 +30,15 @@ public class MaterialConverter { } } - public static int getOrAddMaterialId(NamespacedKey nameSpaceKey) { - return getOrAddMaterialId(nameSpaceKey.toString()); + public static int getOrAddMaterialId(BlockData blockData) { + return getOrAddMaterialId(blockData == null ? Material.AIR : blockData.getMaterial()); } - public static int getOrAddMaterialId(String blockDataString) { - String materialString = blockDataString; - int dataPart = blockDataString.indexOf("["); - if (dataPart >= 0) { - materialString = blockDataString.substring(0, dataPart); + public static int getOrAddMaterialId(Material material) { + if (material == null) { + material = Material.AIR; } + String materialString = material.getKey().toString(); Integer key = materialToID.get(materialString); int tries = 0; while (key == null && tries < 10) { @@ -78,7 +76,11 @@ public static int getOrAddMaterialId(String blockDataString) { return key.intValue(); } - public static int getOrAddBlockStateId(String blockDataString) { + public static int getOrAddBlockStateId(BlockData blockData) { + if (blockData == null) { + blockData = Material.AIR.createBlockData(); + } + String blockDataString = blockData.getAsString(); int dataPart = blockDataString.indexOf("["); if (dataPart < 0) { return -1; diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index feb9d272..288e7407 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -756,7 +756,7 @@ public void parseArgs(CommandSender sender, List args, boolean validate) throw new IllegalArgumentException("No material matching: '" + weaponName + "'"); } types.add(mat); - typeIds.add(MaterialConverter.getOrAddMaterialId(mat.getKey())); + typeIds.add(MaterialConverter.getOrAddMaterialId(mat)); } needWeapon = true; } else if (param.equals("block") || param.equals("type")) { @@ -778,7 +778,7 @@ public void parseArgs(CommandSender sender, List args, boolean validate) } } for (Material mat : tag.getValues()) { - typeIds.add(MaterialConverter.getOrAddMaterialId(mat.getKey())); + typeIds.add(MaterialConverter.getOrAddMaterialId(mat)); } typeTags.add(tag); } else if (blockName.contains("*")) { @@ -807,7 +807,7 @@ public void parseArgs(CommandSender sender, List args, boolean validate) } for (Material mat : matched) { types.add(mat); - typeIds.add(MaterialConverter.getOrAddMaterialId(mat.getKey())); + typeIds.add(MaterialConverter.getOrAddMaterialId(mat)); } } else { final Material mat = Material.matchMaterial(blockName); @@ -815,7 +815,7 @@ public void parseArgs(CommandSender sender, List args, boolean validate) throw new IllegalArgumentException("No material matching: '" + blockName + "'"); } types.add(mat); - typeIds.add(MaterialConverter.getOrAddMaterialId(mat.getKey())); + typeIds.add(MaterialConverter.getOrAddMaterialId(mat)); } } } else if (param.equals("area")) { diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index dcdfec3b..562d81d6 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -454,8 +454,8 @@ boolean update() { } try { - String replacedBlockData = materialUpdater.getBlockData(replaced, data).getAsString(); - String setBlockData = materialUpdater.getBlockData(type, data).getAsString(); + BlockData replacedBlockData = materialUpdater.getBlockData(replaced, data); + BlockData setBlockData = materialUpdater.getBlockData(type, data); int newReplacedId = MaterialConverter.getOrAddMaterialId(replacedBlockData); int newReplacedData = MaterialConverter.getOrAddBlockStateId(replacedBlockData); @@ -536,7 +536,7 @@ boolean update() { insertChestData.setInt(1, id); insertChestData.setBytes(2, Utils.saveItemStack(stack)); insertChestData.setInt(3, amount >= 0 ? 0 : 1); - insertChestData.setInt(4, MaterialConverter.getOrAddMaterialId(weaponMaterial.getKey())); + insertChestData.setInt(4, MaterialConverter.getOrAddMaterialId(weaponMaterial)); insertChestData.addBatch(); deleteChest.setInt(1, id); @@ -592,7 +592,7 @@ boolean update() { if (weaponMaterial == null) { weaponMaterial = Material.AIR; } - int newWeapon = MaterialConverter.getOrAddMaterialId(weaponMaterial.getKey()); + int newWeapon = MaterialConverter.getOrAddMaterialId(weaponMaterial); if (newWeapon != weapon) { anyUpdate = true; updateWeaponStatement.setInt(1, newWeapon); @@ -860,19 +860,19 @@ private void updateMaterialsPost1_13() { if (comparablePreviousMinecraftVersion.compareTo("1.14") < 0 && comparableCurrentMinecraftVersion.compareTo("1.14") >= 0) { logblock.getLogger().info("[Updater] Upgrading Materials to 1.14"); - renameMaterial("minecraft:sign", "minecraft:oak_sign"); - renameMaterial("minecraft:wall_sign", "minecraft:oak_wall_sign"); - renameMaterial("minecraft:stone_slab", "minecraft:smooth_stone_slab"); - renameMaterial("minecraft:rose_red", "minecraft:red_dye"); - renameMaterial("minecraft:dandelion_yellow", "minecraft:yellow_dye"); - renameMaterial("minecraft:cactus_green", "minecraft:green_dye"); + renameMaterial("minecraft:sign", Material.OAK_SIGN); + renameMaterial("minecraft:wall_sign", Material.OAK_WALL_SIGN); + renameMaterial("minecraft:stone_slab", Material.SMOOTH_STONE_SLAB); + renameMaterial("minecraft:rose_red", Material.RED_DYE); + renameMaterial("minecraft:dandelion_yellow", Material.YELLOW_DYE); + renameMaterial("minecraft:cactus_green", Material.GREEN_DYE); } config.set("previousMinecraftVersion", currentMinecraftVersion); logblock.saveConfig(); } - private void renameMaterial(String oldName, String newName) { + private void renameMaterial(String oldName, Material newName) { final Connection conn = logblock.getConnection(); try { conn.setAutoCommit(false); From 650f7e20f1eacfddefa70b041a1be901d03bef39 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 20 Jul 2020 06:17:06 +0200 Subject: [PATCH 248/399] Make MaterialConverter and EntityTypeConverter thread safe --- .../de/diddiz/LogBlock/EntityTypeConverter.java | 8 ++++---- .../de/diddiz/LogBlock/MaterialConverter.java | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java b/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java index 88ca1ef2..7b96ca3a 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java +++ b/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java @@ -16,7 +16,7 @@ public class EntityTypeConverter { private static HashMap entityTypeToId = new HashMap<>(); private static int nextEntityTypeId; - public static int getOrAddEntityTypeId(EntityType entityType) { + public synchronized static int getOrAddEntityTypeId(EntityType entityType) { Integer key = entityTypeToId.get(entityType); int tries = 0; while (key == null && tries < 10) { @@ -54,7 +54,7 @@ public static int getOrAddEntityTypeId(EntityType entityType) { return key.intValue(); } - public static EntityType getEntityType(int entityTypeId) { + public synchronized static EntityType getEntityType(int entityTypeId) { return entityTypeId >= 0 && entityTypeId < idToEntityType.length ? idToEntityType[entityTypeId] : null; } @@ -73,7 +73,7 @@ private static void reinitializeEntityTypesCatchException() { } } - public static void initializeEntityTypes(Connection connection) throws SQLException { + protected synchronized static void initializeEntityTypes(Connection connection) throws SQLException { Statement smt = connection.createStatement(); ResultSet rs = smt.executeQuery("SELECT id, name FROM `lb-entitytypes`"); while (rs.next()) { @@ -93,7 +93,7 @@ public static void initializeEntityTypes(Connection connection) throws SQLExcept connection.close(); } - private synchronized static void internalAddEntityType(int key, EntityType entityType) { + private static void internalAddEntityType(int key, EntityType entityType) { entityTypeToId.put(entityType, key); int length = idToEntityType.length; while (length <= key) { diff --git a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java index dbafc514..3f4034cf 100644 --- a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java +++ b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java @@ -30,11 +30,11 @@ public class MaterialConverter { } } - public static int getOrAddMaterialId(BlockData blockData) { + public synchronized static int getOrAddMaterialId(BlockData blockData) { return getOrAddMaterialId(blockData == null ? Material.AIR : blockData.getMaterial()); } - public static int getOrAddMaterialId(Material material) { + public synchronized static int getOrAddMaterialId(Material material) { if (material == null) { material = Material.AIR; } @@ -76,7 +76,7 @@ public static int getOrAddMaterialId(Material material) { return key.intValue(); } - public static int getOrAddBlockStateId(BlockData blockData) { + public synchronized static int getOrAddBlockStateId(BlockData blockData) { if (blockData == null) { blockData = Material.AIR.createBlockData(); } @@ -123,7 +123,7 @@ public static int getOrAddBlockStateId(BlockData blockData) { return key.intValue(); } - public static BlockData getBlockData(int materialId, int blockStateId) { + public synchronized static BlockData getBlockData(int materialId, int blockStateId) { String material = materialId >= 0 && materialId < idToMaterial.length ? idToMaterial[materialId] : null; if (material == null) { return null; @@ -143,7 +143,7 @@ public static BlockData getBlockData(int materialId, int blockStateId) { } } - public static Material getMaterial(int materialId) { + public synchronized static Material getMaterial(int materialId) { return materialId >= 0 && materialId < idToMaterial.length ? materialKeyToMaterial.get(idToMaterial[materialId]) : null; } @@ -162,7 +162,7 @@ private static void reinitializeMaterialsCatchException() { } } - public static void initializeMaterials(Connection connection) throws SQLException { + protected synchronized static void initializeMaterials(Connection connection) throws SQLException { Statement smt = connection.createStatement(); ResultSet rs = smt.executeQuery("SELECT id, name FROM `lb-materials`"); while (rs.next()) { @@ -182,7 +182,7 @@ public static void initializeMaterials(Connection connection) throws SQLExceptio connection.close(); } - private synchronized static void internalAddMaterial(int key, String materialString) { + private static void internalAddMaterial(int key, String materialString) { materialToID.put(materialString, key); int length = idToMaterial.length; while (length <= key) { @@ -197,7 +197,7 @@ private synchronized static void internalAddMaterial(int key, String materialStr } } - private synchronized static void internalAddBlockState(int key, String materialString) { + private static void internalAddBlockState(int key, String materialString) { blockStateToID.put(materialString, key); int length = idToBlockState.length; while (length <= key) { From 6dcca54637cf0cc62ae8663236242df66c371cc8 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 20 Jul 2020 06:47:43 +0200 Subject: [PATCH 249/399] Do not use the numeric material/entity ids for the api --- .../java/de/diddiz/LogBlock/QueryParams.java | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 288e7407..5e353d48 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -72,10 +72,8 @@ public final class QueryParams implements Cloneable { public CuboidRegion sel = null; public SummarizationMode sum = SummarizationMode.NONE; public List types = new ArrayList<>(); - public List> typeTags = new ArrayList<>(); - public List typeIds = new ArrayList<>(); + public List> typeTags = new ArrayList<>(); public List entityTypes = new ArrayList<>(); - public List entityTypeIds = new ArrayList<>(); public World world = null; public String match = null; public boolean needCount = false, needId = false, needDate = false, needType = false, needData = false, needPlayerId = false, needPlayer = false, needCoords = false, needChestAccess = false, needMessage = false, needKiller = false, needVictim = false, needWeapon = false; @@ -484,6 +482,7 @@ public String getWhere(BlockChangeType blockChangeType) { } } } else if (blockChangeType == BlockChangeType.ENTITIES || blockChangeType == BlockChangeType.ENTITIES_CREATED || blockChangeType == BlockChangeType.ENTITIES_KILLED) { + Set entityTypeIds = getEntityTypeIds(); if (!entityTypeIds.isEmpty()) { if (excludeBlocksEntitiesMode) { where.append("NOT "); @@ -502,6 +501,7 @@ public String getWhere(BlockChangeType blockChangeType) { where.append("action = " + EntityChange.EntityChangeType.KILL.ordinal() + " AND "); } } else { + Set typeIds = getTypeIds(); switch (blockChangeType) { case ALL: if (!typeIds.isEmpty()) { @@ -756,7 +756,6 @@ public void parseArgs(CommandSender sender, List args, boolean validate) throw new IllegalArgumentException("No material matching: '" + weaponName + "'"); } types.add(mat); - typeIds.add(MaterialConverter.getOrAddMaterialId(mat)); } needWeapon = true; } else if (param.equals("block") || param.equals("type")) { @@ -777,9 +776,6 @@ public void parseArgs(CommandSender sender, List args, boolean validate) throw new IllegalArgumentException("No block tag matching: '" + blockName + "'"); } } - for (Material mat : tag.getValues()) { - typeIds.add(MaterialConverter.getOrAddMaterialId(mat)); - } typeTags.add(tag); } else if (blockName.contains("*")) { StringBuilder sb = new StringBuilder(); @@ -807,7 +803,6 @@ public void parseArgs(CommandSender sender, List args, boolean validate) } for (Material mat : matched) { types.add(mat); - typeIds.add(MaterialConverter.getOrAddMaterialId(mat)); } } else { final Material mat = Material.matchMaterial(blockName); @@ -815,7 +810,6 @@ public void parseArgs(CommandSender sender, List args, boolean validate) throw new IllegalArgumentException("No material matching: '" + blockName + "'"); } types.add(mat); - typeIds.add(MaterialConverter.getOrAddMaterialId(mat)); } } } else if (param.equals("area")) { @@ -890,7 +884,6 @@ public void parseArgs(CommandSender sender, List args, boolean validate) throw new IllegalArgumentException("No entity type matching: '" + entityTypeName + "'"); } entityTypes.add(entityType); - entityTypeIds.add(EntityTypeConverter.getOrAddEntityTypeId(entityType)); } } } else if (param.equals("all")) { @@ -1008,10 +1001,8 @@ public QueryParams clone() { params.players = new ArrayList<>(players); params.killers = new ArrayList<>(killers); params.victims = new ArrayList<>(victims); - params.typeIds = new ArrayList<>(typeIds); params.types = new ArrayList<>(types); params.typeTags = new ArrayList<>(typeTags); - params.entityTypeIds = new ArrayList<>(entityTypeIds); params.entityTypes = new ArrayList<>(entityTypes); params.loc = loc == null ? null : loc.clone(); params.sel = sel == null ? null : sel.clone(); @@ -1021,6 +1012,33 @@ public QueryParams clone() { } } + private Set getTypeIds() { + HashSet typeIds = new HashSet<>(); + for (Material type : types) { + if (type != null) { + typeIds.add(MaterialConverter.getOrAddMaterialId(type)); + } + } + for (Tag tag : typeTags) { + if (tag != null) { + for (Material type : tag.getValues()) { + typeIds.add(MaterialConverter.getOrAddMaterialId(type)); + } + } + } + return typeIds; + } + + private Set getEntityTypeIds() { + HashSet typeIds = new HashSet<>(); + for (EntityType type : entityTypes) { + if (type != null) { + typeIds.add(EntityTypeConverter.getOrAddEntityTypeId(type)); + } + } + return typeIds; + } + private static String[] getValues(List args, int offset, int minParams) { // The variable i will store the last value's index int i; @@ -1055,10 +1073,8 @@ public void merge(QueryParams p) { killers.addAll(p.killers); victims.addAll(p.victims); excludePlayersMode = p.excludePlayersMode; - typeIds.addAll(p.typeIds); types.addAll(p.types); typeTags.addAll(p.typeTags); - entityTypeIds.addAll(p.entityTypeIds); entityTypes.addAll(p.entityTypes); loc = p.loc == null ? null : p.loc.clone(); radius = p.radius; From 6a398a67abc61249778565b5583d74525ee9a7b6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 20 Jul 2020 07:13:32 +0200 Subject: [PATCH 250/399] Protect against sql injections when using the api --- .../java/de/diddiz/LogBlock/QueryParams.java | 23 +++++++++--------- src/main/java/de/diddiz/util/SqlUtil.java | 24 +++++++++++++++++++ 2 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 src/main/java/de/diddiz/util/SqlUtil.java diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 5e353d48..f459ea76 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -3,6 +3,7 @@ import de.diddiz.LogBlock.config.Config; import de.diddiz.util.BukkitUtils; import de.diddiz.util.CuboidRegion; +import de.diddiz.util.SqlUtil; import de.diddiz.util.Utils; import de.diddiz.worldedit.WorldEditHelper; import org.bukkit.Location; @@ -425,9 +426,9 @@ public String getWhere(BlockChangeType blockChangeType) { if (match != null && match.length() > 0) { final boolean unlike = match.startsWith("-"); if (match.length() > 3 && !unlike || match.length() > 4) { - where.append("MATCH (message) AGAINST ('").append(match).append("' IN BOOLEAN MODE) AND "); + where.append("MATCH (message) AGAINST ('").append(SqlUtil.escapeString(match)).append("' IN BOOLEAN MODE) AND "); } else { - where.append("message ").append(unlike ? "NOT " : "").append("LIKE '%").append(unlike ? match.substring(1) : match).append("%' AND "); + where.append("message ").append(unlike ? "NOT " : "").append("LIKE '%").append(SqlUtil.escapeString(unlike ? match.substring(1) : match, true)).append("%' AND "); } } } else if (blockChangeType == BlockChangeType.KILLS) { @@ -435,19 +436,19 @@ public String getWhere(BlockChangeType blockChangeType) { if (!excludePlayersMode) { where.append('('); for (final String killerName : players) { - where.append("killers.playername = '").append(killerName).append("' OR "); + where.append("killers.playername = '").append(SqlUtil.escapeString(killerName)).append("' OR "); } for (final String victimName : players) { - where.append("victims.playername = '").append(victimName).append("' OR "); + where.append("victims.playername = '").append(SqlUtil.escapeString(victimName)).append("' OR "); } where.delete(where.length() - 4, where.length()); where.append(") AND "); } else { for (final String killerName : players) { - where.append("killers.playername != '").append(killerName).append("' AND "); + where.append("killers.playername != '").append(SqlUtil.escapeString(killerName)).append("' AND "); } for (final String victimName : players) { - where.append("victims.playername != '").append(victimName).append("' AND "); + where.append("victims.playername != '").append(SqlUtil.escapeString(victimName)).append("' AND "); } } } @@ -456,13 +457,13 @@ public String getWhere(BlockChangeType blockChangeType) { if (!excludeKillersMode) { where.append('('); for (final String killerName : killers) { - where.append("killers.playername = '").append(killerName).append("' OR "); + where.append("killers.playername = '").append(SqlUtil.escapeString(killerName)).append("' OR "); } where.delete(where.length() - 4, where.length()); where.append(") AND "); } else { for (final String killerName : killers) { - where.append("killers.playername != '").append(killerName).append("' AND "); + where.append("killers.playername != '").append(SqlUtil.escapeString(killerName)).append("' AND "); } } } @@ -613,13 +614,13 @@ public String getWhere(BlockChangeType blockChangeType) { if (!excludePlayersMode) { where.append('('); for (final String playerName : players) { - where.append("playername = '").append(playerName).append("' OR "); + where.append("playername = '").append(SqlUtil.escapeString(playerName)).append("' OR "); } where.delete(where.length() - 4, where.length()); where.append(") AND "); } else { for (final String playerName : players) { - where.append("playername != '").append(playerName).append("' AND "); + where.append("playername != '").append(SqlUtil.escapeString(playerName)).append("' AND "); } } } @@ -921,7 +922,7 @@ public void parseArgs(CommandSender sender, List args, boolean validate) if (values.length == 0) { throw new IllegalArgumentException("No arguments for '" + param + "'"); } - match = mysqlTextEscape(join(values, " ")); + match = join(values, " "); } else if (param.equals("loc") || param.equals("location")) { final String[] vectors = values.length == 1 ? values[0].split(":") : values; if (vectors.length != 3) { diff --git a/src/main/java/de/diddiz/util/SqlUtil.java b/src/main/java/de/diddiz/util/SqlUtil.java new file mode 100644 index 00000000..d84df36c --- /dev/null +++ b/src/main/java/de/diddiz/util/SqlUtil.java @@ -0,0 +1,24 @@ +package de.diddiz.util; + +public class SqlUtil { + public static String escapeString(String s) { + return escapeString(s, false); + } + + public static String escapeString(String s, boolean escapeMatcher) { + s = s.replace("\u0000", "\\0"); + s = s.replace("\u0026", "\\Z"); + s = s.replace("\\", "\\\\"); + s = s.replace("'", "\\'"); + s = s.replace("\"", "\\\""); + s = s.replace("\b", "\\b"); + s = s.replace("\n", "\\n"); + s = s.replace("\r", "\\r"); + s = s.replace("\t", "\\t"); + if (escapeMatcher) { + s = s.replace("%", "\\%"); + s = s.replace("_", "\\_"); + } + return s; + } +} From 0d7a8016a128eab3f7cef1bbb53b237514d13b6b Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 9 Aug 2020 23:25:30 +0200 Subject: [PATCH 251/399] Do not add unnecessary materials or entity types to the database --- .../diddiz/LogBlock/EntityTypeConverter.java | 4 +++ .../de/diddiz/LogBlock/MaterialConverter.java | 27 ++++++++++++++++++- .../java/de/diddiz/LogBlock/QueryParams.java | 20 +++++++++++--- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java b/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java index 7b96ca3a..8a99d50b 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java +++ b/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java @@ -16,6 +16,10 @@ public class EntityTypeConverter { private static HashMap entityTypeToId = new HashMap<>(); private static int nextEntityTypeId; + public synchronized static int getExistingEntityTypeId(EntityType entityType) { + return entityType == null ? null : entityTypeToId.get(entityType); + } + public synchronized static int getOrAddEntityTypeId(EntityType entityType) { Integer key = entityTypeToId.get(entityType); int tries = 0; diff --git a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java index 3f4034cf..9dbceac7 100644 --- a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java +++ b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java @@ -30,6 +30,18 @@ public class MaterialConverter { } } + public synchronized static Integer getExistingMaterialId(BlockData blockData) { + return blockData == null ? null : getExistingMaterialId(blockData.getMaterial()); + } + + public synchronized static Integer getExistingMaterialId(Material material) { + if (material == null) { + return null; + } + String materialString = material.getKey().toString(); + return materialToID.get(materialString); + } + public synchronized static int getOrAddMaterialId(BlockData blockData) { return getOrAddMaterialId(blockData == null ? Material.AIR : blockData.getMaterial()); } @@ -76,9 +88,22 @@ public synchronized static int getOrAddMaterialId(Material material) { return key.intValue(); } + public synchronized static Integer getExistingBlockStateId(BlockData blockData) { + if (blockData == null) { + return -1; + } + String blockDataString = blockData.getAsString(); + int dataPart = blockDataString.indexOf("["); + if (dataPart < 0) { + return -1; + } + String materialString = blockDataString.substring(dataPart); + return blockStateToID.get(materialString); + } + public synchronized static int getOrAddBlockStateId(BlockData blockData) { if (blockData == null) { - blockData = Material.AIR.createBlockData(); + return -1; } String blockDataString = blockData.getAsString(); int dataPart = blockDataString.indexOf("["); diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index f459ea76..e3a1035a 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -1017,16 +1017,26 @@ private Set getTypeIds() { HashSet typeIds = new HashSet<>(); for (Material type : types) { if (type != null) { - typeIds.add(MaterialConverter.getOrAddMaterialId(type)); + Integer id = MaterialConverter.getExistingMaterialId(type); + if (id != null) { + typeIds.add(id); + } } } for (Tag tag : typeTags) { if (tag != null) { for (Material type : tag.getValues()) { - typeIds.add(MaterialConverter.getOrAddMaterialId(type)); + Integer id = MaterialConverter.getExistingMaterialId(type); + if (id != null) { + typeIds.add(id); + } } } } + // add invalid id, so the type list is not ignored + if ((!types.isEmpty() || !typeTags.isEmpty()) && typeIds.isEmpty()) { + typeIds.add(-1); + } return typeIds; } @@ -1034,9 +1044,13 @@ private Set getEntityTypeIds() { HashSet typeIds = new HashSet<>(); for (EntityType type : entityTypes) { if (type != null) { - typeIds.add(EntityTypeConverter.getOrAddEntityTypeId(type)); + typeIds.add(EntityTypeConverter.getExistingEntityTypeId(type)); } } + // add invalid id, so the type list is not ignored + if (!entityTypes.isEmpty() && typeIds.isEmpty()) { + typeIds.add(-1); + } return typeIds; } From 35f921a9a0b70777b8de9e9290bfc5b457c9e3e8 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 23 Aug 2020 05:40:15 +0200 Subject: [PATCH 252/399] Fix loading old walls --- .../de/diddiz/LogBlock/MaterialConverter.java | 19 ++++++++++++++++++- src/main/resources/blockdata.txt | 4 ++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java index 9dbceac7..3d0988cb 100644 --- a/src/main/java/de/diddiz/LogBlock/MaterialConverter.java +++ b/src/main/java/de/diddiz/LogBlock/MaterialConverter.java @@ -154,7 +154,7 @@ public synchronized static BlockData getBlockData(int materialId, int blockState return null; } if (blockStateId >= 0 && blockStateId < idToBlockState.length && idToBlockState[blockStateId] != null) { - material = material + idToBlockState[blockStateId]; + material = material + updateBlockState(material, idToBlockState[blockStateId]); } try { return Bukkit.createBlockData(material); @@ -236,4 +236,21 @@ private static void internalAddBlockState(int key, String materialString) { nextBlockStateId = key + 1; } } + + private static String updateBlockState(String material, String blockState) { + // since 1.16 + if (material.endsWith("_wall")) { + if (blockState.contains("east=false") || blockState.contains("east=true")) { + blockState = blockState.replace("east=false", "east=none"); + blockState = blockState.replace("west=false", "west=none"); + blockState = blockState.replace("north=false", "north=none"); + blockState = blockState.replace("south=false", "south=none"); + blockState = blockState.replace("east=true", "east=low"); + blockState = blockState.replace("west=true", "west=low"); + blockState = blockState.replace("north=true", "north=low"); + blockState = blockState.replace("south=true", "south=low"); + } + } + return blockState; + } } diff --git a/src/main/resources/blockdata.txt b/src/main/resources/blockdata.txt index 4a6dd576..8859bb30 100644 --- a/src/main/resources/blockdata.txt +++ b/src/main/resources/blockdata.txt @@ -1113,8 +1113,8 @@ 137:14,minecraft:command_block[conditional=true,facing=down] 137:15,minecraft:command_block[conditional=true,facing=up] 138:0,minecraft:beacon -139:0,minecraft:cobblestone_wall[east=false,north=false,south=false,up=false,waterlogged=false,west=false] -139:1,minecraft:mossy_cobblestone_wall[east=false,north=false,south=false,up=false,waterlogged=false,west=false] +139:0,minecraft:cobblestone_wall[east=none,north=none,south=none,up=false,waterlogged=false,west=none] +139:1,minecraft:mossy_cobblestone_wall[east=none,north=none,south=none,up=false,waterlogged=false,west=none] 140:0,minecraft:flower_pot 141:0,minecraft:carrots[age=0] 141:1,minecraft:carrots[age=1] From 24b5455f0828d62bd3d8ad693cd12126cb6dfcbb Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 23 Aug 2020 07:10:11 +0200 Subject: [PATCH 253/399] Use Spigots new HoverEvent api --- src/main/java/de/diddiz/util/BukkitUtils.java | 3 ++- src/main/java/de/diddiz/util/MessagingUtil.java | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index d75c520a..2cab998d 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -17,6 +17,7 @@ import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.HoverEvent.Action; import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.chat.hover.content.Text; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Chunk; @@ -759,7 +760,7 @@ public static TextComponent toString(ItemStack stack) { } } if (metaStarted) { - msg.setHoverEvent(new HoverEvent(Action.SHOW_TEXT, new BaseComponent[] { hover })); + msg.setHoverEvent(new HoverEvent(Action.SHOW_TEXT, new Text(new BaseComponent[] { hover }))); } return msg; diff --git a/src/main/java/de/diddiz/util/MessagingUtil.java b/src/main/java/de/diddiz/util/MessagingUtil.java index f1c81288..b9f6a22f 100644 --- a/src/main/java/de/diddiz/util/MessagingUtil.java +++ b/src/main/java/de/diddiz/util/MessagingUtil.java @@ -9,9 +9,9 @@ import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ClickEvent; -import net.md_5.bungee.api.chat.ComponentBuilder; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.chat.hover.content.Text; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.data.BlockData; @@ -41,7 +41,7 @@ public static TextComponent brackets(BracketType type, BaseComponent... content) public static TextComponent prettyDate(long date) { TextComponent tc = brackets(BracketType.STANDARD, createTextComponentWithColor(Config.formatterShort.format(date), TypeColor.DATE.getColor())); - tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(Config.formatter.format(date)).create())); + tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(Config.formatter.format(date)))); return tc; } @@ -73,7 +73,7 @@ public static TextComponent prettyMaterial(BlockData material) { int bracket2 = bdString.indexOf("]", bracket); if (bracket2 >= 0) { String state = bdString.substring(bracket + 1, bracket2).replace(',', '\n'); - tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(state).create())); + tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(state))); } } return tc; @@ -96,7 +96,7 @@ public static TextComponent prettyLocation(int x, int y, int z, int entryId) { tc.addExtra(createTextComponentWithColor(Integer.toString(z), TypeColor.COORDINATE.getColor())); if (entryId > 0) { tc.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/lb tp " + entryId)); - tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("Teleport here").create())); + tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Teleport here"))); } return tc; } From d548206c3a12c14e55b79158d327a62e5d94f7bf Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 28 Aug 2020 05:34:48 +0200 Subject: [PATCH 254/399] Workaround for SPIGOT-6025 (catch the exception and log it) --- src/main/java/de/diddiz/util/BukkitUtils.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 2cab998d..848e5ed7 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -1,6 +1,8 @@ package de.diddiz.util; import static de.diddiz.util.MessagingUtil.prettyMaterial; + +import de.diddiz.LogBlock.LogBlock; import java.io.File; import java.util.ArrayList; import java.util.Arrays; @@ -11,6 +13,7 @@ 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; import net.md_5.bungee.api.chat.BaseComponent; @@ -525,7 +528,11 @@ public static Location getInventoryHolderLocation(InventoryHolder holder) { public static ItemStack[] compareInventories(ItemStack[] items1, ItemStack[] items2) { final ArrayList diff = new ArrayList<>(); for (ItemStack current : items2) { - diff.add(new ItemStack(current)); + try { + diff.add(new ItemStack(current)); + } catch (NullPointerException e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not clone ItemStack, probably Spigot bug SPIGOT-6025", e); // SPIGOT-6025 + } } for (ItemStack previous : items1) { boolean found = false; @@ -542,9 +549,13 @@ public static ItemStack[] compareInventories(ItemStack[] items1, ItemStack[] ite } } if (!found) { - ItemStack subtracted = new ItemStack(previous); - subtracted.setAmount(-subtracted.getAmount()); - diff.add(subtracted); + try { + ItemStack subtracted = new ItemStack(previous); + subtracted.setAmount(-subtracted.getAmount()); + diff.add(subtracted); + } catch (NullPointerException e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not clone ItemStack, probably Spigot bug SPIGOT-6025", e); // SPIGOT-6025 + } } } return diff.toArray(new ItemStack[diff.size()]); From 42715de2659c5e27ff1d3d8fb22c654947e415e2 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 31 Aug 2020 00:28:12 +0200 Subject: [PATCH 255/399] getExistingEntityTypeId should return Integer instead of int Fixes #804 --- src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java | 2 +- src/main/java/de/diddiz/LogBlock/QueryParams.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java b/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java index 8a99d50b..c1fcc597 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java +++ b/src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java @@ -16,7 +16,7 @@ public class EntityTypeConverter { private static HashMap entityTypeToId = new HashMap<>(); private static int nextEntityTypeId; - public synchronized static int getExistingEntityTypeId(EntityType entityType) { + public synchronized static Integer getExistingEntityTypeId(EntityType entityType) { return entityType == null ? null : entityTypeToId.get(entityType); } diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index e3a1035a..9bf68947 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -1043,8 +1043,9 @@ private Set getTypeIds() { private Set getEntityTypeIds() { HashSet typeIds = new HashSet<>(); for (EntityType type : entityTypes) { - if (type != null) { - typeIds.add(EntityTypeConverter.getExistingEntityTypeId(type)); + Integer id = EntityTypeConverter.getExistingEntityTypeId(type); + if (id != null) { + typeIds.add(id); } } // add invalid id, so the type list is not ignored From ac462261dc71a20981477ca12d33c15fa1036c16 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 16 Jan 2021 06:20:36 +0100 Subject: [PATCH 256/399] Add missing entityid index for entities tables --- src/main/java/de/diddiz/LogBlock/Updater.java | 20 ++++++++++++++++++- .../de/diddiz/LogBlock/config/Config.java | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 562d81d6..8e80e165 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -729,6 +729,24 @@ boolean update() { config.set("version", "1.13.1"); } + if (configVersion.compareTo(new ComparableVersion("1.16.0")) < 0) { + for (final WorldConfig wcfg : getLoggedWorlds()) { + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + st.execute("ALTER TABLE `" + wcfg.table + "-entities` KEY entityid (entityid)"); + logblock.getLogger().info("Added index for table " + wcfg.table + "-entities"); + st.close(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + } + config.set("version", "1.16.0"); + } + if (configVersion.compareTo(new ComparableVersion(Config.CURRENT_CONFIG_VERSION)) < 0) { config.set("version", Config.CURRENT_CONFIG_VERSION); } @@ -821,7 +839,7 @@ void checkTables() throws SQLException { createTable(dbm, state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id))"); } createTable(dbm, 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(dbm, 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))"); + createTable(dbm, 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(); diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index eba25d64..38e9950d 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -59,7 +59,7 @@ public class Config { // Not loaded from config - checked at runtime public static boolean mb4 = false; - public static final String CURRENT_CONFIG_VERSION = "1.15.1"; + public static final String CURRENT_CONFIG_VERSION = "1.16.0"; public static enum LogKillsLevel { PLAYERS, From dde8dc8289bea35ff3cc33769f2ab59ba06f3c12 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 16 Jan 2021 06:21:53 +0100 Subject: [PATCH 257/399] Do not log bees leaving beehives --- .../de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index 4867f692..c460e729 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -136,7 +136,7 @@ public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { @EventHandler(priority = EventPriority.MONITOR) public void onEntitySpawn(CreatureSpawnEvent event) { if (!event.isCancelled()) { - if (event.getSpawnReason() == SpawnReason.CUSTOM) { + if (event.getSpawnReason() == SpawnReason.CUSTOM || event.getSpawnReason() == SpawnReason.BEEHIVE) { return; } LivingEntity entity = event.getEntity(); From e181c856476cd1cf9fb40c98890d0786acab8e41 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 16 Jan 2021 07:16:01 +0100 Subject: [PATCH 258/399] Fix table update and to not break on update issues --- src/main/java/de/diddiz/LogBlock/Updater.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 8e80e165..a521659a 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -735,13 +735,12 @@ boolean update() { try { conn.setAutoCommit(true); final Statement st = conn.createStatement(); - st.execute("ALTER TABLE `" + wcfg.table + "-entities` KEY entityid (entityid)"); + st.execute("ALTER TABLE `" + wcfg.table + "-entities` ADD KEY entityid (entityid)"); logblock.getLogger().info("Added index for table " + wcfg.table + "-entities"); st.close(); conn.close(); } catch (final SQLException ex) { logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; } } config.set("version", "1.16.0"); From 81e013504680e031d4d1a34d91d0ff5c1bc49134 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 16 Jan 2021 07:37:56 +0100 Subject: [PATCH 259/399] Remove tool from offhand if it is not found in the main inventory --- .../de/diddiz/LogBlock/CommandsHandler.java | 2053 +++++++++-------- 1 file changed, 1032 insertions(+), 1021 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 71f22a7d..3ac86e52 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -1,1021 +1,1032 @@ -package de.diddiz.LogBlock; - -import static de.diddiz.LogBlock.Session.getSession; -import static de.diddiz.LogBlock.config.Config.askClearLogAfterRollback; -import static de.diddiz.LogBlock.config.Config.askClearLogs; -import static de.diddiz.LogBlock.config.Config.askRedos; -import static de.diddiz.LogBlock.config.Config.askRollbacks; -import static de.diddiz.LogBlock.config.Config.defaultTime; -import static de.diddiz.LogBlock.config.Config.dumpDeletedLog; -import static de.diddiz.LogBlock.config.Config.getWorldConfig; -import static de.diddiz.LogBlock.config.Config.linesLimit; -import static de.diddiz.LogBlock.config.Config.linesPerPage; -import static de.diddiz.LogBlock.config.Config.rollbackMaxArea; -import static de.diddiz.LogBlock.config.Config.rollbackMaxTime; -import static de.diddiz.LogBlock.config.Config.toolsByName; -import static de.diddiz.LogBlock.config.Config.toolsByType; -import static de.diddiz.util.BukkitUtils.giveTool; -import static de.diddiz.util.BukkitUtils.saveSpawnHeight; -import static de.diddiz.util.TypeColor.DEFAULT; -import static de.diddiz.util.TypeColor.ERROR; -import static de.diddiz.util.TypeColor.HEADER; -import static de.diddiz.util.Utils.isInt; -import static de.diddiz.util.Utils.listing; - -import de.diddiz.LogBlock.QueryParams.BlockChangeType; -import de.diddiz.LogBlock.QueryParams.Order; -import de.diddiz.LogBlock.QueryParams.SummarizationMode; -import de.diddiz.LogBlock.config.Config; -import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.util.Utils; -import java.io.BufferedOutputStream; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.OutputStreamWriter; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.logging.Level; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitScheduler; - -public class CommandsHandler implements CommandExecutor { - private final LogBlock logblock; - private final BukkitScheduler scheduler; - - CommandsHandler(LogBlock logblock) { - this.logblock = logblock; - scheduler = logblock.getServer().getScheduler(); - } - - @Override - public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { - try { - if (args.length == 0) { - sender.sendMessage(ChatColor.LIGHT_PURPLE + "LogBlock v" + logblock.getDescription().getVersion() + " by DiddiZ"); - sender.sendMessage(ChatColor.LIGHT_PURPLE + "Type /lb help for help"); - } else { - final String command = args[0].toLowerCase(); - if (command.equals("help")) { - sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Help:"); - sender.sendMessage(ChatColor.GOLD + "For the commands list type '/lb commands'"); - sender.sendMessage(ChatColor.GOLD + "For the parameters list type '/lb params'"); - sender.sendMessage(ChatColor.GOLD + "For the list of permissions you got type '/lb permissions'"); - } else if (command.equals("commands")) { - sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Commands:"); - sender.sendMessage(ChatColor.GOLD + "/lb tool -- Gives you the lb tool"); - sender.sendMessage(ChatColor.GOLD + "/lb tool [on|off] -- Enables/Disables tool"); - sender.sendMessage(ChatColor.GOLD + "/lb tool [params] -- Sets the tool lookup query"); - sender.sendMessage(ChatColor.GOLD + "/lb tool default -- Sets the tool lookup query to default"); - sender.sendMessage(ChatColor.GOLD + "/lb toolblock -- Analog to tool"); - sender.sendMessage(ChatColor.GOLD + "/lb hide -- Hides you from log"); - sender.sendMessage(ChatColor.GOLD + "/lb rollback [params] -- Rollback"); - sender.sendMessage(ChatColor.GOLD + "/lb redo [params] -- Redo"); - sender.sendMessage(ChatColor.GOLD + "/lb tp [params] -- Teleports you to the location of griefing"); - sender.sendMessage(ChatColor.GOLD + "/lb writelogfile [params] -- Writes a log file"); - sender.sendMessage(ChatColor.GOLD + "/lb lookup [params] -- Lookup"); - sender.sendMessage(ChatColor.GOLD + "/lb prev|next -- Browse lookup result pages"); - sender.sendMessage(ChatColor.GOLD + "/lb page -- Shows a specific lookup result page"); - sender.sendMessage(ChatColor.GOLD + "/lb me -- Displays your stats"); - sender.sendMessage(ChatColor.GOLD + "Look at github.com/LogBlock/LogBlock/wiki/Commands for the full commands reference"); - } else if (command.equals("params")) { - sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Query Parameters:"); - sender.sendMessage(ChatColor.GOLD + "Use doublequotes to escape a keyword: world \"world\""); - sender.sendMessage(ChatColor.GOLD + "player [name1] -- List of players"); - sender.sendMessage(ChatColor.GOLD + "block [type1] -- List of block types"); - sender.sendMessage(ChatColor.GOLD + "created, destroyed -- Show only created/destroyed blocks"); - sender.sendMessage(ChatColor.GOLD + "chestaccess -- Show only chest accesses"); - sender.sendMessage(ChatColor.GOLD + "entities [type1] -- List of entity types; can not be combined with blocks"); - sender.sendMessage(ChatColor.GOLD + "area -- Area around you"); - sender.sendMessage(ChatColor.GOLD + "selection, sel -- Inside current WorldEdit selection"); - sender.sendMessage(ChatColor.GOLD + "world [worldname] -- Changes the world"); - sender.sendMessage(ChatColor.GOLD + "time [number] [minutes|hours|days] -- Limits time"); - sender.sendMessage(ChatColor.GOLD + "since -- Limits time to a fixed point"); - sender.sendMessage(ChatColor.GOLD + "before -- Affects only blocks before a fixed time"); - sender.sendMessage(ChatColor.GOLD + "force -- Forces replacing not matching blocks"); - sender.sendMessage(ChatColor.GOLD + "limit -- Limits the result to count of rows"); - sender.sendMessage(ChatColor.GOLD + "sum [none|blocks|players] -- Sums the result"); - sender.sendMessage(ChatColor.GOLD + "asc, desc -- Changes the order of the displayed log"); - sender.sendMessage(ChatColor.GOLD + "coords -- Shows coordinates for each block"); - sender.sendMessage(ChatColor.GOLD + "nocache -- Don't set the lookup cache"); - sender.sendMessage(ChatColor.GOLD + "silent -- Displays lesser messages"); - } else if (command.equals("permissions")) { - sender.sendMessage(ChatColor.DARK_AQUA + "You've got the following permissions:"); - for (final String permission : new String[] { "me", "lookup", "tp", "rollback", "clearlog", "hide", "ignoreRestrictions", "spawnTools" }) { - if (logblock.hasPermission(sender, "logblock." + permission)) { - sender.sendMessage(ChatColor.GOLD + "logblock." + permission); - } - } - for (final Tool tool : toolsByType.values()) { - if (logblock.hasPermission(sender, "logblock.tools." + tool.name)) { - sender.sendMessage(ChatColor.GOLD + "logblock.tools." + tool.name); - } - } - } else if (command.equals("logging")) { - if (logblock.hasPermission(sender, "logblock.lookup")) { - World world = null; - if (args.length > 1) { - world = logblock.getServer().getWorld(args[1]); - } else if (sender instanceof Player) { - world = ((Player) sender).getWorld(); - } - if (world != null) { - final WorldConfig wcfg = getWorldConfig(world.getName()); - if (wcfg != null) { - sender.sendMessage(ChatColor.DARK_AQUA + "Currently logging in " + world.getName() + ":"); - final List logging = new ArrayList<>(); - for (final Logging l : Logging.values()) { - if (wcfg.isLogging(l)) { - logging.add(l.toString()); - } - } - sender.sendMessage(ChatColor.GOLD + listing(logging, ", ", " and ")); - } else { - sender.sendMessage(ChatColor.RED + "World not logged: '" + world.getName() + "'"); - sender.sendMessage(ChatColor.LIGHT_PURPLE + "Make the world name is listed at loggedWorlds in config. World names are case sensitive and must contains the path (if any), exactly like in the message above."); - } - } else { - sender.sendMessage(ChatColor.RED + "No world specified"); - } - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); - } - } else if (toolsByName.get(command) != null) { - final Tool tool = toolsByName.get(command); - if (logblock.hasPermission(sender, "logblock.tools." + tool.name)) { - if (sender instanceof Player) { - final Player player = (Player) sender; - final Session session = Session.getSession(player); - final ToolData toolData = session.toolData.get(tool); - if (args.length == 1) { - if (logblock.hasPermission(player, "logblock.spawnTools")) { - giveTool(player, tool.item); - toolData.enabled = true; - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); - } - } else if (args[1].equalsIgnoreCase("enable") || args[1].equalsIgnoreCase("on")) { - toolData.enabled = true; - player.sendMessage(ChatColor.GREEN + "Tool enabled."); - } else if (args[1].equalsIgnoreCase("disable") || args[1].equalsIgnoreCase("off")) { - toolData.enabled = false; - if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) { - player.getInventory().removeItem(new ItemStack(tool.item, 1)); - } - player.sendMessage(ChatColor.GREEN + "Tool disabled."); - } else if (args[1].equalsIgnoreCase("mode")) { - if (args.length == 3) { - final ToolMode mode; - try { - mode = ToolMode.valueOf(args[2].toUpperCase()); - } catch (final IllegalArgumentException ex) { - sender.sendMessage(ChatColor.RED + "Can't find mode " + args[2]); - return true; - } - if (logblock.hasPermission(player, mode.getPermission())) { - toolData.mode = mode; - sender.sendMessage(ChatColor.GREEN + "Tool mode set to " + args[2]); - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to use mode " + args[2]); - } - } else { - player.sendMessage(ChatColor.RED + "No mode specified"); - } - } else if (args[1].equalsIgnoreCase("default")) { - toolData.params = tool.params.clone(); - toolData.mode = tool.mode; - sender.sendMessage(ChatColor.GREEN + "Tool set to default."); - } else if (logblock.hasPermission(player, "logblock.lookup")) { - try { - final QueryParams params = tool.params.clone(); - params.parseArgs(sender, argsToList(args, 1)); - toolData.params = params; - sender.sendMessage(ChatColor.GREEN + "Set tool query to: " + params.getTitle()); - } catch (final Exception ex) { - sender.sendMessage(ChatColor.RED + ex.getMessage()); - } - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); - } - } else { - sender.sendMessage(ChatColor.RED + "You have to be a player."); - } - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); - } - } else if (command.equals("hide")) { - if (sender instanceof Player) { - if (logblock.hasPermission(sender, "logblock.hide")) { - if (args.length == 2) { - if (args[1].equalsIgnoreCase("on")) { - Consumer.hide((Player) sender); - sender.sendMessage(ChatColor.GREEN + "You are now hidden and aren't logged. Type /lb hide to unhide."); - } else if (args[1].equalsIgnoreCase("off")) { - Consumer.unHide((Player) sender); - sender.sendMessage(ChatColor.GREEN + "You aren't hidden any longer."); - } - } else { - if (Consumer.toggleHide((Player) sender)) { - sender.sendMessage(ChatColor.GREEN + "You are now hidden and aren't logged. Type '/lb hide' again to unhide."); - } else { - sender.sendMessage(ChatColor.GREEN + "You aren't hidden any longer."); - } - } - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); - } - } else { - sender.sendMessage(ChatColor.RED + "You have to be a player."); - } - } else if (command.equals("page")) { - if (args.length == 2 && isInt(args[1])) { - showPage(sender, Integer.valueOf(args[1])); - } else { - sender.sendMessage(ChatColor.RED + "You have to specify a page"); - } - } else if (command.equals("next") || command.equals("+")) { - showPage(sender, getSession(sender).page + 1); - } else if (command.equals("prev") || command.equals("-")) { - showPage(sender, getSession(sender).page - 1); - } else if (args[0].equalsIgnoreCase("savequeue")) { - if (logblock.hasPermission(sender, "logblock.rollback")) { - new CommandSaveQueue(sender, null, true); - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); - } - } else if (args[0].equalsIgnoreCase("queuesize")) { - if (logblock.hasPermission(sender, "logblock.rollback")) { - sender.sendMessage("Current queue size: " + logblock.getConsumer().getQueueSize()); - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); - } - } else if (command.equals("rollback") || command.equals("undo") || command.equals("rb")) { - if (logblock.hasPermission(sender, "logblock.rollback")) { - final QueryParams params = new QueryParams(logblock); - params.since = defaultTime; - params.bct = BlockChangeType.ALL; - params.parseArgs(sender, argsToList(args, 1)); - new CommandRollback(sender, params, true); - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); - } - } else if (command.equals("redo")) { - if (logblock.hasPermission(sender, "logblock.rollback")) { - final QueryParams params = new QueryParams(logblock); - params.since = defaultTime; - params.bct = BlockChangeType.ALL; - params.parseArgs(sender, argsToList(args, 1)); - new CommandRedo(sender, params, true); - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); - } - } else if (command.equals("me")) { - if (sender instanceof Player) { - if (logblock.hasPermission(sender, "logblock.me")) { - final Player player = (Player) sender; - if (Config.isLogged(player.getWorld())) { - final QueryParams params = new QueryParams(logblock); - params.setPlayer(player.getName()); - params.world = player.getWorld(); - player.sendMessage("Total block changes: " + logblock.getCount(params)); - params.sum = SummarizationMode.TYPES; - new CommandLookup(sender, params, true); - } else { - sender.sendMessage(ChatColor.RED + "This world isn't logged"); - } - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); - } - } else { - sender.sendMessage(ChatColor.RED + "You have to be a player."); - } - } else if (command.equals("writelogfile")) { - if (logblock.hasPermission(sender, "logblock.rollback")) { - final QueryParams params = new QueryParams(logblock); - params.limit = -1; - params.bct = BlockChangeType.ALL; - params.parseArgs(sender, argsToList(args, 1)); - new CommandWriteLogFile(sender, params, true); - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to do this"); - } - } else if (command.equals("clearlog")) { - if (logblock.hasPermission(sender, "logblock.clearlog")) { - final QueryParams params = new QueryParams(logblock); - params.limit = -1; - params.bct = BlockChangeType.ALL; - params.parseArgs(sender, argsToList(args, 1)); - new CommandClearLog(sender, params, true); - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to do this"); - } - } else if (command.equals("tp")) { - if (sender instanceof Player) { - if (logblock.hasPermission(sender, "logblock.tp")) { - if (args.length == 2 || isInt(args[1])) { - final int pos = Integer.parseInt(args[1]) - 1; - final Player player = (Player) sender; - final Session session = getSession(player); - if (session.lookupCache != null) { - if (pos >= 0 && pos < session.lookupCache.length) { - final Location loc = session.lookupCache[pos].getLocation(); - if (loc != null) { - player.teleport(new Location(loc.getWorld(), loc.getX() + 0.5, saveSpawnHeight(loc), loc.getZ() + 0.5, player.getLocation().getYaw(), 90)); - player.sendMessage(ChatColor.LIGHT_PURPLE + "Teleported to " + loc.getBlockX() + ":" + loc.getBlockY() + ":" + loc.getBlockZ()); - } else { - sender.sendMessage(ChatColor.RED + "There is no location associated with that. Did you forget coords parameter?"); - } - } else { - sender.sendMessage(ChatColor.RED + "'" + args[1] + " is out of range"); - } - } else { - sender.sendMessage(ChatColor.RED + "You havn't done a lookup yet"); - } - } else { - new CommandTeleport(sender, new QueryParams(logblock, sender, argsToList(args, 1)), true); - } - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to do this"); - } - } else { - sender.sendMessage(ChatColor.RED + "You have to be a player."); - } - } else if (command.equals("lookup") || QueryParams.isKeyWord(args[0])) { - if (logblock.hasPermission(sender, "logblock.lookup")) { - final List argsList = new ArrayList<>(Arrays.asList(args)); - if (command.equals("lookup")) { - argsList.remove(0); - } - final QueryParams params = new QueryParams(logblock); - params.since = defaultTime; - params.bct = BlockChangeType.ALL; - params.limit = Config.linesLimit; - params.parseArgs(sender, argsList); - new CommandLookup(sender, params, true); - } else { - sender.sendMessage(ChatColor.RED + "You aren't allowed to do this"); - } - } else { - sender.sendMessage(ChatColor.RED + "Unknown command '" + args[0] + "'"); - } - } - } catch (final IllegalArgumentException ex) { - sender.sendMessage(ChatColor.RED + ex.getMessage()); - } catch (final ArrayIndexOutOfBoundsException ex) { - sender.sendMessage(ChatColor.RED + "Not enough arguments given"); - } catch (final Exception ex) { - sender.sendMessage(ChatColor.RED + "Error, check server.log"); - logblock.getLogger().log(Level.WARNING, "Exception in commands handler: ", ex); - } - return true; - } - - private static void showPage(CommandSender sender, int page) { - showPage(sender, page, getSession(sender).lookupCache, true); - } - - private static void showPage(CommandSender sender, int page, LookupCacheElement[] lookupElements, boolean setSessionPage) { - if (lookupElements != null && lookupElements.length > 0) { - final int startpos = (page - 1) * linesPerPage; - if (page > 0 && startpos <= lookupElements.length - 1) { - final int stoppos = startpos + linesPerPage >= lookupElements.length ? lookupElements.length - 1 : startpos + linesPerPage - 1; - final int numberOfPages = (int) Math.ceil(lookupElements.length / (double) linesPerPage); - if (numberOfPages != 1) { - sender.sendMessage(HEADER + "Page " + page + "/" + numberOfPages); - } - for (int i = startpos; i <= stoppos; i++) { - TextComponent message = new TextComponent(); - message.setColor(DEFAULT.getColor()); - if (lookupElements[i].getLocation() != null) { - message.addExtra(new TextComponent("(" + (i + 1) + ") ")); - } - for (BaseComponent component : lookupElements[i].getLogMessage(i + 1)) { - message.addExtra(component); - } - sender.spigot().sendMessage(message); - } - if (setSessionPage) { - getSession(sender).page = page; - } - } else { - sender.sendMessage(ERROR + "There isn't a page '" + page + "'"); - } - } else { - sender.sendMessage(ERROR + "No blocks in lookup cache"); - } - } - - private boolean checkRestrictions(CommandSender sender, QueryParams params) { - if (sender.isOp() || logblock.hasPermission(sender, "logblock.ignoreRestrictions")) { - return true; - } - if (rollbackMaxTime > 0 && (params.since <= 0 || params.since > rollbackMaxTime)) { - sender.sendMessage(ChatColor.RED + "You are not allowed to rollback more than " + rollbackMaxTime + " minutes"); - return false; - } - if (rollbackMaxArea > 0 && (params.sel == null && params.loc == null || params.radius > rollbackMaxArea || params.sel != null && (params.sel.getSizeX() > rollbackMaxArea || params.sel.getSizeZ() > rollbackMaxArea))) { - sender.sendMessage(ChatColor.RED + "You are not allowed to rollback an area larger than " + rollbackMaxArea + " blocks"); - return false; - } - return true; - } - - public abstract class AbstractCommand implements Runnable { - protected CommandSender sender; - protected QueryParams params; - protected Connection conn = null; - protected Statement state = null; - protected ResultSet rs = null; - - protected AbstractCommand(CommandSender sender, QueryParams params, boolean async) throws Exception { - this.sender = sender; - this.params = params == null ? null : params.clone(); - if (async) { - scheduler.runTaskAsynchronously(logblock, this); - } else { - run(); - } - } - - public final void close() { - try { - if (conn != null) { - conn.close(); - } - if (state != null) { - state.close(); - } - if (rs != null) { - rs.close(); - } - } catch (final SQLException ex) { - if (logblock.isCompletelyEnabled()) { - logblock.getLogger().log(Level.SEVERE, "[CommandsHandler] SQL exception on close", ex); - } - } - } - } - - public class CommandLookup extends AbstractCommand { - public CommandLookup(CommandSender sender, QueryParams params, boolean async) throws Exception { - super(sender, params, async); - } - - @Override - public void run() { - try { - if (params.bct == BlockChangeType.CHAT) { - params.needDate = true; - params.needPlayer = true; - params.needMessage = true; - } else if (params.bct == BlockChangeType.KILLS) { - params.needDate = true; - params.needPlayer = true; - params.needKiller = true; - params.needVictim = true; - params.needWeapon = true; - } else { - params.needDate = true; - params.needType = true; - params.needData = true; - params.needPlayer = true; - if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) { - params.needChestAccess = true; - } - } - conn = logblock.getConnection(); - if (conn == null) { - sender.sendMessage(ChatColor.RED + "MySQL connection lost"); - return; - } - state = conn.createStatement(); - rs = executeQuery(state, params.getQuery()); - sender.sendMessage(ChatColor.DARK_AQUA + params.getTitle() + ":"); - if (rs.next()) { - rs.beforeFirst(); - final List blockchanges = new ArrayList<>(); - final LookupCacheElementFactory factory = new LookupCacheElementFactory(params, sender instanceof Player ? 2 / 3f : 1); - while (rs.next()) { - blockchanges.add(factory.getLookupCacheElement(rs)); - } - LookupCacheElement[] blockChangeArray = blockchanges.toArray(new LookupCacheElement[blockchanges.size()]); - if (!params.noCache) { - getSession(sender).lookupCache = blockChangeArray; - } - if (blockchanges.size() > linesPerPage) { - sender.sendMessage(ChatColor.DARK_AQUA.toString() + blockchanges.size() + " changes found." + (blockchanges.size() == linesLimit ? " Use 'limit -1' to see all changes." : "")); - } - if (params.sum != SummarizationMode.NONE) { - if (params.bct == BlockChangeType.KILLS && params.sum == SummarizationMode.PLAYERS) { - sender.sendMessage(ChatColor.GOLD + "Kills - Killed - Player"); - } else { - sender.sendMessage(ChatColor.GOLD + "Created - Destroyed - " + (params.sum == SummarizationMode.TYPES ? (params.bct == BlockChangeType.ENTITIES ? "Entity" : "Block") : "Player")); - } - } - if (!params.noCache) { - showPage(sender, 1); - } else { - showPage(sender, 1, blockChangeArray, false); - } - } else { - sender.sendMessage(ChatColor.DARK_AQUA + "No results found."); - if (!params.noCache) { - getSession(sender).lookupCache = null; - } - } - } catch (final Exception ex) { - if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { - sender.sendMessage(ChatColor.RED + "Exception, check error log"); - logblock.getLogger().log(Level.SEVERE, "[Lookup] " + params.getQuery() + ": ", ex); - } - } finally { - close(); - } - } - } - - public class CommandWriteLogFile extends AbstractCommand { - public CommandWriteLogFile(CommandSender sender, QueryParams params, boolean async) throws Exception { - super(sender, params, async); - } - - @Override - public void run() { - File file = null; - try { - if (params.bct == BlockChangeType.CHAT) { - params.needDate = true; - params.needPlayer = true; - params.needMessage = true; - } else { - params.needDate = true; - params.needType = true; - params.needData = true; - params.needPlayer = true; - if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) { - params.needChestAccess = true; - } - } - conn = logblock.getConnection(); - if (conn == null) { - sender.sendMessage(ChatColor.RED + "MySQL connection lost"); - return; - } - state = conn.createStatement(); - final File dumpFolder = new File(logblock.getDataFolder(), "log"); - if (!dumpFolder.exists()) { - dumpFolder.mkdirs(); - } - file = new File(dumpFolder, params.getTitle().replace(":", ".").replace("/", "_").replace("\\", "_") + ".log"); - sender.sendMessage(ChatColor.GREEN + "Creating " + file.getName()); - rs = executeQuery(state, params.getQuery()); - file.getParentFile().mkdirs(); - file.createNewFile(); - final FileWriter writer = new FileWriter(file); - final String newline = System.getProperty("line.separator"); - file.getParentFile().mkdirs(); - int counter = 0; - if (params.sum != SummarizationMode.NONE) { - writer.write("Created - Destroyed - " + (params.sum == SummarizationMode.TYPES ? (params.bct == BlockChangeType.ENTITIES ? "Entity" : "Block") : "Player") + newline); - } - final LookupCacheElementFactory factory = new LookupCacheElementFactory(params, sender instanceof Player ? 2 / 3f : 1); - while (rs.next()) { - writer.write(BaseComponent.toPlainText(factory.getLookupCacheElement(rs).getLogMessage()) + newline); - counter++; - } - writer.close(); - sender.sendMessage(ChatColor.GREEN + "Wrote " + counter + " lines."); - } catch (final Exception ex) { - if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { - sender.sendMessage(ChatColor.RED + "Exception, check error log"); - logblock.getLogger().log(Level.SEVERE, "[WriteLogFile] " + params.getQuery() + " (file was " + file.getAbsolutePath() + "): ", ex); - } - } finally { - close(); - } - } - } - - public class CommandSaveQueue extends AbstractCommand { - public CommandSaveQueue(CommandSender sender, QueryParams params, boolean async) throws Exception { - super(sender, params, async); - } - - @Override - public void run() { - final Consumer consumer = logblock.getConsumer(); - sender.sendMessage(ChatColor.DARK_AQUA + "Current queue size: " + consumer.getQueueSize()); - } - } - - public class CommandTeleport extends AbstractCommand { - public CommandTeleport(CommandSender sender, QueryParams params, boolean async) throws Exception { - super(sender, params, async); - } - - @Override - public void run() { - try { - params.needCoords = true; - if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) { - params.needChestAccess = true; - } - params.limit = 1; - params.sum = SummarizationMode.NONE; - conn = logblock.getConnection(); - if (conn == null) { - sender.sendMessage(ChatColor.RED + "MySQL connection lost"); - return; - } - state = conn.createStatement(); - rs = executeQuery(state, params.getQuery()); - if (rs.next()) { - final Player player = (Player) sender; - final int y = rs.getInt("y"); - final Location loc = new Location(params.world, rs.getInt("x") + 0.5, y, rs.getInt("z") + 0.5, player.getLocation().getYaw(), 90); - - // Teleport the player sync because omg thread safety - logblock.getServer().getScheduler().scheduleSyncDelayedTask(logblock, new Runnable() { - @Override - public void run() { - final int y2 = saveSpawnHeight(loc); - loc.setY(y2); - player.teleport(loc); - sender.sendMessage(ChatColor.GREEN + "You were teleported " + Math.abs(y2 - y) + " blocks " + (y2 - y > 0 ? "above" : "below")); - } - }); - } else { - sender.sendMessage(ChatColor.RED + "No block change found to teleport to"); - } - } catch (final Exception ex) { - if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { - sender.sendMessage(ChatColor.RED + "Exception, check error log"); - logblock.getLogger().log(Level.SEVERE, "[Teleport] " + params.getQuery() + ": ", ex); - } - } finally { - close(); - } - } - } - - public class CommandRollback extends AbstractCommand { - public CommandRollback(CommandSender sender, QueryParams params, boolean async) throws Exception { - super(sender, params, async); - } - - @Override - public void run() { - try { - if (params.bct == BlockChangeType.CHAT) { - sender.sendMessage(ChatColor.RED + "Chat cannot be rolled back"); - return; - } - if (params.bct == BlockChangeType.KILLS) { - sender.sendMessage(ChatColor.RED + "Kills cannot be rolled back"); - return; - } - if (params.sum != SummarizationMode.NONE) { - sender.sendMessage(ChatColor.RED + "Cannot rollback summarized changes"); - return; - } - params.needDate = true; - params.needCoords = true; - params.needType = true; - params.needData = true; - params.needChestAccess = true; - params.sum = SummarizationMode.NONE; - conn = logblock.getConnection(); - if (conn == null) { - sender.sendMessage(ChatColor.RED + "MySQL connection lost"); - return; - } - state = conn.createStatement(); - if (!checkRestrictions(sender, params)) { - return; - } - if (!params.silent) { - sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); - } - rs = executeQuery(state, params.getQuery()); - final WorldEditor editor = new WorldEditor(logblock, params.world, params.forceReplace); - WorldEditorEditFactory editFactory = new WorldEditorEditFactory(editor, params, true); - while (rs.next()) { - editFactory.processRow(rs); - } - if (params.order == Order.DESC) { - editor.reverseRowOrder(); - } - editor.sortRows(Order.DESC); - final int changes = editor.getSize(); - if (changes > 10000) { - editor.setSender(sender); - } - if (!params.silent) { - sender.sendMessage(ChatColor.GREEN.toString() + changes + " " + (params.bct == BlockChangeType.ENTITIES ? "entities" : "blocks") + " found."); - } - if (changes == 0) { - if (!params.silent) { - sender.sendMessage(ChatColor.RED + "Rollback aborted"); - } - return; - } - if (!params.silent && askRollbacks && sender instanceof Player && !logblock.getQuestioner().ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { - sender.sendMessage(ChatColor.RED + "Rollback aborted"); - return; - } - editor.start(); - if (!params.noCache) { - getSession(sender).lookupCache = editor.errors; - } - sender.sendMessage(ChatColor.GREEN + "Rollback finished successfully (" + editor.getElapsedTime() + " ms, " + editor.getSuccesses() + "/" + changes + " blocks" + (editor.getErrors() > 0 ? ", " + ChatColor.RED + editor.getErrors() + " errors" + ChatColor.GREEN : "") + (editor.getBlacklistCollisions() > 0 ? ", " + editor.getBlacklistCollisions() + " blacklist collisions" : "") + ")"); - if (!params.silent && askClearLogAfterRollback && logblock.hasPermission(sender, "logblock.clearlog") && sender instanceof Player) { - Thread.sleep(1000); - if (logblock.getQuestioner().ask((Player) sender, "Do you want to delete the rollbacked log?", "yes", "no").equals("yes")) { - params.silent = true; - new CommandClearLog(sender, params, false); - } else { - sender.sendMessage(ChatColor.LIGHT_PURPLE + "Clearlog cancelled"); - } - } - } catch (final Exception ex) { - if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { - sender.sendMessage(ChatColor.RED + "Exception, check error log"); - logblock.getLogger().log(Level.SEVERE, "[Rollback] " + params.getQuery() + ": ", ex); - } - } finally { - close(); - } - } - } - - public class CommandRedo extends AbstractCommand { - public CommandRedo(CommandSender sender, QueryParams params, boolean async) throws Exception { - super(sender, params, async); - } - - @Override - public void run() { - try { - if (params.bct == BlockChangeType.CHAT) { - sender.sendMessage(ChatColor.RED + "Chat cannot be redone"); - return; - } - if (params.bct == BlockChangeType.KILLS) { - sender.sendMessage(ChatColor.RED + "Kills cannot be redone"); - return; - } - if (params.sum != SummarizationMode.NONE) { - sender.sendMessage(ChatColor.RED + "Cannot redo summarized changes"); - return; - } - params.needDate = true; - params.needCoords = true; - params.needType = true; - params.needData = true; - params.needChestAccess = true; - params.sum = SummarizationMode.NONE; - conn = logblock.getConnection(); - if (conn == null) { - sender.sendMessage(ChatColor.RED + "MySQL connection lost"); - return; - } - state = conn.createStatement(); - if (!checkRestrictions(sender, params)) { - return; - } - rs = executeQuery(state, params.getQuery()); - if (!params.silent) { - sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); - } - final WorldEditor editor = new WorldEditor(logblock, params.world, params.forceReplace); - WorldEditorEditFactory editFactory = new WorldEditorEditFactory(editor, params, false); - while (rs.next()) { - editFactory.processRow(rs); - } - if (params.order == Order.ASC) { - editor.reverseRowOrder(); - } - editor.sortRows(Order.ASC); - final int changes = editor.getSize(); - if (!params.silent) { - sender.sendMessage(ChatColor.GREEN.toString() + changes + " " + (params.bct == BlockChangeType.ENTITIES ? "entities" : "blocks") + " found."); - } - if (changes == 0) { - if (!params.silent) { - sender.sendMessage(ChatColor.RED + "Redo aborted"); - } - return; - } - if (!params.silent && askRedos && sender instanceof Player && !logblock.getQuestioner().ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { - sender.sendMessage(ChatColor.RED + "Redo aborted"); - return; - } - editor.start(); - sender.sendMessage(ChatColor.GREEN + "Redo finished successfully (" + editor.getElapsedTime() + " ms, " + editor.getSuccesses() + "/" + changes + " blocks" + (editor.getErrors() > 0 ? ", " + ChatColor.RED + editor.getErrors() + " errors" + ChatColor.GREEN : "") + (editor.getBlacklistCollisions() > 0 ? ", " + editor.getBlacklistCollisions() + " blacklist collisions" : "") + ")"); - } catch (final Exception ex) { - if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { - sender.sendMessage(ChatColor.RED + "Exception, check error log"); - logblock.getLogger().log(Level.SEVERE, "[Redo] " + params.getQuery() + ": ", ex); - } - } finally { - close(); - } - } - } - - public class CommandClearLog extends AbstractCommand { - public CommandClearLog(CommandSender sender, QueryParams params, boolean async) throws Exception { - super(sender, params, async); - } - - @Override - public void run() { - try { - conn = logblock.getConnection(); - conn.setAutoCommit(true); - state = conn.createStatement(); - if (conn == null) { - sender.sendMessage(ChatColor.RED + "MySQL connection lost"); - return; - } - if (!checkRestrictions(sender, params)) { - return; - } - if (params.sum != SummarizationMode.NONE) { - sender.sendMessage(ChatColor.RED + "Cannot summarize on ClearLog"); - return; - } - String tableBase; - String deleteFromTables; - String tableName; - params.needId = true; - params.needDate = true; - params.needPlayerId = true; - if (params.bct == BlockChangeType.CHAT) { - params.needMessage = true; - tableBase = "lb-chat"; - deleteFromTables = "`lb-chat` "; - tableName = "lb-chat"; - } else if (params.bct == BlockChangeType.KILLS) { - params.needWeapon = true; - params.needCoords = true; - tableBase = params.getTable(); - deleteFromTables = "`" + tableBase + "-kills` "; - tableName = tableBase + "-kills"; - } else if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) { - params.needType = true; - params.needCoords = true; - params.needData = true; - tableBase = params.getTable(); - deleteFromTables = "`" + tableBase + "-entities` "; - tableName = tableBase + "-entities"; - } else { - params.needType = true; - params.needCoords = true; - params.needData = true; - params.needChestAccess = true; - tableBase = params.getTable(); - deleteFromTables = "`" + tableBase + "-blocks`, `" + tableBase + "-state`, `" + tableBase + "-chestdata` "; - tableName = tableBase + "-blocks"; - } - final File dumpFolder = new File(logblock.getDataFolder(), "dump"); - if (!dumpFolder.exists()) { - dumpFolder.mkdirs(); - } - rs = state.executeQuery("SELECT count(*) " + params.getFrom() + params.getWhere()); - int deleted = rs.next() ? rs.getInt(1) : 0; - rs.close(); - if (!params.silent && askClearLogs && sender instanceof Player) { - sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); - sender.sendMessage(ChatColor.GREEN.toString() + deleted + " entries found."); - if (deleted == 0 || !logblock.getQuestioner().ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { - sender.sendMessage(ChatColor.RED + "ClearLog aborted"); - return; - } - } - if (deleted > 0 && dumpDeletedLog) { - final String time = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss").format(System.currentTimeMillis()); - try { - File outFile = new File(dumpFolder, (time + " " + tableName + " " + params.getTitle() + ".sql").replace(':', '.').replace('/', '_').replace('\\', '_')); - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(outFile)), "UTF-8")); - try { - rs = state.executeQuery("SELECT " + params.getFields() + params.getFrom() + params.getWhere()); - while (rs.next()) { - StringBuilder sb = new StringBuilder(); - if (params.bct == BlockChangeType.CHAT) { - sb.append("INSERT INTO `lb-chat` (`id`, `date`, `playerid`, `message`) VALUES ("); - sb.append(rs.getInt("id")).append(", FROM_UNIXTIME("); - sb.append(rs.getTimestamp("date").getTime() / 1000).append("), "); - sb.append(rs.getInt("playerid")).append(", '"); - sb.append(Utils.mysqlTextEscape(rs.getString("message"))); - sb.append("');\n"); - } else if (params.bct == BlockChangeType.KILLS) { - sb.append("INSERT INTO `").append(tableBase).append("-kills` (`id`, `date`, `killer`, `victim`, `weapon`, `x`, `y`, `z`) VALUES ("); - sb.append(rs.getInt("id")).append(", FROM_UNIXTIME("); - sb.append(rs.getTimestamp("date").getTime() / 1000).append("), "); - sb.append(rs.getInt("killerid")).append(", "); - sb.append(rs.getInt("victimid")).append(", "); - sb.append(rs.getInt("weapon")).append(", "); - sb.append(rs.getInt("x")).append(", "); - sb.append(rs.getInt("y")).append(", "); - sb.append(rs.getInt("z")); - sb.append(");\n"); - } else if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) { - - } else { - sb.append("INSERT INTO `").append(tableBase).append("-blocks` (`id`, `date`, `playerid`, `replaced`, `replacedData`, `type`, `typeData`, `x`, `y`, `z`) VALUES ("); - sb.append(rs.getInt("id")).append(", FROM_UNIXTIME("); - sb.append(rs.getTimestamp("date").getTime() / 1000).append("), "); - sb.append(rs.getInt("playerid")).append(", "); - sb.append(rs.getInt("replaced")).append(", "); - sb.append(rs.getInt("replacedData")).append(", "); - sb.append(rs.getInt("type")).append(", "); - sb.append(rs.getInt("typeData")).append(", "); - sb.append(rs.getInt("x")).append(", "); - sb.append(rs.getInt("y")).append(", "); - sb.append(rs.getInt("z")); - sb.append(");\n"); - byte[] replacedState = rs.getBytes("replacedState"); - byte[] typeState = rs.getBytes("typeState"); - if (replacedState != null || typeState != null) { - sb.append("INSERT INTO `").append(tableBase).append("-state` (`id`, `replacedState`, `typeState`) VALUES ("); - sb.append(rs.getInt("id")).append(", "); - sb.append(Utils.mysqlPrepareBytesForInsertAllowNull(replacedState)).append(", "); - sb.append(Utils.mysqlPrepareBytesForInsertAllowNull(typeState)); - sb.append(");\n"); - } - byte[] item = rs.getBytes("item"); - if (item != null) { - sb.append("INSERT INTO `").append(tableBase).append("-chestdata` (`id`, `item`, `itemremove`, `itemtype`) VALUES ("); - sb.append(rs.getInt("id")).append(", "); - sb.append(Utils.mysqlPrepareBytesForInsertAllowNull(item)).append(", "); - sb.append(rs.getInt("itemremove")).append(", "); - sb.append(rs.getInt("itemtype")); - sb.append(");\n"); - } - } - writer.write(sb.toString()); - } - rs.close(); - } finally { - writer.close(); - } - } catch (final SQLException ex) { - sender.sendMessage(ChatColor.RED + "Error while dumping log."); - logblock.getLogger().log(Level.SEVERE, "[ClearLog] Exception while dumping log: ", ex); - return; - } - } - if (deleted > 0) { - state.executeUpdate("DELETE " + deleteFromTables + params.getFrom() + params.getWhere()); - if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) { - state.executeUpdate("DELETE `" + tableBase + "-entityids` FROM `" + tableBase + "-entityids` LEFT JOIN `" + tableBase + "-entities` USING (entityid) WHERE `" + tableBase + "-entities`.entityid IS NULL"); - } - } - sender.sendMessage(ChatColor.GREEN + "Cleared out table " + tableName + ". Deleted " + deleted + " entries."); - } catch (final Exception ex) { - if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { - sender.sendMessage(ChatColor.RED + "Exception, check error log"); - logblock.getLogger().log(Level.SEVERE, "[ClearLog] Exception: ", ex); - } - } finally { - close(); - } - } - } - - private ResultSet executeQuery(Statement state, String query) throws SQLException { - if (Config.debug) { - long startTime = System.currentTimeMillis(); - ResultSet rs = state.executeQuery(query); - logblock.getLogger().log(Level.INFO, "[LogBlock Debug] Time Taken: " + (System.currentTimeMillis() - startTime) + " milliseconds. Query: " + query); - return rs; - } else { - return state.executeQuery(query); - } - } - - private static List argsToList(String[] arr, int offset) { - final List list = new ArrayList<>(Arrays.asList(arr)); - for (int i = 0; i < offset; i++) { - list.remove(0); - } - return list; - } -} +package de.diddiz.LogBlock; + +import static de.diddiz.LogBlock.Session.getSession; +import static de.diddiz.LogBlock.config.Config.askClearLogAfterRollback; +import static de.diddiz.LogBlock.config.Config.askClearLogs; +import static de.diddiz.LogBlock.config.Config.askRedos; +import static de.diddiz.LogBlock.config.Config.askRollbacks; +import static de.diddiz.LogBlock.config.Config.defaultTime; +import static de.diddiz.LogBlock.config.Config.dumpDeletedLog; +import static de.diddiz.LogBlock.config.Config.getWorldConfig; +import static de.diddiz.LogBlock.config.Config.linesLimit; +import static de.diddiz.LogBlock.config.Config.linesPerPage; +import static de.diddiz.LogBlock.config.Config.rollbackMaxArea; +import static de.diddiz.LogBlock.config.Config.rollbackMaxTime; +import static de.diddiz.LogBlock.config.Config.toolsByName; +import static de.diddiz.LogBlock.config.Config.toolsByType; +import static de.diddiz.util.BukkitUtils.giveTool; +import static de.diddiz.util.BukkitUtils.saveSpawnHeight; +import static de.diddiz.util.TypeColor.DEFAULT; +import static de.diddiz.util.TypeColor.ERROR; +import static de.diddiz.util.TypeColor.HEADER; +import static de.diddiz.util.Utils.isInt; +import static de.diddiz.util.Utils.listing; + +import de.diddiz.LogBlock.QueryParams.BlockChangeType; +import de.diddiz.LogBlock.QueryParams.Order; +import de.diddiz.LogBlock.QueryParams.SummarizationMode; +import de.diddiz.LogBlock.config.Config; +import de.diddiz.LogBlock.config.WorldConfig; +import de.diddiz.util.Utils; +import java.io.BufferedOutputStream; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.OutputStreamWriter; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitScheduler; + +public class CommandsHandler implements CommandExecutor { + private final LogBlock logblock; + private final BukkitScheduler scheduler; + + CommandsHandler(LogBlock logblock) { + this.logblock = logblock; + scheduler = logblock.getServer().getScheduler(); + } + + @Override + public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { + try { + if (args.length == 0) { + sender.sendMessage(ChatColor.LIGHT_PURPLE + "LogBlock v" + logblock.getDescription().getVersion() + " by DiddiZ"); + sender.sendMessage(ChatColor.LIGHT_PURPLE + "Type /lb help for help"); + } else { + final String command = args[0].toLowerCase(); + if (command.equals("help")) { + sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Help:"); + sender.sendMessage(ChatColor.GOLD + "For the commands list type '/lb commands'"); + sender.sendMessage(ChatColor.GOLD + "For the parameters list type '/lb params'"); + sender.sendMessage(ChatColor.GOLD + "For the list of permissions you got type '/lb permissions'"); + } else if (command.equals("commands")) { + sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Commands:"); + sender.sendMessage(ChatColor.GOLD + "/lb tool -- Gives you the lb tool"); + sender.sendMessage(ChatColor.GOLD + "/lb tool [on|off] -- Enables/Disables tool"); + sender.sendMessage(ChatColor.GOLD + "/lb tool [params] -- Sets the tool lookup query"); + sender.sendMessage(ChatColor.GOLD + "/lb tool default -- Sets the tool lookup query to default"); + sender.sendMessage(ChatColor.GOLD + "/lb toolblock -- Analog to tool"); + sender.sendMessage(ChatColor.GOLD + "/lb hide -- Hides you from log"); + sender.sendMessage(ChatColor.GOLD + "/lb rollback [params] -- Rollback"); + sender.sendMessage(ChatColor.GOLD + "/lb redo [params] -- Redo"); + sender.sendMessage(ChatColor.GOLD + "/lb tp [params] -- Teleports you to the location of griefing"); + sender.sendMessage(ChatColor.GOLD + "/lb writelogfile [params] -- Writes a log file"); + sender.sendMessage(ChatColor.GOLD + "/lb lookup [params] -- Lookup"); + sender.sendMessage(ChatColor.GOLD + "/lb prev|next -- Browse lookup result pages"); + sender.sendMessage(ChatColor.GOLD + "/lb page -- Shows a specific lookup result page"); + sender.sendMessage(ChatColor.GOLD + "/lb me -- Displays your stats"); + sender.sendMessage(ChatColor.GOLD + "Look at github.com/LogBlock/LogBlock/wiki/Commands for the full commands reference"); + } else if (command.equals("params")) { + sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Query Parameters:"); + sender.sendMessage(ChatColor.GOLD + "Use doublequotes to escape a keyword: world \"world\""); + sender.sendMessage(ChatColor.GOLD + "player [name1] -- List of players"); + sender.sendMessage(ChatColor.GOLD + "block [type1] -- List of block types"); + sender.sendMessage(ChatColor.GOLD + "created, destroyed -- Show only created/destroyed blocks"); + sender.sendMessage(ChatColor.GOLD + "chestaccess -- Show only chest accesses"); + sender.sendMessage(ChatColor.GOLD + "entities [type1] -- List of entity types; can not be combined with blocks"); + sender.sendMessage(ChatColor.GOLD + "area -- Area around you"); + sender.sendMessage(ChatColor.GOLD + "selection, sel -- Inside current WorldEdit selection"); + sender.sendMessage(ChatColor.GOLD + "world [worldname] -- Changes the world"); + sender.sendMessage(ChatColor.GOLD + "time [number] [minutes|hours|days] -- Limits time"); + sender.sendMessage(ChatColor.GOLD + "since -- Limits time to a fixed point"); + sender.sendMessage(ChatColor.GOLD + "before -- Affects only blocks before a fixed time"); + sender.sendMessage(ChatColor.GOLD + "force -- Forces replacing not matching blocks"); + sender.sendMessage(ChatColor.GOLD + "limit -- Limits the result to count of rows"); + sender.sendMessage(ChatColor.GOLD + "sum [none|blocks|players] -- Sums the result"); + sender.sendMessage(ChatColor.GOLD + "asc, desc -- Changes the order of the displayed log"); + sender.sendMessage(ChatColor.GOLD + "coords -- Shows coordinates for each block"); + sender.sendMessage(ChatColor.GOLD + "nocache -- Don't set the lookup cache"); + sender.sendMessage(ChatColor.GOLD + "silent -- Displays lesser messages"); + } else if (command.equals("permissions")) { + sender.sendMessage(ChatColor.DARK_AQUA + "You've got the following permissions:"); + for (final String permission : new String[] { "me", "lookup", "tp", "rollback", "clearlog", "hide", "ignoreRestrictions", "spawnTools" }) { + if (logblock.hasPermission(sender, "logblock." + permission)) { + sender.sendMessage(ChatColor.GOLD + "logblock." + permission); + } + } + for (final Tool tool : toolsByType.values()) { + if (logblock.hasPermission(sender, "logblock.tools." + tool.name)) { + sender.sendMessage(ChatColor.GOLD + "logblock.tools." + tool.name); + } + } + } else if (command.equals("logging")) { + if (logblock.hasPermission(sender, "logblock.lookup")) { + World world = null; + if (args.length > 1) { + world = logblock.getServer().getWorld(args[1]); + } else if (sender instanceof Player) { + world = ((Player) sender).getWorld(); + } + if (world != null) { + final WorldConfig wcfg = getWorldConfig(world.getName()); + if (wcfg != null) { + sender.sendMessage(ChatColor.DARK_AQUA + "Currently logging in " + world.getName() + ":"); + final List logging = new ArrayList<>(); + for (final Logging l : Logging.values()) { + if (wcfg.isLogging(l)) { + logging.add(l.toString()); + } + } + sender.sendMessage(ChatColor.GOLD + listing(logging, ", ", " and ")); + } else { + sender.sendMessage(ChatColor.RED + "World not logged: '" + world.getName() + "'"); + sender.sendMessage(ChatColor.LIGHT_PURPLE + "Make the world name is listed at loggedWorlds in config. World names are case sensitive and must contains the path (if any), exactly like in the message above."); + } + } else { + sender.sendMessage(ChatColor.RED + "No world specified"); + } + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); + } + } else if (toolsByName.get(command) != null) { + final Tool tool = toolsByName.get(command); + if (logblock.hasPermission(sender, "logblock.tools." + tool.name)) { + if (sender instanceof Player) { + final Player player = (Player) sender; + final Session session = Session.getSession(player); + final ToolData toolData = session.toolData.get(tool); + if (args.length == 1) { + if (logblock.hasPermission(player, "logblock.spawnTools")) { + giveTool(player, tool.item); + toolData.enabled = true; + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); + } + } else if (args[1].equalsIgnoreCase("enable") || args[1].equalsIgnoreCase("on")) { + toolData.enabled = true; + player.sendMessage(ChatColor.GREEN + "Tool enabled."); + } else if (args[1].equalsIgnoreCase("disable") || args[1].equalsIgnoreCase("off")) { + toolData.enabled = false; + if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) { + if (!player.getInventory().removeItem(new ItemStack(tool.item, 1)).isEmpty()) { + // remove the tool from the offhand if it cannot be found in the main hand + ItemStack offhandItem = player.getInventory().getItemInOffHand(); + if (offhandItem != null && offhandItem.isSimilar(new ItemStack(tool.item, 1))) { + if (offhandItem.getAmount() <= 1) { + player.getInventory().setItemInOffHand(null); + } else { + offhandItem.setAmount(offhandItem.getAmount() - 1); + player.getInventory().setItemInOffHand(offhandItem); + } + } + } + } + player.sendMessage(ChatColor.GREEN + "Tool disabled."); + } else if (args[1].equalsIgnoreCase("mode")) { + if (args.length == 3) { + final ToolMode mode; + try { + mode = ToolMode.valueOf(args[2].toUpperCase()); + } catch (final IllegalArgumentException ex) { + sender.sendMessage(ChatColor.RED + "Can't find mode " + args[2]); + return true; + } + if (logblock.hasPermission(player, mode.getPermission())) { + toolData.mode = mode; + sender.sendMessage(ChatColor.GREEN + "Tool mode set to " + args[2]); + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to use mode " + args[2]); + } + } else { + player.sendMessage(ChatColor.RED + "No mode specified"); + } + } else if (args[1].equalsIgnoreCase("default")) { + toolData.params = tool.params.clone(); + toolData.mode = tool.mode; + sender.sendMessage(ChatColor.GREEN + "Tool set to default."); + } else if (logblock.hasPermission(player, "logblock.lookup")) { + try { + final QueryParams params = tool.params.clone(); + params.parseArgs(sender, argsToList(args, 1)); + toolData.params = params; + sender.sendMessage(ChatColor.GREEN + "Set tool query to: " + params.getTitle()); + } catch (final Exception ex) { + sender.sendMessage(ChatColor.RED + ex.getMessage()); + } + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); + } + } else { + sender.sendMessage(ChatColor.RED + "You have to be a player."); + } + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); + } + } else if (command.equals("hide")) { + if (sender instanceof Player) { + if (logblock.hasPermission(sender, "logblock.hide")) { + if (args.length == 2) { + if (args[1].equalsIgnoreCase("on")) { + Consumer.hide((Player) sender); + sender.sendMessage(ChatColor.GREEN + "You are now hidden and aren't logged. Type /lb hide to unhide."); + } else if (args[1].equalsIgnoreCase("off")) { + Consumer.unHide((Player) sender); + sender.sendMessage(ChatColor.GREEN + "You aren't hidden any longer."); + } + } else { + if (Consumer.toggleHide((Player) sender)) { + sender.sendMessage(ChatColor.GREEN + "You are now hidden and aren't logged. Type '/lb hide' again to unhide."); + } else { + sender.sendMessage(ChatColor.GREEN + "You aren't hidden any longer."); + } + } + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); + } + } else { + sender.sendMessage(ChatColor.RED + "You have to be a player."); + } + } else if (command.equals("page")) { + if (args.length == 2 && isInt(args[1])) { + showPage(sender, Integer.valueOf(args[1])); + } else { + sender.sendMessage(ChatColor.RED + "You have to specify a page"); + } + } else if (command.equals("next") || command.equals("+")) { + showPage(sender, getSession(sender).page + 1); + } else if (command.equals("prev") || command.equals("-")) { + showPage(sender, getSession(sender).page - 1); + } else if (args[0].equalsIgnoreCase("savequeue")) { + if (logblock.hasPermission(sender, "logblock.rollback")) { + new CommandSaveQueue(sender, null, true); + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); + } + } else if (args[0].equalsIgnoreCase("queuesize")) { + if (logblock.hasPermission(sender, "logblock.rollback")) { + sender.sendMessage("Current queue size: " + logblock.getConsumer().getQueueSize()); + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); + } + } else if (command.equals("rollback") || command.equals("undo") || command.equals("rb")) { + if (logblock.hasPermission(sender, "logblock.rollback")) { + final QueryParams params = new QueryParams(logblock); + params.since = defaultTime; + params.bct = BlockChangeType.ALL; + params.parseArgs(sender, argsToList(args, 1)); + new CommandRollback(sender, params, true); + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); + } + } else if (command.equals("redo")) { + if (logblock.hasPermission(sender, "logblock.rollback")) { + final QueryParams params = new QueryParams(logblock); + params.since = defaultTime; + params.bct = BlockChangeType.ALL; + params.parseArgs(sender, argsToList(args, 1)); + new CommandRedo(sender, params, true); + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); + } + } else if (command.equals("me")) { + if (sender instanceof Player) { + if (logblock.hasPermission(sender, "logblock.me")) { + final Player player = (Player) sender; + if (Config.isLogged(player.getWorld())) { + final QueryParams params = new QueryParams(logblock); + params.setPlayer(player.getName()); + params.world = player.getWorld(); + player.sendMessage("Total block changes: " + logblock.getCount(params)); + params.sum = SummarizationMode.TYPES; + new CommandLookup(sender, params, true); + } else { + sender.sendMessage(ChatColor.RED + "This world isn't logged"); + } + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); + } + } else { + sender.sendMessage(ChatColor.RED + "You have to be a player."); + } + } else if (command.equals("writelogfile")) { + if (logblock.hasPermission(sender, "logblock.rollback")) { + final QueryParams params = new QueryParams(logblock); + params.limit = -1; + params.bct = BlockChangeType.ALL; + params.parseArgs(sender, argsToList(args, 1)); + new CommandWriteLogFile(sender, params, true); + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to do this"); + } + } else if (command.equals("clearlog")) { + if (logblock.hasPermission(sender, "logblock.clearlog")) { + final QueryParams params = new QueryParams(logblock); + params.limit = -1; + params.bct = BlockChangeType.ALL; + params.parseArgs(sender, argsToList(args, 1)); + new CommandClearLog(sender, params, true); + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to do this"); + } + } else if (command.equals("tp")) { + if (sender instanceof Player) { + if (logblock.hasPermission(sender, "logblock.tp")) { + if (args.length == 2 || isInt(args[1])) { + final int pos = Integer.parseInt(args[1]) - 1; + final Player player = (Player) sender; + final Session session = getSession(player); + if (session.lookupCache != null) { + if (pos >= 0 && pos < session.lookupCache.length) { + final Location loc = session.lookupCache[pos].getLocation(); + if (loc != null) { + player.teleport(new Location(loc.getWorld(), loc.getX() + 0.5, saveSpawnHeight(loc), loc.getZ() + 0.5, player.getLocation().getYaw(), 90)); + player.sendMessage(ChatColor.LIGHT_PURPLE + "Teleported to " + loc.getBlockX() + ":" + loc.getBlockY() + ":" + loc.getBlockZ()); + } else { + sender.sendMessage(ChatColor.RED + "There is no location associated with that. Did you forget coords parameter?"); + } + } else { + sender.sendMessage(ChatColor.RED + "'" + args[1] + " is out of range"); + } + } else { + sender.sendMessage(ChatColor.RED + "You havn't done a lookup yet"); + } + } else { + new CommandTeleport(sender, new QueryParams(logblock, sender, argsToList(args, 1)), true); + } + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to do this"); + } + } else { + sender.sendMessage(ChatColor.RED + "You have to be a player."); + } + } else if (command.equals("lookup") || QueryParams.isKeyWord(args[0])) { + if (logblock.hasPermission(sender, "logblock.lookup")) { + final List argsList = new ArrayList<>(Arrays.asList(args)); + if (command.equals("lookup")) { + argsList.remove(0); + } + final QueryParams params = new QueryParams(logblock); + params.since = defaultTime; + params.bct = BlockChangeType.ALL; + params.limit = Config.linesLimit; + params.parseArgs(sender, argsList); + new CommandLookup(sender, params, true); + } else { + sender.sendMessage(ChatColor.RED + "You aren't allowed to do this"); + } + } else { + sender.sendMessage(ChatColor.RED + "Unknown command '" + args[0] + "'"); + } + } + } catch (final IllegalArgumentException ex) { + sender.sendMessage(ChatColor.RED + ex.getMessage()); + } catch (final ArrayIndexOutOfBoundsException ex) { + sender.sendMessage(ChatColor.RED + "Not enough arguments given"); + } catch (final Exception ex) { + sender.sendMessage(ChatColor.RED + "Error, check server.log"); + logblock.getLogger().log(Level.WARNING, "Exception in commands handler: ", ex); + } + return true; + } + + private static void showPage(CommandSender sender, int page) { + showPage(sender, page, getSession(sender).lookupCache, true); + } + + private static void showPage(CommandSender sender, int page, LookupCacheElement[] lookupElements, boolean setSessionPage) { + if (lookupElements != null && lookupElements.length > 0) { + final int startpos = (page - 1) * linesPerPage; + if (page > 0 && startpos <= lookupElements.length - 1) { + final int stoppos = startpos + linesPerPage >= lookupElements.length ? lookupElements.length - 1 : startpos + linesPerPage - 1; + final int numberOfPages = (int) Math.ceil(lookupElements.length / (double) linesPerPage); + if (numberOfPages != 1) { + sender.sendMessage(HEADER + "Page " + page + "/" + numberOfPages); + } + for (int i = startpos; i <= stoppos; i++) { + TextComponent message = new TextComponent(); + message.setColor(DEFAULT.getColor()); + if (lookupElements[i].getLocation() != null) { + message.addExtra(new TextComponent("(" + (i + 1) + ") ")); + } + for (BaseComponent component : lookupElements[i].getLogMessage(i + 1)) { + message.addExtra(component); + } + sender.spigot().sendMessage(message); + } + if (setSessionPage) { + getSession(sender).page = page; + } + } else { + sender.sendMessage(ERROR + "There isn't a page '" + page + "'"); + } + } else { + sender.sendMessage(ERROR + "No blocks in lookup cache"); + } + } + + private boolean checkRestrictions(CommandSender sender, QueryParams params) { + if (sender.isOp() || logblock.hasPermission(sender, "logblock.ignoreRestrictions")) { + return true; + } + if (rollbackMaxTime > 0 && (params.since <= 0 || params.since > rollbackMaxTime)) { + sender.sendMessage(ChatColor.RED + "You are not allowed to rollback more than " + rollbackMaxTime + " minutes"); + return false; + } + if (rollbackMaxArea > 0 && (params.sel == null && params.loc == null || params.radius > rollbackMaxArea || params.sel != null && (params.sel.getSizeX() > rollbackMaxArea || params.sel.getSizeZ() > rollbackMaxArea))) { + sender.sendMessage(ChatColor.RED + "You are not allowed to rollback an area larger than " + rollbackMaxArea + " blocks"); + return false; + } + return true; + } + + public abstract class AbstractCommand implements Runnable { + protected CommandSender sender; + protected QueryParams params; + protected Connection conn = null; + protected Statement state = null; + protected ResultSet rs = null; + + protected AbstractCommand(CommandSender sender, QueryParams params, boolean async) throws Exception { + this.sender = sender; + this.params = params == null ? null : params.clone(); + if (async) { + scheduler.runTaskAsynchronously(logblock, this); + } else { + run(); + } + } + + public final void close() { + try { + if (conn != null) { + conn.close(); + } + if (state != null) { + state.close(); + } + if (rs != null) { + rs.close(); + } + } catch (final SQLException ex) { + if (logblock.isCompletelyEnabled()) { + logblock.getLogger().log(Level.SEVERE, "[CommandsHandler] SQL exception on close", ex); + } + } + } + } + + public class CommandLookup extends AbstractCommand { + public CommandLookup(CommandSender sender, QueryParams params, boolean async) throws Exception { + super(sender, params, async); + } + + @Override + public void run() { + try { + if (params.bct == BlockChangeType.CHAT) { + params.needDate = true; + params.needPlayer = true; + params.needMessage = true; + } else if (params.bct == BlockChangeType.KILLS) { + params.needDate = true; + params.needPlayer = true; + params.needKiller = true; + params.needVictim = true; + params.needWeapon = true; + } else { + params.needDate = true; + params.needType = true; + params.needData = true; + params.needPlayer = true; + if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) { + params.needChestAccess = true; + } + } + conn = logblock.getConnection(); + if (conn == null) { + sender.sendMessage(ChatColor.RED + "MySQL connection lost"); + return; + } + state = conn.createStatement(); + rs = executeQuery(state, params.getQuery()); + sender.sendMessage(ChatColor.DARK_AQUA + params.getTitle() + ":"); + if (rs.next()) { + rs.beforeFirst(); + final List blockchanges = new ArrayList<>(); + final LookupCacheElementFactory factory = new LookupCacheElementFactory(params, sender instanceof Player ? 2 / 3f : 1); + while (rs.next()) { + blockchanges.add(factory.getLookupCacheElement(rs)); + } + LookupCacheElement[] blockChangeArray = blockchanges.toArray(new LookupCacheElement[blockchanges.size()]); + if (!params.noCache) { + getSession(sender).lookupCache = blockChangeArray; + } + if (blockchanges.size() > linesPerPage) { + sender.sendMessage(ChatColor.DARK_AQUA.toString() + blockchanges.size() + " changes found." + (blockchanges.size() == linesLimit ? " Use 'limit -1' to see all changes." : "")); + } + if (params.sum != SummarizationMode.NONE) { + if (params.bct == BlockChangeType.KILLS && params.sum == SummarizationMode.PLAYERS) { + sender.sendMessage(ChatColor.GOLD + "Kills - Killed - Player"); + } else { + sender.sendMessage(ChatColor.GOLD + "Created - Destroyed - " + (params.sum == SummarizationMode.TYPES ? (params.bct == BlockChangeType.ENTITIES ? "Entity" : "Block") : "Player")); + } + } + if (!params.noCache) { + showPage(sender, 1); + } else { + showPage(sender, 1, blockChangeArray, false); + } + } else { + sender.sendMessage(ChatColor.DARK_AQUA + "No results found."); + if (!params.noCache) { + getSession(sender).lookupCache = null; + } + } + } catch (final Exception ex) { + if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { + sender.sendMessage(ChatColor.RED + "Exception, check error log"); + logblock.getLogger().log(Level.SEVERE, "[Lookup] " + params.getQuery() + ": ", ex); + } + } finally { + close(); + } + } + } + + public class CommandWriteLogFile extends AbstractCommand { + public CommandWriteLogFile(CommandSender sender, QueryParams params, boolean async) throws Exception { + super(sender, params, async); + } + + @Override + public void run() { + File file = null; + try { + if (params.bct == BlockChangeType.CHAT) { + params.needDate = true; + params.needPlayer = true; + params.needMessage = true; + } else { + params.needDate = true; + params.needType = true; + params.needData = true; + params.needPlayer = true; + if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) { + params.needChestAccess = true; + } + } + conn = logblock.getConnection(); + if (conn == null) { + sender.sendMessage(ChatColor.RED + "MySQL connection lost"); + return; + } + state = conn.createStatement(); + final File dumpFolder = new File(logblock.getDataFolder(), "log"); + if (!dumpFolder.exists()) { + dumpFolder.mkdirs(); + } + file = new File(dumpFolder, params.getTitle().replace(":", ".").replace("/", "_").replace("\\", "_") + ".log"); + sender.sendMessage(ChatColor.GREEN + "Creating " + file.getName()); + rs = executeQuery(state, params.getQuery()); + file.getParentFile().mkdirs(); + file.createNewFile(); + final FileWriter writer = new FileWriter(file); + final String newline = System.getProperty("line.separator"); + file.getParentFile().mkdirs(); + int counter = 0; + if (params.sum != SummarizationMode.NONE) { + writer.write("Created - Destroyed - " + (params.sum == SummarizationMode.TYPES ? (params.bct == BlockChangeType.ENTITIES ? "Entity" : "Block") : "Player") + newline); + } + final LookupCacheElementFactory factory = new LookupCacheElementFactory(params, sender instanceof Player ? 2 / 3f : 1); + while (rs.next()) { + writer.write(BaseComponent.toPlainText(factory.getLookupCacheElement(rs).getLogMessage()) + newline); + counter++; + } + writer.close(); + sender.sendMessage(ChatColor.GREEN + "Wrote " + counter + " lines."); + } catch (final Exception ex) { + if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { + sender.sendMessage(ChatColor.RED + "Exception, check error log"); + logblock.getLogger().log(Level.SEVERE, "[WriteLogFile] " + params.getQuery() + " (file was " + file.getAbsolutePath() + "): ", ex); + } + } finally { + close(); + } + } + } + + public class CommandSaveQueue extends AbstractCommand { + public CommandSaveQueue(CommandSender sender, QueryParams params, boolean async) throws Exception { + super(sender, params, async); + } + + @Override + public void run() { + final Consumer consumer = logblock.getConsumer(); + sender.sendMessage(ChatColor.DARK_AQUA + "Current queue size: " + consumer.getQueueSize()); + } + } + + public class CommandTeleport extends AbstractCommand { + public CommandTeleport(CommandSender sender, QueryParams params, boolean async) throws Exception { + super(sender, params, async); + } + + @Override + public void run() { + try { + params.needCoords = true; + if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) { + params.needChestAccess = true; + } + params.limit = 1; + params.sum = SummarizationMode.NONE; + conn = logblock.getConnection(); + if (conn == null) { + sender.sendMessage(ChatColor.RED + "MySQL connection lost"); + return; + } + state = conn.createStatement(); + rs = executeQuery(state, params.getQuery()); + if (rs.next()) { + final Player player = (Player) sender; + final int y = rs.getInt("y"); + final Location loc = new Location(params.world, rs.getInt("x") + 0.5, y, rs.getInt("z") + 0.5, player.getLocation().getYaw(), 90); + + // Teleport the player sync because omg thread safety + logblock.getServer().getScheduler().scheduleSyncDelayedTask(logblock, new Runnable() { + @Override + public void run() { + final int y2 = saveSpawnHeight(loc); + loc.setY(y2); + player.teleport(loc); + sender.sendMessage(ChatColor.GREEN + "You were teleported " + Math.abs(y2 - y) + " blocks " + (y2 - y > 0 ? "above" : "below")); + } + }); + } else { + sender.sendMessage(ChatColor.RED + "No block change found to teleport to"); + } + } catch (final Exception ex) { + if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { + sender.sendMessage(ChatColor.RED + "Exception, check error log"); + logblock.getLogger().log(Level.SEVERE, "[Teleport] " + params.getQuery() + ": ", ex); + } + } finally { + close(); + } + } + } + + public class CommandRollback extends AbstractCommand { + public CommandRollback(CommandSender sender, QueryParams params, boolean async) throws Exception { + super(sender, params, async); + } + + @Override + public void run() { + try { + if (params.bct == BlockChangeType.CHAT) { + sender.sendMessage(ChatColor.RED + "Chat cannot be rolled back"); + return; + } + if (params.bct == BlockChangeType.KILLS) { + sender.sendMessage(ChatColor.RED + "Kills cannot be rolled back"); + return; + } + if (params.sum != SummarizationMode.NONE) { + sender.sendMessage(ChatColor.RED + "Cannot rollback summarized changes"); + return; + } + params.needDate = true; + params.needCoords = true; + params.needType = true; + params.needData = true; + params.needChestAccess = true; + params.sum = SummarizationMode.NONE; + conn = logblock.getConnection(); + if (conn == null) { + sender.sendMessage(ChatColor.RED + "MySQL connection lost"); + return; + } + state = conn.createStatement(); + if (!checkRestrictions(sender, params)) { + return; + } + if (!params.silent) { + sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); + } + rs = executeQuery(state, params.getQuery()); + final WorldEditor editor = new WorldEditor(logblock, params.world, params.forceReplace); + WorldEditorEditFactory editFactory = new WorldEditorEditFactory(editor, params, true); + while (rs.next()) { + editFactory.processRow(rs); + } + if (params.order == Order.DESC) { + editor.reverseRowOrder(); + } + editor.sortRows(Order.DESC); + final int changes = editor.getSize(); + if (changes > 10000) { + editor.setSender(sender); + } + if (!params.silent) { + sender.sendMessage(ChatColor.GREEN.toString() + changes + " " + (params.bct == BlockChangeType.ENTITIES ? "entities" : "blocks") + " found."); + } + if (changes == 0) { + if (!params.silent) { + sender.sendMessage(ChatColor.RED + "Rollback aborted"); + } + return; + } + if (!params.silent && askRollbacks && sender instanceof Player && !logblock.getQuestioner().ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { + sender.sendMessage(ChatColor.RED + "Rollback aborted"); + return; + } + editor.start(); + if (!params.noCache) { + getSession(sender).lookupCache = editor.errors; + } + sender.sendMessage(ChatColor.GREEN + "Rollback finished successfully (" + editor.getElapsedTime() + " ms, " + editor.getSuccesses() + "/" + changes + " blocks" + (editor.getErrors() > 0 ? ", " + ChatColor.RED + editor.getErrors() + " errors" + ChatColor.GREEN : "") + (editor.getBlacklistCollisions() > 0 ? ", " + editor.getBlacklistCollisions() + " blacklist collisions" : "") + ")"); + if (!params.silent && askClearLogAfterRollback && logblock.hasPermission(sender, "logblock.clearlog") && sender instanceof Player) { + Thread.sleep(1000); + if (logblock.getQuestioner().ask((Player) sender, "Do you want to delete the rollbacked log?", "yes", "no").equals("yes")) { + params.silent = true; + new CommandClearLog(sender, params, false); + } else { + sender.sendMessage(ChatColor.LIGHT_PURPLE + "Clearlog cancelled"); + } + } + } catch (final Exception ex) { + if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { + sender.sendMessage(ChatColor.RED + "Exception, check error log"); + logblock.getLogger().log(Level.SEVERE, "[Rollback] " + params.getQuery() + ": ", ex); + } + } finally { + close(); + } + } + } + + public class CommandRedo extends AbstractCommand { + public CommandRedo(CommandSender sender, QueryParams params, boolean async) throws Exception { + super(sender, params, async); + } + + @Override + public void run() { + try { + if (params.bct == BlockChangeType.CHAT) { + sender.sendMessage(ChatColor.RED + "Chat cannot be redone"); + return; + } + if (params.bct == BlockChangeType.KILLS) { + sender.sendMessage(ChatColor.RED + "Kills cannot be redone"); + return; + } + if (params.sum != SummarizationMode.NONE) { + sender.sendMessage(ChatColor.RED + "Cannot redo summarized changes"); + return; + } + params.needDate = true; + params.needCoords = true; + params.needType = true; + params.needData = true; + params.needChestAccess = true; + params.sum = SummarizationMode.NONE; + conn = logblock.getConnection(); + if (conn == null) { + sender.sendMessage(ChatColor.RED + "MySQL connection lost"); + return; + } + state = conn.createStatement(); + if (!checkRestrictions(sender, params)) { + return; + } + rs = executeQuery(state, params.getQuery()); + if (!params.silent) { + sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); + } + final WorldEditor editor = new WorldEditor(logblock, params.world, params.forceReplace); + WorldEditorEditFactory editFactory = new WorldEditorEditFactory(editor, params, false); + while (rs.next()) { + editFactory.processRow(rs); + } + if (params.order == Order.ASC) { + editor.reverseRowOrder(); + } + editor.sortRows(Order.ASC); + final int changes = editor.getSize(); + if (!params.silent) { + sender.sendMessage(ChatColor.GREEN.toString() + changes + " " + (params.bct == BlockChangeType.ENTITIES ? "entities" : "blocks") + " found."); + } + if (changes == 0) { + if (!params.silent) { + sender.sendMessage(ChatColor.RED + "Redo aborted"); + } + return; + } + if (!params.silent && askRedos && sender instanceof Player && !logblock.getQuestioner().ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { + sender.sendMessage(ChatColor.RED + "Redo aborted"); + return; + } + editor.start(); + sender.sendMessage(ChatColor.GREEN + "Redo finished successfully (" + editor.getElapsedTime() + " ms, " + editor.getSuccesses() + "/" + changes + " blocks" + (editor.getErrors() > 0 ? ", " + ChatColor.RED + editor.getErrors() + " errors" + ChatColor.GREEN : "") + (editor.getBlacklistCollisions() > 0 ? ", " + editor.getBlacklistCollisions() + " blacklist collisions" : "") + ")"); + } catch (final Exception ex) { + if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { + sender.sendMessage(ChatColor.RED + "Exception, check error log"); + logblock.getLogger().log(Level.SEVERE, "[Redo] " + params.getQuery() + ": ", ex); + } + } finally { + close(); + } + } + } + + public class CommandClearLog extends AbstractCommand { + public CommandClearLog(CommandSender sender, QueryParams params, boolean async) throws Exception { + super(sender, params, async); + } + + @Override + public void run() { + try { + conn = logblock.getConnection(); + conn.setAutoCommit(true); + state = conn.createStatement(); + if (conn == null) { + sender.sendMessage(ChatColor.RED + "MySQL connection lost"); + return; + } + if (!checkRestrictions(sender, params)) { + return; + } + if (params.sum != SummarizationMode.NONE) { + sender.sendMessage(ChatColor.RED + "Cannot summarize on ClearLog"); + return; + } + String tableBase; + String deleteFromTables; + String tableName; + params.needId = true; + params.needDate = true; + params.needPlayerId = true; + if (params.bct == BlockChangeType.CHAT) { + params.needMessage = true; + tableBase = "lb-chat"; + deleteFromTables = "`lb-chat` "; + tableName = "lb-chat"; + } else if (params.bct == BlockChangeType.KILLS) { + params.needWeapon = true; + params.needCoords = true; + tableBase = params.getTable(); + deleteFromTables = "`" + tableBase + "-kills` "; + tableName = tableBase + "-kills"; + } else if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) { + params.needType = true; + params.needCoords = true; + params.needData = true; + tableBase = params.getTable(); + deleteFromTables = "`" + tableBase + "-entities` "; + tableName = tableBase + "-entities"; + } else { + params.needType = true; + params.needCoords = true; + params.needData = true; + params.needChestAccess = true; + tableBase = params.getTable(); + deleteFromTables = "`" + tableBase + "-blocks`, `" + tableBase + "-state`, `" + tableBase + "-chestdata` "; + tableName = tableBase + "-blocks"; + } + final File dumpFolder = new File(logblock.getDataFolder(), "dump"); + if (!dumpFolder.exists()) { + dumpFolder.mkdirs(); + } + rs = state.executeQuery("SELECT count(*) " + params.getFrom() + params.getWhere()); + int deleted = rs.next() ? rs.getInt(1) : 0; + rs.close(); + if (!params.silent && askClearLogs && sender instanceof Player) { + sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); + sender.sendMessage(ChatColor.GREEN.toString() + deleted + " entries found."); + if (deleted == 0 || !logblock.getQuestioner().ask((Player) sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { + sender.sendMessage(ChatColor.RED + "ClearLog aborted"); + return; + } + } + if (deleted > 0 && dumpDeletedLog) { + final String time = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss").format(System.currentTimeMillis()); + try { + File outFile = new File(dumpFolder, (time + " " + tableName + " " + params.getTitle() + ".sql").replace(':', '.').replace('/', '_').replace('\\', '_')); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(outFile)), "UTF-8")); + try { + rs = state.executeQuery("SELECT " + params.getFields() + params.getFrom() + params.getWhere()); + while (rs.next()) { + StringBuilder sb = new StringBuilder(); + if (params.bct == BlockChangeType.CHAT) { + sb.append("INSERT INTO `lb-chat` (`id`, `date`, `playerid`, `message`) VALUES ("); + sb.append(rs.getInt("id")).append(", FROM_UNIXTIME("); + sb.append(rs.getTimestamp("date").getTime() / 1000).append("), "); + sb.append(rs.getInt("playerid")).append(", '"); + sb.append(Utils.mysqlTextEscape(rs.getString("message"))); + sb.append("');\n"); + } else if (params.bct == BlockChangeType.KILLS) { + sb.append("INSERT INTO `").append(tableBase).append("-kills` (`id`, `date`, `killer`, `victim`, `weapon`, `x`, `y`, `z`) VALUES ("); + sb.append(rs.getInt("id")).append(", FROM_UNIXTIME("); + sb.append(rs.getTimestamp("date").getTime() / 1000).append("), "); + sb.append(rs.getInt("killerid")).append(", "); + sb.append(rs.getInt("victimid")).append(", "); + sb.append(rs.getInt("weapon")).append(", "); + sb.append(rs.getInt("x")).append(", "); + sb.append(rs.getInt("y")).append(", "); + sb.append(rs.getInt("z")); + sb.append(");\n"); + } else if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) { + + } else { + sb.append("INSERT INTO `").append(tableBase).append("-blocks` (`id`, `date`, `playerid`, `replaced`, `replacedData`, `type`, `typeData`, `x`, `y`, `z`) VALUES ("); + sb.append(rs.getInt("id")).append(", FROM_UNIXTIME("); + sb.append(rs.getTimestamp("date").getTime() / 1000).append("), "); + sb.append(rs.getInt("playerid")).append(", "); + sb.append(rs.getInt("replaced")).append(", "); + sb.append(rs.getInt("replacedData")).append(", "); + sb.append(rs.getInt("type")).append(", "); + sb.append(rs.getInt("typeData")).append(", "); + sb.append(rs.getInt("x")).append(", "); + sb.append(rs.getInt("y")).append(", "); + sb.append(rs.getInt("z")); + sb.append(");\n"); + byte[] replacedState = rs.getBytes("replacedState"); + byte[] typeState = rs.getBytes("typeState"); + if (replacedState != null || typeState != null) { + sb.append("INSERT INTO `").append(tableBase).append("-state` (`id`, `replacedState`, `typeState`) VALUES ("); + sb.append(rs.getInt("id")).append(", "); + sb.append(Utils.mysqlPrepareBytesForInsertAllowNull(replacedState)).append(", "); + sb.append(Utils.mysqlPrepareBytesForInsertAllowNull(typeState)); + sb.append(");\n"); + } + byte[] item = rs.getBytes("item"); + if (item != null) { + sb.append("INSERT INTO `").append(tableBase).append("-chestdata` (`id`, `item`, `itemremove`, `itemtype`) VALUES ("); + sb.append(rs.getInt("id")).append(", "); + sb.append(Utils.mysqlPrepareBytesForInsertAllowNull(item)).append(", "); + sb.append(rs.getInt("itemremove")).append(", "); + sb.append(rs.getInt("itemtype")); + sb.append(");\n"); + } + } + writer.write(sb.toString()); + } + rs.close(); + } finally { + writer.close(); + } + } catch (final SQLException ex) { + sender.sendMessage(ChatColor.RED + "Error while dumping log."); + logblock.getLogger().log(Level.SEVERE, "[ClearLog] Exception while dumping log: ", ex); + return; + } + } + if (deleted > 0) { + state.executeUpdate("DELETE " + deleteFromTables + params.getFrom() + params.getWhere()); + if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) { + state.executeUpdate("DELETE `" + tableBase + "-entityids` FROM `" + tableBase + "-entityids` LEFT JOIN `" + tableBase + "-entities` USING (entityid) WHERE `" + tableBase + "-entities`.entityid IS NULL"); + } + } + sender.sendMessage(ChatColor.GREEN + "Cleared out table " + tableName + ". Deleted " + deleted + " entries."); + } catch (final Exception ex) { + if (logblock.isCompletelyEnabled() || !(ex instanceof SQLException)) { + sender.sendMessage(ChatColor.RED + "Exception, check error log"); + logblock.getLogger().log(Level.SEVERE, "[ClearLog] Exception: ", ex); + } + } finally { + close(); + } + } + } + + private ResultSet executeQuery(Statement state, String query) throws SQLException { + if (Config.debug) { + long startTime = System.currentTimeMillis(); + ResultSet rs = state.executeQuery(query); + logblock.getLogger().log(Level.INFO, "[LogBlock Debug] Time Taken: " + (System.currentTimeMillis() - startTime) + " milliseconds. Query: " + query); + return rs; + } else { + return state.executeQuery(query); + } + } + + private static List argsToList(String[] arr, int offset) { + final List list = new ArrayList<>(Arrays.asList(arr)); + for (int i = 0; i < offset; i++) { + list.remove(0); + } + return list; + } +} From f42649adc368bc9182ac0e6bbca15399560d6404 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 29 Jan 2021 20:10:43 +0100 Subject: [PATCH 260/399] Do not forget to close connection when upgrading a table fails --- src/main/java/de/diddiz/LogBlock/Updater.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index a521659a..fcd2b704 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -738,9 +738,14 @@ boolean update() { st.execute("ALTER TABLE `" + wcfg.table + "-entities` ADD KEY entityid (entityid)"); logblock.getLogger().info("Added index for table " + wcfg.table + "-entities"); st.close(); - conn.close(); } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + logblock.getLogger().log(Level.SEVERE, "[Updater] Warning: Could not upgrade the database: " + ex.getMessage()); + } finally { + try { + conn.close(); + } catch (SQLException e) { + // ignored + } } } config.set("version", "1.16.0"); From 033a53e338fd905ad2c040a464ce959163d87d34 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 30 Jan 2021 17:34:24 +0100 Subject: [PATCH 261/399] Improve database upgrade logic --- src/main/java/de/diddiz/LogBlock/Updater.java | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index fcd2b704..67ca04aa 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -730,23 +730,15 @@ boolean update() { } if (configVersion.compareTo(new ComparableVersion("1.16.0")) < 0) { - for (final WorldConfig wcfg : getLoggedWorlds()) { - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - st.execute("ALTER TABLE `" + wcfg.table + "-entities` ADD KEY entityid (entityid)"); - logblock.getLogger().info("Added index for table " + wcfg.table + "-entities"); - st.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Warning: Could not upgrade the database: " + ex.getMessage()); - } finally { - try { - conn.close(); - } catch (SQLException e) { - // ignored - } + try (Connection conn = logblock.getConnection()) { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + for (final WorldConfig wcfg : getLoggedWorlds()) { + createIndexIfDoesNotExist(wcfg.table + "-entities", "entityid", "KEY `entityid` (entityid)", st, false); } + st.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Warning: Could not add index", ex); } config.set("version", "1.16.0"); } From 841ce89f2180d41be606ad432c04c208af853291 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 17 Feb 2021 07:10:51 +0100 Subject: [PATCH 262/399] UUIDs are stored differently since 1.16 --- src/main/java/de/diddiz/worldedit/WorldEditHelper.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java b/src/main/java/de/diddiz/worldedit/WorldEditHelper.java index b3cf56f4..b24413ec 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditHelper.java @@ -117,7 +117,12 @@ public static Entity restoreEntity(Location location, EntityType type, byte[] se com.sk89q.worldedit.entity.Entity weEntity = weLocation.getExtent().createEntity(weLocation, state); if (weEntity != null) { CompoundTag newNbt = weEntity.getState().getNbtData(); - newUUID = new UUID(newNbt.getLong("UUIDMost"), newNbt.getLong("UUIDLeast")); + 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 { + newUUID = new UUID(newNbt.getLong("UUIDMost"), newNbt.getLong("UUIDLeast")); // pre 1.16 + } } } return newUUID == null ? null : Bukkit.getEntity(newUUID); From 76df1a49134c90bc857887ea675bacde2975d92f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 17 Feb 2021 07:31:50 +0100 Subject: [PATCH 263/399] Use GSON in UUIDFetcher --- src/main/java/de/diddiz/util/UUIDFetcher.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/diddiz/util/UUIDFetcher.java b/src/main/java/de/diddiz/util/UUIDFetcher.java index 1368dc3d..14d42fda 100644 --- a/src/main/java/de/diddiz/util/UUIDFetcher.java +++ b/src/main/java/de/diddiz/util/UUIDFetcher.java @@ -1,9 +1,10 @@ package de.diddiz.util; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; - +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; @@ -18,18 +19,18 @@ public class UUIDFetcher { private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft"; - private static final JSONParser jsonParser = new JSONParser(); + private static final Gson gson = new GsonBuilder().setLenient().create(); public static Map getUUIDs(List names) throws Exception { Map uuidMap = new HashMap<>(); HttpURLConnection connection = createConnection(); - String body = JSONArray.toJSONString(names); + String body = gson.toJson(names); writeBody(connection, body); - JSONArray array = (JSONArray) jsonParser.parse(new InputStreamReader(connection.getInputStream())); - for (Object profile : array) { - JSONObject jsonProfile = (JSONObject) profile; - String id = (String) jsonProfile.get("id"); - String name = (String) jsonProfile.get("name"); + JsonArray array = gson.fromJson(new InputStreamReader(connection.getInputStream()), JsonArray.class); + for (JsonElement profile : array) { + JsonObject jsonProfile = (JsonObject) profile; + String id = jsonProfile.get("id").getAsString(); + String name = jsonProfile.get("name").getAsString(); UUID uuid = getUUID(id); uuidMap.put(name, uuid); } From fe98370acd949b3f6aa7b5b20a6241f233ad00de Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 20 Feb 2021 06:32:53 +0100 Subject: [PATCH 264/399] Avoid syncronous query in /lb me and improve changes count display in sumarized changes Fixes #819 --- .../de/diddiz/LogBlock/CommandsHandler.java | 17 ++++++++++++----- .../de/diddiz/LogBlock/LookupCacheElement.java | 4 ++++ .../de/diddiz/LogBlock/SummedBlockChanges.java | 5 +++++ .../de/diddiz/LogBlock/SummedEntityChanges.java | 5 +++++ .../java/de/diddiz/LogBlock/SummedKills.java | 5 +++++ 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 3ac86e52..5052cb00 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -304,7 +304,6 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, final QueryParams params = new QueryParams(logblock); params.setPlayer(player.getName()); params.world = player.getWorld(); - player.sendMessage("Total block changes: " + logblock.getCount(params)); params.sum = SummarizationMode.TYPES; new CommandLookup(sender, params, true); } else { @@ -529,13 +528,21 @@ public void run() { if (!params.noCache) { getSession(sender).lookupCache = blockChangeArray; } - if (blockchanges.size() > linesPerPage) { - sender.sendMessage(ChatColor.DARK_AQUA.toString() + blockchanges.size() + " changes found." + (blockchanges.size() == linesLimit ? " Use 'limit -1' to see all changes." : "")); - } - if (params.sum != SummarizationMode.NONE) { + if (params.sum == SummarizationMode.NONE) { + if (blockchanges.size() > linesPerPage) { + sender.sendMessage(ChatColor.DARK_AQUA.toString() + blockchanges.size() + " changes found." + (blockchanges.size() == linesLimit ? " Use 'limit -1' to see all changes." : "")); + } + } else { + int totalChanges = 0; + for (LookupCacheElement element : blockchanges) { + totalChanges += element.getNumChanges(); + } + sender.sendMessage(ChatColor.DARK_AQUA.toString() + totalChanges + " changes found."); if (params.bct == BlockChangeType.KILLS && params.sum == SummarizationMode.PLAYERS) { + sender.sendMessage(ChatColor.DARK_AQUA.toString() + blockchanges.size() + " distinct players found."); sender.sendMessage(ChatColor.GOLD + "Kills - Killed - Player"); } else { + sender.sendMessage(ChatColor.DARK_AQUA.toString() + blockchanges.size() + " distinct " + (params.sum == SummarizationMode.TYPES ? (params.bct == BlockChangeType.ENTITIES ? "entities" : "blocks") : "players") + " found."); sender.sendMessage(ChatColor.GOLD + "Created - Destroyed - " + (params.sum == SummarizationMode.TYPES ? (params.bct == BlockChangeType.ENTITIES ? "Entity" : "Block") : "Player")); } } diff --git a/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java b/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java index 402ec8a4..0bffb6b2 100644 --- a/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java +++ b/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java @@ -11,4 +11,8 @@ public default BaseComponent[] getLogMessage() { } public BaseComponent[] getLogMessage(int entry); + + public default int getNumChanges() { + return 1; + } } diff --git a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java index c9eceae5..f7c36d93 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java @@ -34,4 +34,9 @@ public Location getLocation() { 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); } + + @Override + public int getNumChanges() { + return created + destroyed; + } } diff --git a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java index 5677cb01..4c14f5f9 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java @@ -36,4 +36,9 @@ public Location getLocation() { 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); } + + @Override + public int getNumChanges() { + return created + destroyed; + } } diff --git a/src/main/java/de/diddiz/LogBlock/SummedKills.java b/src/main/java/de/diddiz/LogBlock/SummedKills.java index 6151a737..2bec40c7 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedKills.java +++ b/src/main/java/de/diddiz/LogBlock/SummedKills.java @@ -28,4 +28,9 @@ public Location getLocation() { public BaseComponent[] getLogMessage(int entry) { return MessagingUtil.formatSummarizedChanges(kills, killed, new TextComponent(player.getName()), 6, 7, spaceFactor); } + + @Override + public int getNumChanges() { + return kills + killed; + } } From 8a8471c3e60e6e26dea1797cbaa1c06a2d35d22f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 21 Feb 2021 07:29:50 +0100 Subject: [PATCH 265/399] Initial work for improved inventory logging --- .../listeners/ChestAccessLogging.java | 222 ++++++++++++++++-- 1 file changed, 206 insertions(+), 16 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index 0b8422bd..b726116b 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -10,19 +10,52 @@ import org.bukkit.entity.HumanEntity; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +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.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; import static de.diddiz.LogBlock.config.Config.isLogging; import static de.diddiz.util.BukkitUtils.*; public class ChestAccessLogging extends LoggingListener { - private final Map containers = new HashMap<>(); + private class PlayerActiveInventoryModifications { + private HashMap modifications; + + public PlayerActiveInventoryModifications() { + this.modifications = new HashMap<>(); + } + + public void addModification(ItemStack stack, int amount) { + if (amount == 0) { + return; + } + consumer.getLogblock().getLogger().info("Modify container: " + stack + " change: " + amount); + stack = new ItemStack(stack); + stack.setAmount(1); + Integer existing = modifications.get(stack); + int newTotal = amount + (existing == null ? 0 : existing); + if (newTotal == 0) { + modifications.remove(stack); + } else { + modifications.put(stack, newTotal); + } + } + + public HashMap getModifications() { + return modifications; + } + } + + private final Map containers = new HashMap<>(); public ChestAccessLogging(LogBlock lb) { super(lb); @@ -30,41 +63,198 @@ public ChestAccessLogging(LogBlock lb) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onInventoryClose(InventoryCloseEvent event) { - - if (!isLogging(event.getPlayer().getWorld(), Logging.CHESTACCESS)) { + final HumanEntity player = event.getPlayer(); + if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) { return; } InventoryHolder holder = event.getInventory().getHolder(); if (holder instanceof BlockState || holder instanceof DoubleChest) { - final HumanEntity player = event.getPlayer(); - final ItemStack[] before = containers.get(player); - if (before != null) { - final ItemStack[] after = compressInventory(event.getInventory().getContents()); - final ItemStack[] diff = compareInventories(before, after); + final PlayerActiveInventoryModifications modifications = containers.remove(player); + if (modifications != null) { final Location loc = getInventoryHolderLocation(holder); if (loc != null) { - for (final ItemStack item : diff) { - ItemStack item2 = item.clone(); - item2.setAmount(Math.abs(item.getAmount())); - consumer.queueChestAccess(Actor.actorFromEntity(player), loc, loc.getWorld().getBlockAt(loc).getBlockData(), item2, item.getAmount() < 0); + for (Entry e : modifications.getModifications().entrySet()) { + ItemStack stack = e.getKey(); + int amount = e.getValue(); + stack.setAmount(Math.abs(amount)); + consumer.getLogblock().getLogger().info("Store container: " + stack + " take: " + (amount < 0)); + consumer.queueChestAccess(Actor.actorFromEntity(player), loc, loc.getWorld().getBlockAt(loc).getBlockData(), stack, amount < 0); } } - containers.remove(player); } } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onInventoryOpen(InventoryOpenEvent event) { - - if (!isLogging(event.getPlayer().getWorld(), Logging.CHESTACCESS)) { + final HumanEntity player = event.getPlayer(); + if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) { return; } if (event.getInventory() != null) { InventoryHolder holder = event.getInventory().getHolder(); if (holder instanceof BlockState || holder instanceof DoubleChest) { if (getInventoryHolderType(holder) != Material.CRAFTING_TABLE) { - containers.put(event.getPlayer(), compressInventory(event.getInventory().getContents())); + containers.put(player, new PlayerActiveInventoryModifications()); + } + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onInventoryClick(InventoryClickEvent event) { + final HumanEntity player = event.getWhoClicked(); + if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) { + return; + } + InventoryHolder holder = event.getInventory().getHolder(); + if (holder instanceof BlockState || holder instanceof DoubleChest) { + final PlayerActiveInventoryModifications modifications = containers.get(player); + if (modifications != null) { + switch (event.getAction()) { + case PICKUP_ONE: + case DROP_ONE_SLOT: + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + modifications.addModification(event.getCurrentItem(), -1); + } + break; + case PICKUP_HALF: + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + modifications.addModification(event.getCurrentItem(), -(event.getCurrentItem().getAmount() + 1) / 2); + } + break; + case PICKUP_SOME: // oversized stack - can not take all when clicking + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + int taken = event.getCurrentItem().getAmount() - event.getCurrentItem().getMaxStackSize(); + modifications.addModification(event.getCursor(), -taken); + } + break; + case PICKUP_ALL: + case DROP_ALL_SLOT: + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount()); + } + break; + case PLACE_ONE: + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + modifications.addModification(event.getCursor(), 1); + } + break; + case PLACE_SOME: // not enough free place in target slot + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + int placeable = event.getCurrentItem().getMaxStackSize() - event.getCurrentItem().getAmount(); + modifications.addModification(event.getCursor(), placeable); + } + break; + case PLACE_ALL: + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + modifications.addModification(event.getCursor(), event.getCursor().getAmount()); + } + break; + case SWAP_WITH_CURSOR: + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + modifications.addModification(event.getCursor(), event.getCursor().getAmount()); + modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount()); + } + break; + case MOVE_TO_OTHER_INVENTORY: // shift + click + boolean removed = event.getRawSlot() < event.getView().getTopInventory().getSize(); + modifications.addModification(event.getCurrentItem(), event.getCurrentItem().getAmount() * (removed ? -1 : 1)); + break; + case COLLECT_TO_CURSOR: // double click + // first collect all with an amount != maxstacksize, then others, starting from slot 0 (container) + ItemStack cursor = event.getCursor(); + if (cursor == null) { + return; + } + int toPickUp = cursor.getMaxStackSize() - cursor.getAmount(); + int takenFromContainer = 0; + boolean takeFromFullStacks = false; + Inventory top = event.getView().getTopInventory(); + Inventory bottom = event.getView().getBottomInventory(); + while (true) { + for (ItemStack stack : top.getStorageContents()) { + if (cursor.isSimilar(stack)) { + if (takeFromFullStacks == (stack.getAmount() == stack.getMaxStackSize())) { + consumer.getLogblock().getLogger().info("Collect, from " + stack + ": " + takeFromFullStacks + ";" + stack.getAmount() + ";" + stack.getMaxStackSize()); + int take = Math.min(toPickUp, stack.getAmount()); + toPickUp -= take; + takenFromContainer += take; + if (toPickUp <= 0) { + break; + } + } + } + } + for (ItemStack stack : bottom.getStorageContents()) { + if (cursor.isSimilar(stack)) { + if (takeFromFullStacks == (stack.getAmount() == stack.getMaxStackSize())) { + consumer.getLogblock().getLogger().info("Collect 2, from " + stack + ": " + takeFromFullStacks + ";" + stack.getAmount() + ";" + stack.getMaxStackSize()); + int take = Math.min(toPickUp, stack.getAmount()); + toPickUp -= take; + if (toPickUp <= 0) { + break; + } + } + } + } + if (takeFromFullStacks) { + break; + } else { + takeFromFullStacks = true; + } + } + if (takenFromContainer > 0) { + modifications.addModification(event.getCursor(), -takenFromContainer); + } + break; + case HOTBAR_SWAP: // number key or offhand key + case HOTBAR_MOVE_AND_READD: + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + ItemStack otherSlot = (event.getClick() == ClickType.SWAP_OFFHAND) ? event.getWhoClicked().getInventory().getItemInOffHand() : event.getWhoClicked().getInventory().getItem(event.getHotbarButton()); + if (event.getCurrentItem() != null && event.getCurrentItem().getType() != Material.AIR) { + modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount()); + } + if (otherSlot != null && otherSlot.getType() != Material.AIR) { + modifications.addModification(otherSlot, otherSlot.getAmount()); + } + } + break; + case DROP_ALL_CURSOR: + case DROP_ONE_CURSOR: + case CLONE_STACK: + case NOTHING: + // only the cursor or nothing (but not the inventory) was modified + break; + case UNKNOWN: + default: + // unable to log something we don't know + consumer.getLogblock().getLogger().warning("Unknown inventory action by " + event.getWhoClicked().getName() + ": " + event.getAction() + " Slot: " + event.getSlot() + " Slot type: " + event.getSlotType()); + break; + } + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onInventoryClick(InventoryDragEvent event) { + final HumanEntity player = event.getWhoClicked(); + if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) { + return; + } + InventoryHolder holder = event.getInventory().getHolder(); + if (holder instanceof BlockState || holder instanceof DoubleChest) { + final PlayerActiveInventoryModifications modifications = containers.get(player); + if (modifications != null) { + Inventory container = event.getView().getTopInventory(); + int containerSize = container.getSize(); + for (Entry e : event.getNewItems().entrySet()) { + int slot = e.getKey(); + if (slot < containerSize) { + ItemStack old = container.getItem(slot); + int oldAmount = (old == null || old.getType() == Material.AIR) ? 0 : old.getAmount(); + modifications.addModification(e.getValue(), e.getValue().getAmount() - oldAmount); + } } } } From 4f7c02b28547b3434a3c43e5582a3b2479d5d1ca Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 22 Feb 2021 07:42:50 +0100 Subject: [PATCH 266/399] Flush other viewers of the same inventory; add some documentation --- .../listeners/ChestAccessLogging.java | 91 ++++++++++++++----- 1 file changed, 66 insertions(+), 25 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index b726116b..dc71834f 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -18,7 +18,7 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; - +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -28,9 +28,13 @@ public class ChestAccessLogging extends LoggingListener { private class PlayerActiveInventoryModifications { - private HashMap modifications; + private final HumanEntity actor; + private final Location location; + private final HashMap modifications; - public PlayerActiveInventoryModifications() { + public PlayerActiveInventoryModifications(HumanEntity actor, Location location) { + this.actor = actor; + this.location = location; this.modifications = new HashMap<>(); } @@ -38,6 +42,16 @@ public void addModification(ItemStack stack, int amount) { if (amount == 0) { return; } + // if we have other viewers, we have to flush their changes + ArrayList allViewers = containersByLocation.get(location); + if (allViewers.size() > 1) { + for (PlayerActiveInventoryModifications other : allViewers) { + if (other != this) { + other.flush(); + } + } + } + consumer.getLogblock().getLogger().info("Modify container: " + stack + " change: " + amount); stack = new ItemStack(stack); stack.setAmount(1); @@ -50,12 +64,30 @@ public void addModification(ItemStack stack, int amount) { } } - public HashMap getModifications() { - return modifications; + public void flush() { + if (!modifications.isEmpty()) { + for (Entry e : modifications.entrySet()) { + ItemStack stack = e.getKey(); + int amount = e.getValue(); + 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(); + } + } + + public HumanEntity getActor() { + return actor; + } + + public Location getLocation() { + return location; } } - private final Map containers = new HashMap<>(); + private final Map containersByOwner = new HashMap<>(); + private final Map> containersByLocation = new HashMap<>(); public ChestAccessLogging(LogBlock lb) { super(lb); @@ -69,18 +101,15 @@ public void onInventoryClose(InventoryCloseEvent event) { } InventoryHolder holder = event.getInventory().getHolder(); if (holder instanceof BlockState || holder instanceof DoubleChest) { - final PlayerActiveInventoryModifications modifications = containers.remove(player); + final PlayerActiveInventoryModifications modifications = containersByOwner.remove(player); if (modifications != null) { - final Location loc = getInventoryHolderLocation(holder); - if (loc != null) { - for (Entry e : modifications.getModifications().entrySet()) { - ItemStack stack = e.getKey(); - int amount = e.getValue(); - stack.setAmount(Math.abs(amount)); - consumer.getLogblock().getLogger().info("Store container: " + stack + " take: " + (amount < 0)); - consumer.queueChestAccess(Actor.actorFromEntity(player), loc, loc.getWorld().getBlockAt(loc).getBlockData(), stack, amount < 0); - } + final Location loc = modifications.getLocation(); + ArrayList atLocation = containersByLocation.get(loc); + atLocation.remove(modifications); + if (atLocation.isEmpty()) { + containersByLocation.remove(loc); } + modifications.flush(); } } } @@ -95,7 +124,15 @@ public void onInventoryOpen(InventoryOpenEvent event) { InventoryHolder holder = event.getInventory().getHolder(); if (holder instanceof BlockState || holder instanceof DoubleChest) { if (getInventoryHolderType(holder) != Material.CRAFTING_TABLE) { - containers.put(player, new PlayerActiveInventoryModifications()); + PlayerActiveInventoryModifications modifications = new PlayerActiveInventoryModifications(event.getPlayer(), getInventoryHolderLocation(holder)); + containersByOwner.put(modifications.getActor(), modifications); + containersByLocation.compute(modifications.getLocation(), (k, v) -> { + if (v == null) { + v = new ArrayList<>(); + } + v.add(modifications); + return v; + }); } } } @@ -109,7 +146,7 @@ public void onInventoryClick(InventoryClickEvent event) { } InventoryHolder holder = event.getInventory().getHolder(); if (holder instanceof BlockState || holder instanceof DoubleChest) { - final PlayerActiveInventoryModifications modifications = containers.get(player); + final PlayerActiveInventoryModifications modifications = containersByOwner.get(player); if (modifications != null) { switch (event.getAction()) { case PICKUP_ONE: @@ -119,11 +156,13 @@ public void onInventoryClick(InventoryClickEvent event) { } break; case PICKUP_HALF: + // server behaviour: round up if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { modifications.addModification(event.getCurrentItem(), -(event.getCurrentItem().getAmount() + 1) / 2); } break; case PICKUP_SOME: // oversized stack - can not take all when clicking + // server behaviour: leave a full stack in the slot, take everything else if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { int taken = event.getCurrentItem().getAmount() - event.getCurrentItem().getMaxStackSize(); modifications.addModification(event.getCursor(), -taken); @@ -141,6 +180,7 @@ public void onInventoryClick(InventoryClickEvent event) { } break; case PLACE_SOME: // not enough free place in target slot + // server behaviour: place as much as possible if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { int placeable = event.getCurrentItem().getMaxStackSize() - event.getCurrentItem().getAmount(); modifications.addModification(event.getCursor(), placeable); @@ -162,7 +202,7 @@ public void onInventoryClick(InventoryClickEvent event) { modifications.addModification(event.getCurrentItem(), event.getCurrentItem().getAmount() * (removed ? -1 : 1)); break; case COLLECT_TO_CURSOR: // double click - // first collect all with an amount != maxstacksize, then others, starting from slot 0 (container) + // server behaviour: first collect all with an amount != maxstacksize, then others, starting from slot 0 (container) ItemStack cursor = event.getCursor(); if (cursor == null) { return; @@ -172,11 +212,10 @@ public void onInventoryClick(InventoryClickEvent event) { boolean takeFromFullStacks = false; Inventory top = event.getView().getTopInventory(); Inventory bottom = event.getView().getBottomInventory(); - while (true) { + while (toPickUp > 0) { for (ItemStack stack : top.getStorageContents()) { if (cursor.isSimilar(stack)) { if (takeFromFullStacks == (stack.getAmount() == stack.getMaxStackSize())) { - consumer.getLogblock().getLogger().info("Collect, from " + stack + ": " + takeFromFullStacks + ";" + stack.getAmount() + ";" + stack.getMaxStackSize()); int take = Math.min(toPickUp, stack.getAmount()); toPickUp -= take; takenFromContainer += take; @@ -186,10 +225,12 @@ public void onInventoryClick(InventoryClickEvent event) { } } } + if (toPickUp <= 0) { + break; + } for (ItemStack stack : bottom.getStorageContents()) { if (cursor.isSimilar(stack)) { if (takeFromFullStacks == (stack.getAmount() == stack.getMaxStackSize())) { - consumer.getLogblock().getLogger().info("Collect 2, from " + stack + ": " + takeFromFullStacks + ";" + stack.getAmount() + ";" + stack.getMaxStackSize()); int take = Math.min(toPickUp, stack.getAmount()); toPickUp -= take; if (toPickUp <= 0) { @@ -209,7 +250,7 @@ public void onInventoryClick(InventoryClickEvent event) { } break; case HOTBAR_SWAP: // number key or offhand key - case HOTBAR_MOVE_AND_READD: + case HOTBAR_MOVE_AND_READD: // something was in the other slot if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { ItemStack otherSlot = (event.getClick() == ClickType.SWAP_OFFHAND) ? event.getWhoClicked().getInventory().getItemInOffHand() : event.getWhoClicked().getInventory().getItem(event.getHotbarButton()); if (event.getCurrentItem() != null && event.getCurrentItem().getType() != Material.AIR) { @@ -237,14 +278,14 @@ public void onInventoryClick(InventoryClickEvent event) { } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onInventoryClick(InventoryDragEvent event) { + public void onInventoryDrag(InventoryDragEvent event) { final HumanEntity player = event.getWhoClicked(); if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) { return; } InventoryHolder holder = event.getInventory().getHolder(); if (holder instanceof BlockState || holder instanceof DoubleChest) { - final PlayerActiveInventoryModifications modifications = containers.get(player); + final PlayerActiveInventoryModifications modifications = containersByOwner.get(player); if (modifications != null) { Inventory container = event.getView().getTopInventory(); int containerSize = container.getSize(); From fe7e24489855b5c00192c2eceee453f99618f727 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 18 Mar 2021 21:25:10 +0100 Subject: [PATCH 267/399] Do not scroll in a result set when we don't have to --- .../java/de/diddiz/LogBlock/CommandsHandler.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 5052cb00..d3cd581f 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -517,13 +517,12 @@ public void run() { state = conn.createStatement(); rs = executeQuery(state, params.getQuery()); sender.sendMessage(ChatColor.DARK_AQUA + params.getTitle() + ":"); - if (rs.next()) { - rs.beforeFirst(); - final List blockchanges = new ArrayList<>(); - final LookupCacheElementFactory factory = new LookupCacheElementFactory(params, sender instanceof Player ? 2 / 3f : 1); - while (rs.next()) { - blockchanges.add(factory.getLookupCacheElement(rs)); - } + final List blockchanges = new ArrayList<>(); + final LookupCacheElementFactory factory = new LookupCacheElementFactory(params, sender instanceof Player ? 2 / 3f : 1); + while (rs.next()) { + blockchanges.add(factory.getLookupCacheElement(rs)); + } + if (!blockchanges.isEmpty()) { LookupCacheElement[] blockChangeArray = blockchanges.toArray(new LookupCacheElement[blockchanges.size()]); if (!params.noCache) { getSession(sender).lookupCache = blockChangeArray; From c20b677507df7eba33ffb54194a50367b01bd3ad Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 13 Apr 2021 18:24:54 +0200 Subject: [PATCH 268/399] Improve table creation logic --- src/main/java/de/diddiz/LogBlock/Updater.java | 14 +++++++++----- .../java/de/diddiz/LogBlock/config/Config.java | 4 +++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 67ca04aa..36b4b29b 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -842,11 +842,15 @@ void checkTables() throws SQLException { } private void createTable(DatabaseMetaData dbm, Statement state, String table, String query) throws SQLException { - if (!dbm.getTables(null, null, table, null).next()) { - logblock.getLogger().log(Level.INFO, "Creating table " + table + "."); - state.execute("CREATE TABLE `" + table + "` " + query); - if (!dbm.getTables(null, null, table, null).next()) { - throw new SQLException("Table " + table + " not found and failed to create"); + try (ResultSet tableResult = dbm.getTables(Config.mysqlDatabase, null, table, null)) { + if (!tableResult.next()) { + logblock.getLogger().log(Level.INFO, "Creating table " + table + "."); + state.execute("CREATE TABLE `" + table + "` " + query); + try (ResultSet tableResultNew = dbm.getTables(Config.mysqlDatabase, null, table, null)) { + if (!tableResultNew.next()) { + throw new SQLException("Table " + table + " not found and failed to create"); + } + } } } } diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 38e9950d..a30f422b 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -25,6 +25,7 @@ public class Config { private static LoggingEnabledMapping superWorldConfig; private static Map worldConfigs; public static String url, user, password; + public static String mysqlDatabase; public static boolean mysqlUseSSL; public static boolean mysqlRequireSSL; public static int delayBetweenRuns, forceToProcessAtLeast, timePerRun; @@ -175,7 +176,8 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti ComparableVersion configVersion = new ComparableVersion(config.getString("version")); boolean oldConfig = configVersion.compareTo(new ComparableVersion(CURRENT_CONFIG_VERSION)) < 0; - url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database"); + mysqlDatabase = getStringIncludingInts(config, "mysql.database"); + url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + mysqlDatabase; user = getStringIncludingInts(config, "mysql.user"); password = getStringIncludingInts(config, "mysql.password"); mysqlUseSSL = config.getBoolean("mysql.useSSL", true); From 0fd3266c7b47851a528bb3fbf558cfb4d6a76d8e Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 13 Apr 2021 18:32:16 +0200 Subject: [PATCH 269/399] Load the new mysql driver class if available --- src/main/java/de/diddiz/LogBlock/LogBlock.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 36a849ef..e45b204a 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -73,7 +73,11 @@ public void onEnable() { } try { getLogger().info("Connecting to " + user + "@" + url + "..."); - Class.forName("com.mysql.jdbc.Driver"); + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException ignored) { + Class.forName("com.mysql.jdbc.Driver"); + } pool = new MySQLConnectionPool(url, user, password, mysqlUseSSL, mysqlRequireSSL); final Connection conn = getConnection(true); if (conn == null) { From 87074da8a12f742a4a83bcd3ed52b7388f7fbec4 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 13 Apr 2021 20:53:56 +0200 Subject: [PATCH 270/399] Release Logblock 1.16.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 78d6c6d8..2337c74b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.16.1.2-SNAPSHOT + 1.16.5 jar LogBlock From 8148386e3ed3c64187e7b22cd0cee8c9c1606855 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 13 Apr 2021 21:01:37 +0200 Subject: [PATCH 271/399] Back to snapshots --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2337c74b..25214fdd 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.16.5 + 1.16.5.1-SNAPSHOT jar LogBlock From 2049a7a7a45b604750a248bab418ec9d51a438eb Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 14 Apr 2021 18:52:06 +0200 Subject: [PATCH 272/399] Use a different way to check for existing tables --- src/main/java/de/diddiz/LogBlock/Updater.java | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 36b4b29b..294de53a 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -808,9 +808,8 @@ void checkTables() throws SQLException { throw new SQLException("No connection"); } final Statement state = conn.createStatement(); - final DatabaseMetaData dbm = conn.getMetaData(); conn.setAutoCommit(true); - createTable(dbm, 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, 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); // 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;"); if (!rs.next()) { @@ -818,35 +817,35 @@ void checkTables() throws SQLException { } if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { try { - createTable(dbm, 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(dbm, 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(dbm, state, "lb-materials", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); - createTable(dbm, state, "lb-blockstates", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); - createTable(dbm, 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(dbm, state, wcfg.table + "-blocks", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced SMALLINT UNSIGNED NOT NULL, replacedData SMALLINT NOT NULL, type SMALLINT UNSIGNED NOT NULL, typeData SMALLINT NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))"); - createTable(dbm, state, wcfg.table + "-chestdata", "(id INT UNSIGNED NOT NULL, item MEDIUMBLOB, itemremove TINYINT, itemtype SMALLINT NOT NULL DEFAULT '0', PRIMARY KEY (id))"); - createTable(dbm, 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 UNSIGNED 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(dbm, state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id))"); + 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(dbm, 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(dbm, 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(DatabaseMetaData dbm, Statement state, String table, String query) throws SQLException { - try (ResultSet tableResult = dbm.getTables(Config.mysqlDatabase, null, table, null)) { + 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 = dbm.getTables(Config.mysqlDatabase, null, table, null)) { + try (ResultSet tableResultNew = state.executeQuery("SHOW TABLES LIKE '" + table + "'")) { if (!tableResultNew.next()) { throw new SQLException("Table " + table + " not found and failed to create"); } From 1df380741ba4ed4557410d48fa51ffc99749c60f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 15 Apr 2021 03:19:14 +0200 Subject: [PATCH 273/399] Release 1.16.5.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 25214fdd..1abab87b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.16.5.1-SNAPSHOT + 1.16.5.1 jar LogBlock From cb1231eab532d81c9aba4f05e96ae8696037e98b Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 15 Apr 2021 03:23:55 +0200 Subject: [PATCH 274/399] Snapshots --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1abab87b..bd8e9510 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.16.5.1 + 1.16.5.2-SNAPSHOT jar LogBlock From f0e3353fc96e634291bc44c57431a531c07a4cbc Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 28 Apr 2021 05:21:13 +0200 Subject: [PATCH 275/399] Prettier help formating Fixes #592 --- .../de/diddiz/LogBlock/CommandsHandler.java | 106 +++++++++++------- 1 file changed, 65 insertions(+), 41 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index d3cd581f..9ef9654f 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -27,6 +27,7 @@ import de.diddiz.LogBlock.QueryParams.SummarizationMode; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.WorldConfig; +import de.diddiz.util.MessagingUtil; import de.diddiz.util.Utils; import java.io.BufferedOutputStream; import java.io.BufferedWriter; @@ -44,6 +45,7 @@ import java.util.List; import java.util.logging.Level; import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.ChatColor; import org.bukkit.Location; @@ -68,53 +70,75 @@ public class CommandsHandler implements CommandExecutor { public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { try { if (args.length == 0) { - sender.sendMessage(ChatColor.LIGHT_PURPLE + "LogBlock v" + logblock.getDescription().getVersion() + " by DiddiZ"); - sender.sendMessage(ChatColor.LIGHT_PURPLE + "Type /lb help for help"); + sender.sendMessage(ChatColor.YELLOW + "------------------[ " + ChatColor.WHITE + "LogBlock" + ChatColor.YELLOW + " ]-------------------"); + sender.sendMessage(ChatColor.GOLD + "LogBlock " + ChatColor.WHITE + "v" + logblock.getDescription().getVersion() + ChatColor.GOLD + " by DiddiZ"); + TextComponent message = MessagingUtil.createTextComponentWithColor("Type ", net.md_5.bungee.api.ChatColor.GOLD); + TextComponent clickable = MessagingUtil.createTextComponentWithColor("/lb help", net.md_5.bungee.api.ChatColor.WHITE); + clickable.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/lb help")); + message.addExtra(clickable); + message.addExtra(" for help"); + sender.spigot().sendMessage(message); } else { final String command = args[0].toLowerCase(); if (command.equals("help")) { - sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Help:"); - sender.sendMessage(ChatColor.GOLD + "For the commands list type '/lb commands'"); - sender.sendMessage(ChatColor.GOLD + "For the parameters list type '/lb params'"); - sender.sendMessage(ChatColor.GOLD + "For the list of permissions you got type '/lb permissions'"); + sender.sendMessage(ChatColor.YELLOW + "----------------[ " + ChatColor.WHITE + "LogBlock Help" + ChatColor.YELLOW + " ]----------------"); + + TextComponent message = MessagingUtil.createTextComponentWithColor("For the commands list type ", net.md_5.bungee.api.ChatColor.GOLD); + TextComponent clickable = MessagingUtil.createTextComponentWithColor("/lb commands", net.md_5.bungee.api.ChatColor.WHITE); + clickable.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/lb commands")); + message.addExtra(clickable); + sender.spigot().sendMessage(message); + + message = MessagingUtil.createTextComponentWithColor("For the parameters list type ", net.md_5.bungee.api.ChatColor.GOLD); + clickable = MessagingUtil.createTextComponentWithColor("/lb params", net.md_5.bungee.api.ChatColor.WHITE); + clickable.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/lb params")); + message.addExtra(clickable); + sender.spigot().sendMessage(message); + + message = MessagingUtil.createTextComponentWithColor("For the list of permissions you got type ", net.md_5.bungee.api.ChatColor.GOLD); + clickable = MessagingUtil.createTextComponentWithColor("/lb permissions", net.md_5.bungee.api.ChatColor.WHITE); + clickable.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/lb permissions")); + message.addExtra(clickable); + sender.spigot().sendMessage(message); } else if (command.equals("commands")) { - sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Commands:"); - sender.sendMessage(ChatColor.GOLD + "/lb tool -- Gives you the lb tool"); - sender.sendMessage(ChatColor.GOLD + "/lb tool [on|off] -- Enables/Disables tool"); - sender.sendMessage(ChatColor.GOLD + "/lb tool [params] -- Sets the tool lookup query"); - sender.sendMessage(ChatColor.GOLD + "/lb tool default -- Sets the tool lookup query to default"); - sender.sendMessage(ChatColor.GOLD + "/lb toolblock -- Analog to tool"); - sender.sendMessage(ChatColor.GOLD + "/lb hide -- Hides you from log"); - sender.sendMessage(ChatColor.GOLD + "/lb rollback [params] -- Rollback"); - sender.sendMessage(ChatColor.GOLD + "/lb redo [params] -- Redo"); - sender.sendMessage(ChatColor.GOLD + "/lb tp [params] -- Teleports you to the location of griefing"); - sender.sendMessage(ChatColor.GOLD + "/lb writelogfile [params] -- Writes a log file"); - sender.sendMessage(ChatColor.GOLD + "/lb lookup [params] -- Lookup"); - sender.sendMessage(ChatColor.GOLD + "/lb prev|next -- Browse lookup result pages"); - sender.sendMessage(ChatColor.GOLD + "/lb page -- Shows a specific lookup result page"); - sender.sendMessage(ChatColor.GOLD + "/lb me -- Displays your stats"); - sender.sendMessage(ChatColor.GOLD + "Look at github.com/LogBlock/LogBlock/wiki/Commands for the full commands reference"); + sender.sendMessage(ChatColor.YELLOW + "--------------[ " + ChatColor.WHITE + "LogBlock Commands" + ChatColor.YELLOW + " ]--------------"); + sender.sendMessage(ChatColor.GOLD + "/lb tool " + ChatColor.WHITE + "-- Gives you the lb tool"); + sender.sendMessage(ChatColor.GOLD + "/lb tool [on|off] " + ChatColor.WHITE + "-- Enables/Disables tool"); + sender.sendMessage(ChatColor.GOLD + "/lb tool [params] " + ChatColor.WHITE + "-- Sets the tool lookup query"); + sender.sendMessage(ChatColor.GOLD + "/lb tool default " + ChatColor.WHITE + "-- Sets the tool lookup query to default"); + sender.sendMessage(ChatColor.GOLD + "/lb toolblock " + ChatColor.WHITE + "-- Analog to tool"); + sender.sendMessage(ChatColor.GOLD + "/lb hide " + ChatColor.WHITE + "-- Hides you from log"); + sender.sendMessage(ChatColor.GOLD + "/lb rollback [params] " + ChatColor.WHITE + "-- Rollback"); + sender.sendMessage(ChatColor.GOLD + "/lb redo [params] " + ChatColor.WHITE + "-- Redo"); + sender.sendMessage(ChatColor.GOLD + "/lb tp [params] " + ChatColor.WHITE + "-- Teleports you to the location of griefing"); + sender.sendMessage(ChatColor.GOLD + "/lb writelogfile [params] " + ChatColor.WHITE + "-- Writes a log file"); + sender.sendMessage(ChatColor.GOLD + "/lb lookup [params] " + ChatColor.WHITE + "-- Lookup"); + sender.sendMessage(ChatColor.GOLD + "/lb prev|next " + ChatColor.WHITE + "-- Browse lookup result pages"); + sender.sendMessage(ChatColor.GOLD + "/lb page " + ChatColor.WHITE + "-- Shows a specific lookup result page"); + sender.sendMessage(ChatColor.GOLD + "/lb me " + ChatColor.WHITE + "-- Displays your stats"); + sender.sendMessage(""); + sender.sendMessage(ChatColor.GOLD + "Look at " + ChatColor.WHITE + "github.com/LogBlock/LogBlock/wiki/Commands" + ChatColor.GOLD + " for the full commands reference"); } else if (command.equals("params")) { - sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Query Parameters:"); + sender.sendMessage(ChatColor.YELLOW + "----------[ " + ChatColor.WHITE + "LogBlock Query Parameters" + ChatColor.YELLOW + " ]----------"); sender.sendMessage(ChatColor.GOLD + "Use doublequotes to escape a keyword: world \"world\""); - sender.sendMessage(ChatColor.GOLD + "player [name1] -- List of players"); - sender.sendMessage(ChatColor.GOLD + "block [type1] -- List of block types"); - sender.sendMessage(ChatColor.GOLD + "created, destroyed -- Show only created/destroyed blocks"); - sender.sendMessage(ChatColor.GOLD + "chestaccess -- Show only chest accesses"); - sender.sendMessage(ChatColor.GOLD + "entities [type1] -- List of entity types; can not be combined with blocks"); - sender.sendMessage(ChatColor.GOLD + "area -- Area around you"); - sender.sendMessage(ChatColor.GOLD + "selection, sel -- Inside current WorldEdit selection"); - sender.sendMessage(ChatColor.GOLD + "world [worldname] -- Changes the world"); - sender.sendMessage(ChatColor.GOLD + "time [number] [minutes|hours|days] -- Limits time"); - sender.sendMessage(ChatColor.GOLD + "since -- Limits time to a fixed point"); - sender.sendMessage(ChatColor.GOLD + "before -- Affects only blocks before a fixed time"); - sender.sendMessage(ChatColor.GOLD + "force -- Forces replacing not matching blocks"); - sender.sendMessage(ChatColor.GOLD + "limit -- Limits the result to count of rows"); - sender.sendMessage(ChatColor.GOLD + "sum [none|blocks|players] -- Sums the result"); - sender.sendMessage(ChatColor.GOLD + "asc, desc -- Changes the order of the displayed log"); - sender.sendMessage(ChatColor.GOLD + "coords -- Shows coordinates for each block"); - sender.sendMessage(ChatColor.GOLD + "nocache -- Don't set the lookup cache"); - sender.sendMessage(ChatColor.GOLD + "silent -- Displays lesser messages"); + sender.sendMessage(ChatColor.GOLD + "player [name1] " + ChatColor.WHITE + "-- List of players"); + sender.sendMessage(ChatColor.GOLD + "block [type1] " + ChatColor.WHITE + "-- List of block types"); + sender.sendMessage(ChatColor.GOLD + "created, destroyed " + ChatColor.WHITE + "-- Show only created/destroyed blocks"); + sender.sendMessage(ChatColor.GOLD + "chestaccess " + ChatColor.WHITE + "-- Show only chest accesses"); + sender.sendMessage(ChatColor.GOLD + "entities [type1] " + ChatColor.WHITE + "-- List of entity types; can not be combined with blocks"); + sender.sendMessage(ChatColor.GOLD + "area " + ChatColor.WHITE + "-- Area around you"); + sender.sendMessage(ChatColor.GOLD + "selection, sel " + ChatColor.WHITE + "-- Inside current WorldEdit selection"); + sender.sendMessage(ChatColor.GOLD + "world [worldname] " + ChatColor.WHITE + "-- Changes the world"); + sender.sendMessage(ChatColor.GOLD + "time [number] [minutes|hours|days] " + ChatColor.WHITE + "-- Limits time"); + sender.sendMessage(ChatColor.GOLD + "since " + ChatColor.WHITE + "-- Limits time to a fixed point"); + sender.sendMessage(ChatColor.GOLD + "before " + ChatColor.WHITE + "-- Affects only blocks before a fixed time"); + sender.sendMessage(ChatColor.GOLD + "force " + ChatColor.WHITE + "-- Forces replacing not matching blocks"); + sender.sendMessage(ChatColor.GOLD + "limit " + ChatColor.WHITE + "-- Limits the result to count of rows"); + sender.sendMessage(ChatColor.GOLD + "sum [none|blocks|players] " + ChatColor.WHITE + "-- Sums the result"); + sender.sendMessage(ChatColor.GOLD + "asc, desc " + ChatColor.WHITE + "-- Changes the order of the displayed log"); + sender.sendMessage(ChatColor.GOLD + "coords " + ChatColor.WHITE + "-- Shows coordinates for each block"); + sender.sendMessage(ChatColor.GOLD + "nocache " + ChatColor.WHITE + "-- Don't set the lookup cache"); + sender.sendMessage(ChatColor.GOLD + "silent " + ChatColor.WHITE + "-- Displays lesser messages"); } else if (command.equals("permissions")) { sender.sendMessage(ChatColor.DARK_AQUA + "You've got the following permissions:"); for (final String permission : new String[] { "me", "lookup", "tp", "rollback", "clearlog", "hide", "ignoreRestrictions", "spawnTools" }) { From 2d9456409ce5ecc37c5af9106deda1d968e5f33a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 29 Apr 2021 16:27:14 +0200 Subject: [PATCH 276/399] Remove accidentally committed debug logging --- .../java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index dc71834f..6211d071 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -52,7 +52,7 @@ public void addModification(ItemStack stack, int amount) { } } - consumer.getLogblock().getLogger().info("Modify container: " + stack + " change: " + amount); + // consumer.getLogblock().getLogger().info("Modify container: " + stack + " change: " + amount); stack = new ItemStack(stack); stack.setAmount(1); Integer existing = modifications.get(stack); @@ -70,7 +70,7 @@ public void flush() { ItemStack stack = e.getKey(); int amount = e.getValue(); 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(), stack, amount < 0); } modifications.clear(); From 8e3f5aca56fb381ae5c01018d335eb5351e4d810 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 29 Apr 2021 20:37:38 +0200 Subject: [PATCH 277/399] Improve entity killer logging Fixes #622 --- .../de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java | 3 +++ src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index c460e729..65ef176c 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -170,6 +170,9 @@ public void onEntityDeath(EntityDeathEvent event) { actor = Actor.actorFromEntity(damager); } } + if (actor == null && entity.getKiller() != null) { + actor = Actor.actorFromEntity(entity.getKiller()); + } if (actor == null) { actor = new Actor(lastDamage == null ? "UNKNOWN" : lastDamage.getCause().toString()); } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java index d70a740d..3011fc21 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java @@ -36,6 +36,8 @@ public void onEntityDeath(EntityDeathEvent deathEvent) { 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; From cf8da11cca5c2ed571d6e34f3cebdcffe3e27eda Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 30 Apr 2021 04:05:30 +0200 Subject: [PATCH 278/399] Fix setting actor when a creeper causes an explosion --- .../java/de/diddiz/LogBlock/listeners/ExplosionLogging.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index 237c5d1a..1442362d 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -65,7 +65,7 @@ public void onEntityExplode(EntityExplodeEvent event) { final Entity target = ((Creeper) source).getTarget(); actor = target instanceof Player ? Actor.actorFromEntity(target) : new Actor("Creeper"); } else { - new Actor("Creeper"); + actor = new Actor("Creeper"); } } else if (source instanceof Fireball) { Fireball fireball = (Fireball) source; From 1a9827cc32544ec044ae787856df9808ccb37834 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 11 Jun 2021 04:03:37 +0200 Subject: [PATCH 279/399] Explosion logging: Move WitherSkull up, because it is a Fireball too --- .../LogBlock/listeners/ExplosionLogging.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index 1442362d..ad46e9b5 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -67,13 +67,25 @@ public void onEntityExplode(EntityExplodeEvent event) { } else { actor = new Actor("Creeper"); } + } else if (source instanceof Wither) { + if (!wcfg.isLogging(Logging.WITHER)) { + return; + } + actor = Actor.actorFromEntity(source); + } else if (source instanceof WitherSkull) { + if (!wcfg.isLogging(Logging.WITHER_SKULL)) { + return; + } + actor = Actor.actorFromEntity(source); } else if (source instanceof Fireball) { Fireball fireball = (Fireball) source; ProjectileSource shooter = fireball.getShooter(); if (shooter == null) { - return; - } - if (shooter instanceof Ghast) { + if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { + return; + } + actor = Actor.actorFromEntity(source); + } else if (shooter instanceof Ghast) { if (!wcfg.isLogging(Logging.GHASTFIREBALLEXPLOSION)) { return; } @@ -89,17 +101,6 @@ public void onEntityExplode(EntityExplodeEvent event) { return; } actor = Actor.actorFromEntity(source); - } else if (source instanceof Wither) { - if (!wcfg.isLogging(Logging.WITHER)) { - return; - } - actor = Actor.actorFromEntity(source); - } else if (source instanceof WitherSkull) { - if (!wcfg.isLogging(Logging.WITHER_SKULL)) { - return; - } - actor = Actor.actorFromEntity(source); - } else if (source instanceof EnderCrystal) { if (!wcfg.isLogging(Logging.ENDERCRYSTALEXPLOSION)) { return; From aca012778184f3f81f78892d758e3cfbab203793 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 23 Jun 2021 05:48:06 +0200 Subject: [PATCH 280/399] Update spigot dependency to 1.16.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bd8e9510..e7c9d2d0 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ org.spigotmc spigot-api - 1.16.1-R0.1-SNAPSHOT + 1.16.5-R0.1-SNAPSHOT provided From a58206b21d2a3e6379d2b3899186a3e02caa3631 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 23 Jun 2021 05:50:32 +0200 Subject: [PATCH 281/399] Add End Crystal logging Fixes #830 --- .../listeners/AdvancedEntityLogging.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index 65ef176c..c46f61e2 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -6,7 +6,9 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Bee; +import org.bukkit.entity.EnderCrystal; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Hanging; import org.bukkit.entity.IronGolem; import org.bukkit.entity.ItemFrame; @@ -23,6 +25,7 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntityPlaceEvent; import org.bukkit.event.hanging.HangingBreakByEntityEvent; import org.bukkit.event.hanging.HangingBreakEvent; import org.bukkit.event.hanging.HangingPlaceEvent; @@ -52,6 +55,7 @@ public class AdvancedEntityLogging extends LoggingListener { // serialize them before the death event private UUID lastEntityDamagedForDeathUUID; private byte[] lastEntityDamagedForDeathSerialized; + private Entity lastEntityDamagedForDeathDamager; public AdvancedEntityLogging(LogBlock lb) { super(lb); @@ -69,6 +73,7 @@ private void resetOnTick() { lastSpawnerEgg = false; lastEntityDamagedForDeathUUID = null; lastEntityDamagedForDeathSerialized = null; + lastEntityDamagedForDeathDamager = null; } private void setLastSpawner(Player player, Class spawning, boolean spawnEgg) { @@ -139,6 +144,10 @@ public void onEntitySpawn(CreatureSpawnEvent event) { if (event.getSpawnReason() == SpawnReason.CUSTOM || event.getSpawnReason() == SpawnReason.BEEHIVE) { return; } + if (event.getEntityType() == EntityType.ARMOR_STAND) { + resetOnTick(); + return; // logged in the method below + } LivingEntity entity = event.getEntity(); if (Config.isLogging(entity.getWorld(), EntityLogging.SPAWN, entity)) { Actor actor = null; @@ -158,6 +167,23 @@ public void onEntitySpawn(CreatureSpawnEvent event) { resetOnTick(); } + @EventHandler(priority = EventPriority.MONITOR) + public void onEntityPlace(EntityPlaceEvent event) { + if (!event.isCancelled()) { + Entity entity = event.getEntity(); + if (Config.isLogging(entity.getWorld(), EntityLogging.SPAWN, entity)) { + Actor actor = null; + if (event.getPlayer() != null) { + actor = Actor.actorFromEntity(event.getPlayer()); + } + if (actor == null) { + actor = new Actor("UNKNOWN"); + } + queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE); + } + } + } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityDeath(EntityDeathEvent event) { LivingEntity entity = event.getEntity(); @@ -228,6 +254,18 @@ public void onEntityDamage(EntityDamageEvent event) { lastEntityDamagedForDeathUUID = entity.getUniqueId(); lastEntityDamagedForDeathSerialized = WorldEditHelper.serializeEntity(entity); } + if (entity instanceof EnderCrystal) { + if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) { + if (event instanceof EntityDamageByEntityEvent) { + Entity damager = LoggingUtil.getRealDamager(((EntityDamageByEntityEvent) event).getDamager()); + if (lastEntityDamagedForDeathDamager == null || !(damager instanceof EnderCrystal)) { + lastEntityDamagedForDeathDamager = damager; + } + } + Actor actor = lastEntityDamagedForDeathDamager != null ? Actor.actorFromEntity(lastEntityDamagedForDeathDamager) : new Actor(event.getCause().toString()); + queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); + } + } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) From 9399b7062e33357979c0b5d9504607a019c5d03f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 29 Jun 2021 05:23:17 +0200 Subject: [PATCH 282/399] Update to 1.17 --- pom.xml | 6 +- .../java/de/diddiz/LogBlock/Consumer.java | 5 ++ .../java/de/diddiz/LogBlock/LogBlock.java | 5 +- src/main/java/de/diddiz/LogBlock/Logging.java | 2 + src/main/java/de/diddiz/LogBlock/Updater.java | 5 ++ .../listeners/BlockSpreadLogging.java | 47 +++++++++++-- .../listeners/OxidizationLogging.java | 28 ++++++++ src/main/java/de/diddiz/util/BukkitUtils.java | 70 +++++++++++++++++-- src/main/java/de/diddiz/util/LoggingUtil.java | 22 +++++- src/main/resources/blockdata.txt | 2 +- src/main/resources/itemdata.txt | 2 +- 11 files changed, 175 insertions(+), 19 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/listeners/OxidizationLogging.java diff --git a/pom.xml b/pom.xml index e7c9d2d0..3194a156 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.16.5.2-SNAPSHOT + 1.17.0.0-SNAPSHOT jar LogBlock @@ -42,13 +42,13 @@ org.spigotmc spigot-api - 1.16.5-R0.1-SNAPSHOT + 1.17-R0.1-SNAPSHOT provided com.sk89q.worldedit worldedit-bukkit - 7.1.0-SNAPSHOT + 7.2.0-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 572fcb56..0e696b95 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -35,6 +35,7 @@ import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.WallSign; import org.bukkit.configuration.file.YamlConfiguration; @@ -52,6 +53,7 @@ import de.diddiz.LogBlock.blockstate.BlockStateCodecs; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.events.BlockChangePreLogEvent; +import de.diddiz.util.BukkitUtils; import de.diddiz.util.Utils; public class Consumer extends Thread { @@ -693,6 +695,9 @@ private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDa if (typeBefore == null || typeBefore.getMaterial() == Material.CAVE_AIR || typeBefore.getMaterial() == Material.VOID_AIR) { typeBefore = Bukkit.createBlockData(Material.AIR); } + if (typeAfter == null && ((typeBefore instanceof Waterlogged && ((Waterlogged) typeBefore).isWaterlogged()) || BukkitUtils.isAlwaysWaterlogged(typeBefore.getMaterial()))) { + typeAfter = Bukkit.createBlockData(Material.WATER); + } if (typeAfter == null || typeAfter.getMaterial() == Material.CAVE_AIR || typeAfter.getMaterial() == Material.VOID_AIR) { typeAfter = Bukkit.createBlockData(Material.AIR); } diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index e45b204a..38e9d427 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -192,7 +192,7 @@ private void registerEvents() { if (isLogging(Logging.NATURALSTRUCTUREGROW) || isLogging(Logging.BONEMEALSTRUCTUREGROW)) { pm.registerEvents(new StructureGrowLogging(this), this); } - if (isLogging(Logging.GRASSGROWTH) || isLogging(Logging.MYCELIUMSPREAD) || isLogging(Logging.VINEGROWTH) || isLogging(Logging.MUSHROOMSPREAD)) { + if (isLogging(Logging.GRASSGROWTH) || isLogging(Logging.MYCELIUMSPREAD) || isLogging(Logging.VINEGROWTH) || isLogging(Logging.MUSHROOMSPREAD) || isLogging(Logging.BAMBOOGROWTH) || isLogging(Logging.DRIPSTONEGROWTH)) { pm.registerEvents(new BlockSpreadLogging(this), this); } if (isLogging(Logging.DRAGONEGGTELEPORT)) { @@ -201,6 +201,9 @@ private void registerEvents() { if (isLogging(Logging.LECTERNBOOKCHANGE)) { pm.registerEvents(new LecternLogging(this), this); } + if (isLogging(Logging.OXIDIZATION)) { + pm.registerEvents(new OxidizationLogging(this), this); + } if (Config.isLoggingAnyEntities()) { if (!WorldEditHelper.hasFullWorldEdit()) { getLogger().severe("No compatible WorldEdit found, entity logging will not work!"); diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index ba6d7c04..62eef5e5 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -33,6 +33,7 @@ public enum Logging { GRASSGROWTH, MYCELIUMSPREAD, VINEGROWTH, + DRIPSTONEGROWTH, MUSHROOMSPREAD, BAMBOOGROWTH, WITHER(true), @@ -46,6 +47,7 @@ public enum Logging { DAYLIGHTDETECTORINTERACT, LECTERNBOOKCHANGE(true), SCAFFOLDING(true), + OXIDIZATION, SHULKER_BOX_CONTENT, PLAYER_COMMANDS, COMMANDBLOCK_COMMANDS, diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 294de53a..e547e87c 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -885,6 +885,11 @@ private void updateMaterialsPost1_13() { renameMaterial("minecraft:cactus_green", Material.GREEN_DYE); } + if (comparablePreviousMinecraftVersion.compareTo("1.17") < 0 && comparableCurrentMinecraftVersion.compareTo("1.17") >= 0) { + logblock.getLogger().info("[Updater] Upgrading Materials to 1.17"); + renameMaterial("minecraft:grass_path", Material.DIRT_PATH); + } + config.set("previousMinecraftVersion", currentMinecraftVersion); logblock.saveConfig(); } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java index 22f29a58..22b077f0 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java @@ -5,6 +5,10 @@ import de.diddiz.LogBlock.Logging; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.data.type.PointedDripstone; +import org.bukkit.block.data.type.PointedDripstone.Thickness; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockSpreadEvent; @@ -22,8 +26,8 @@ public void onBlockSpread(BlockSpreadEvent event) { String name; - World world = event.getBlock().getWorld(); - Material type = event.getSource().getType(); + World world = event.getNewState().getWorld(); + Material type = event.getNewState().getType(); switch (type) { case GRASS: @@ -39,6 +43,12 @@ public void onBlockSpread(BlockSpreadEvent event) { name = "MyceliumSpread"; break; case VINE: + case CAVE_VINES: + case CAVE_VINES_PLANT: + case WEEPING_VINES: + case WEEPING_VINES_PLANT: + case TWISTING_VINES: + case TWISTING_VINES_PLANT: if (!isLogging(world, Logging.VINEGROWTH)) { return; } @@ -52,7 +62,7 @@ public void onBlockSpread(BlockSpreadEvent event) { name = "MushroomSpread"; break; case BAMBOO: - case BAMBOO_SAPLING: { + case BAMBOO_SAPLING: if (!isLogging(world, Logging.BAMBOOGROWTH)) { return; } @@ -62,7 +72,36 @@ public void onBlockSpread(BlockSpreadEvent event) { consumer.queueBlockReplace(new Actor(name), event.getSource().getState(), Material.BAMBOO.createBlockData()); } break; - } + case POINTED_DRIPSTONE: + if (!isLogging(world, Logging.DRIPSTONEGROWTH)) { + return; + } + name = "DripstoneGrowth"; + PointedDripstone pointed = (PointedDripstone) event.getNewState().getBlockData(); + if (pointed.getThickness() != Thickness.TIP_MERGE) { + BlockFace direction = pointed.getVerticalDirection(); + Block previousPart = event.getBlock().getRelative(direction.getOppositeFace()); + if (previousPart.getType() == Material.POINTED_DRIPSTONE) { + PointedDripstone newBelow = (PointedDripstone) previousPart.getBlockData(); + newBelow.setThickness(Thickness.FRUSTUM); + consumer.queueBlockReplace(new Actor(name), previousPart.getState(), newBelow); + + previousPart = previousPart.getRelative(direction.getOppositeFace()); + if (previousPart.getType() == Material.POINTED_DRIPSTONE) { + Block evenMorePrevious = previousPart.getRelative(direction.getOppositeFace()); + newBelow = (PointedDripstone) previousPart.getBlockData(); + newBelow.setThickness(evenMorePrevious.getType() == Material.POINTED_DRIPSTONE ? Thickness.MIDDLE : Thickness.BASE); + consumer.queueBlockReplace(new Actor(name), previousPart.getState(), newBelow); + } + } + } else { + // special case because the old state is already changed (for one half) + PointedDripstone oldState = (PointedDripstone) event.getNewState().getBlockData(); + oldState.setThickness(Thickness.TIP); + consumer.queueBlockReplace(new Actor(name), oldState, event.getNewState()); + return; + } + break; default: return; } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/OxidizationLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/OxidizationLogging.java new file mode 100644 index 00000000..fcdfd673 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/listeners/OxidizationLogging.java @@ -0,0 +1,28 @@ +package de.diddiz.LogBlock.listeners; + +import static de.diddiz.LogBlock.config.Config.isLogging; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockFormEvent; + +public class OxidizationLogging extends LoggingListener { + public OxidizationLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPhysics(BlockFormEvent event) { + if (isLogging(event.getBlock().getWorld(), Logging.OXIDIZATION)) { + final Material type = event.getNewState().getType(); + if (type.name().contains("COPPER")) { + consumer.queueBlockReplace(new Actor("NaturalOxidization"), event.getBlock().getState(), event.getNewState()); + } + } + } + +} diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 848e5ed7..eb0e7e34 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -78,6 +78,7 @@ public class BukkitUtils { private static final EnumSet slabs; private static final EnumSet concreteBlocks; private static final EnumMap dyes; + private static final EnumSet alwaysWaterlogged; static { pressurePlates = EnumSet.noneOf(Material.class); @@ -155,6 +156,10 @@ public class BukkitUtils { slabs.add(Material.PRISMARINE_BRICK_SLAB); slabs.add(Material.BLACKSTONE_SLAB); slabs.add(Material.POLISHED_BLACKSTONE_SLAB); + slabs.add(Material.DEEPSLATE_BRICK_SLAB); + slabs.add(Material.DEEPSLATE_TILE_SLAB); + slabs.add(Material.COBBLED_DEEPSLATE_SLAB); + slabs.add(Material.POLISHED_DEEPSLATE_SLAB); buttons = EnumSet.noneOf(Material.class); buttons.add(Material.STONE_BUTTON); @@ -216,6 +221,8 @@ public class BukkitUtils { singleBlockPlants.add(Material.CRIMSON_ROOTS); singleBlockPlants.add(Material.WARPED_ROOTS); singleBlockPlants.add(Material.NETHER_SPROUTS); + singleBlockPlants.add(Material.AZALEA); + singleBlockPlants.add(Material.FLOWERING_AZALEA); doublePlants = EnumSet.noneOf(Material.class); doublePlants.add(Material.TALL_GRASS); @@ -225,6 +232,7 @@ public class BukkitUtils { doublePlants.add(Material.LILAC); doublePlants.add(Material.SUNFLOWER); doublePlants.add(Material.PEONY); + doublePlants.add(Material.SMALL_DRIPLEAF); blockEquivalents = new HashSet<>(7); blockEquivalents.add(new HashSet<>(Arrays.asList(2, 3, 60))); @@ -246,6 +254,10 @@ public class BukkitUtils { relativeBreakable.add(Material.TRIPWIRE_HOOK); relativeBreakable.add(Material.COCOA); relativeBreakable.add(Material.BELL); + relativeBreakable.add(Material.AMETHYST_CLUSTER); + relativeBreakable.add(Material.SMALL_AMETHYST_BUD); + relativeBreakable.add(Material.MEDIUM_AMETHYST_BUD); + relativeBreakable.add(Material.LARGE_AMETHYST_BUD); // Blocks that break when they are on top of a block relativeTopBreakable = EnumSet.noneOf(Material.class); @@ -279,10 +291,15 @@ public class BukkitUtils { relativeTopBreakable.add(Material.BAMBOO_SAPLING); relativeTopBreakable.add(Material.TWISTING_VINES); relativeTopBreakable.add(Material.TWISTING_VINES_PLANT); + relativeTopBreakable.add(Material.BIG_DRIPLEAF); + relativeTopBreakable.add(Material.BIG_DRIPLEAF_STEM); for (Material m : Material.values()) { if (m.name().startsWith("POTTED_")) { relativeTopBreakable.add(m); } + if (m.name().endsWith("CANDLE_CAKE")) { + relativeTopBreakable.add(m); + } } // Blocks that break falling entities @@ -331,6 +348,11 @@ public class BukkitUtils { fallingEntityKillers.add(Material.SKELETON_WALL_SKULL); fallingEntityKillers.add(Material.WITHER_SKELETON_SKULL); fallingEntityKillers.add(Material.WITHER_SKELETON_WALL_SKULL); + for (Material m : Material.values()) { + if (m.name().contains("CANDLE")) { + fallingEntityKillers.add(m); + } + } // Crop Blocks cropBlocks = EnumSet.noneOf(Material.class); @@ -410,10 +432,10 @@ public class BukkitUtils { nonFluidProofBlocks.add(Material.TORCH); nonFluidProofBlocks.add(Material.SOUL_TORCH); nonFluidProofBlocks.add(Material.FLOWER_POT); - nonFluidProofBlocks.add(Material.POWERED_RAIL); - nonFluidProofBlocks.add(Material.DETECTOR_RAIL); - nonFluidProofBlocks.add(Material.ACTIVATOR_RAIL); - nonFluidProofBlocks.add(Material.RAIL); + // nonFluidProofBlocks.add(Material.POWERED_RAIL); + // nonFluidProofBlocks.add(Material.DETECTOR_RAIL); + // nonFluidProofBlocks.add(Material.ACTIVATOR_RAIL); + // nonFluidProofBlocks.add(Material.RAIL); nonFluidProofBlocks.add(Material.LEVER); nonFluidProofBlocks.add(Material.REDSTONE_WIRE); nonFluidProofBlocks.add(Material.REDSTONE_TORCH); @@ -422,6 +444,12 @@ public class BukkitUtils { nonFluidProofBlocks.add(Material.DAYLIGHT_DETECTOR); nonFluidProofBlocks.addAll(carpets); + alwaysWaterlogged = EnumSet.noneOf(Material.class); + alwaysWaterlogged.add(Material.SEAGRASS); + alwaysWaterlogged.add(Material.TALL_SEAGRASS); + alwaysWaterlogged.add(Material.KELP); + alwaysWaterlogged.add(Material.KELP_PLANT); + bedBlocks = EnumSet.noneOf(Material.class); bedBlocks.add(Material.BLACK_BED); bedBlocks.add(Material.BLUE_BED); @@ -1018,8 +1046,8 @@ public static boolean isSimilarForRollback(Material expected, Material found) { case FARMLAND: case GRASS_BLOCK: case PODZOL: - case GRASS_PATH: - return found == Material.DIRT || found == Material.MYCELIUM || found == Material.FARMLAND || found == Material.GRASS_BLOCK || found == Material.PODZOL || found == Material.GRASS_PATH; + case DIRT_PATH: + return found == Material.DIRT || found == Material.MYCELIUM || found == Material.FARMLAND || found == Material.GRASS_BLOCK || found == Material.PODZOL || found == Material.DIRT_PATH; case BAMBOO: case BAMBOO_SAPLING: return found == Material.BAMBOO || found == Material.BAMBOO_SAPLING; @@ -1038,6 +1066,32 @@ public static boolean isSimilarForRollback(Material expected, Material found) { case WEEPING_VINES: case WEEPING_VINES_PLANT: return found == Material.WEEPING_VINES || found == Material.WEEPING_VINES_PLANT; + case CAVE_VINES: + case CAVE_VINES_PLANT: + return found == Material.CAVE_VINES || found == Material.CAVE_VINES_PLANT; + case BIG_DRIPLEAF: + case BIG_DRIPLEAF_STEM: + return found == Material.BIG_DRIPLEAF || found == Material.BIG_DRIPLEAF_STEM; + case COPPER_BLOCK: + case EXPOSED_COPPER: + case WEATHERED_COPPER: + case OXIDIZED_COPPER: + return found == Material.COPPER_BLOCK || found == Material.EXPOSED_COPPER || found == Material.WEATHERED_COPPER || found == Material.OXIDIZED_COPPER; + case CUT_COPPER: + case EXPOSED_CUT_COPPER: + case WEATHERED_CUT_COPPER: + case OXIDIZED_CUT_COPPER: + return found == Material.CUT_COPPER || found == Material.EXPOSED_CUT_COPPER || found == Material.WEATHERED_CUT_COPPER || found == Material.OXIDIZED_CUT_COPPER; + case CUT_COPPER_STAIRS: + case EXPOSED_CUT_COPPER_STAIRS: + case WEATHERED_CUT_COPPER_STAIRS: + case OXIDIZED_CUT_COPPER_STAIRS: + return found == Material.CUT_COPPER_STAIRS || found == Material.EXPOSED_CUT_COPPER_STAIRS || found == Material.WEATHERED_CUT_COPPER_STAIRS || found == Material.OXIDIZED_CUT_COPPER_STAIRS; + case CUT_COPPER_SLAB: + case EXPOSED_CUT_COPPER_SLAB: + case WEATHERED_CUT_COPPER_SLAB: + case OXIDIZED_CUT_COPPER_SLAB: + return found == Material.CUT_COPPER_SLAB || found == Material.EXPOSED_CUT_COPPER_SLAB || found == Material.WEATHERED_CUT_COPPER_SLAB || found == Material.OXIDIZED_CUT_COPPER_SLAB; } return false; } @@ -1045,4 +1099,8 @@ public static boolean isSimilarForRollback(Material expected, Material found) { public static Material[] getAllSignsArray() { return allSigns.toArray(new Material[allSigns.size()]); } + + public static boolean isAlwaysWaterlogged(Material m) { + return alwaysWaterlogged.contains(m); + } } diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index 8764c67c..afdf0bad 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -144,6 +144,12 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or consumer.queueBlockReplace(actor, above.getState(), Material.WEEPING_VINES.createBlockData()); } } + if (replacedType == Material.CAVE_VINES || replacedType == Material.CAVE_VINES_PLANT) { + Block above = origin.getRelative(BlockFace.UP); + if (above.getType() == Material.CAVE_VINES_PLANT) { + consumer.queueBlockReplace(actor, above.getState(), Material.CAVE_VINES.createBlockData()); + } + } Block checkBlock = origin.getRelative(BlockFace.UP); Material typeAbove = checkBlock.getType(); @@ -207,12 +213,22 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or if (bell.getAttachment() == Attachment.CEILING) { consumer.queueBlockBreak(actor, checkBlock.getState()); } - } else if (typeBelow == Material.WEEPING_VINES || typeBelow == Material.WEEPING_VINES_PLANT) { + } else if (typeBelow == Material.WEEPING_VINES || typeBelow == Material.WEEPING_VINES_PLANT || typeBelow == Material.CAVE_VINES || typeBelow == Material.CAVE_VINES_PLANT) { + consumer.queueBlockBreak(actor, checkBlock.getState()); + // check next blocks below + checkBlock = checkBlock.getRelative(BlockFace.DOWN); + typeBelow = checkBlock.getType(); + while (typeBelow == Material.WEEPING_VINES || typeBelow == Material.WEEPING_VINES_PLANT || typeBelow == Material.CAVE_VINES || typeBelow == Material.CAVE_VINES_PLANT) { + consumer.queueBlockBreak(actor, checkBlock.getState()); + checkBlock = checkBlock.getRelative(BlockFace.DOWN); + typeBelow = checkBlock.getType(); + } + } else if ((replacedType == Material.BIG_DRIPLEAF || replacedType == Material.BIG_DRIPLEAF_STEM) && (typeBelow == Material.BIG_DRIPLEAF || typeBelow == Material.BIG_DRIPLEAF_STEM)) { consumer.queueBlockBreak(actor, checkBlock.getState()); - // check next blocks above + // check next blocks below checkBlock = checkBlock.getRelative(BlockFace.DOWN); typeBelow = checkBlock.getType(); - while (typeBelow == Material.WEEPING_VINES || typeBelow == Material.WEEPING_VINES_PLANT) { + while (typeBelow == Material.BIG_DRIPLEAF || typeBelow == Material.BIG_DRIPLEAF_STEM) { consumer.queueBlockBreak(actor, checkBlock.getState()); checkBlock = checkBlock.getRelative(BlockFace.DOWN); typeBelow = checkBlock.getType(); diff --git a/src/main/resources/blockdata.txt b/src/main/resources/blockdata.txt index 8859bb30..3f2b8414 100644 --- a/src/main/resources/blockdata.txt +++ b/src/main/resources/blockdata.txt @@ -1813,7 +1813,7 @@ 207:13,minecraft:air 207:14,minecraft:air 207:15,minecraft:air -208:0,minecraft:grass_path +208:0,minecraft:dirt_path 209:0,minecraft:end_gateway 210:0,minecraft:repeating_command_block[conditional=false,facing=down] 210:1,minecraft:repeating_command_block[conditional=false,facing=up] diff --git a/src/main/resources/itemdata.txt b/src/main/resources/itemdata.txt index 01764f2c..25223ce3 100644 --- a/src/main/resources/itemdata.txt +++ b/src/main/resources/itemdata.txt @@ -454,7 +454,7 @@ 205:0,minecraft:purpur_slab 206:0,minecraft:end_stone_bricks 207:0,minecraft:beetroots -208:0,minecraft:grass_path +208:0,minecraft:dirt_path 209:0,minecraft:end_gateway 210:0,minecraft:repeating_command_block 211:0,minecraft:chain_command_block From 7f3837f1fe94f9fc1ecfb943aa07ecd3eb3c23f4 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 9 Jul 2021 06:27:21 +0200 Subject: [PATCH 283/399] Fix logging bonemealing moss --- .../java/de/diddiz/LogBlock/LogBlock.java | 5 ++- .../listeners/BlockFertilizeLogging.java | 36 +++++++++++++++++++ .../listeners/StructureGrowLogging.java | 20 ++++------- 3 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/listeners/BlockFertilizeLogging.java diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 38e9d427..4075e236 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -189,9 +189,12 @@ private void registerEvents() { if (isLogging(Logging.WITHER)) { pm.registerEvents(new WitherLogging(this), this); } - if (isLogging(Logging.NATURALSTRUCTUREGROW) || isLogging(Logging.BONEMEALSTRUCTUREGROW)) { + if (isLogging(Logging.NATURALSTRUCTUREGROW)) { pm.registerEvents(new StructureGrowLogging(this), this); } + if (isLogging(Logging.BONEMEALSTRUCTUREGROW)) { + pm.registerEvents(new BlockFertilizeLogging(this), this); + } if (isLogging(Logging.GRASSGROWTH) || isLogging(Logging.MYCELIUMSPREAD) || isLogging(Logging.VINEGROWTH) || isLogging(Logging.MUSHROOMSPREAD) || isLogging(Logging.BAMBOOGROWTH) || isLogging(Logging.DRIPSTONEGROWTH)) { pm.registerEvents(new BlockSpreadLogging(this), this); } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockFertilizeLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockFertilizeLogging.java new file mode 100644 index 00000000..b77ebcdf --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockFertilizeLogging.java @@ -0,0 +1,36 @@ +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.WorldConfig; +import org.bukkit.block.BlockState; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockFertilizeEvent; +import static de.diddiz.LogBlock.config.Config.getWorldConfig; + +public class BlockFertilizeLogging extends LoggingListener { + public BlockFertilizeLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockFertilize(BlockFertilizeEvent event) { + final WorldConfig wcfg = getWorldConfig(event.getBlock().getLocation().getWorld()); + if (wcfg != null) { + if (!wcfg.isLogging(Logging.BONEMEALSTRUCTUREGROW)) { + return; + } + final Actor actor; + if (event.getPlayer() != null) { + actor = Actor.actorFromEntity(event.getPlayer()); + } else { + actor = new Actor("Dispenser"); + } + for (final BlockState state : event.getBlocks()) { + consumer.queueBlockReplace(actor, state.getBlock().getState(), state); + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/StructureGrowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/StructureGrowLogging.java index c5730d26..62f43573 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/StructureGrowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/StructureGrowLogging.java @@ -20,20 +20,14 @@ public StructureGrowLogging(LogBlock lb) { public void onStructureGrow(StructureGrowEvent event) { final WorldConfig wcfg = getWorldConfig(event.getWorld()); if (wcfg != null) { - final Actor actor; - if (event.getPlayer() != null) { - if (!wcfg.isLogging(Logging.BONEMEALSTRUCTUREGROW)) { - return; - } - actor = Actor.actorFromEntity(event.getPlayer()); - } else { - if (!wcfg.isLogging(Logging.NATURALSTRUCTUREGROW)) { - return; - } - actor = new Actor("NaturalGrow"); + if (!wcfg.isLogging(Logging.NATURALSTRUCTUREGROW)) { + return; } - for (final BlockState state : event.getBlocks()) { - consumer.queueBlockReplace(actor, state.getBlock().getState(), state); + if (!event.isFromBonemeal()) { + final Actor actor = new Actor("NaturalGrow"); + for (final BlockState state : event.getBlocks()) { + consumer.queueBlockReplace(actor, state.getBlock().getState(), state); + } } } } From 1e1243449f51144c07d418a603188c0cb61400fe Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 12 Jul 2021 03:32:09 +0200 Subject: [PATCH 284/399] Log make signs glowing/unglowing --- .../LogBlock/listeners/InteractLogging.java | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index 350c4312..40af564c 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -235,17 +235,33 @@ public void onPlayerInteract(PlayerInteractEvent event) { case DARK_OAK_WALL_SIGN: case WARPED_WALL_SIGN: case CRIMSON_WALL_SIGN: - if (wcfg.isLogging(Logging.SIGNTEXT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - ItemStack stack = event.getItem(); - if (stack != null && BukkitUtils.isDye(stack.getType())) { + if (wcfg.isLogging(Logging.SIGNTEXT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getItem() != null) { + Material itemType = event.getItem().getType(); + if (BukkitUtils.isDye(itemType) || itemType == Material.GLOW_INK_SAC || itemType == Material.INK_SAC) { final BlockState before = event.getClickedBlock().getState(); if (before instanceof Sign) { - DyeColor newColor = BukkitUtils.dyeToDyeColor(stack.getType()); - Sign signBefore = (Sign) before; - if (newColor != null && signBefore.getColor() != newColor) { - final Sign signAfter = (Sign) event.getClickedBlock().getState(); - signAfter.setColor(newColor); - consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + if (itemType == Material.GLOW_INK_SAC) { + Sign signBefore = (Sign) before; + if (!signBefore.isGlowingText()) { + final Sign signAfter = (Sign) event.getClickedBlock().getState(); + signAfter.setGlowingText(true); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } + } else if (itemType == Material.INK_SAC) { + Sign signBefore = (Sign) before; + if (signBefore.isGlowingText()) { + final Sign signAfter = (Sign) event.getClickedBlock().getState(); + signAfter.setGlowingText(false); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } + } else { + DyeColor newColor = BukkitUtils.dyeToDyeColor(itemType); + Sign signBefore = (Sign) before; + if (newColor != null && signBefore.getColor() != newColor) { + final Sign signAfter = (Sign) event.getClickedBlock().getState(); + signAfter.setColor(newColor); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } } } } From 9c2caa6af88914a54c751d2670058aea59b98aa5 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 12 Jul 2021 03:57:36 +0200 Subject: [PATCH 285/399] Better display sign changes in log messages --- .../java/de/diddiz/LogBlock/BlockChange.java | 10 +++- .../LogBlock/blockstate/BlockStateCodec.java | 2 +- .../blockstate/BlockStateCodecBanner.java | 2 +- .../blockstate/BlockStateCodecLectern.java | 2 +- .../blockstate/BlockStateCodecShulkerBox.java | 2 +- .../blockstate/BlockStateCodecSign.java | 57 +++++++++++++++++-- .../blockstate/BlockStateCodecSkull.java | 2 +- .../blockstate/BlockStateCodecSpawner.java | 2 +- .../LogBlock/blockstate/BlockStateCodecs.java | 4 +- 9 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 55b396a5..da136f43 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -82,11 +82,15 @@ public BlockChange(ResultSet rs, QueryParams p) throws SQLException { } private String getTypeDetails(BlockData type, byte[] typeState) { + return getTypeDetails(type, typeState, null, null); + } + + private String getTypeDetails(BlockData type, byte[] typeState, BlockData oldType, byte[] oldTypeState) { String typeDetails = null; if (BlockStateCodecs.hasCodec(type.getMaterial())) { try { - typeDetails = BlockStateCodecs.toString(type.getMaterial(), Utils.deserializeYamlConfiguration(typeState)); + typeDetails = BlockStateCodecs.toString(type.getMaterial(), Utils.deserializeYamlConfiguration(typeState), type.equals(oldType) ? Utils.deserializeYamlConfiguration(oldTypeState) : null); } catch (Exception e) { LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + type.getMaterial(), e); } @@ -123,7 +127,7 @@ public BaseComponent[] getLogMessage(int entry) { } // Process type details once for later use. - String typeDetails = getTypeDetails(type, typeState); + String typeDetails = getTypeDetails(type, typeState, replaced, replacedState); String replacedDetails = getTypeDetails(replaced, replacedState); if (type.getMaterial().equals(replaced.getMaterial())) { @@ -205,7 +209,7 @@ public BaseComponent[] getLogMessage(int entry) { } else if (type instanceof Sign || type instanceof WallSign) { msg.addExtra(createTextComponentWithColor("edited a ", CREATE.getColor())); msg.addExtra(prettyMaterial(type)); - msg.addExtra(createTextComponentWithColor(" to ", CREATE.getColor())); + msg.addExtra(createTextComponentWithColor(" to", CREATE.getColor())); msg.addExtra(prettyState(typeDetails)); } else { msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor())); diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java index a3e5b0b1..28e9e3f6 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java @@ -11,5 +11,5 @@ public interface BlockStateCodec { void deserialize(BlockState state, YamlConfiguration conf); - String toString(YamlConfiguration conf); + String toString(YamlConfiguration conf, YamlConfiguration oldState); } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java index 65359ebd..8cd7a166 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java @@ -64,7 +64,7 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public String toString(YamlConfiguration conf) { + public String toString(YamlConfiguration conf, YamlConfiguration oldState) { return null; } } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java index ec450803..ab7f764e 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java @@ -43,7 +43,7 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public String toString(YamlConfiguration conf) { + public String toString(YamlConfiguration conf, YamlConfiguration oldState) { if (conf != null) { StringBuilder sb = new StringBuilder(); sb.append("[").append("book").append("]"); diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java index ac59c276..ccbeca82 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java @@ -60,7 +60,7 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public String toString(YamlConfiguration conf) { + public String toString(YamlConfiguration conf, YamlConfiguration oldState) { if (conf != null) { StringBuilder sb = new StringBuilder(); sb.append("["); diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index ee883028..656ec742 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -40,6 +40,9 @@ public YamlConfiguration serialize(BlockState state) { if (signColor != DyeColor.BLACK) { conf.set("color", signColor.name()); } + if (sign.isGlowingText()) { + conf.set("glowing", true); + } return conf; } } @@ -60,6 +63,7 @@ public void deserialize(BlockState state, YamlConfiguration conf) { if (state instanceof Sign) { Sign sign = (Sign) state; DyeColor signColor = DyeColor.BLACK; + boolean glowing = false; List lines = Collections.emptyList(); if (conf != null) { if (conf.contains("lines")) { @@ -72,24 +76,69 @@ public void deserialize(BlockState state, YamlConfiguration conf) { // ignored } } + glowing = conf.getBoolean("glowing", false); } for (int i = 0; i < 4; i++) { String line = lines.size() > i && lines.get(i) != null ? lines.get(i) : ""; sign.setLine(i, line); } sign.setColor(signColor); + sign.setGlowingText(glowing); } } @Override - public String toString(YamlConfiguration conf) { - if (conf != null) { + public String toString(YamlConfiguration state, YamlConfiguration oldState) { + if (state != null) { + List lines = state.getStringList("lines"); + List oldLines = Collections.emptyList(); + DyeColor signColor = DyeColor.BLACK; + if (state.contains("color")) { + try { + signColor = DyeColor.valueOf(state.getString("color")); + } catch (IllegalArgumentException | NullPointerException e) { + // ignored + } + } + DyeColor oldSignColor = DyeColor.BLACK; + boolean glowing = state.getBoolean("glowing", false); + boolean oldGlowing = false; + if (oldState != null) { + oldLines = oldState.getStringList("lines"); + if (oldState.contains("color")) { + try { + oldSignColor = DyeColor.valueOf(oldState.getString("color")); + } catch (IllegalArgumentException | NullPointerException e) { + // ignored + } + } + oldGlowing = oldState.getBoolean("glowing", false); + } + StringBuilder sb = new StringBuilder(); - for (String line : conf.getStringList("lines")) { + if (!lines.equals(oldLines)) { + for (String line : lines) { + if (sb.length() > 0) { + sb.append(" "); + } + sb.append("[").append(line).append("]"); + } + } + if (signColor != oldSignColor) { if (sb.length() > 0) { sb.append(" "); } - sb.append("[").append(line).append("]"); + sb.append("(color: " + signColor.name().toLowerCase() + ")"); + } + if (glowing != oldGlowing) { + if (sb.length() > 0) { + sb.append(" "); + } + if (glowing) { + sb.append("(glowing)"); + } else { + sb.append("(not glowing)"); + } } return sb.toString(); } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java index dbeeaf85..19399448 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java @@ -43,7 +43,7 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public String toString(YamlConfiguration conf) { + public String toString(YamlConfiguration conf, YamlConfiguration oldState) { UUID ownerId = conf == null ? null : UUID.fromString(conf.getString("owner")); if (ownerId != null) { OfflinePlayer owner = Bukkit.getOfflinePlayer(ownerId); diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java index 32696844..0d93fe99 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java @@ -48,7 +48,7 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public String toString(YamlConfiguration conf) { + public String toString(YamlConfiguration conf, YamlConfiguration oldState) { if (conf != null) { EntityType entity = EntityType.valueOf(conf.getString("spawnedType")); if (entity != null) { diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java index b610fa38..515347b8 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java @@ -51,10 +51,10 @@ public static void deserialize(BlockState block, YamlConfiguration state) { } } - public static String toString(Material material, YamlConfiguration state) { + public static String toString(Material material, YamlConfiguration state, YamlConfiguration oldState) { BlockStateCodec codec = codecs.get(material); if (codec != null) { - return codec.toString(state); + return codec.toString(state, oldState); } return null; } From 07924138ea1e955d532e59facbc816d0641d7735 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 12 Jul 2021 04:28:16 +0200 Subject: [PATCH 286/399] Add cauldron interact logging --- .../java/de/diddiz/LogBlock/LogBlock.java | 3 +++ src/main/java/de/diddiz/LogBlock/Logging.java | 1 + .../LogBlock/listeners/CauldronLogging.java | 27 +++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 src/main/java/de/diddiz/LogBlock/listeners/CauldronLogging.java diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 4075e236..40791042 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -161,6 +161,9 @@ private void registerEvents() { if (isLogging(Logging.SCAFFOLDING)) { pm.registerEvents(scaffoldingLogging = new ScaffoldingLogging(this), this); } + if (isLogging(Logging.CAULDRONINTERACT)) { + pm.registerEvents(new CauldronLogging(this), this); + } if (isLogging(Logging.CREEPEREXPLOSION) || isLogging(Logging.TNTEXPLOSION) || isLogging(Logging.GHASTFIREBALLEXPLOSION) || isLogging(Logging.ENDERDRAGON) || isLogging(Logging.MISCEXPLOSION)) { pm.registerEvents(new ExplosionLogging(this), this); } diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index 62eef5e5..7f8a3621 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -27,6 +27,7 @@ public enum Logging { COMPARATORINTERACT, PRESUREPLATEINTERACT, TRIPWIREINTERACT, + CAULDRONINTERACT(true), CREATURECROPTRAMPLE, CROPTRAMPLE, NATURALSTRUCTUREGROW, diff --git a/src/main/java/de/diddiz/LogBlock/listeners/CauldronLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/CauldronLogging.java new file mode 100644 index 00000000..5676adb7 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/listeners/CauldronLogging.java @@ -0,0 +1,27 @@ +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.Config; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.CauldronLevelChangeEvent; + +public class CauldronLogging extends LoggingListener { + public CauldronLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onCauldronLevelChange(CauldronLevelChangeEvent event) { + if (Config.isLogging(event.getBlock().getWorld(), Logging.CAULDRONINTERACT)) { + Entity causingEntity = event.getEntity(); + if (causingEntity instanceof Player) { + consumer.queueBlockReplace(Actor.actorFromEntity(causingEntity), event.getBlock().getBlockData(), event.getNewState()); + } + } + } +} From 701f434fae1af6a9f6205e44f16234888a4e2d11 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 12 Jul 2021 05:08:03 +0200 Subject: [PATCH 287/399] cancel auto clearlog when plugin is disabled --- src/main/java/de/diddiz/LogBlock/AutoClearLog.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/AutoClearLog.java b/src/main/java/de/diddiz/LogBlock/AutoClearLog.java index c4175431..a57f3576 100644 --- a/src/main/java/de/diddiz/LogBlock/AutoClearLog.java +++ b/src/main/java/de/diddiz/LogBlock/AutoClearLog.java @@ -17,6 +17,9 @@ public class AutoClearLog implements Runnable { public void run() { final CommandsHandler handler = logblock.getCommandsHandler(); for (final String paramStr : autoClearLog) { + if (!logblock.isCompletelyEnabled()) { + return; // do not try when plugin is disabled + } try { final QueryParams params = new QueryParams(logblock, getConsoleSender(), Arrays.asList(paramStr.split(" "))); params.noForcedLimit = true; From 5aac2d712b6052f9f04fc496c80aa588cc360c04 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 17 Aug 2021 05:47:37 +0200 Subject: [PATCH 288/399] Fix logging blocks below 0 Fixes #834 --- src/main/java/de/diddiz/LogBlock/Consumer.java | 8 ++++---- src/main/java/de/diddiz/LogBlock/Updater.java | 17 ++++++++++++++++- .../java/de/diddiz/LogBlock/config/Config.java | 2 +- src/main/java/de/diddiz/util/LoggingUtil.java | 12 ++++++------ 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 0e696b95..b075a7d0 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -1135,11 +1135,11 @@ public void process(Connection conn, BatchHelper batchHelper) throws SQLExceptio private int safeY(Location loc) { int safeY = loc.getBlockY(); - if (safeY < 0) { - safeY = 0; + if (safeY < Short.MIN_VALUE) { + safeY = Short.MIN_VALUE; } - if (safeY > 65535) { - safeY = 65535; + if (safeY > Short.MAX_VALUE) { + safeY = Short.MAX_VALUE; } return safeY; } diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index e547e87c..53e605b7 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -730,6 +730,7 @@ boolean update() { } if (configVersion.compareTo(new ComparableVersion("1.16.0")) < 0) { + logblock.getLogger().info("Updating tables to 1.16.0 ..."); try (Connection conn = logblock.getConnection()) { conn.setAutoCommit(true); final Statement st = conn.createStatement(); @@ -742,6 +743,20 @@ boolean update() { } config.set("version", "1.16.0"); } + if (configVersion.compareTo(new ComparableVersion("1.17.0")) < 0) { + logblock.getLogger().info("Updating tables to 1.17.0 ..."); + try (Connection conn = logblock.getConnection()) { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + for (final WorldConfig wcfg : getLoggedWorlds()) { + st.executeUpdate("ALTER TABLE `" + wcfg.table + "-blocks` CHANGE `y` `y` SMALLINT(5) NOT NULL"); + } + st.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Warning: Could not alter table", ex); + } + config.set("version", "1.17.0"); + } if (configVersion.compareTo(new ComparableVersion(Config.CURRENT_CONFIG_VERSION)) < 0) { config.set("version", Config.CURRENT_CONFIG_VERSION); @@ -827,7 +842,7 @@ void checkTables() throws SQLException { 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 UNSIGNED 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", "(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)) { diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index a30f422b..085e680a 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -60,7 +60,7 @@ public class Config { // Not loaded from config - checked at runtime public static boolean mb4 = false; - public static final String CURRENT_CONFIG_VERSION = "1.16.0"; + public static final String CURRENT_CONFIG_VERSION = "1.17.0"; public static enum LogKillsLevel { PLAYERS, diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index afdf0bad..77df1234 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -52,15 +52,15 @@ public static void smartLogBlockPlace(Consumer consumer, Actor actor, BlockState int initialy = loc.getBlockY(); int y = initialy; int z = loc.getBlockZ(); - while (y > 0 && BukkitUtils.canFallIn(loc.getWorld(), x, (y - 1), z)) { + while (y > loc.getWorld().getMinHeight() && BukkitUtils.canFallIn(loc.getWorld(), x, (y - 1), z)) { y--; } if (initialy != y && !BukkitUtils.isEmpty(replaced.getType())) { // this is not the final location but the block got removed (vines etc) consumer.queueBlockBreak(actor, replaced); } - // If y is 0 then the block fell out of the world :( - if (y != 0) { + // If y is minHeight then the block fell out of the world :( + if (y > loc.getWorld().getMinHeight()) { // Run this check to avoid false positives Location finalLoc = new Location(loc.getWorld(), x, y, z); if (y == initialy || !BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) { @@ -94,11 +94,11 @@ public static void smartLogFallables(Consumer consumer, Actor actor, Block origi int x = loc.getBlockX(); int y = loc.getBlockY(); int z = loc.getBlockZ(); - while (y > 0 && BukkitUtils.canFallIn(loc.getWorld(), x, (y - 1), z)) { + while (y > loc.getWorld().getMinHeight() && BukkitUtils.canFallIn(loc.getWorld(), x, (y - 1), z)) { y--; } - // If y is 0 then the sand block fell out of the world :( - if (y != 0) { + // If y is minHeight then the sand block fell out of the world :( + if (y > loc.getWorld().getMinHeight()) { Location finalLoc = new Location(loc.getWorld(), x, y, z); // Run this check to avoid false positives if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) { From 3730aa92c4e5f4e644f792aa8c14937634d11819 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 17 Aug 2021 05:54:13 +0200 Subject: [PATCH 289/399] Log breaking dripstone Fixes #831 --- src/main/java/de/diddiz/util/LoggingUtil.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index 77df1234..3c68c5b5 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -14,6 +14,8 @@ import org.bukkit.block.data.type.Bell; import org.bukkit.block.data.type.Bell.Attachment; import org.bukkit.block.data.type.Lantern; +import org.bukkit.block.data.type.PointedDripstone; +import org.bukkit.block.data.type.PointedDripstone.Thickness; import org.bukkit.entity.Entity; import org.bukkit.entity.Projectile; import org.bukkit.entity.TNTPrimed; @@ -199,6 +201,24 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or if (bell.getAttachment() == Attachment.FLOOR) { consumer.queueBlockBreak(actor, checkBlock.getState()); } + } else if (typeAbove == Material.POINTED_DRIPSTONE) { + Block dripStoneBlock = checkBlock; + while (true) { + if (dripStoneBlock.getType() != Material.POINTED_DRIPSTONE) { + break; + } + PointedDripstone dripstone = (PointedDripstone) dripStoneBlock.getBlockData(); + if (dripstone.getVerticalDirection() != BlockFace.UP) { + if (dripstone.getThickness() == Thickness.TIP_MERGE) { + PointedDripstone newDripstone = (PointedDripstone) dripstone.clone(); + newDripstone.setThickness(Thickness.TIP); + consumer.queueBlockReplace(actor, dripStoneBlock.getState(), newDripstone); + } + break; + } + consumer.queueBlockBreak(actor, dripStoneBlock.getState()); + dripStoneBlock = dripStoneBlock.getRelative(BlockFace.UP); + } } checkBlock = origin.getRelative(BlockFace.DOWN); @@ -233,6 +253,24 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or checkBlock = checkBlock.getRelative(BlockFace.DOWN); typeBelow = checkBlock.getType(); } + } else if (typeBelow == Material.POINTED_DRIPSTONE) { + Block dripStoneBlock = checkBlock; + while (true) { + if (dripStoneBlock.getType() != Material.POINTED_DRIPSTONE) { + break; + } + PointedDripstone dripstone = (PointedDripstone) dripStoneBlock.getBlockData(); + if (dripstone.getVerticalDirection() != BlockFace.DOWN) { + if (dripstone.getThickness() == Thickness.TIP_MERGE) { + PointedDripstone newDripstone = (PointedDripstone) dripstone.clone(); + newDripstone.setThickness(Thickness.TIP); + consumer.queueBlockReplace(actor, dripStoneBlock.getState(), newDripstone); + } + break; + } + consumer.queueBlockBreak(actor, dripStoneBlock.getState()); + dripStoneBlock = dripStoneBlock.getRelative(BlockFace.DOWN); + } } List relativeBreakables = BukkitUtils.getBlocksNearby(origin, BukkitUtils.getRelativeBreakables()); From f2f988b15b22bbcd4836f66f64589c2d9b9d17e6 Mon Sep 17 00:00:00 2001 From: EpicPlayerA10 <62206933+EpicPlayerA10@users.noreply.github.com> Date: Fri, 20 Aug 2021 23:49:58 +0200 Subject: [PATCH 290/399] Added more pleasant HoverEvent (#835) * Added more pleasant hoverevent * Remove synchronized * Changed item amount * Requested changes --- src/main/java/de/diddiz/util/BukkitUtils.java | 71 +++++++++---------- .../java/de/diddiz/util/ReflectionUtil.java | 33 +++++++++ 2 files changed, 67 insertions(+), 37 deletions(-) create mode 100644 src/main/java/de/diddiz/util/ReflectionUtil.java diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index eb0e7e34..39c4880a 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -4,6 +4,8 @@ import de.diddiz.LogBlock.LogBlock; import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumMap; @@ -12,7 +14,6 @@ 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; @@ -38,7 +39,6 @@ import org.bukkit.block.data.type.Slab; import org.bukkit.block.data.type.Slab.Type; import org.bukkit.block.data.type.Stairs; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -48,8 +48,6 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.EnchantmentStorageMeta; -import org.bukkit.inventory.meta.ItemMeta; public class BukkitUtils { private static final Set> blockEquivalents; @@ -766,45 +764,44 @@ public static TextComponent toString(ItemStack stack) { TextComponent msg = MessagingUtil.createTextComponentWithColor(stack.getAmount() + "x ", TypeColor.DEFAULT.getColor()); msg.addExtra(prettyMaterial(stack.getType())); - ItemMeta meta = stack.getItemMeta(); - TextComponent hover = MessagingUtil.createTextComponentWithColor("", TypeColor.STATE.getColor()); - boolean metaStarted = false; - if (meta.hasEnchants()) { - Map enchants = meta.getEnchants(); - if (!enchants.isEmpty()) { - for (Entry e : enchants.entrySet()) { - if (!metaStarted) { - metaStarted = true; - } else { - hover.addExtra("\n"); - } - hover.addExtra(formatMinecraftKey(e.getKey().getKey().getKey()) + ((e.getKey().getMaxLevel() != 1 || e.getValue() != 1) ? " " + maybeToRoman(e.getValue()) : "")); - } - } - } - if (meta instanceof EnchantmentStorageMeta) { - EnchantmentStorageMeta emeta = (EnchantmentStorageMeta) meta; - if (emeta.hasStoredEnchants()) { - Map enchants = emeta.getStoredEnchants(); - if (!enchants.isEmpty()) { - for (Entry e : enchants.entrySet()) { - if (!metaStarted) { - metaStarted = true; - } else { - hover.addExtra("\n"); - } - hover.addExtra(formatMinecraftKey(e.getKey().getKey().getKey()) + ((e.getKey().getMaxLevel() != 1 || e.getValue() != 1) ? " " + maybeToRoman(e.getValue()) : "")); - } - } - } + ItemStack copy = stack.clone(); + copy.setAmount(1); + + String itemJson = null; + try { + itemJson = convertItemStackToJson(copy); + } catch (Exception e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Failed to convert Itemstack to JSON", e); } - if (metaStarted) { - msg.setHoverEvent(new HoverEvent(Action.SHOW_TEXT, new Text(new BaseComponent[] { hover }))); + + if (itemJson != null) { + BaseComponent[] hoverEventComponents = new BaseComponent[]{ + new TextComponent(itemJson) + }; + + msg.setHoverEvent(new HoverEvent(Action.SHOW_ITEM, hoverEventComponents)); + } else { + msg.setHoverEvent(new HoverEvent(Action.SHOW_TEXT, new Text(new BaseComponent[] { MessagingUtil.createTextComponentWithColor("Error", TypeColor.ERROR.getColor())} ))); } return msg; } + public static String convertItemStackToJson(ItemStack itemStack) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + Class craftItemStackClazz = ReflectionUtil.getCraftBukkitClass("inventory.CraftItemStack"); + Method asNMSCopyMethod = ReflectionUtil.getMethod(craftItemStackClazz, "asNMSCopy", ItemStack.class); + + Class nmsItemStackClazz = ReflectionUtil.getMinecraftClass("world.item.ItemStack"); + Class nbtTagCompoundClazz = ReflectionUtil.getMinecraftClass("nbt.NBTTagCompound"); + Method saveNmsItemStackMethod = ReflectionUtil.getMethod(nmsItemStackClazz, "save", nbtTagCompoundClazz); + + Object nmsNbtTagCompoundObj = nbtTagCompoundClazz.getDeclaredConstructor().newInstance(); + Object nmsItemStackObj = asNMSCopyMethod.invoke(null, itemStack); + Object itemAsJsonObject = saveNmsItemStackMethod.invoke(nmsItemStackObj, nmsNbtTagCompoundObj); + + return itemAsJsonObject.toString(); + } + private static final String[] romanNumbers = new String[] { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "XI", "X" }; private static String maybeToRoman(int value) { diff --git a/src/main/java/de/diddiz/util/ReflectionUtil.java b/src/main/java/de/diddiz/util/ReflectionUtil.java new file mode 100644 index 00000000..7e4c9840 --- /dev/null +++ b/src/main/java/de/diddiz/util/ReflectionUtil.java @@ -0,0 +1,33 @@ +package de.diddiz.util; + +import org.bukkit.Bukkit; + +import java.lang.reflect.Method; + +public class ReflectionUtil { + + private static String versionString; + + public static String getVersion() { + if (versionString == null) { + String name = Bukkit.getServer().getClass().getPackage().getName(); + versionString = name.substring(name.lastIndexOf('.') + 1) + "."; + } + + return versionString; + } + + public static Class getMinecraftClass(String minecraftClassName) throws ClassNotFoundException { + String clazzName = "net.minecraft." + minecraftClassName; + return Class.forName(clazzName); + } + + public static Class getCraftBukkitClass(String craftBukkitClassName) throws ClassNotFoundException { + String clazzName = "org.bukkit.craftbukkit." + getVersion() + craftBukkitClassName; + return Class.forName(clazzName); + } + + public static Method getMethod(Class clazz, String methodName, Class... params) throws NoSuchMethodException { + return clazz.getMethod(methodName, params); + } +} From b3f268cd0490544d527e56e1c1e2f8af7398e53a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 21 Aug 2021 00:01:15 +0200 Subject: [PATCH 291/399] Avoid deprecated methods when creating the item hover and some cleanup --- src/main/java/de/diddiz/util/BukkitUtils.java | 44 +++++-------------- .../java/de/diddiz/util/ReflectionUtil.java | 10 +---- 2 files changed, 13 insertions(+), 41 deletions(-) diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 39c4880a..2228c931 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -4,7 +4,6 @@ import de.diddiz.LogBlock.LogBlock; import java.io.File; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; @@ -20,7 +19,9 @@ import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.HoverEvent.Action; +import net.md_5.bungee.api.chat.ItemTag; import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.chat.hover.content.Item; import net.md_5.bungee.api.chat.hover.content.Text; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -764,51 +765,28 @@ public static TextComponent toString(ItemStack stack) { TextComponent msg = MessagingUtil.createTextComponentWithColor(stack.getAmount() + "x ", TypeColor.DEFAULT.getColor()); msg.addExtra(prettyMaterial(stack.getType())); - ItemStack copy = stack.clone(); - copy.setAmount(1); - - String itemJson = null; try { - itemJson = convertItemStackToJson(copy); + 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); - } - - if (itemJson != null) { - BaseComponent[] hoverEventComponents = new BaseComponent[]{ - new TextComponent(itemJson) - }; - - msg.setHoverEvent(new HoverEvent(Action.SHOW_ITEM, hoverEventComponents)); - } else { - 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()) }))); } return msg; } - public static String convertItemStackToJson(ItemStack itemStack) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + public static String getItemTag(ItemStack itemStack) throws ReflectiveOperationException { Class craftItemStackClazz = ReflectionUtil.getCraftBukkitClass("inventory.CraftItemStack"); - Method asNMSCopyMethod = ReflectionUtil.getMethod(craftItemStackClazz, "asNMSCopy", ItemStack.class); + Method asNMSCopyMethod = craftItemStackClazz.getMethod("asNMSCopy", ItemStack.class); Class nmsItemStackClazz = ReflectionUtil.getMinecraftClass("world.item.ItemStack"); - Class nbtTagCompoundClazz = ReflectionUtil.getMinecraftClass("nbt.NBTTagCompound"); - Method saveNmsItemStackMethod = ReflectionUtil.getMethod(nmsItemStackClazz, "save", nbtTagCompoundClazz); + Method getTagMethod = nmsItemStackClazz.getMethod("getTag"); - Object nmsNbtTagCompoundObj = nbtTagCompoundClazz.getDeclaredConstructor().newInstance(); - Object nmsItemStackObj = asNMSCopyMethod.invoke(null, itemStack); - Object itemAsJsonObject = saveNmsItemStackMethod.invoke(nmsItemStackObj, nmsNbtTagCompoundObj); + Object nmsItemStack = asNMSCopyMethod.invoke(null, itemStack); + Object itemTag = getTagMethod.invoke(nmsItemStack); - return itemAsJsonObject.toString(); - } - - private static final String[] romanNumbers = new String[] { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "XI", "X" }; - - private static String maybeToRoman(int value) { - if (value > 0 && value <= 10) { - return romanNumbers[value - 1]; - } - return Integer.toString(value); + return itemTag != null ? itemTag.toString() : null; } public static String formatMinecraftKey(String s) { diff --git a/src/main/java/de/diddiz/util/ReflectionUtil.java b/src/main/java/de/diddiz/util/ReflectionUtil.java index 7e4c9840..ba50bd83 100644 --- a/src/main/java/de/diddiz/util/ReflectionUtil.java +++ b/src/main/java/de/diddiz/util/ReflectionUtil.java @@ -2,8 +2,6 @@ import org.bukkit.Bukkit; -import java.lang.reflect.Method; - public class ReflectionUtil { private static String versionString; @@ -11,7 +9,7 @@ public class ReflectionUtil { public static String getVersion() { if (versionString == null) { String name = Bukkit.getServer().getClass().getPackage().getName(); - versionString = name.substring(name.lastIndexOf('.') + 1) + "."; + versionString = name.substring(name.lastIndexOf('.') + 1); } return versionString; @@ -23,11 +21,7 @@ public static Class getMinecraftClass(String minecraftClassName) throws Class } public static Class getCraftBukkitClass(String craftBukkitClassName) throws ClassNotFoundException { - String clazzName = "org.bukkit.craftbukkit." + getVersion() + craftBukkitClassName; + String clazzName = "org.bukkit.craftbukkit." + getVersion() + "." + craftBukkitClassName; return Class.forName(clazzName); } - - public static Method getMethod(Class clazz, String methodName, Class... params) throws NoSuchMethodException { - return clazz.getMethod(methodName, params); - } } From 522def8b2e0fddd155ec8753369dd83b86ff4439 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 23 Aug 2021 19:41:23 +0200 Subject: [PATCH 292/399] Add a warning that the table conversion for 1.17 might take a long time --- src/main/java/de/diddiz/LogBlock/Updater.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 53e605b7..c548701b 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -745,6 +745,7 @@ boolean update() { } if (configVersion.compareTo(new ComparableVersion("1.17.0")) < 0) { logblock.getLogger().info("Updating tables to 1.17.0 ..."); + logblock.getLogger().warning("The updating process might take several minutes if you have a huge log table! Please do not shutdown your server until it is completed."); try (Connection conn = logblock.getConnection()) { conn.setAutoCommit(true); final Statement st = conn.createStatement(); @@ -755,6 +756,7 @@ boolean update() { } catch (final SQLException ex) { logblock.getLogger().log(Level.SEVERE, "[Updater] Warning: Could not alter table", ex); } + logblock.getLogger().info("Update to 1.17.0 completed."); config.set("version", "1.17.0"); } From 4b7b5b984dc0287ad09287d77b390fb1446a3be6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 26 Aug 2021 07:58:44 +0200 Subject: [PATCH 293/399] Remove fireCustomEvents config option / fire event when any listener is registered --- src/main/java/de/diddiz/LogBlock/Consumer.java | 2 +- src/main/java/de/diddiz/LogBlock/config/Config.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index b075a7d0..474a549f 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -701,7 +701,7 @@ private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDa if (typeAfter == null || typeAfter.getMaterial() == Material.CAVE_AIR || typeAfter.getMaterial() == Material.VOID_AIR) { typeAfter = Bukkit.createBlockData(Material.AIR); } - if (Config.fireCustomEvents) { + if (BlockChangePreLogEvent.getHandlerList().getRegisteredListeners().length > 0) { // Create and call the event BlockChangePreLogEvent event = new BlockChangePreLogEvent(actor, loc, typeBefore, typeAfter, stateBefore, stateAfter, ca); logblock.getServer().getPluginManager().callEvent(event); diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 085e680a..11be9f85 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -29,7 +29,6 @@ public class Config { public static boolean mysqlUseSSL; public static boolean mysqlRequireSSL; public static int delayBetweenRuns, forceToProcessAtLeast, timePerRun; - public static boolean fireCustomEvents; public static boolean useBukkitScheduler; public static int queueWarningSize; public static boolean enableAutoClearLog; @@ -92,7 +91,6 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("consumer.delayBetweenRuns", 2); def.put("consumer.forceToProcessAtLeast", 200); def.put("consumer.timePerRun", 1000); - def.put("consumer.fireCustomEvents", false); def.put("consumer.useBukkitScheduler", true); def.put("consumer.queueWarningSize", 1000); def.put("clearlog.dumpDeletedLog", false); @@ -171,6 +169,9 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti config.set(e.getKey(), e.getValue()); } } + if (config.contains("consumer.fireCustomEvents")) { + config.set("consumer.fireCustomEvents", null); + } logblock.saveConfig(); ComparableVersion configVersion = new ComparableVersion(config.getString("version")); @@ -185,7 +186,6 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti delayBetweenRuns = config.getInt("consumer.delayBetweenRuns", 2); forceToProcessAtLeast = config.getInt("consumer.forceToProcessAtLeast", 0); timePerRun = config.getInt("consumer.timePerRun", 1000); - fireCustomEvents = config.getBoolean("consumer.fireCustomEvents", false); useBukkitScheduler = config.getBoolean("consumer.useBukkitScheduler", true); queueWarningSize = config.getInt("consumer.queueWarningSize", 1000); enableAutoClearLog = config.getBoolean("clearlog.enableAutoClearLog"); From d084372876d40d2ef5531c63e1e434c01c1cc71b Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 26 Aug 2021 08:07:28 +0200 Subject: [PATCH 294/399] Simplify Actor.actorFromString --- src/main/java/de/diddiz/LogBlock/Actor.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index 4ed73aff..d2225898 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -9,8 +9,6 @@ import java.sql.ResultSet; import java.sql.SQLException; -import java.util.Collection; - import static de.diddiz.util.BukkitUtils.entityName; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -131,11 +129,9 @@ public static Actor actorFromProjectileSource(ProjectileSource psource) { */ @Deprecated public static Actor actorFromString(String actorName) { - Collection players = Bukkit.getServer().getOnlinePlayers(); - for (Player p : players) { - if (p.getName().equalsIgnoreCase(actorName)) { - return actorFromEntity(p); - } + Player p = Bukkit.getServer().getPlayerExact(actorName); + if (p != null) { + return actorFromEntity(p); } // No player found online with that name, assuming non-player entity/effect return new Actor(actorName); From 597b1831f198e5ec2946facd6741533c109247a8 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 26 Aug 2021 20:53:42 +0200 Subject: [PATCH 295/399] Normalize actor for crop trampling mobs --- src/main/java/de/diddiz/LogBlock/Actor.java | 1 + .../diddiz/LogBlock/listeners/CreatureInteractLogging.java | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index d2225898..1b48b252 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -95,6 +95,7 @@ public static Actor actorFromEntity(Entity entity) { return new Actor(entityName(entity)); } + @Deprecated public static Actor actorFromEntity(EntityType entity) { return new Actor(entity.name()); } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java index f831d841..84651b28 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java @@ -10,7 +10,6 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.data.type.TurtleEgg; -import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -27,10 +26,8 @@ public CreatureInteractLogging(LogBlock lb) { public void onEntityInteract(EntityInteractEvent event) { final WorldConfig wcfg = getWorldConfig(event.getEntity().getWorld()); - final EntityType entityType = event.getEntityType(); - // Mobs only - if (event.getEntity() instanceof Player || entityType == null) { + if (event.getEntity() instanceof Player) { return; } @@ -42,7 +39,7 @@ public void onEntityInteract(EntityInteractEvent event) { if (type == Material.FARMLAND) { if (wcfg.isLogging(Logging.CREATURECROPTRAMPLE)) { // 3 = Dirt ID - consumer.queueBlock(Actor.actorFromEntity(entityType), loc, type.createBlockData(), Material.DIRT.createBlockData()); + consumer.queueBlock(new Actor("CreatureTrample"), loc, type.createBlockData(), Material.DIRT.createBlockData()); // Log the crop on top as being broken Block trampledCrop = clicked.getRelative(BlockFace.UP); if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) { From 610f3edcab370770dbb56b61169ebcc7a5c3cd2f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 26 Aug 2021 20:54:55 +0200 Subject: [PATCH 296/399] Add EntityChangePreLogEvent --- .../java/de/diddiz/LogBlock/Consumer.java | 26 ++++++++- .../events/EntityChangePreLogEvent.java | 54 +++++++++++++++++++ .../listeners/AdvancedEntityLogging.java | 12 ++--- 3 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/events/EntityChangePreLogEvent.java diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 474a549f..d530f0a2 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -53,6 +53,7 @@ import de.diddiz.LogBlock.blockstate.BlockStateCodecs; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.events.BlockChangePreLogEvent; +import de.diddiz.LogBlock.events.EntityChangePreLogEvent; import de.diddiz.util.BukkitUtils; import de.diddiz.util.Utils; @@ -731,10 +732,31 @@ private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockDa addQueueLast(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, Utils.serializeYamlConfiguration(stateBefore), typeMaterialId, typeStateId, Utils.serializeYamlConfiguration(stateAfter), ca)); } - public void queueEntityModification(Actor actor, UUID entityId, EntityType entityType, Location loc, EntityChangeType changeType, YamlConfiguration data) { - if (actor == null || loc == null || changeType == null || entityId == null || entityType == null || hiddenPlayers.contains(actor.getName().toLowerCase()) || !isLogged(loc.getWorld())) { + public void queueEntityModification(Actor actor, Entity entity, EntityChangeType changeType, YamlConfiguration data) { + if (actor == null || changeType == null || entity == null || hiddenPlayers.contains(actor.getName().toLowerCase()) || !isLogged(entity.getWorld())) { return; } + UUID entityId = entity.getUniqueId(); + EntityType entityType = entity.getType(); + Location loc = entity.getLocation(); + + if (EntityChangePreLogEvent.getHandlerList().getRegisteredListeners().length > 0) { + // Create and call the event + EntityChangePreLogEvent event = new EntityChangePreLogEvent(actor, loc, entity, changeType, data); + logblock.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + + // Update variables + actor = event.getOwnerActor(); + loc = event.getLocation(); + } + // Do this last so LogBlock still has final say in what is being added + if (actor == null || loc == null || hiddenPlayers.contains(actor.getName().toLowerCase()) || !isLogged(loc.getWorld())) { + return; + } + addQueueLast(new EntityRow(loc, actor, entityType, entityId, changeType, Utils.serializeYamlConfiguration(data))); } diff --git a/src/main/java/de/diddiz/LogBlock/events/EntityChangePreLogEvent.java b/src/main/java/de/diddiz/LogBlock/events/EntityChangePreLogEvent.java new file mode 100644 index 00000000..061aaa9e --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/events/EntityChangePreLogEvent.java @@ -0,0 +1,54 @@ +package de.diddiz.LogBlock.events; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.EntityChange.EntityChangeType; +import org.bukkit.Location; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Entity; +import org.bukkit.event.HandlerList; + +public class EntityChangePreLogEvent extends PreLogEvent { + + private static final HandlerList handlers = new HandlerList(); + private Location location; + private Entity entity; + private EntityChangeType changeType; + private YamlConfiguration changeData; + + public EntityChangePreLogEvent(Actor owner, Location location, Entity entity, EntityChangeType changeType, YamlConfiguration changeData) { + super(owner); + this.location = location; + this.entity = entity; + this.changeType = changeType; + this.changeData = changeData; + } + + public Location getLocation() { + return location; + } + + public void setLocation(Location location) { + this.location = location; + } + + public Entity getEntity() { + return entity; + } + + public EntityChangeType getChangeType() { + return changeType; + } + + public YamlConfiguration getChangeData() { + return changeData; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index c46f61e2..f8b13e00 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -131,7 +131,7 @@ public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { inHand = inHand.clone(); inHand.setAmount(1); data.set("item", inHand); - consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.ADDEQUIP, data); + consumer.queueEntityModification(actor, entity, EntityChange.EntityChangeType.ADDEQUIP, data); } } } @@ -246,7 +246,7 @@ public void onEntityDamage(EntityDamageEvent event) { } YamlConfiguration data = new YamlConfiguration(); data.set("item", oldItem); - consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.REMOVEEQUIP, data); + consumer.queueEntityModification(actor, entity, EntityChange.EntityChangeType.REMOVEEQUIP, data); } } } @@ -274,7 +274,7 @@ public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { if (damager instanceof Bee && !((Bee) damager).hasStung()) { if (Config.isLogging(damager.getWorld(), EntityLogging.MODIFY, damager)) { Actor actor = Actor.actorFromEntity(event.getEntity()); - consumer.queueEntityModification(actor, damager.getUniqueId(), damager.getType(), damager.getLocation(), EntityChange.EntityChangeType.GET_STUNG, null); + consumer.queueEntityModification(actor, damager, EntityChange.EntityChangeType.GET_STUNG, null); } } } @@ -295,13 +295,13 @@ public void onPlayerArmorStandManipulate(PlayerArmorStandManipulateEvent event) YamlConfiguration data = new YamlConfiguration(); data.set("item", oldItem); data.set("slot", event.getSlot().name()); - consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.REMOVEEQUIP, data); + consumer.queueEntityModification(actor, entity, EntityChange.EntityChangeType.REMOVEEQUIP, data); } if (!newEmpty) { YamlConfiguration data = new YamlConfiguration(); data.set("item", newItem); data.set("slot", event.getSlot().name()); - consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), entity.getLocation(), EntityChange.EntityChangeType.ADDEQUIP, data); + consumer.queueEntityModification(actor, entity, EntityChange.EntityChangeType.ADDEQUIP, data); } } } @@ -319,6 +319,6 @@ protected void queueEntitySpawnOrKill(Entity entity, Actor actor, EntityChange.E } else { data.set("worldedit", WorldEditHelper.serializeEntity(entity)); } - consumer.queueEntityModification(actor, entity.getUniqueId(), entity.getType(), location, changeType, data); + consumer.queueEntityModification(actor, entity, changeType, data); } } From c940dfc05ae555eb9e795402023b72ee775e1f34 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 26 Aug 2021 21:16:40 +0200 Subject: [PATCH 297/399] Store the acting entity object in the actor class --- src/main/java/de/diddiz/LogBlock/Actor.java | 30 +++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index 1b48b252..e8f3b792 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -33,29 +33,41 @@ public boolean equals(Object obj) { final String name; final String UUID; final Location blockLocation; + final Entity entity; public Actor(String name, String UUID) { this.name = name; this.UUID = UUID == null ? "unknown" : (UUID.length() > 36 ? UUID.substring(0, 36) : UUID); this.blockLocation = null; + this.entity = null; } public Actor(String name, String UUID, Block block) { this.name = name; this.UUID = UUID == null ? "unknown" : (UUID.length() > 36 ? UUID.substring(0, 36) : UUID); this.blockLocation = block == null ? null : block.getLocation(); + this.entity = null; } public Actor(String name, java.util.UUID UUID) { this.name = name; this.UUID = UUID.toString(); this.blockLocation = null; + this.entity = null; } public Actor(String name, java.util.UUID UUID, Block block) { this.name = name; this.UUID = UUID.toString(); this.blockLocation = block == null ? null : block.getLocation(); + this.entity = null; + } + + public Actor(String name, java.util.UUID UUID, Entity entity) { + this.name = name; + this.UUID = UUID.toString(); + this.blockLocation = null; + this.entity = entity; } public Actor(String name) { @@ -66,6 +78,13 @@ public Actor(String name, Block block) { this(name, generateUUID(name), block); } + public Actor(String name, Entity entity) { + this.name = name; + this.UUID = generateUUID(name); + this.blockLocation = null; + this.entity = entity; + } + public Actor(ResultSet rs) throws SQLException { this(rs.getString("playername"), rs.getString("UUID")); } @@ -82,9 +101,16 @@ public Location getBlockLocation() { return blockLocation; } + /** + * The acting entity object (if known) + */ + public Entity getEntity() { + return entity; + } + public static Actor actorFromEntity(Entity entity) { if (entity instanceof Player) { - return new Actor(entityName(entity), entity.getUniqueId()); + return new Actor(entityName(entity), entity.getUniqueId(), entity); } if (entity instanceof Projectile) { ProjectileSource shooter = ((Projectile) entity).getShooter(); @@ -92,7 +118,7 @@ public static Actor actorFromEntity(Entity entity) { return actorFromProjectileSource(shooter); } } - return new Actor(entityName(entity)); + return new Actor(entityName(entity), entity); } @Deprecated From e430ee073f074ab7c7fb827253d54a9c3a492128 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 27 Aug 2021 02:25:11 +0200 Subject: [PATCH 298/399] Move all classes to the logblock package --- src/main/java/de/diddiz/LogBlock/Actor.java | 3 ++- .../java/de/diddiz/LogBlock/BlockChange.java | 22 +++++++++---------- .../java/de/diddiz/LogBlock/ChatMessage.java | 10 ++++----- .../de/diddiz/LogBlock/CommandsHandler.java | 18 +++++++-------- .../java/de/diddiz/LogBlock/Consumer.java | 10 ++++----- .../de/diddiz/LogBlock/DumpedLogImporter.java | 5 ++--- .../java/de/diddiz/LogBlock/EntityChange.java | 18 +++++++-------- src/main/java/de/diddiz/LogBlock/Kill.java | 13 ++++++----- .../java/de/diddiz/LogBlock/LogBlock.java | 8 +++---- .../java/de/diddiz/LogBlock/QueryParams.java | 14 ++++++------ .../diddiz/LogBlock/SummedBlockChanges.java | 5 +++-- .../diddiz/LogBlock/SummedEntityChanges.java | 6 ++--- .../java/de/diddiz/LogBlock/SummedKills.java | 2 +- src/main/java/de/diddiz/LogBlock/Updater.java | 9 ++++---- .../java/de/diddiz/LogBlock/WorldEditor.java | 9 ++++---- .../LogBlock/WorldEditorEditFactory.java | 2 +- .../blockstate/BlockStateCodecShulkerBox.java | 2 +- .../blockstate/BlockStateCodecSign.java | 2 +- .../de/diddiz/LogBlock/config/Config.java | 7 +++--- .../diddiz/LogBlock/config/WorldConfig.java | 3 +-- .../listeners/AdvancedEntityLogging.java | 4 ++-- .../LogBlock/listeners/BlockBreakLogging.java | 9 ++++---- .../LogBlock/listeners/BlockBurnLogging.java | 6 ++--- .../LogBlock/listeners/BlockPlaceLogging.java | 3 +-- .../listeners/ChestAccessLogging.java | 2 +- .../listeners/CreatureInteractLogging.java | 2 +- .../LogBlock/listeners/DragonEggLogging.java | 2 +- .../LogBlock/listeners/ExplosionLogging.java | 5 ++--- .../LogBlock/listeners/FluidFlowLogging.java | 3 +-- .../LogBlock/listeners/InteractLogging.java | 2 +- .../listeners/LeavesDecayLogging.java | 4 ++-- .../listeners/ScaffoldingLogging.java | 2 +- .../LogBlock/listeners/ToolListener.java | 4 ++-- .../{ => LogBlock}/util/ActionColor.java | 2 +- .../{ => LogBlock}/util/BukkitUtils.java | 4 ++-- .../util/ComparableVersion.java | 2 +- .../{ => LogBlock}/util/CuboidRegion.java | 2 +- .../{ => LogBlock}/util/LoggingUtil.java | 2 +- .../{ => LogBlock}/util/MessagingUtil.java | 10 ++++----- .../util/MySQLConnectionPool.java | 2 +- .../{ => LogBlock}/util/ReflectionUtil.java | 2 +- .../diddiz/{ => LogBlock}/util/SqlUtil.java | 2 +- .../diddiz/{ => LogBlock}/util/TypeColor.java | 2 +- .../{ => LogBlock}/util/UUIDFetcher.java | 2 +- .../de/diddiz/{ => LogBlock}/util/Utils.java | 2 +- .../worldedit/WorldEditHelper.java | 4 ++-- .../worldedit/WorldEditLoggingHook.java | 5 ++--- .../de/diddiz/LogBlock/QueryParsingTest.java | 3 +-- 48 files changed, 127 insertions(+), 135 deletions(-) rename src/main/java/de/diddiz/{ => LogBlock}/util/ActionColor.java (92%) rename src/main/java/de/diddiz/{ => LogBlock}/util/BukkitUtils.java (97%) rename src/main/java/de/diddiz/{ => LogBlock}/util/ComparableVersion.java (96%) rename src/main/java/de/diddiz/{ => LogBlock}/util/CuboidRegion.java (98%) rename src/main/java/de/diddiz/{ => LogBlock}/util/LoggingUtil.java (99%) rename src/main/java/de/diddiz/{ => LogBlock}/util/MessagingUtil.java (94%) rename src/main/java/de/diddiz/{ => LogBlock}/util/MySQLConnectionPool.java (95%) rename src/main/java/de/diddiz/{ => LogBlock}/util/ReflectionUtil.java (96%) rename src/main/java/de/diddiz/{ => LogBlock}/util/SqlUtil.java (95%) rename src/main/java/de/diddiz/{ => LogBlock}/util/TypeColor.java (94%) rename src/main/java/de/diddiz/{ => LogBlock}/util/UUIDFetcher.java (96%) rename src/main/java/de/diddiz/{ => LogBlock}/util/Utils.java (96%) rename src/main/java/de/diddiz/{ => LogBlock}/worldedit/WorldEditHelper.java (98%) rename src/main/java/de/diddiz/{ => LogBlock}/worldedit/WorldEditLoggingHook.java (98%) diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index e8f3b792..6364ab97 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -7,9 +7,10 @@ import org.bukkit.projectiles.BlockProjectileSource; import org.bukkit.projectiles.ProjectileSource; +import static de.diddiz.LogBlock.util.BukkitUtils.entityName; + import java.sql.ResultSet; import java.sql.SQLException; -import static de.diddiz.util.BukkitUtils.entityName; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.block.Block; diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index da136f43..5585853d 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -1,18 +1,18 @@ package de.diddiz.LogBlock; -import static de.diddiz.util.ActionColor.CREATE; -import static de.diddiz.util.ActionColor.DESTROY; -import static de.diddiz.util.ActionColor.INTERACT; -import static de.diddiz.util.TypeColor.DEFAULT; -import static de.diddiz.util.MessagingUtil.createTextComponentWithColor; -import static de.diddiz.util.MessagingUtil.prettyDate; -import static de.diddiz.util.MessagingUtil.prettyLocation; -import static de.diddiz.util.MessagingUtil.prettyMaterial; -import static de.diddiz.util.MessagingUtil.prettyState; +import static de.diddiz.LogBlock.util.ActionColor.CREATE; +import static de.diddiz.LogBlock.util.ActionColor.DESTROY; +import static de.diddiz.LogBlock.util.ActionColor.INTERACT; +import static de.diddiz.LogBlock.util.MessagingUtil.createTextComponentWithColor; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyDate; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyLocation; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyState; +import static de.diddiz.LogBlock.util.TypeColor.DEFAULT; import de.diddiz.LogBlock.blockstate.BlockStateCodecs; -import de.diddiz.util.BukkitUtils; -import de.diddiz.util.Utils; +import de.diddiz.LogBlock.util.BukkitUtils; +import de.diddiz.LogBlock.util.Utils; import java.sql.ResultSet; import java.sql.SQLException; import java.util.logging.Level; diff --git a/src/main/java/de/diddiz/LogBlock/ChatMessage.java b/src/main/java/de/diddiz/LogBlock/ChatMessage.java index 1f55dd2a..379e6369 100644 --- a/src/main/java/de/diddiz/LogBlock/ChatMessage.java +++ b/src/main/java/de/diddiz/LogBlock/ChatMessage.java @@ -1,11 +1,11 @@ package de.diddiz.LogBlock; -import static de.diddiz.util.LoggingUtil.checkText; -import static de.diddiz.util.MessagingUtil.brackets; -import static de.diddiz.util.MessagingUtil.prettyDate; +import static de.diddiz.LogBlock.util.LoggingUtil.checkText; +import static de.diddiz.LogBlock.util.MessagingUtil.brackets; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyDate; -import de.diddiz.util.MessagingUtil; -import de.diddiz.util.MessagingUtil.BracketType; +import de.diddiz.LogBlock.util.MessagingUtil; +import de.diddiz.LogBlock.util.MessagingUtil.BracketType; import java.sql.ResultSet; import java.sql.SQLException; import net.md_5.bungee.api.chat.BaseComponent; diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 9ef9654f..1a76ca9e 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -14,21 +14,21 @@ import static de.diddiz.LogBlock.config.Config.rollbackMaxTime; import static de.diddiz.LogBlock.config.Config.toolsByName; import static de.diddiz.LogBlock.config.Config.toolsByType; -import static de.diddiz.util.BukkitUtils.giveTool; -import static de.diddiz.util.BukkitUtils.saveSpawnHeight; -import static de.diddiz.util.TypeColor.DEFAULT; -import static de.diddiz.util.TypeColor.ERROR; -import static de.diddiz.util.TypeColor.HEADER; -import static de.diddiz.util.Utils.isInt; -import static de.diddiz.util.Utils.listing; +import static de.diddiz.LogBlock.util.BukkitUtils.giveTool; +import static de.diddiz.LogBlock.util.BukkitUtils.saveSpawnHeight; +import static de.diddiz.LogBlock.util.TypeColor.DEFAULT; +import static de.diddiz.LogBlock.util.TypeColor.ERROR; +import static de.diddiz.LogBlock.util.TypeColor.HEADER; +import static de.diddiz.LogBlock.util.Utils.isInt; +import static de.diddiz.LogBlock.util.Utils.listing; import de.diddiz.LogBlock.QueryParams.BlockChangeType; import de.diddiz.LogBlock.QueryParams.Order; import de.diddiz.LogBlock.QueryParams.SummarizationMode; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.util.MessagingUtil; -import de.diddiz.util.Utils; +import de.diddiz.LogBlock.util.MessagingUtil; +import de.diddiz.LogBlock.util.Utils; import java.io.BufferedOutputStream; import java.io.BufferedWriter; import java.io.File; diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index d530f0a2..d90c1f38 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -5,9 +5,9 @@ import static de.diddiz.LogBlock.config.Config.hiddenPlayers; import static de.diddiz.LogBlock.config.Config.isLogged; import static de.diddiz.LogBlock.config.Config.logPlayerInfo; -import static de.diddiz.util.BukkitUtils.compressInventory; -import static de.diddiz.util.BukkitUtils.itemIDfromProjectileEntity; -import static de.diddiz.util.Utils.mysqlTextEscape; +import static de.diddiz.LogBlock.util.BukkitUtils.compressInventory; +import static de.diddiz.LogBlock.util.BukkitUtils.itemIDfromProjectileEntity; +import static de.diddiz.LogBlock.util.Utils.mysqlTextEscape; import java.io.File; import java.io.FileNotFoundException; @@ -54,8 +54,8 @@ import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.events.BlockChangePreLogEvent; import de.diddiz.LogBlock.events.EntityChangePreLogEvent; -import de.diddiz.util.BukkitUtils; -import de.diddiz.util.Utils; +import de.diddiz.LogBlock.util.BukkitUtils; +import de.diddiz.LogBlock.util.Utils; public class Consumer extends Thread { private static final int MAX_SHUTDOWN_TIME_MILLIS = 20000; diff --git a/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java b/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java index a871efaf..f430bb42 100644 --- a/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java +++ b/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java @@ -1,7 +1,8 @@ package de.diddiz.LogBlock; -import de.diddiz.util.Utils.ExtensionFilenameFilter; +import static de.diddiz.LogBlock.util.Utils.newline; +import de.diddiz.LogBlock.util.Utils.ExtensionFilenameFilter; import java.io.*; import java.sql.Connection; import java.sql.SQLException; @@ -11,8 +12,6 @@ import java.util.logging.Level; import java.util.regex.Pattern; -import static de.diddiz.util.Utils.newline; - public class DumpedLogImporter implements Runnable { private final LogBlock logblock; diff --git a/src/main/java/de/diddiz/LogBlock/EntityChange.java b/src/main/java/de/diddiz/LogBlock/EntityChange.java index 77a1d230..77c8acfa 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityChange.java +++ b/src/main/java/de/diddiz/LogBlock/EntityChange.java @@ -1,15 +1,15 @@ package de.diddiz.LogBlock; -import static de.diddiz.util.ActionColor.CREATE; -import static de.diddiz.util.ActionColor.DESTROY; -import static de.diddiz.util.ActionColor.INTERACT; -import static de.diddiz.util.MessagingUtil.createTextComponentWithColor; -import static de.diddiz.util.MessagingUtil.prettyDate; -import static de.diddiz.util.MessagingUtil.prettyEntityType; -import static de.diddiz.util.MessagingUtil.prettyLocation; -import static de.diddiz.util.MessagingUtil.prettyMaterial; +import static de.diddiz.LogBlock.util.ActionColor.CREATE; +import static de.diddiz.LogBlock.util.ActionColor.DESTROY; +import static de.diddiz.LogBlock.util.ActionColor.INTERACT; +import static de.diddiz.LogBlock.util.MessagingUtil.createTextComponentWithColor; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyDate; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyEntityType; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyLocation; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; -import de.diddiz.util.Utils; +import de.diddiz.LogBlock.util.Utils; import java.sql.ResultSet; import java.sql.SQLException; import java.util.UUID; diff --git a/src/main/java/de/diddiz/LogBlock/Kill.java b/src/main/java/de/diddiz/LogBlock/Kill.java index bec4f18f..2302c631 100755 --- a/src/main/java/de/diddiz/LogBlock/Kill.java +++ b/src/main/java/de/diddiz/LogBlock/Kill.java @@ -1,11 +1,12 @@ package de.diddiz.LogBlock; -import static de.diddiz.util.ActionColor.DESTROY; -import static de.diddiz.util.MessagingUtil.prettyDate; -import static de.diddiz.util.MessagingUtil.prettyLocation; -import static de.diddiz.util.MessagingUtil.prettyMaterial; -import de.diddiz.util.BukkitUtils; -import de.diddiz.util.MessagingUtil; +import static de.diddiz.LogBlock.util.ActionColor.DESTROY; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyDate; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyLocation; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; + +import de.diddiz.LogBlock.util.BukkitUtils; +import de.diddiz.LogBlock.util.MessagingUtil; import java.sql.ResultSet; import java.sql.SQLException; import net.md_5.bungee.api.chat.BaseComponent; diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 40791042..36f8dc71 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -3,10 +3,10 @@ import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.listeners.*; import de.diddiz.LogBlock.questioner.Questioner; -import de.diddiz.util.BukkitUtils; -import de.diddiz.util.MySQLConnectionPool; -import de.diddiz.worldedit.WorldEditHelper; -import de.diddiz.worldedit.WorldEditLoggingHook; +import de.diddiz.LogBlock.util.BukkitUtils; +import de.diddiz.LogBlock.util.MySQLConnectionPool; +import de.diddiz.LogBlock.worldedit.WorldEditHelper; +import de.diddiz.LogBlock.worldedit.WorldEditLoggingHook; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.command.Command; diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 9bf68947..1151726e 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -1,11 +1,11 @@ package de.diddiz.LogBlock; import de.diddiz.LogBlock.config.Config; -import de.diddiz.util.BukkitUtils; -import de.diddiz.util.CuboidRegion; -import de.diddiz.util.SqlUtil; -import de.diddiz.util.Utils; -import de.diddiz.worldedit.WorldEditHelper; +import de.diddiz.LogBlock.util.BukkitUtils; +import de.diddiz.LogBlock.util.CuboidRegion; +import de.diddiz.LogBlock.util.SqlUtil; +import de.diddiz.LogBlock.util.Utils; +import de.diddiz.LogBlock.worldedit.WorldEditHelper; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.NamespacedKey; @@ -20,8 +20,8 @@ import static de.diddiz.LogBlock.Session.getSession; import static de.diddiz.LogBlock.config.Config.*; -import static de.diddiz.util.BukkitUtils.friendlyWorldname; -import static de.diddiz.util.Utils.*; +import static de.diddiz.LogBlock.util.BukkitUtils.friendlyWorldname; +import static de.diddiz.LogBlock.util.Utils.*; public final class QueryParams implements Cloneable { private static final HashMap keywords = new HashMap<>(); diff --git a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java index f7c36d93..2e357c16 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java @@ -1,8 +1,9 @@ package de.diddiz.LogBlock; -import static de.diddiz.util.MessagingUtil.prettyMaterial; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; + import de.diddiz.LogBlock.QueryParams.SummarizationMode; -import de.diddiz.util.MessagingUtil; +import de.diddiz.LogBlock.util.MessagingUtil; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Objects; diff --git a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java index 4c14f5f9..d9a1499f 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java @@ -1,7 +1,9 @@ package de.diddiz.LogBlock; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; + import de.diddiz.LogBlock.QueryParams.SummarizationMode; -import de.diddiz.util.MessagingUtil; +import de.diddiz.LogBlock.util.MessagingUtil; import org.bukkit.Location; import java.sql.ResultSet; @@ -10,8 +12,6 @@ import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.TextComponent; -import static de.diddiz.util.MessagingUtil.prettyMaterial; - public class SummedEntityChanges implements LookupCacheElement { private final int type; private final int created, destroyed; diff --git a/src/main/java/de/diddiz/LogBlock/SummedKills.java b/src/main/java/de/diddiz/LogBlock/SummedKills.java index 2bec40c7..a185e9d2 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedKills.java +++ b/src/main/java/de/diddiz/LogBlock/SummedKills.java @@ -1,6 +1,6 @@ package de.diddiz.LogBlock; -import de.diddiz.util.MessagingUtil; +import de.diddiz.LogBlock.util.MessagingUtil; import java.sql.ResultSet; import java.sql.SQLException; import net.md_5.bungee.api.chat.BaseComponent; diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index c548701b..99183842 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -3,9 +3,9 @@ import de.diddiz.LogBlock.blockstate.BlockStateCodecSign; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.util.UUIDFetcher; -import de.diddiz.util.Utils; - +import de.diddiz.LogBlock.util.ComparableVersion; +import de.diddiz.LogBlock.util.UUIDFetcher; +import de.diddiz.LogBlock.util.Utils; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.data.BlockData; @@ -25,8 +25,7 @@ import static de.diddiz.LogBlock.config.Config.getLoggedWorlds; import static de.diddiz.LogBlock.config.Config.isLogging; -import static de.diddiz.util.BukkitUtils.friendlyWorldname; -import de.diddiz.util.ComparableVersion; +import static de.diddiz.LogBlock.util.BukkitUtils.friendlyWorldname; class Updater { private final LogBlock logblock; diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index d5624793..15fa285a 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -28,10 +28,9 @@ import de.diddiz.LogBlock.QueryParams.Order; import de.diddiz.LogBlock.blockstate.BlockStateCodecs; -import de.diddiz.util.BukkitUtils; -import de.diddiz.util.Utils; -import de.diddiz.worldedit.WorldEditHelper; - +import de.diddiz.LogBlock.util.BukkitUtils; +import de.diddiz.LogBlock.util.Utils; +import de.diddiz.LogBlock.worldedit.WorldEditHelper; import java.io.File; import java.io.PrintWriter; import java.sql.ResultSet; @@ -49,7 +48,7 @@ import static de.diddiz.LogBlock.config.Config.dontRollback; import static de.diddiz.LogBlock.config.Config.replaceAnyway; -import static de.diddiz.util.BukkitUtils.*; +import static de.diddiz.LogBlock.util.BukkitUtils.*; public class WorldEditor implements Runnable { private final LogBlock logblock; diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java b/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java index efec5087..d167d235 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java @@ -6,7 +6,7 @@ import org.bukkit.inventory.ItemStack; import de.diddiz.LogBlock.QueryParams.BlockChangeType; -import de.diddiz.util.Utils; +import de.diddiz.LogBlock.util.Utils; public class WorldEditorEditFactory { private final WorldEditor editor; diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java index ccbeca82..d26c2343 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java @@ -4,7 +4,7 @@ import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.util.BukkitUtils; +import de.diddiz.LogBlock.util.BukkitUtils; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.block.ShulkerBox; diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index 656ec742..e60c2a89 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -1,6 +1,6 @@ package de.diddiz.LogBlock.blockstate; -import de.diddiz.util.BukkitUtils; +import de.diddiz.LogBlock.util.BukkitUtils; import java.util.Arrays; import java.util.Collections; import java.util.List; diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 11be9f85..f0ec2ad9 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -1,8 +1,7 @@ package de.diddiz.LogBlock.config; import de.diddiz.LogBlock.*; -import de.diddiz.util.ComparableVersion; - +import de.diddiz.LogBlock.util.ComparableVersion; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; @@ -17,8 +16,8 @@ import java.util.logging.Level; import java.util.zip.DataFormatException; -import static de.diddiz.util.BukkitUtils.friendlyWorldname; -import static de.diddiz.util.Utils.parseTimeSpec; +import static de.diddiz.LogBlock.util.BukkitUtils.friendlyWorldname; +import static de.diddiz.LogBlock.util.Utils.parseTimeSpec; import static org.bukkit.Bukkit.*; public class Config { diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index 19230bd4..da4f8e5d 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -2,8 +2,7 @@ import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; -import de.diddiz.util.BukkitUtils; - +import de.diddiz.LogBlock.util.BukkitUtils; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Animals; import org.bukkit.entity.ArmorStand; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index f8b13e00..457ffd6a 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -42,8 +42,8 @@ import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.EntityLogging; -import de.diddiz.util.LoggingUtil; -import de.diddiz.worldedit.WorldEditHelper; +import de.diddiz.LogBlock.util.LoggingUtil; +import de.diddiz.LogBlock.worldedit.WorldEditHelper; import java.util.UUID; public class AdvancedEntityLogging extends LoggingListener { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java index 9f1d11c5..c5614560 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java @@ -4,8 +4,7 @@ import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.util.BukkitUtils; - +import de.diddiz.LogBlock.util.BukkitUtils; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Material; @@ -19,9 +18,9 @@ import static de.diddiz.LogBlock.config.Config.getWorldConfig; import static de.diddiz.LogBlock.config.Config.isLogging; -import static de.diddiz.util.LoggingUtil.smartLogBlockBreak; -import static de.diddiz.util.LoggingUtil.smartLogBlockReplace; -import static de.diddiz.util.LoggingUtil.smartLogFallables; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockBreak; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockReplace; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogFallables; public class BlockBreakLogging extends LoggingListener { public BlockBreakLogging(LogBlock lb) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java index e329ccf0..5ba55c63 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java @@ -17,9 +17,9 @@ import org.bukkit.event.player.PlayerInteractEvent; import static de.diddiz.LogBlock.config.Config.isLogging; -import static de.diddiz.util.LoggingUtil.smartLogBlockBreak; -import static de.diddiz.util.LoggingUtil.smartLogBlockReplace; -import static de.diddiz.util.LoggingUtil.smartLogFallables; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockBreak; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockReplace; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogFallables; public class BlockBurnLogging extends LoggingListener { public BlockBurnLogging(LogBlock lb) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java index 58ce7a27..b24cfcf8 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java @@ -4,8 +4,7 @@ import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.Config; -import de.diddiz.util.LoggingUtil; - +import de.diddiz.LogBlock.util.LoggingUtil; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index 6211d071..15606ecf 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -24,7 +24,7 @@ import java.util.Map.Entry; import static de.diddiz.LogBlock.config.Config.isLogging; -import static de.diddiz.util.BukkitUtils.*; +import static de.diddiz.LogBlock.util.BukkitUtils.*; public class ChestAccessLogging extends LoggingListener { private class PlayerActiveInventoryModifications { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java index 84651b28..395fe353 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java @@ -4,7 +4,7 @@ import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.util.BukkitUtils; +import de.diddiz.LogBlock.util.BukkitUtils; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/DragonEggLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/DragonEggLogging.java index 45fde6d8..657ae9ed 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/DragonEggLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/DragonEggLogging.java @@ -20,7 +20,7 @@ import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.Config; -import de.diddiz.util.LoggingUtil; +import de.diddiz.LogBlock.util.LoggingUtil; public class DragonEggLogging extends LoggingListener { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index ad46e9b5..9695e969 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -5,8 +5,7 @@ import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.util.BukkitUtils; - +import de.diddiz.LogBlock.util.BukkitUtils; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -24,7 +23,7 @@ import static de.diddiz.LogBlock.config.Config.getWorldConfig; import static de.diddiz.LogBlock.config.Config.logCreeperExplosionsAsPlayerWhoTriggeredThese; -import static de.diddiz.util.BukkitUtils.getContainerBlocks; +import static de.diddiz.LogBlock.util.BukkitUtils.getContainerBlocks; import java.util.UUID; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index 51fe14d5..b5710111 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -5,8 +5,7 @@ import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.util.BukkitUtils; - +import de.diddiz.LogBlock.util.BukkitUtils; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index 40af564c..a865cee4 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -4,7 +4,7 @@ import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.util.BukkitUtils; +import de.diddiz.LogBlock.util.BukkitUtils; import org.bukkit.DyeColor; import org.bukkit.Location; import org.bukkit.Material; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/LeavesDecayLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/LeavesDecayLogging.java index 055974ea..5b1a9d8d 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/LeavesDecayLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/LeavesDecayLogging.java @@ -8,8 +8,8 @@ import org.bukkit.event.block.LeavesDecayEvent; import static de.diddiz.LogBlock.config.Config.isLogging; -import static de.diddiz.util.LoggingUtil.smartLogBlockBreak; -import static de.diddiz.util.LoggingUtil.smartLogFallables; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockBreak; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogFallables; public class LeavesDecayLogging extends LoggingListener { public LeavesDecayLogging(LogBlock lb) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ScaffoldingLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ScaffoldingLogging.java index cf7e1f38..032c7e94 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ScaffoldingLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ScaffoldingLogging.java @@ -18,7 +18,7 @@ import org.bukkit.event.block.BlockPlaceEvent; import static de.diddiz.LogBlock.config.Config.isLogging; -import static de.diddiz.util.LoggingUtil.smartLogFallables; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogFallables; public class ScaffoldingLogging extends LoggingListener { private final static long MAX_SCAFFOLDING_LOG_TIME_MS = 2000; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java index e20b1c46..7a192c59 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java @@ -2,8 +2,8 @@ import de.diddiz.LogBlock.*; import de.diddiz.LogBlock.events.ToolUseEvent; -import de.diddiz.util.BukkitUtils; -import de.diddiz.util.CuboidRegion; +import de.diddiz.LogBlock.util.BukkitUtils; +import de.diddiz.LogBlock.util.CuboidRegion; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.block.Block; diff --git a/src/main/java/de/diddiz/util/ActionColor.java b/src/main/java/de/diddiz/LogBlock/util/ActionColor.java similarity index 92% rename from src/main/java/de/diddiz/util/ActionColor.java rename to src/main/java/de/diddiz/LogBlock/util/ActionColor.java index e336ba02..fa69d50a 100644 --- a/src/main/java/de/diddiz/util/ActionColor.java +++ b/src/main/java/de/diddiz/LogBlock/util/ActionColor.java @@ -1,4 +1,4 @@ -package de.diddiz.util; +package de.diddiz.LogBlock.util; import net.md_5.bungee.api.ChatColor; diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java similarity index 97% rename from src/main/java/de/diddiz/util/BukkitUtils.java rename to src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 2228c931..5622882c 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -1,6 +1,6 @@ -package de.diddiz.util; +package de.diddiz.LogBlock.util; -import static de.diddiz.util.MessagingUtil.prettyMaterial; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; import de.diddiz.LogBlock.LogBlock; import java.io.File; diff --git a/src/main/java/de/diddiz/util/ComparableVersion.java b/src/main/java/de/diddiz/LogBlock/util/ComparableVersion.java similarity index 96% rename from src/main/java/de/diddiz/util/ComparableVersion.java rename to src/main/java/de/diddiz/LogBlock/util/ComparableVersion.java index 95aba246..17e88246 100644 --- a/src/main/java/de/diddiz/util/ComparableVersion.java +++ b/src/main/java/de/diddiz/LogBlock/util/ComparableVersion.java @@ -1,4 +1,4 @@ -package de.diddiz.util; +package de.diddiz.LogBlock.util; // Taken from maven-artifact at // http://grepcode.com/file_/repo1.maven.org/maven2/org.apache.maven/maven-artifact/3.2.3/org/apache/maven/artifact/versioning/ComparableVersion.java/?v=source diff --git a/src/main/java/de/diddiz/util/CuboidRegion.java b/src/main/java/de/diddiz/LogBlock/util/CuboidRegion.java similarity index 98% rename from src/main/java/de/diddiz/util/CuboidRegion.java rename to src/main/java/de/diddiz/LogBlock/util/CuboidRegion.java index a7046096..7247706c 100644 --- a/src/main/java/de/diddiz/util/CuboidRegion.java +++ b/src/main/java/de/diddiz/LogBlock/util/CuboidRegion.java @@ -1,4 +1,4 @@ -package de.diddiz.util; +package de.diddiz.LogBlock.util; import org.bukkit.Location; import org.bukkit.World; diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/LogBlock/util/LoggingUtil.java similarity index 99% rename from src/main/java/de/diddiz/util/LoggingUtil.java rename to src/main/java/de/diddiz/LogBlock/util/LoggingUtil.java index 3c68c5b5..2c8ede75 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/LogBlock/util/LoggingUtil.java @@ -1,4 +1,4 @@ -package de.diddiz.util; +package de.diddiz.LogBlock.util; import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.Consumer; diff --git a/src/main/java/de/diddiz/util/MessagingUtil.java b/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java similarity index 94% rename from src/main/java/de/diddiz/util/MessagingUtil.java rename to src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java index b9f6a22f..3a828945 100644 --- a/src/main/java/de/diddiz/util/MessagingUtil.java +++ b/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java @@ -1,9 +1,9 @@ -package de.diddiz.util; +package de.diddiz.LogBlock.util; -import static de.diddiz.util.ActionColor.CREATE; -import static de.diddiz.util.ActionColor.DESTROY; -import static de.diddiz.util.TypeColor.DEFAULT; -import static de.diddiz.util.Utils.spaces; +import static de.diddiz.LogBlock.util.ActionColor.CREATE; +import static de.diddiz.LogBlock.util.ActionColor.DESTROY; +import static de.diddiz.LogBlock.util.TypeColor.DEFAULT; +import static de.diddiz.LogBlock.util.Utils.spaces; import de.diddiz.LogBlock.config.Config; import net.md_5.bungee.api.ChatColor; diff --git a/src/main/java/de/diddiz/util/MySQLConnectionPool.java b/src/main/java/de/diddiz/LogBlock/util/MySQLConnectionPool.java similarity index 95% rename from src/main/java/de/diddiz/util/MySQLConnectionPool.java rename to src/main/java/de/diddiz/LogBlock/util/MySQLConnectionPool.java index b064d708..c5b78827 100644 --- a/src/main/java/de/diddiz/util/MySQLConnectionPool.java +++ b/src/main/java/de/diddiz/LogBlock/util/MySQLConnectionPool.java @@ -1,4 +1,4 @@ -package de.diddiz.util; +package de.diddiz.LogBlock.util; import com.zaxxer.hikari.HikariDataSource; import de.diddiz.LogBlock.config.Config; diff --git a/src/main/java/de/diddiz/util/ReflectionUtil.java b/src/main/java/de/diddiz/LogBlock/util/ReflectionUtil.java similarity index 96% rename from src/main/java/de/diddiz/util/ReflectionUtil.java rename to src/main/java/de/diddiz/LogBlock/util/ReflectionUtil.java index ba50bd83..5a797708 100644 --- a/src/main/java/de/diddiz/util/ReflectionUtil.java +++ b/src/main/java/de/diddiz/LogBlock/util/ReflectionUtil.java @@ -1,4 +1,4 @@ -package de.diddiz.util; +package de.diddiz.LogBlock.util; import org.bukkit.Bukkit; diff --git a/src/main/java/de/diddiz/util/SqlUtil.java b/src/main/java/de/diddiz/LogBlock/util/SqlUtil.java similarity index 95% rename from src/main/java/de/diddiz/util/SqlUtil.java rename to src/main/java/de/diddiz/LogBlock/util/SqlUtil.java index d84df36c..a21c2c40 100644 --- a/src/main/java/de/diddiz/util/SqlUtil.java +++ b/src/main/java/de/diddiz/LogBlock/util/SqlUtil.java @@ -1,4 +1,4 @@ -package de.diddiz.util; +package de.diddiz.LogBlock.util; public class SqlUtil { public static String escapeString(String s) { diff --git a/src/main/java/de/diddiz/util/TypeColor.java b/src/main/java/de/diddiz/LogBlock/util/TypeColor.java similarity index 94% rename from src/main/java/de/diddiz/util/TypeColor.java rename to src/main/java/de/diddiz/LogBlock/util/TypeColor.java index 00904d02..db62b567 100644 --- a/src/main/java/de/diddiz/util/TypeColor.java +++ b/src/main/java/de/diddiz/LogBlock/util/TypeColor.java @@ -1,4 +1,4 @@ -package de.diddiz.util; +package de.diddiz.LogBlock.util; import net.md_5.bungee.api.ChatColor; diff --git a/src/main/java/de/diddiz/util/UUIDFetcher.java b/src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java similarity index 96% rename from src/main/java/de/diddiz/util/UUIDFetcher.java rename to src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java index 14d42fda..d6bca85b 100644 --- a/src/main/java/de/diddiz/util/UUIDFetcher.java +++ b/src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java @@ -1,4 +1,4 @@ -package de.diddiz.util; +package de.diddiz.LogBlock.util; import com.google.gson.Gson; import com.google.gson.GsonBuilder; diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/LogBlock/util/Utils.java similarity index 96% rename from src/main/java/de/diddiz/util/Utils.java rename to src/main/java/de/diddiz/LogBlock/util/Utils.java index 3e38a3b1..e84f1f95 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/LogBlock/util/Utils.java @@ -1,4 +1,4 @@ -package de.diddiz.util; +package de.diddiz.LogBlock.util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; diff --git a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java b/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java similarity index 98% rename from src/main/java/de/diddiz/worldedit/WorldEditHelper.java rename to src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java index b24413ec..f59aa8a1 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditHelper.java +++ b/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java @@ -1,4 +1,4 @@ -package de.diddiz.worldedit; +package de.diddiz.LogBlock.worldedit; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -34,7 +34,7 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import de.diddiz.LogBlock.LogBlock; -import de.diddiz.util.CuboidRegion; +import de.diddiz.LogBlock.util.CuboidRegion; public class WorldEditHelper { private static boolean checkedForWorldEdit; diff --git a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java b/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditLoggingHook.java similarity index 98% rename from src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java rename to src/main/java/de/diddiz/LogBlock/worldedit/WorldEditLoggingHook.java index 1a9ab285..613405f6 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java +++ b/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditLoggingHook.java @@ -1,4 +1,4 @@ -package de.diddiz.worldedit; +package de.diddiz.LogBlock.worldedit; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEdit; @@ -15,8 +15,7 @@ import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.blockstate.BlockStateCodecs; import de.diddiz.LogBlock.config.Config; -import de.diddiz.util.BukkitUtils; - +import de.diddiz.LogBlock.util.BukkitUtils; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; diff --git a/src/test/java/de/diddiz/LogBlock/QueryParsingTest.java b/src/test/java/de/diddiz/LogBlock/QueryParsingTest.java index 9e7d828d..751aa4c0 100644 --- a/src/test/java/de/diddiz/LogBlock/QueryParsingTest.java +++ b/src/test/java/de/diddiz/LogBlock/QueryParsingTest.java @@ -1,9 +1,8 @@ package de.diddiz.LogBlock; -import de.diddiz.util.Utils; import org.junit.Assert; import org.junit.Test; - +import de.diddiz.LogBlock.util.Utils; import java.util.Arrays; import java.util.List; From 5dfee1f906f53c0f4bdcf5c85c21e50690665571 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 27 Aug 2021 02:43:18 +0200 Subject: [PATCH 299/399] Load config in onLoad --- src/main/java/de/diddiz/LogBlock/LogBlock.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 36f8dc71..0da90341 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -38,6 +38,7 @@ public class LogBlock extends JavaPlugin { private PlayerInfoLogging playerInfoLogging; private ScaffoldingLogging scaffoldingLogging; private Questioner questioner; + private boolean isConfigLoaded; private volatile boolean isCompletelyEnabled; public static LogBlock getInstance() { @@ -57,20 +58,25 @@ public CommandsHandler getCommandsHandler() { } @Override - public void onEnable() { + public void onLoad() { logblock = this; - BukkitUtils.isDoublePlant(Material.AIR); // Force static code to run - final PluginManager pm = getPluginManager(); - - consumer = new Consumer(this); try { Config.load(this); + isConfigLoaded = true; } catch (final Exception ex) { - getLogger().log(Level.SEVERE, "Could not load LogBlock config! " + ex.getMessage()); + getLogger().log(Level.SEVERE, "Could not load LogBlock config! " + ex.getMessage(), ex); + } + } + + @Override + public void onEnable() { + final PluginManager pm = getPluginManager(); + if (!isConfigLoaded) { pm.disablePlugin(this); return; } + consumer = new Consumer(this); try { getLogger().info("Connecting to " + user + "@" + url + "..."); try { From 142bcae2ca4ad3d4043c085676cc098d3a3098a5 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 27 Aug 2021 03:22:29 +0200 Subject: [PATCH 300/399] Add feature to disable logging in WorldGuard regions resolves #826 --- pom.xml | 10 ++- .../java/de/diddiz/LogBlock/LogBlock.java | 13 +++ .../WorldGuardLoggingFlagsAddon.java | 80 +++++++++++++++++++ .../de/diddiz/LogBlock/config/Config.java | 4 + src/main/resources/plugin.yml | 4 +- 5 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/addons/worldguard/WorldGuardLoggingFlagsAddon.java diff --git a/pom.xml b/pom.xml index 3194a156..589f662d 100644 --- a/pom.xml +++ b/pom.xml @@ -42,13 +42,19 @@ org.spigotmc spigot-api - 1.17-R0.1-SNAPSHOT + 1.17.1-R0.1-SNAPSHOT provided com.sk89q.worldedit worldedit-bukkit - 7.2.0-SNAPSHOT + 7.2.7-SNAPSHOT + provided + + + com.sk89q.worldguard + worldguard-bukkit + 7.0.6-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 0da90341..57cd09ea 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock; +import de.diddiz.LogBlock.addons.worldguard.WorldGuardLoggingFlagsAddon; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.listeners.*; import de.diddiz.LogBlock.questioner.Questioner; @@ -38,6 +39,7 @@ public class LogBlock extends JavaPlugin { private PlayerInfoLogging playerInfoLogging; private ScaffoldingLogging scaffoldingLogging; private Questioner questioner; + private WorldGuardLoggingFlagsAddon worldGuardLoggingFlagsAddon; private boolean isConfigLoaded; private volatile boolean isCompletelyEnabled; @@ -67,6 +69,14 @@ public void onLoad() { } catch (final Exception ex) { getLogger().log(Level.SEVERE, "Could not load LogBlock config! " + ex.getMessage(), ex); } + if (Config.worldGuardLoggingFlags) { + if (getServer().getPluginManager().getPlugin("WorldGuard") == null) { + getLogger().log(Level.SEVERE, "Invalid config! addons.worldguardLoggingFlags is set to true, but WorldGuard is not loaded."); + } else { + worldGuardLoggingFlagsAddon = new WorldGuardLoggingFlagsAddon(this); + worldGuardLoggingFlagsAddon.onPluginLoad(); + } + } } @Override @@ -132,6 +142,9 @@ public void onEnable() { } } questioner = new Questioner(this); + if (worldGuardLoggingFlagsAddon != null) { + worldGuardLoggingFlagsAddon.onPluginEnable(); + } isCompletelyEnabled = true; getServer().getScheduler().runTaskAsynchronously(this, new Updater.PlayerCountChecker(this)); } diff --git a/src/main/java/de/diddiz/LogBlock/addons/worldguard/WorldGuardLoggingFlagsAddon.java b/src/main/java/de/diddiz/LogBlock/addons/worldguard/WorldGuardLoggingFlagsAddon.java new file mode 100644 index 00000000..92f726c3 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/addons/worldguard/WorldGuardLoggingFlagsAddon.java @@ -0,0 +1,80 @@ +package de.diddiz.LogBlock.addons.worldguard; + +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldguard.WorldGuard; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.association.RegionAssociable; +import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.flags.registry.FlagConflictException; +import com.sk89q.worldguard.protection.flags.registry.FlagRegistry; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.events.BlockChangePreLogEvent; +import de.diddiz.LogBlock.events.EntityChangePreLogEvent; +import java.util.logging.Level; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class WorldGuardLoggingFlagsAddon { + private final StateFlag LOGBLOCK_LOG_BLOCKS = new StateFlag("logblock-log-blocks", true); + private final StateFlag LOGBLOCK_LOG_ENTITIES = new StateFlag("logblock-log-entities", true); + + private LogBlock plugin; + private WorldGuardPlugin worldGuard; + + public WorldGuardLoggingFlagsAddon(LogBlock plugin) { + this.plugin = plugin; + } + + public void onPluginLoad() { + registerFlags(); + } + + public void onPluginEnable() { + worldGuard = (WorldGuardPlugin) plugin.getServer().getPluginManager().getPlugin("WorldGuard"); + plugin.getServer().getPluginManager().registerEvents(new LoggingListener(), plugin); + } + + private void registerFlags() { + try { + FlagRegistry registry = WorldGuard.getInstance().getFlagRegistry(); + registry.register(LOGBLOCK_LOG_BLOCKS); + registry.register(LOGBLOCK_LOG_ENTITIES); + } catch (FlagConflictException e) { + plugin.getLogger().log(Level.SEVERE, "Could not initialize Flags", e); + } + } + + private class LoggingListener implements Listener { + @EventHandler(ignoreCancelled = true) + public void onBlockChangePreLog(BlockChangePreLogEvent event) { + RegionAssociable regionAssociable = null; + Location location = event.getLocation(); + Entity actorEntity = event.getOwnerActor().getEntity(); + if (actorEntity instanceof Player) { + regionAssociable = worldGuard.wrapPlayer((Player) actorEntity); + } + ApplicableRegionSet set = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery().getApplicableRegions(BukkitAdapter.adapt(location)); + if (!set.testState(regionAssociable, LOGBLOCK_LOG_BLOCKS)) { + event.setCancelled(true); + } + } + + @EventHandler(ignoreCancelled = true) + public void onEntityChangePreLog(EntityChangePreLogEvent event) { + RegionAssociable regionAssociable = null; + Location location = event.getLocation(); + Entity actorEntity = event.getOwnerActor().getEntity(); + if (actorEntity instanceof Player) { + regionAssociable = worldGuard.wrapPlayer((Player) actorEntity); + } + ApplicableRegionSet set = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery().getApplicableRegions(BukkitAdapter.adapt(location)); + if (!set.testState(regionAssociable, LOGBLOCK_LOG_ENTITIES)) { + event.setCancelled(true); + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index f0ec2ad9..59dec807 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -55,6 +55,8 @@ public class Config { public static boolean safetyIdCheck; public static boolean debug; public static boolean logEnvironmentalKills; + // addons + public static boolean worldGuardLoggingFlags; // Not loaded from config - checked at runtime public static boolean mb4 = false; @@ -162,6 +164,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti def.put("tools.toolblock.mode", "LOOKUP"); def.put("tools.toolblock.permissionDefault", "OP"); def.put("safety.id.check", true); + def.put("addons.worldguardLoggingFlags", false); def.put("debug", false); for (final Entry e : def.entrySet()) { if (!config.contains(e.getKey())) { @@ -284,6 +287,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti toolsByName.put(alias, tool); } } + worldGuardLoggingFlags = config.getBoolean("addons.worldguardLoggingFlags"); final List loggedWorlds = config.getStringList("loggedWorlds"); worldConfigs = new HashMap<>(); if (loggedWorlds.isEmpty()) { diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index f7982088..43cee15f 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -5,8 +5,8 @@ authors: [md_5, ammar2, frymaster] website: http://dev.bukkit.org/server-mods/logblock/ main: de.diddiz.LogBlock.LogBlock description: ${project.description} -softdepend: [WorldEdit] -api-version: 1.14 +softdepend: [WorldEdit, WorldGuard] +api-version: 1.17 commands: lb: description: 'LogBlock plugin commands' From 964e60b2e57200aa7640a27d05399289b4a58979 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 8 Nov 2021 05:49:33 +0100 Subject: [PATCH 301/399] update distribution repository --- pom.xml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 589f662d..6605935a 100644 --- a/pom.xml +++ b/pom.xml @@ -29,12 +29,14 @@ - md_5-releases - https://repo.md-5.net/content/repositories/releases/ + nexus + Releases + https://www.iani.de/nexus/content/repositories/releases/ - md_5-snapshots - https://repo.md-5.net/content/repositories/snapshots/ + nexus + Snapshot + https://www.iani.de/nexus/content/repositories/snapshots/ From 749d114acd16f44ca30e57a6ee5387cfec06cffd Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 1 Dec 2021 07:48:03 +0100 Subject: [PATCH 302/399] Fix issues with minecraft 1.18 --- src/main/java/de/diddiz/LogBlock/LogBlock.java | 2 +- src/main/java/de/diddiz/LogBlock/util/MySQLConnectionPool.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 57cd09ea..756575b8 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -105,7 +105,7 @@ public void onEnable() { if (rs.next()) { Config.mb4 = true; // Allegedly JDBC driver since 2010 hasn't needed this. I did. - st.executeQuery("SET NAMES utf8mb4;"); + st.executeUpdate("SET NAMES utf8mb4;"); } conn.close(); Updater updater = new Updater(this); diff --git a/src/main/java/de/diddiz/LogBlock/util/MySQLConnectionPool.java b/src/main/java/de/diddiz/LogBlock/util/MySQLConnectionPool.java index c5b78827..3a0f854a 100644 --- a/src/main/java/de/diddiz/LogBlock/util/MySQLConnectionPool.java +++ b/src/main/java/de/diddiz/LogBlock/util/MySQLConnectionPool.java @@ -43,7 +43,7 @@ public void close() { public Connection getConnection() throws SQLException { Connection connection = ds.getConnection(); if (Config.mb4) { - connection.createStatement().executeQuery("SET NAMES utf8mb4"); + connection.createStatement().executeUpdate("SET NAMES utf8mb4"); } return connection; } From 31589ceec736bb661a85bf619c568de8f44b6c14 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 6 Dec 2021 03:58:16 +0100 Subject: [PATCH 303/399] Build against spigot-api 1.18 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6605935a..c2637691 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ org.spigotmc spigot-api - 1.17.1-R0.1-SNAPSHOT + 1.18-R0.1-SNAPSHOT provided From e87e9e2939a19826dd12cfd658e4b278cc96a60f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 6 Dec 2021 03:58:39 +0100 Subject: [PATCH 304/399] Fix itemstack reflection --- src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 5622882c..0959688a 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -781,7 +781,7 @@ public static String getItemTag(ItemStack itemStack) throws ReflectiveOperationE Method asNMSCopyMethod = craftItemStackClazz.getMethod("asNMSCopy", ItemStack.class); Class nmsItemStackClazz = ReflectionUtil.getMinecraftClass("world.item.ItemStack"); - Method getTagMethod = nmsItemStackClazz.getMethod("getTag"); + Method getTagMethod = nmsItemStackClazz.getMethod("getTagClone"); Object nmsItemStack = asNMSCopyMethod.invoke(null, itemStack); Object itemTag = getTagMethod.invoke(nmsItemStack); From eac100852530a75041fe1dec743a30419d18ccc4 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 19 Dec 2021 06:41:10 +0100 Subject: [PATCH 305/399] ItemStack.getTagClone is private so we have to use setAccessible --- src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 0959688a..a6511033 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -781,7 +781,8 @@ public static String getItemTag(ItemStack itemStack) throws ReflectiveOperationE Method asNMSCopyMethod = craftItemStackClazz.getMethod("asNMSCopy", ItemStack.class); Class nmsItemStackClazz = ReflectionUtil.getMinecraftClass("world.item.ItemStack"); - Method getTagMethod = nmsItemStackClazz.getMethod("getTagClone"); + Method getTagMethod = nmsItemStackClazz.getDeclaredMethod("getTagClone"); + getTagMethod.setAccessible(true); Object nmsItemStack = asNMSCopyMethod.invoke(null, itemStack); Object itemTag = getTagMethod.invoke(nmsItemStack); From 4e4b5de15d9e8966ff168e74e382d85ffb77acb3 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 19 Dec 2021 07:27:37 +0100 Subject: [PATCH 306/399] fix some y column types on startup if required --- src/main/java/de/diddiz/LogBlock/Updater.java | 52 +++++++++++++++++-- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 99183842..40b109e5 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -637,8 +637,7 @@ boolean update() { if (configVersion.compareTo(new ComparableVersion("1.13.1")) < 0) { logblock.getLogger().info("Updating tables to 1.13.1 ..."); - try { - final Connection conn = logblock.getConnection(); + try (Connection conn = logblock.getConnection()) { conn.setAutoCommit(false); final Statement st = conn.createStatement(); for (final WorldConfig wcfg : getLoggedWorlds()) { @@ -719,7 +718,6 @@ boolean update() { } st.close(); - conn.close(); } catch (final SQLException ex) { logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; @@ -764,8 +762,7 @@ boolean update() { } // this can always be checked - try { - final Connection conn = logblock.getConnection(); + try (Connection conn = logblock.getConnection()) { conn.setAutoCommit(true); final Statement st = conn.createStatement(); checkCharset("lb-players", "name", st, true); @@ -776,6 +773,51 @@ boolean update() { createIndexIfDoesNotExist("lb-blockstates", "name", "UNIQUE KEY `name` (`name`(150))", st, true); st.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + try (Connection conn = logblock.getConnection()) { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + PreparedStatement stSelectColumnType = conn.prepareStatement("SELECT `TABLE_NAME`, `COLUMN_TYPE` FROM information_schema.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `COLUMN_NAME` = ?"); + stSelectColumnType.setString(1, Config.mysqlDatabase); + stSelectColumnType.setString(2, "y"); + HashMap tablesAndYColumnType = new HashMap<>(); + try (ResultSet rs = stSelectColumnType.executeQuery()) { + while (rs.next()) { + String table = rs.getString("TABLE_NAME").toLowerCase(); + String type = rs.getString("COLUMN_TYPE").toLowerCase(); + tablesAndYColumnType.put(table, type); + } + } + for (final WorldConfig wcfg : getLoggedWorlds()) { + String type = tablesAndYColumnType.get((wcfg.table + "-blocks").toLowerCase()); + if (type != null) { + if (type.contains("tinyint") || type.contains("unsigned")) { + logblock.getLogger().info("Fixing y column type for table " + wcfg.table + "-blocks ..."); + logblock.getLogger().warning("The updating process might take several minutes if you have a huge log table! Please do not shutdown your server until it is completed."); + st.executeUpdate("ALTER TABLE `" + wcfg.table + "-blocks` CHANGE `y` `y` SMALLINT(5) NOT NULL"); + } + } + type = tablesAndYColumnType.get((wcfg.table + "-entities").toLowerCase()); + if (type != null) { + if (type.contains("tinyint") || type.contains("unsigned")) { + logblock.getLogger().info("Fixing y column type for table " + wcfg.table + "-entities ..."); + logblock.getLogger().warning("The updating process might take several minutes if you have a huge log table! Please do not shutdown your server until it is completed."); + st.executeUpdate("ALTER TABLE `" + wcfg.table + "-entities` CHANGE `y` `y` SMALLINT(5) NOT NULL"); + } + } + type = tablesAndYColumnType.get((wcfg.table + "-kills").toLowerCase()); + if (type != null) { + if (type.contains("tinyint") || type.contains("unsigned")) { + logblock.getLogger().info("Fixing y column type for table " + wcfg.table + "-kills ..."); + logblock.getLogger().warning("The updating process might take several minutes if you have a huge log table! Please do not shutdown your server until it is completed."); + st.executeUpdate("ALTER TABLE `" + wcfg.table + "-kills` CHANGE `y` `y` SMALLINT(5) NOT NULL"); + } + } + } + st.close(); conn.close(); } catch (final SQLException ex) { logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); From 5e9be562cda443ca44d995382b7f264c7a0c4056 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 19 Dec 2021 09:25:20 +0100 Subject: [PATCH 307/399] fix candle logging --- .../java/de/diddiz/LogBlock/BlockChange.java | 15 ++++- .../LogBlock/listeners/InteractLogging.java | 60 ++++++++++++++++++- .../de/diddiz/LogBlock/util/BukkitUtils.java | 48 +++++++++++++++ 3 files changed, 121 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 5585853d..b2174584 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -22,9 +22,11 @@ import org.bukkit.Material; import org.bukkit.Note; import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Lightable; import org.bukkit.block.data.Openable; import org.bukkit.block.data.Powerable; import org.bukkit.block.data.Waterlogged; +import org.bukkit.block.data.type.Candle; import org.bukkit.block.data.type.Comparator; import org.bukkit.block.data.type.DaylightDetector; import org.bukkit.block.data.type.Lectern; @@ -130,7 +132,7 @@ public BaseComponent[] getLogMessage(int entry) { String typeDetails = getTypeDetails(type, typeState, replaced, replacedState); String replacedDetails = getTypeDetails(replaced, replacedState); - if (type.getMaterial().equals(replaced.getMaterial())) { + if (type.getMaterial().equals(replaced.getMaterial()) || (type.getMaterial() == Material.CAKE && BukkitUtils.isCandleCake(replaced.getMaterial()))) { if (BukkitUtils.isEmpty(type.getMaterial())) { msg.addExtra(createTextComponentWithColor("did an unspecified action", INTERACT.getColor())); } else if (ca != null) { @@ -211,6 +213,17 @@ public BaseComponent[] getLogMessage(int entry) { msg.addExtra(prettyMaterial(type)); msg.addExtra(createTextComponentWithColor(" to", CREATE.getColor())); msg.addExtra(prettyState(typeDetails)); + } else if (type instanceof Candle && ((Candle) type).getCandles() != ((Candle) replaced).getCandles()) { + msg.addExtra(createTextComponentWithColor("added a candle to ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type)); + } else if ((type instanceof Candle || BukkitUtils.isCandleCake(type.getMaterial())) && ((Lightable) type).isLit() != ((Lightable) replaced).isLit()) { + if (((Lightable) type).isLit()) { + msg.addExtra(createTextComponentWithColor("lit a ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type)); + } else { + msg.addExtra(createTextComponentWithColor("extinguished a ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type)); + } } else { msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor())); msg.addExtra(prettyMaterial(replaced)); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index a865cee4..e0ade555 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -5,7 +5,9 @@ import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.LogBlock.util.BukkitUtils; +import java.util.UUID; import org.bukkit.DyeColor; +import org.bukkit.GameEvent; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Note; @@ -16,8 +18,10 @@ import org.bukkit.block.Sign; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Directional; +import org.bukkit.block.data.Lightable; import org.bukkit.block.data.Openable; import org.bukkit.block.data.type.Cake; +import org.bukkit.block.data.type.Candle; import org.bukkit.block.data.type.Comparator; import org.bukkit.block.data.type.Comparator.Mode; import org.bukkit.block.data.type.DaylightDetector; @@ -27,10 +31,12 @@ import org.bukkit.block.data.type.Switch; import org.bukkit.block.data.type.TurtleEgg; import org.bukkit.entity.Player; +import org.bukkit.event.Event.Result; 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.world.GenericGameEvent; import org.bukkit.inventory.ItemStack; import static de.diddiz.LogBlock.config.Config.getWorldConfig; @@ -40,6 +46,10 @@ public InteractLogging(LogBlock lb) { super(lb); } + private UUID lastInteractionPlayer; + private BlockData lastInteractionBlockData; + private Location lastInteractionLocation; + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerInteract(PlayerInteractEvent event) { final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld()); @@ -52,6 +62,9 @@ public void onPlayerInteract(PlayerInteractEvent event) { final Material type = blockData.getMaterial(); final Player player = event.getPlayer(); final Location loc = clicked.getLocation(); + lastInteractionPlayer = player.getUniqueId(); + lastInteractionBlockData = blockData; + lastInteractionLocation = loc; switch (type) { case OAK_FENCE_GATE: @@ -77,7 +90,10 @@ public void onPlayerInteract(PlayerInteractEvent event) { } break; case CAKE: - if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20) { + if (event.hasItem() && BukkitUtils.isCandle(event.getItem().getType()) && event.useItemInHand() != Result.DENY) { + BlockData newBlockData = Material.valueOf(event.getItem().getType().name() + "_CAKE").createBlockData(); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } else if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20) { Cake newBlockData = (Cake) blockData.clone(); if (newBlockData.getBites() < 6) { newBlockData.setBites(newBlockData.getBites() + 1); @@ -271,4 +287,46 @@ public void onPlayerInteract(PlayerInteractEvent event) { } } } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onGenericGameEvent(GenericGameEvent event) { + if (lastInteractionPlayer != null && event.getEntity() != null && event.getEntity().getUniqueId().equals(lastInteractionPlayer) && lastInteractionLocation != null && event.getLocation().equals(lastInteractionLocation)) { + if (lastInteractionBlockData instanceof Candle) { + Candle previousCandle = (Candle) lastInteractionBlockData; + if (previousCandle.isLit()) { + BlockData newData = lastInteractionLocation.getBlock().getBlockData(); + if (newData instanceof Candle) { + Candle newCandle = (Candle) newData; + if (!newCandle.isLit() && !newCandle.isWaterlogged()) { + // log candle extinguish + consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), lastInteractionLocation, lastInteractionBlockData, newData); + } + } + } + } else if (lastInteractionBlockData instanceof Lightable && BukkitUtils.isCandleCake(lastInteractionBlockData.getMaterial())) { + Lightable previousLightable = (Lightable) lastInteractionBlockData; + BlockData newData = lastInteractionLocation.getBlock().getBlockData(); + if (event.getEvent().equals(GameEvent.EAT)) { + final WorldConfig wcfg = getWorldConfig(event.getLocation().getWorld()); + if (wcfg.isLogging(Logging.CAKEEAT)) { + // nom nom (don't know why newData is incorrect here) + newData = Material.CAKE.createBlockData(); + ((Cake) newData).setBites(1); + consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), lastInteractionLocation, lastInteractionBlockData, newData); + } + } else if (previousLightable.isLit()) { + if (newData instanceof Lightable) { + Lightable newLightable = (Lightable) newData; + if (!newLightable.isLit()) { + // log cake extinguish + consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), lastInteractionLocation, lastInteractionBlockData, newData); + } + } + } + } + } + lastInteractionPlayer = null; + lastInteractionBlockData = null; + lastInteractionLocation = null; + } } diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index a6511033..bcc96698 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -78,6 +78,8 @@ public class BukkitUtils { private static final EnumSet concreteBlocks; private static final EnumMap dyes; private static final EnumSet alwaysWaterlogged; + private static final EnumSet candles; + private static final EnumSet candleCakes; static { pressurePlates = EnumSet.noneOf(Material.class); @@ -485,6 +487,44 @@ public class BukkitUtils { concreteBlocks.add(Material.WHITE_CONCRETE); concreteBlocks.add(Material.YELLOW_CONCRETE); + candles = EnumSet.noneOf(Material.class); + candles.add(Material.CANDLE); + candles.add(Material.BLACK_CANDLE); + candles.add(Material.BLUE_CANDLE); + candles.add(Material.LIGHT_GRAY_CANDLE); + candles.add(Material.BROWN_CANDLE); + candles.add(Material.CYAN_CANDLE); + candles.add(Material.GRAY_CANDLE); + candles.add(Material.GREEN_CANDLE); + candles.add(Material.LIGHT_BLUE_CANDLE); + candles.add(Material.MAGENTA_CANDLE); + candles.add(Material.LIME_CANDLE); + candles.add(Material.ORANGE_CANDLE); + candles.add(Material.PINK_CANDLE); + candles.add(Material.PURPLE_CANDLE); + candles.add(Material.RED_CANDLE); + candles.add(Material.WHITE_CANDLE); + candles.add(Material.YELLOW_CANDLE); + + candleCakes = EnumSet.noneOf(Material.class); + candleCakes.add(Material.CANDLE_CAKE); + candleCakes.add(Material.BLACK_CANDLE_CAKE); + candleCakes.add(Material.BLUE_CANDLE_CAKE); + candleCakes.add(Material.LIGHT_GRAY_CANDLE_CAKE); + candleCakes.add(Material.BROWN_CANDLE_CAKE); + candleCakes.add(Material.CYAN_CANDLE_CAKE); + candleCakes.add(Material.GRAY_CANDLE_CAKE); + candleCakes.add(Material.GREEN_CANDLE_CAKE); + candleCakes.add(Material.LIGHT_BLUE_CANDLE_CAKE); + candleCakes.add(Material.MAGENTA_CANDLE_CAKE); + candleCakes.add(Material.LIME_CANDLE_CAKE); + candleCakes.add(Material.ORANGE_CANDLE_CAKE); + candleCakes.add(Material.PINK_CANDLE_CAKE); + candleCakes.add(Material.PURPLE_CANDLE_CAKE); + candleCakes.add(Material.RED_CANDLE_CAKE); + candleCakes.add(Material.WHITE_CANDLE_CAKE); + candleCakes.add(Material.YELLOW_CANDLE_CAKE); + dyes = new EnumMap<>(Material.class); dyes.put(Material.BLACK_DYE, DyeColor.BLACK); dyes.put(Material.BLUE_DYE, DyeColor.BLUE); @@ -1079,4 +1119,12 @@ public static Material[] getAllSignsArray() { public static boolean isAlwaysWaterlogged(Material m) { return alwaysWaterlogged.contains(m); } + + public static boolean isCandle(Material m) { + return candles.contains(m); + } + + public static boolean isCandleCake(Material m) { + return candleCakes.contains(m); + } } From 6d0ac7169c4903f463a23041c2ae4397d9148baa Mon Sep 17 00:00:00 2001 From: qwertyuioplkjhgfd <45241413+qwertyuioplkjhgfd@users.noreply.github.com> Date: Tue, 4 Jan 2022 16:37:45 -0800 Subject: [PATCH 308/399] update enginehub repository location (#849) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c2637691..32ec5e5c 100644 --- a/pom.xml +++ b/pom.xml @@ -85,7 +85,7 @@ sk89q-repo - https://maven.sk89q.com/repo/ + https://maven.enginehub.org/repo/ brokkonaut-repo From 676f862d2d6e153582d6713ac8e5b8a613b8a9f0 Mon Sep 17 00:00:00 2001 From: qwertyuioplkjhgfd <45241413+qwertyuioplkjhgfd@users.noreply.github.com> Date: Fri, 7 Jan 2022 00:46:51 +0000 Subject: [PATCH 309/399] exclude worldedit dependencies (#850) Co-authored-by: qwertyuioplkjhgfd --- pom.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pom.xml b/pom.xml index 32ec5e5c..d42778a6 100644 --- a/pom.xml +++ b/pom.xml @@ -52,12 +52,24 @@ worldedit-bukkit 7.2.7-SNAPSHOT provided + + + * + * + + com.sk89q.worldguard worldguard-bukkit 7.0.6-SNAPSHOT provided + + + * + * + + junit From 8def317c6242a2baecdb51db198ba605b4c36af5 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 7 Jan 2022 21:34:19 +0100 Subject: [PATCH 310/399] Revert "exclude worldedit dependencies (#850)" This reverts commit 676f862d2d6e153582d6713ac8e5b8a613b8a9f0. --- pom.xml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/pom.xml b/pom.xml index d42778a6..32ec5e5c 100644 --- a/pom.xml +++ b/pom.xml @@ -52,24 +52,12 @@ worldedit-bukkit 7.2.7-SNAPSHOT provided - - - * - * - - com.sk89q.worldguard worldguard-bukkit 7.0.6-SNAPSHOT provided - - - * - * - - junit From 1b2948c912782d58073c8ca1b3e094bca5488db8 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 8 Jan 2022 21:49:07 +0100 Subject: [PATCH 311/399] use https for xml schema location --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 32ec5e5c..bc4125d0 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,5 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 de.diddiz From e61f9b058da34e099e4b49942bcb31cfccc0f255 Mon Sep 17 00:00:00 2001 From: fantahund <42190420+fantahund@users.noreply.github.com> Date: Tue, 1 Feb 2022 20:42:48 +0100 Subject: [PATCH 312/399] Fix world height during safe teleport --- src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index bcc96698..7d7944ea 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -734,11 +734,11 @@ public static int saveSpawnHeight(Location loc) { final int x = loc.getBlockX(), z = loc.getBlockZ(); int y = loc.getBlockY(); boolean lower = world.getBlockAt(x, y, z).isEmpty(), upper = world.getBlockAt(x, y + 1, z).isEmpty(); - while ((!lower || !upper) && y != 127) { + while ((!lower || !upper) && y != world.getMaxHeight()) { lower = upper; upper = world.getBlockAt(x, ++y, z).isEmpty(); } - while (world.getBlockAt(x, y - 1, z).isEmpty() && y != 0) { + while (world.getBlockAt(x, y - 1, z).isEmpty() && y != world.getMinHeight()) { y--; } return y; From c3394fa8c54756af3a730da8d9e32d321658c445 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 16 Feb 2022 08:38:50 +0100 Subject: [PATCH 313/399] Save full skull profile instead of just the uuid if available --- pom.xml | 2 +- .../blockstate/BlockStateCodecSkull.java | 43 ++++++++++++++++--- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index bc4125d0..2801bb80 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ org.spigotmc spigot-api - 1.18-R0.1-SNAPSHOT + 1.18.1-R0.1-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java index 19399448..d4ad35c8 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java @@ -8,8 +8,20 @@ import org.bukkit.block.BlockState; import org.bukkit.block.Skull; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.profile.PlayerProfile; public class BlockStateCodecSkull implements BlockStateCodec { + private static final boolean HAS_PROFILE_API; + static { + boolean hasProfileApi = false; + try { + Skull.class.getMethod("getOwnerProfile"); + hasProfileApi = true; + } catch (NoSuchMethodException ignored) { + } + HAS_PROFILE_API = hasProfileApi; + } + @Override public Material[] getApplicableMaterials() { return new Material[] { Material.PLAYER_WALL_HEAD, Material.PLAYER_HEAD }; @@ -20,9 +32,14 @@ public YamlConfiguration serialize(BlockState state) { if (state instanceof Skull) { Skull skull = (Skull) state; OfflinePlayer owner = skull.hasOwner() ? skull.getOwningPlayer() : null; - if (owner != null) { + PlayerProfile profile = HAS_PROFILE_API ? skull.getOwnerProfile() : null; + if (owner != null || profile != null) { YamlConfiguration conf = new YamlConfiguration(); - conf.set("owner", owner.getUniqueId().toString()); + if (profile != null) { + conf.set("profile", profile); + } else if (owner != null) { + conf.set("owner", owner.getUniqueId().toString()); + } return conf; } } @@ -33,18 +50,30 @@ public YamlConfiguration serialize(BlockState state) { public void deserialize(BlockState state, YamlConfiguration conf) { if (state instanceof Skull) { Skull skull = (Skull) state; - UUID ownerId = conf == null ? null : UUID.fromString(conf.getString("owner")); - if (ownerId == null) { - skull.setOwningPlayer(null); + PlayerProfile profile = conf == null || !HAS_PROFILE_API ? null : (PlayerProfile) conf.get("profile"); + if (profile != null) { + skull.setOwnerProfile(profile); } else { - skull.setOwningPlayer(Bukkit.getOfflinePlayer(ownerId)); + UUID ownerId = conf == null ? null : UUID.fromString(conf.getString("owner")); + if (ownerId == null) { + skull.setOwningPlayer(null); + } else { + skull.setOwningPlayer(Bukkit.getOfflinePlayer(ownerId)); + } } } } @Override public String toString(YamlConfiguration conf, YamlConfiguration oldState) { - UUID ownerId = conf == null ? null : UUID.fromString(conf.getString("owner")); + if (HAS_PROFILE_API && conf != null) { + PlayerProfile profile = (PlayerProfile) conf.get("profile"); + if (profile != null) { + return "[" + (profile.getName() != null ? profile.getName() : (profile.getUniqueId() != null ? profile.getUniqueId().toString() : "~unknown~")) + "]"; + } + } + String ownerIdString = conf == null ? null : conf.getString("owner"); + UUID ownerId = ownerIdString == null ? null : UUID.fromString(ownerIdString); if (ownerId != null) { OfflinePlayer owner = Bukkit.getOfflinePlayer(ownerId); return "[" + (owner.getName() != null ? owner.getName() : owner.getUniqueId().toString()) + "]"; From 81457ced656c1b75e7537ee0fd1a9f7057070a11 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 11 Jun 2022 20:14:48 +0200 Subject: [PATCH 314/399] improve player name parsing --- .../java/de/diddiz/LogBlock/QueryParams.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 1151726e..88eca9d1 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -436,19 +436,19 @@ public String getWhere(BlockChangeType blockChangeType) { if (!excludePlayersMode) { where.append('('); for (final String killerName : players) { - where.append("killers.playername = '").append(SqlUtil.escapeString(killerName)).append("' OR "); + where.append("killers.playername = '").append(SqlUtil.escapeString(killerName, true)).append("' OR "); } for (final String victimName : players) { - where.append("victims.playername = '").append(SqlUtil.escapeString(victimName)).append("' OR "); + where.append("victims.playername = '").append(SqlUtil.escapeString(victimName, true)).append("' OR "); } where.delete(where.length() - 4, where.length()); where.append(") AND "); } else { for (final String killerName : players) { - where.append("killers.playername != '").append(SqlUtil.escapeString(killerName)).append("' AND "); + where.append("killers.playername != '").append(SqlUtil.escapeString(killerName, true)).append("' AND "); } for (final String victimName : players) { - where.append("victims.playername != '").append(SqlUtil.escapeString(victimName)).append("' AND "); + where.append("victims.playername != '").append(SqlUtil.escapeString(victimName, true)).append("' AND "); } } } @@ -614,13 +614,13 @@ public String getWhere(BlockChangeType blockChangeType) { if (!excludePlayersMode) { where.append('('); for (final String playerName : players) { - where.append("playername = '").append(SqlUtil.escapeString(playerName)).append("' OR "); + where.append("playername = '").append(SqlUtil.escapeString(playerName, true)).append("' OR "); } where.delete(where.length() - 4, where.length()); where.append(") AND "); } else { for (final String playerName : players) { - where.append("playername != '").append(SqlUtil.escapeString(playerName)).append("' AND "); + where.append("playername != '").append(SqlUtil.escapeString(playerName, true)).append("' AND "); } } } @@ -691,16 +691,20 @@ public void parseArgs(CommandSender sender, List args, boolean validate) if (values.length < 1) { throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); } - for (final String playerName : values) { + for (String playerName : values) { if (playerName.length() > 0) { - if (playerName.contains("!")) { + if (playerName.startsWith("!")) { + playerName = playerName.substring(1); excludePlayersMode = true; + if (playerName.isEmpty()) { + continue; + } } if (playerName.contains("\"")) { - players.add(playerName.replaceAll("[^a-zA-Z0-9_]", "")); + players.add(playerName.replace("\"", "")); } else { final Player matches = logblock.getServer().getPlayerExact(playerName); - players.add(matches != null ? matches.getName() : playerName.replaceAll("[^a-zA-Z0-9_]", "")); + players.add(matches != null ? matches.getName() : playerName.replace("\\\"", "")); } } } From 0ed501493e02ba548e9cb98cd4a41634b18007b7 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 11 Jun 2022 20:20:09 +0200 Subject: [PATCH 315/399] Update for Minecraft 19 * Update build plugins * Update dependencies * Require Java 17 --- pom.xml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 2801bb80..ac681465 100644 --- a/pom.xml +++ b/pom.xml @@ -44,19 +44,19 @@ org.spigotmc spigot-api - 1.18.1-R0.1-SNAPSHOT + 1.19-R0.1-SNAPSHOT provided com.sk89q.worldedit worldedit-bukkit - 7.2.7-SNAPSHOT + 7.2.9-SNAPSHOT provided com.sk89q.worldguard worldguard-bukkit - 7.0.6-SNAPSHOT + 7.1.0-SNAPSHOT provided @@ -131,16 +131,15 @@ org.apache.maven.plugins maven-compiler-plugin - 3.7.0 + 3.10.1 - 1.8 - 1.8 + 17 org.codehaus.mojo build-helper-maven-plugin - 3.0.0 + 3.3.0 regex-property @@ -160,7 +159,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.1.1 + 3.3.0 From 62a5be6c6b9d1f7e7c3713e11f19f591d14ea5f6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 11 Jun 2022 20:39:23 +0200 Subject: [PATCH 316/399] log sculk --- src/main/java/de/diddiz/LogBlock/LogBlock.java | 2 +- src/main/java/de/diddiz/LogBlock/Logging.java | 1 + .../diddiz/LogBlock/listeners/BlockSpreadLogging.java | 10 ++++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 756575b8..4ea95c66 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -217,7 +217,7 @@ private void registerEvents() { if (isLogging(Logging.BONEMEALSTRUCTUREGROW)) { pm.registerEvents(new BlockFertilizeLogging(this), this); } - if (isLogging(Logging.GRASSGROWTH) || isLogging(Logging.MYCELIUMSPREAD) || isLogging(Logging.VINEGROWTH) || isLogging(Logging.MUSHROOMSPREAD) || isLogging(Logging.BAMBOOGROWTH) || isLogging(Logging.DRIPSTONEGROWTH)) { + if (isLogging(Logging.GRASSGROWTH) || isLogging(Logging.MYCELIUMSPREAD) || isLogging(Logging.VINEGROWTH) || isLogging(Logging.MUSHROOMSPREAD) || isLogging(Logging.BAMBOOGROWTH) || isLogging(Logging.DRIPSTONEGROWTH) || isLogging(Logging.SCULKSPREAD)) { pm.registerEvents(new BlockSpreadLogging(this), this); } if (isLogging(Logging.DRAGONEGGTELEPORT)) { diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index 7f8a3621..af6d966e 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -49,6 +49,7 @@ public enum Logging { LECTERNBOOKCHANGE(true), SCAFFOLDING(true), OXIDIZATION, + SCULKSPREAD(true), SHULKER_BOX_CONTENT, PLAYER_COMMANDS, COMMANDBLOCK_COMMANDS, diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java index 22b077f0..119f721e 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java @@ -102,6 +102,16 @@ public void onBlockSpread(BlockSpreadEvent event) { return; } break; + case SCULK: + case SCULK_VEIN: + case SCULK_CATALYST: + case SCULK_SENSOR: + case SCULK_SHRIEKER: + if (!isLogging(world, Logging.SCULKSPREAD)) { + return; + } + name = "SculkSpread"; + break; default: return; } From 7791c4e960eacc9d05ff3c2ea1babe996bed561d Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 16 Jun 2022 21:32:51 +0200 Subject: [PATCH 317/399] fix player names with underscore --- src/main/java/de/diddiz/LogBlock/QueryParams.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 88eca9d1..6d88d8a0 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -436,19 +436,19 @@ public String getWhere(BlockChangeType blockChangeType) { if (!excludePlayersMode) { where.append('('); for (final String killerName : players) { - where.append("killers.playername = '").append(SqlUtil.escapeString(killerName, true)).append("' OR "); + where.append("killers.playername = '").append(SqlUtil.escapeString(killerName)).append("' OR "); } for (final String victimName : players) { - where.append("victims.playername = '").append(SqlUtil.escapeString(victimName, true)).append("' OR "); + where.append("victims.playername = '").append(SqlUtil.escapeString(victimName)).append("' OR "); } where.delete(where.length() - 4, where.length()); where.append(") AND "); } else { for (final String killerName : players) { - where.append("killers.playername != '").append(SqlUtil.escapeString(killerName, true)).append("' AND "); + where.append("killers.playername != '").append(SqlUtil.escapeString(killerName)).append("' AND "); } for (final String victimName : players) { - where.append("victims.playername != '").append(SqlUtil.escapeString(victimName, true)).append("' AND "); + where.append("victims.playername != '").append(SqlUtil.escapeString(victimName)).append("' AND "); } } } @@ -614,13 +614,13 @@ public String getWhere(BlockChangeType blockChangeType) { if (!excludePlayersMode) { where.append('('); for (final String playerName : players) { - where.append("playername = '").append(SqlUtil.escapeString(playerName, true)).append("' OR "); + where.append("playername = '").append(SqlUtil.escapeString(playerName)).append("' OR "); } where.delete(where.length() - 4, where.length()); where.append(") AND "); } else { for (final String playerName : players) { - where.append("playername != '").append(SqlUtil.escapeString(playerName, true)).append("' AND "); + where.append("playername != '").append(SqlUtil.escapeString(playerName)).append("' AND "); } } } From 86100c18301772895e406c261ae360bae8789c88 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 3 Jul 2022 07:36:40 +0200 Subject: [PATCH 318/399] version 1.19.0.0-SNAPSHOT --- pom.xml | 2 +- src/main/java/de/diddiz/LogBlock/config/Config.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ac681465..989f7e15 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.17.0.0-SNAPSHOT + 1.19.0.0-SNAPSHOT jar LogBlock diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 59dec807..d12aeb63 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -60,7 +60,7 @@ public class Config { // Not loaded from config - checked at runtime public static boolean mb4 = false; - public static final String CURRENT_CONFIG_VERSION = "1.17.0"; + public static final String CURRENT_CONFIG_VERSION = "1.19.0"; public static enum LogKillsLevel { PLAYERS, From b658d3799b022076c7b5a654cec90f94d56b4353 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 14 Jul 2022 05:31:24 +0200 Subject: [PATCH 319/399] add missing 1.19 materials --- src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 7d7944ea..f7516f3d 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -91,6 +91,7 @@ public class BukkitUtils { pressurePlates.add(Material.DARK_OAK_PRESSURE_PLATE); pressurePlates.add(Material.WARPED_PRESSURE_PLATE); pressurePlates.add(Material.CRIMSON_PRESSURE_PLATE); + pressurePlates.add(Material.MANGROVE_PRESSURE_PLATE); pressurePlates.add(Material.STONE_PRESSURE_PLATE); pressurePlates.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); pressurePlates.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); @@ -104,6 +105,7 @@ public class BukkitUtils { woodenDoors.add(Material.DARK_OAK_DOOR); woodenDoors.add(Material.WARPED_DOOR); woodenDoors.add(Material.CRIMSON_DOOR); + woodenDoors.add(Material.MANGROVE_DOOR); EnumSet saplings = EnumSet.noneOf(Material.class); saplings.add(Material.OAK_SAPLING); @@ -114,6 +116,7 @@ public class BukkitUtils { saplings.add(Material.DARK_OAK_SAPLING); saplings.add(Material.WARPED_FUNGUS); saplings.add(Material.CRIMSON_FUNGUS); + saplings.add(Material.MANGROVE_PROPAGULE); EnumSet carpets = EnumSet.noneOf(Material.class); carpets.add(Material.BLACK_CARPET); @@ -161,6 +164,7 @@ public class BukkitUtils { slabs.add(Material.DEEPSLATE_TILE_SLAB); slabs.add(Material.COBBLED_DEEPSLATE_SLAB); slabs.add(Material.POLISHED_DEEPSLATE_SLAB); + slabs.add(Material.MANGROVE_SLAB); buttons = EnumSet.noneOf(Material.class); buttons.add(Material.STONE_BUTTON); @@ -172,6 +176,8 @@ public class BukkitUtils { buttons.add(Material.DARK_OAK_BUTTON); buttons.add(Material.WARPED_BUTTON); buttons.add(Material.CRIMSON_BUTTON); + buttons.add(Material.MANGROVE_BUTTON); + buttons.add(Material.POLISHED_BLACKSTONE_BUTTON); signs = EnumSet.noneOf(Material.class); signs.add(Material.OAK_SIGN); @@ -182,6 +188,7 @@ public class BukkitUtils { signs.add(Material.ACACIA_SIGN); signs.add(Material.WARPED_SIGN); signs.add(Material.CRIMSON_SIGN); + signs.add(Material.MANGROVE_SIGN); wallSigns = EnumSet.noneOf(Material.class); wallSigns.add(Material.OAK_WALL_SIGN); @@ -192,6 +199,7 @@ public class BukkitUtils { wallSigns.add(Material.ACACIA_WALL_SIGN); wallSigns.add(Material.WARPED_WALL_SIGN); wallSigns.add(Material.CRIMSON_WALL_SIGN); + wallSigns.add(Material.MANGROVE_WALL_SIGN); allSigns = EnumSet.noneOf(Material.class); allSigns.addAll(signs); From c6e8105c0ec0d2a42adfbfe03e05a116c000eb13 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 3 Aug 2022 04:36:09 +0200 Subject: [PATCH 320/399] add newline before log output to improve readability --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 1a76ca9e..30d36988 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -280,13 +280,16 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, } } else if (command.equals("page")) { if (args.length == 2 && isInt(args[1])) { + sender.sendMessage(""); showPage(sender, Integer.valueOf(args[1])); } else { sender.sendMessage(ChatColor.RED + "You have to specify a page"); } } else if (command.equals("next") || command.equals("+")) { + sender.sendMessage(""); showPage(sender, getSession(sender).page + 1); } else if (command.equals("prev") || command.equals("-")) { + sender.sendMessage(""); showPage(sender, getSession(sender).page - 1); } else if (args[0].equalsIgnoreCase("savequeue")) { if (logblock.hasPermission(sender, "logblock.rollback")) { @@ -540,6 +543,7 @@ public void run() { } state = conn.createStatement(); rs = executeQuery(state, params.getQuery()); + sender.sendMessage(""); sender.sendMessage(ChatColor.DARK_AQUA + params.getTitle() + ":"); final List blockchanges = new ArrayList<>(); final LookupCacheElementFactory factory = new LookupCacheElementFactory(params, sender instanceof Player ? 2 / 3f : 1); From 9bfe5d09cd544a0042580c68f6810aa9224b2937 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 3 Aug 2022 05:05:44 +0200 Subject: [PATCH 321/399] use long when accessing id columns --- .../java/de/diddiz/LogBlock/BlockChange.java | 2 +- .../java/de/diddiz/LogBlock/ChatMessage.java | 2 +- .../de/diddiz/LogBlock/CommandsHandler.java | 10 ++-- .../java/de/diddiz/LogBlock/Consumer.java | 48 +++++++++---------- .../java/de/diddiz/LogBlock/EntityChange.java | 2 +- src/main/java/de/diddiz/LogBlock/Kill.java | 2 +- src/main/java/de/diddiz/LogBlock/Updater.java | 22 ++++----- 7 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index b2174584..041e82b9 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -62,7 +62,7 @@ public BlockChange(long date, Location loc, Actor actor, int replaced, int repla } public BlockChange(ResultSet rs, QueryParams p) throws SQLException { - id = p.needId ? rs.getInt("id") : 0; + id = p.needId ? rs.getLong("id") : 0; date = p.needDate ? rs.getTimestamp("date").getTime() : 0; loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null; actor = p.needPlayer ? new Actor(rs) : null; diff --git a/src/main/java/de/diddiz/LogBlock/ChatMessage.java b/src/main/java/de/diddiz/LogBlock/ChatMessage.java index 379e6369..7f940276 100644 --- a/src/main/java/de/diddiz/LogBlock/ChatMessage.java +++ b/src/main/java/de/diddiz/LogBlock/ChatMessage.java @@ -26,7 +26,7 @@ public ChatMessage(Actor player, String message) { } public ChatMessage(ResultSet rs, QueryParams p) throws SQLException { - id = p.needId ? rs.getInt("id") : 0; + id = p.needId ? rs.getLong("id") : 0; date = p.needDate ? rs.getTimestamp("date").getTime() : 0; player = p.needPlayer ? new Actor(rs) : null; playerName = p.needPlayer ? rs.getString("playername") : null; diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 30d36988..0679d9a7 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -965,14 +965,14 @@ public void run() { StringBuilder sb = new StringBuilder(); if (params.bct == BlockChangeType.CHAT) { sb.append("INSERT INTO `lb-chat` (`id`, `date`, `playerid`, `message`) VALUES ("); - sb.append(rs.getInt("id")).append(", FROM_UNIXTIME("); + sb.append(rs.getLong("id")).append(", FROM_UNIXTIME("); sb.append(rs.getTimestamp("date").getTime() / 1000).append("), "); sb.append(rs.getInt("playerid")).append(", '"); sb.append(Utils.mysqlTextEscape(rs.getString("message"))); sb.append("');\n"); } else if (params.bct == BlockChangeType.KILLS) { sb.append("INSERT INTO `").append(tableBase).append("-kills` (`id`, `date`, `killer`, `victim`, `weapon`, `x`, `y`, `z`) VALUES ("); - sb.append(rs.getInt("id")).append(", FROM_UNIXTIME("); + sb.append(rs.getLong("id")).append(", FROM_UNIXTIME("); sb.append(rs.getTimestamp("date").getTime() / 1000).append("), "); sb.append(rs.getInt("killerid")).append(", "); sb.append(rs.getInt("victimid")).append(", "); @@ -985,7 +985,7 @@ public void run() { } else { sb.append("INSERT INTO `").append(tableBase).append("-blocks` (`id`, `date`, `playerid`, `replaced`, `replacedData`, `type`, `typeData`, `x`, `y`, `z`) VALUES ("); - sb.append(rs.getInt("id")).append(", FROM_UNIXTIME("); + sb.append(rs.getLong("id")).append(", FROM_UNIXTIME("); sb.append(rs.getTimestamp("date").getTime() / 1000).append("), "); sb.append(rs.getInt("playerid")).append(", "); sb.append(rs.getInt("replaced")).append(", "); @@ -1000,7 +1000,7 @@ public void run() { byte[] typeState = rs.getBytes("typeState"); if (replacedState != null || typeState != null) { sb.append("INSERT INTO `").append(tableBase).append("-state` (`id`, `replacedState`, `typeState`) VALUES ("); - sb.append(rs.getInt("id")).append(", "); + sb.append(rs.getLong("id")).append(", "); sb.append(Utils.mysqlPrepareBytesForInsertAllowNull(replacedState)).append(", "); sb.append(Utils.mysqlPrepareBytesForInsertAllowNull(typeState)); sb.append(");\n"); @@ -1008,7 +1008,7 @@ public void run() { byte[] item = rs.getBytes("item"); if (item != null) { sb.append("INSERT INTO `").append(tableBase).append("-chestdata` (`id`, `item`, `itemremove`, `itemtype`) VALUES ("); - sb.append(rs.getInt("id")).append(", "); + sb.append(rs.getLong("id")).append(", "); sb.append(Utils.mysqlPrepareBytesForInsertAllowNull(item)).append(", "); sb.append(rs.getInt("itemremove")).append(", "); sb.append(rs.getInt("itemtype")); diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index d90c1f38..23f04248 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -67,7 +67,7 @@ public class Consumer extends Thread { private final LogBlock logblock; private final Map playerIds = new HashMap<>(); private final Map uncommitedPlayerIds = new HashMap<>(); - private final Map> uncommitedEntityIds = new HashMap<>(); + private final Map> uncommitedEntityIds = new HashMap<>(); private long addEntryCounter; private long nextWarnCounter; @@ -650,13 +650,13 @@ private boolean addPlayer(Connection conn, Actor actor) throws SQLException { return uncommitedPlayerIds.containsKey(actor); } - private int getEntityUUID(Connection conn, World world, UUID uuid) throws SQLException { - Map uncommitedEntityIdsHere = uncommitedEntityIds.get(world); + private long getEntityUUID(Connection conn, World world, UUID uuid) throws SQLException { + Map uncommitedEntityIdsHere = uncommitedEntityIds.get(world); if (uncommitedEntityIdsHere == null) { uncommitedEntityIdsHere = new HashMap<>(); uncommitedEntityIds.put(world, uncommitedEntityIdsHere); } - Integer existing = uncommitedEntityIdsHere.get(uuid); + Long existing = uncommitedEntityIdsHere.get(uuid); if (existing != null) { return existing; } @@ -670,7 +670,7 @@ private int getEntityUUID(Connection conn, World world, UUID uuid) throws SQLExc int q1Result = state.executeUpdate(q1); ResultSet rs = state.executeQuery(q2); if (rs.next()) { - uncommitedEntityIdsHere.put(uuid, rs.getInt(1)); + uncommitedEntityIdsHere.put(uuid, rs.getLong(1)); } rs.close(); // if there was not any row in the table the query above does not work, so we need to try this one @@ -678,7 +678,7 @@ private int getEntityUUID(Connection conn, World world, UUID uuid) throws SQLExc state.executeUpdate("INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) VALUES ('" + mysqlTextEscape(uuidString) + "')"); rs = state.executeQuery(q2); if (rs.next()) { - uncommitedEntityIdsHere.put(uuid, rs.getInt(1)); + uncommitedEntityIdsHere.put(uuid, rs.getLong(1)); } else { logblock.getLogger().warning("[Consumer] Failed to add entity uuid " + uuidString.toString()); logblock.getLogger().warning("[Consumer-Debug] World: " + world.getName()); @@ -881,22 +881,22 @@ public void process(Connection conn, BatchHelper batchHelper) throws SQLExceptio smt.setInt(8, safeY(loc)); smt.setInt(9, loc.getBlockZ()); batchHelper.addUncommitedBlockActorId(loc, sourceActor); - batchHelper.addBatch(smt, new IntCallback() { + batchHelper.addBatch(smt, new LongCallback() { @Override - public void call(int id) throws SQLException { + public void call(long id) throws SQLException { PreparedStatement ps; if (typeState != null || replacedState != null) { ps = batchHelper.getOrPrepareStatement(conn, getWorldConfig(loc.getWorld()).insertBlockStateStatementString, Statement.NO_GENERATED_KEYS); ps.setBytes(1, replacedState); ps.setBytes(2, typeState); - ps.setInt(3, id); + ps.setLong(3, id); batchHelper.addBatch(ps, null); } if (ca != null) { ps = batchHelper.getOrPrepareStatement(conn, getWorldConfig(loc.getWorld()).insertBlockChestDataStatementString, Statement.NO_GENERATED_KEYS); ps.setBytes(1, finalSerializedItemStack); ps.setInt(2, ca.remove ? 1 : 0); - ps.setInt(3, id); + ps.setLong(3, id); ps.setInt(4, ca.itemType); batchHelper.addBatch(ps, null); } @@ -1108,7 +1108,7 @@ public void process(Connection conn, BatchHelper batchHelper) throws SQLExceptio PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); smt.setLong(1, date); smt.setInt(2, sourceActor); - smt.setInt(3, getEntityUUID(conn, loc.getWorld(), entityUUID)); + smt.setLong(3, getEntityUUID(conn, loc.getWorld(), entityUUID)); smt.setInt(4, EntityTypeConverter.getOrAddEntityTypeId(type)); smt.setInt(5, loc.getBlockX()); smt.setInt(6, safeY(loc)); @@ -1121,11 +1121,11 @@ public void process(Connection conn, BatchHelper batchHelper) throws SQLExceptio private class EntityUUIDChange implements Row { private final World world; - private final int entityId; + private final long entityId; private final UUID entityUUID; final String updateEntityUUIDString; - public EntityUUIDChange(World world, int entityId, UUID entityUUID) { + public EntityUUIDChange(World world, long entityId, UUID entityUUID) { this.world = world; this.entityId = entityId; this.entityUUID = entityUUID; @@ -1150,7 +1150,7 @@ public Actor[] getActors() { public void process(Connection conn, BatchHelper batchHelper) throws SQLException { PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, updateEntityUUIDString, Statement.NO_GENERATED_KEYS); smt.setString(1, entityUUID.toString()); - smt.setInt(2, entityId); + smt.setLong(2, entityId); smt.executeUpdate(); } } @@ -1169,7 +1169,7 @@ private int safeY(Location loc) { private class BatchHelper { private HashMap preparedStatements = new HashMap<>(); private HashSet preparedStatementsWithGeneratedKeys = new HashSet<>(); - private LinkedHashMap> generatedKeyHandler = new LinkedHashMap<>(); + private LinkedHashMap> generatedKeyHandler = new LinkedHashMap<>(); private HashMap uncommitedBlockActors = new HashMap<>(); public void reset() { @@ -1189,21 +1189,21 @@ public Integer getUncommitedBlockActor(Location loc) { public void processStatements(Connection conn) throws SQLException { while (!generatedKeyHandler.isEmpty()) { - Entry> entry = generatedKeyHandler.entrySet().iterator().next(); + Entry> entry = generatedKeyHandler.entrySet().iterator().next(); PreparedStatement smt = entry.getKey(); - ArrayList callbackList = entry.getValue(); + ArrayList callbackList = entry.getValue(); generatedKeyHandler.remove(smt); smt.executeBatch(); if (preparedStatementsWithGeneratedKeys.contains(smt)) { ResultSet keys = smt.getGeneratedKeys(); - int[] results = new int[callbackList.size()]; + long[] results = new long[callbackList.size()]; int pos = 0; while (keys.next() && pos < results.length) { - results[pos++] = keys.getInt(1); + results[pos++] = keys.getLong(1); } keys.close(); for (int i = 0; i < results.length; i++) { - IntCallback callback = callbackList.get(i); + LongCallback callback = callbackList.get(i); if (callback != null) { callback.call(results[i]); } @@ -1225,9 +1225,9 @@ public PreparedStatement getOrPrepareStatement(Connection conn, String sql, int return smt; } - public void addBatch(PreparedStatement smt, IntCallback generatedKeysCallback) throws SQLException { + public void addBatch(PreparedStatement smt, LongCallback generatedKeysCallback) throws SQLException { smt.addBatch(); - ArrayList callbackList = generatedKeyHandler.get(smt); + ArrayList callbackList = generatedKeyHandler.get(smt); if (callbackList == null) { callbackList = new ArrayList<>(); generatedKeyHandler.put(smt, callbackList); @@ -1236,7 +1236,7 @@ public void addBatch(PreparedStatement smt, IntCallback generatedKeysCallback) t } } - protected interface IntCallback { - public void call(int value) throws SQLException; + protected interface LongCallback { + public void call(long value) throws SQLException; } } diff --git a/src/main/java/de/diddiz/LogBlock/EntityChange.java b/src/main/java/de/diddiz/LogBlock/EntityChange.java index 77c8acfa..a252e79d 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityChange.java +++ b/src/main/java/de/diddiz/LogBlock/EntityChange.java @@ -60,7 +60,7 @@ public EntityChange(long date, Location loc, Actor actor, EntityType type, UUID } public EntityChange(ResultSet rs, QueryParams p) throws SQLException { - id = p.needId ? rs.getInt("id") : 0; + id = p.needId ? rs.getLong("id") : 0; date = p.needDate ? rs.getTimestamp("date").getTime() : 0; loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null; actor = p.needPlayer ? new Actor(rs) : null; diff --git a/src/main/java/de/diddiz/LogBlock/Kill.java b/src/main/java/de/diddiz/LogBlock/Kill.java index 2302c631..ac9634e4 100755 --- a/src/main/java/de/diddiz/LogBlock/Kill.java +++ b/src/main/java/de/diddiz/LogBlock/Kill.java @@ -30,7 +30,7 @@ public Kill(String killerName, String victimName, int weapon, Location loc) { } public Kill(ResultSet rs, QueryParams p) throws SQLException { - id = p.needId ? rs.getInt("id") : 0; + id = p.needId ? rs.getLong("id") : 0; date = p.needDate ? rs.getTimestamp("date").getTime() : 0; loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null; killerName = p.needKiller ? rs.getString("killer") : null; diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 40b109e5..d3387369 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -439,7 +439,7 @@ boolean update() { ResultSet entries = st.executeQuery("SELECT id, date, playerid, replaced, type, data, x, y, z FROM `" + wcfg.table + "` ORDER BY id ASC LIMIT " + BLOCKS_CONVERT_BATCH_SIZE); while (entries.next()) { hadRow = true; - int id = entries.getInt("id"); + long id = entries.getLong("id"); Timestamp date = entries.getTimestamp("date"); int playerid = entries.getInt("playerid"); int replaced = entries.getInt("replaced"); @@ -462,7 +462,7 @@ boolean update() { int newSetId = MaterialConverter.getOrAddMaterialId(setBlockData); int newSetData = MaterialConverter.getOrAddBlockStateId(setBlockData); - insertStatement.setInt(1, id); + insertStatement.setLong(1, id); insertStatement.setTimestamp(2, date); insertStatement.setInt(3, playerid); insertStatement.setInt(4, newReplacedId); @@ -476,7 +476,7 @@ boolean update() { } catch (Exception e) { logblock.getLogger().info("Exception in entry " + id + " (" + replaced + ":" + data + "->" + type + ":" + data + "): " + e.getMessage()); } - deleteStatement.setInt(1, id); + deleteStatement.setLong(1, id); deleteStatement.addBatch(); done++; @@ -522,7 +522,7 @@ boolean update() { boolean anyRow = false; while (rs.next()) { anyRow = true; - int id = rs.getInt("id"); + long id = rs.getLong("id"); int itemtype = rs.getInt("itemtype"); int itemdata = rs.getInt("itemdata"); int amount = rs.getInt("itemamount"); @@ -532,13 +532,13 @@ boolean update() { } @SuppressWarnings("deprecation") ItemStack stack = weaponMaterial.getMaxDurability() > 0 ? new ItemStack(weaponMaterial, Math.abs(amount), (short) itemdata) : new ItemStack(weaponMaterial, Math.abs(amount)); - insertChestData.setInt(1, id); + insertChestData.setLong(1, id); insertChestData.setBytes(2, Utils.saveItemStack(stack)); insertChestData.setInt(3, amount >= 0 ? 0 : 1); insertChestData.setInt(4, MaterialConverter.getOrAddMaterialId(weaponMaterial)); insertChestData.addBatch(); - deleteChest.setInt(1, id); + deleteChest.setLong(1, id); deleteChest.addBatch(); done++; } @@ -585,7 +585,7 @@ boolean update() { boolean anyRow = false; while (rs.next()) { anyRow = true; - int id = rs.getInt("id"); + long id = rs.getLong("id"); int weapon = rs.getInt("weapon"); Material weaponMaterial = materialUpdater.getMaterial(weapon, 0); if (weaponMaterial == null) { @@ -595,7 +595,7 @@ boolean update() { if (newWeapon != weapon) { anyUpdate = true; updateWeaponStatement.setInt(1, newWeapon); - updateWeaponStatement.setInt(2, id); + updateWeaponStatement.setLong(2, id); updateWeaponStatement.addBatch(); } done++; @@ -666,7 +666,7 @@ boolean update() { boolean anyRow = false; while (rs.next()) { anyRow = true; - int id = rs.getInt("id"); + long id = rs.getLong("id"); String signText = rs.getString("signtext"); int replaced = rs.getInt("replaced"); boolean nullBlock = rs.wasNull(); @@ -681,13 +681,13 @@ boolean update() { boolean wasSign = replacedMaterial == Material.OAK_SIGN || replacedMaterial == Material.OAK_WALL_SIGN; boolean isSign = typeMaterial == Material.OAK_SIGN || typeMaterial == Material.OAK_WALL_SIGN; - insertSignState.setInt(1, id); + insertSignState.setLong(1, id); insertSignState.setBytes(2, wasSign ? bytes : null); insertSignState.setBytes(3, isSign ? bytes : null); insertSignState.addBatch(); } - deleteSign.setInt(1, id); + deleteSign.setLong(1, id); deleteSign.addBatch(); done++; } From 0e601aa174d49c4552ba7b49acfb5c691a4f5450 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 3 Aug 2022 05:44:57 +0200 Subject: [PATCH 322/399] add config option if natural entity spawns should be logged --- src/main/java/de/diddiz/LogBlock/config/Config.java | 5 +++++ src/main/java/de/diddiz/LogBlock/config/WorldConfig.java | 5 +++++ .../de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java | 3 +++ 3 files changed, 13 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index d12aeb63..9512be05 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -360,6 +360,11 @@ public static boolean isLoggingAnyEntities() { } return false; } + + public static boolean isLoggingNatualSpawns(World world) { + final WorldConfig wcfg = worldConfigs.get(world.getName()); + return wcfg != null && wcfg.logNaturalEntitySpawns; + } } class LoggingEnabledMapping { diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index da4f8e5d..44964b59 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -34,6 +34,7 @@ public class WorldConfig extends LoggingEnabledMapping { public final String updateEntityUUIDString; private final EnumMap entityLogging = new EnumMap<>(EntityLogging.class); + public final boolean logNaturalEntitySpawns; public WorldConfig(String world, File file) throws IOException { this.world = world; @@ -56,6 +57,10 @@ public WorldConfig(String world, File file) throws IOException { } entityLogging.put(el, new EntityLoggingList(config.getStringList("entity." + el.name().toLowerCase()))); } + if (!config.isBoolean("entity.logNaturalSpawns")) { + config.set("entity.logNaturalSpawns", false); + } + logNaturalEntitySpawns = config.getBoolean("entity.logNaturalSpawns"); config.save(file); table = config.getString("table"); for (final Logging l : Logging.values()) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index 457ffd6a..6f71f938 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -159,6 +159,9 @@ public void onEntitySpawn(CreatureSpawnEvent event) { } } if (actor == null) { + if (event.getSpawnReason() == SpawnReason.NATURAL && !Config.isLoggingNatualSpawns(entity.getWorld())) { + return; + } actor = new Actor(event.getSpawnReason().toString()); } queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE); From c34ad1ca0f435a9da2143f0280c4915cf78b476f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 9 Sep 2022 07:47:12 +0200 Subject: [PATCH 323/399] Allow minecraft names instead of bukkit names for entities --- .../de/diddiz/LogBlock/util/BukkitUtils.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index f7516f3d..4f4cfe2a 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -946,15 +946,19 @@ public static Entity loadEntityAround(Chunk chunk, UUID uuid) { private static final HashMap types = new HashMap<>(); static { for (EntityType t : EntityType.values()) { - types.put(t.name().toLowerCase(), t); - @SuppressWarnings("deprecation") - String typeName = t.getName(); - if (typeName != null) { - types.put(typeName.toLowerCase(), t); - } - Class ec = t.getEntityClass(); - if (ec != null) { - types.put(ec.getSimpleName().toLowerCase(), t); + if (t != EntityType.UNKNOWN) { + types.put(t.name().toLowerCase(), t); + @SuppressWarnings("deprecation") + String typeName = t.getName(); + if (typeName != null) { + types.put(typeName.toLowerCase(), t); + } + Class ec = t.getEntityClass(); + if (ec != null) { + types.put(ec.getSimpleName().toLowerCase(), t); + } + types.put(t.getKey().getKey(), t); + types.put(t.getKey().toString(), t); } } } From 43864ad0028080b4e80c46ad8d64110024f33c3d Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 30 Sep 2022 05:26:14 +0200 Subject: [PATCH 324/399] Remove unused config option --- src/main/java/de/diddiz/LogBlock/config/Config.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 9512be05..99fdd86d 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -52,7 +52,6 @@ public class Config { public static List ignoredChat; public static SimpleDateFormat formatter; public static SimpleDateFormat formatterShort; - public static boolean safetyIdCheck; public static boolean debug; public static boolean logEnvironmentalKills; // addons @@ -252,7 +251,6 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti askClearLogs = config.getBoolean("questioner.askClearLogs", true); askClearLogAfterRollback = config.getBoolean("questioner.askClearLogAfterRollback", true); askRollbackAfterBan = config.getBoolean("questioner.askRollbackAfterBan", false); - safetyIdCheck = config.getBoolean("safety.id.check", true); debug = config.getBoolean("debug", false); banPermission = config.getString("questioner.banPermission"); final List tools = new ArrayList<>(); From 0f459440be06cfcf02692fddd35b98574ac73901 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 3 Nov 2022 05:36:55 +0100 Subject: [PATCH 325/399] New entity logging option logAllNamedEntityKills --- .../de/diddiz/LogBlock/config/WorldConfig.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index 44964b59..4a54af5e 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -35,6 +35,7 @@ public class WorldConfig extends LoggingEnabledMapping { private final EnumMap entityLogging = new EnumMap<>(EntityLogging.class); public final boolean logNaturalEntitySpawns; + public final boolean logAllNamedEntityKills; public WorldConfig(String world, File file) throws IOException { this.world = world; @@ -55,12 +56,18 @@ public WorldConfig(String world, File file) throws IOException { if (!(config.get("entity." + el.name().toLowerCase()) instanceof List)) { config.set("entity." + el.name().toLowerCase(), el.getDefaultEnabled()); } - entityLogging.put(el, new EntityLoggingList(config.getStringList("entity." + el.name().toLowerCase()))); + entityLogging.put(el, new EntityLoggingList(el, config.getStringList("entity." + el.name().toLowerCase()))); } if (!config.isBoolean("entity.logNaturalSpawns")) { config.set("entity.logNaturalSpawns", false); } logNaturalEntitySpawns = config.getBoolean("entity.logNaturalSpawns"); + + if (!config.isBoolean("entity.logAllNamedEntityKills")) { + config.set("entity.logAllNamedEntityKills", true); + } + logAllNamedEntityKills = config.getBoolean("entity.logAllNamedEntityKills"); + config.save(file); table = config.getString("table"); for (final Logging l : Logging.values()) { @@ -89,13 +96,15 @@ public boolean isLoggingAnyEntities() { } private class EntityLoggingList { + private EntityLogging entityAction; private final EnumSet logged = EnumSet.noneOf(EntityType.class); private final boolean logAll; private final boolean logAnimals; private final boolean logMonsters; private final boolean logLiving; - public EntityLoggingList(List types) { + public EntityLoggingList(EntityLogging entityAction, List types) { + this.entityAction = entityAction; boolean all = false; boolean animals = false; boolean monsters = false; @@ -141,11 +150,14 @@ public boolean isLogging(Entity entity) { if (logMonsters && (Monster.class.isAssignableFrom(entity.getClass()) || entity.getType() == EntityType.SLIME || entity.getType() == EntityType.WITHER || entity.getType() == EntityType.ENDER_DRAGON || entity.getType() == EntityType.SHULKER || entity.getType() == EntityType.GHAST)) { return true; } + if (entityAction == EntityLogging.DESTROY && logAllNamedEntityKills && entity.getCustomName() != null) { + return true; + } return false; } public boolean isLoggingAnyEntities() { - return logAll || logAnimals || logLiving || logMonsters || !logged.isEmpty(); + return logAll || logAnimals || logLiving || logMonsters || !logged.isEmpty() || (entityAction == EntityLogging.DESTROY && logAllNamedEntityKills); } } } From 4faced94d46c4ea4313d00bb8a4440bd9fba7fb7 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 3 Nov 2022 05:41:41 +0100 Subject: [PATCH 326/399] separate logging option for wateranimals --- .../java/de/diddiz/LogBlock/config/WorldConfig.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index 4a54af5e..b234b4af 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -96,10 +96,11 @@ public boolean isLoggingAnyEntities() { } private class EntityLoggingList { - private EntityLogging entityAction; + private final EntityLogging entityAction; private final EnumSet logged = EnumSet.noneOf(EntityType.class); private final boolean logAll; private final boolean logAnimals; + private final boolean logWateranimals; private final boolean logMonsters; private final boolean logLiving; @@ -107,6 +108,7 @@ public EntityLoggingList(EntityLogging entityAction, List types) { this.entityAction = entityAction; boolean all = false; boolean animals = false; + boolean wateranimals = false; boolean monsters = false; boolean living = false; for (String type : types) { @@ -118,6 +120,8 @@ public EntityLoggingList(EntityLogging entityAction, List types) { all = true; } else if (type.equalsIgnoreCase("animal") || type.equalsIgnoreCase("animals")) { animals = true; + } else if (type.equalsIgnoreCase("wateranimal") || type.equalsIgnoreCase("wateranimals")) { + wateranimals = true; } else if (type.equalsIgnoreCase("monster") || type.equalsIgnoreCase("monsters")) { monsters = true; } else if (type.equalsIgnoreCase("living")) { @@ -129,6 +133,7 @@ public EntityLoggingList(EntityLogging entityAction, List types) { } logAll = all; logAnimals = animals; + logWateranimals = wateranimals; logMonsters = monsters; logLiving = living; } @@ -144,7 +149,10 @@ public boolean isLogging(Entity entity) { if (logLiving && LivingEntity.class.isAssignableFrom(entity.getClass()) && !(entity instanceof ArmorStand)) { return true; } - if (logAnimals && (Animals.class.isAssignableFrom(entity.getClass()) || WaterMob.class.isAssignableFrom(entity.getClass()))) { + if (logAnimals && Animals.class.isAssignableFrom(entity.getClass())) { + return true; + } + if (logWateranimals && WaterMob.class.isAssignableFrom(entity.getClass())) { return true; } if (logMonsters && (Monster.class.isAssignableFrom(entity.getClass()) || entity.getType() == EntityType.SLIME || entity.getType() == EntityType.WITHER || entity.getType() == EntityType.ENDER_DRAGON || entity.getType() == EntityType.SHULKER || entity.getType() == EntityType.GHAST)) { From a395f206bd18f0ba883eb043196c72a2e6ec62ae Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 3 Nov 2022 05:56:30 +0100 Subject: [PATCH 327/399] Log respawn anchor explosions --- src/main/java/de/diddiz/LogBlock/Logging.java | 1 + .../LogBlock/listeners/ExplosionLogging.java | 74 ++++++++++++++++--- 2 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index af6d966e..2e8e0331 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -51,6 +51,7 @@ public enum Logging { OXIDIZATION, SCULKSPREAD(true), SHULKER_BOX_CONTENT, + RESPAWNANCHOREXPLOSION(true), PLAYER_COMMANDS, COMMANDBLOCK_COMMANDS, CONSOLE_COMMANDS; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index 9695e969..20fd01dd 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -10,6 +10,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.data.type.RespawnAnchor; import org.bukkit.entity.*; import org.bukkit.entity.minecart.ExplosiveMinecart; import org.bukkit.event.EventHandler; @@ -18,6 +19,7 @@ import org.bukkit.event.block.BlockExplodeEvent; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; import org.bukkit.projectiles.ProjectileSource; import org.bukkit.scheduler.BukkitRunnable; @@ -31,6 +33,8 @@ public class ExplosionLogging extends LoggingListener { private UUID lastBedInteractionPlayer; private Location lastBedInteractionLocation; + private UUID lastRespawnAnchorInteractionPlayer; + private Location lastRespawnAnchorInteractionLocation; public ExplosionLogging(LogBlock lb) { super(lb); @@ -124,20 +128,48 @@ public void onEntityExplode(EntityExplodeEvent event) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerInteract(PlayerInteractEvent event) { - if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.hasBlock() && BukkitUtils.isBed(event.getClickedBlock().getType())) { + if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.hasBlock()) { Block block = event.getClickedBlock(); - if (!Config.isLogging(block.getWorld(), Logging.BEDEXPLOSION)) { - return; + if (BukkitUtils.isBed(block.getType()) && !block.getWorld().isBedWorks()) { + if (!Config.isLogging(block.getWorld(), Logging.BEDEXPLOSION)) { + return; + } + lastBedInteractionPlayer = event.getPlayer().getUniqueId(); + lastBedInteractionLocation = block.getLocation(); + new BukkitRunnable() { + @Override + public void run() { + lastBedInteractionPlayer = null; + lastBedInteractionLocation = null; + } + }.runTask(LogBlock.getInstance()); + } else if (block.getType() == Material.RESPAWN_ANCHOR && block.getBlockData() instanceof RespawnAnchor data) { + if (!Config.isLogging(block.getWorld(), Logging.RESPAWNANCHOREXPLOSION)) { + return; + } + ItemStack inHand = event.getItem(); + int charges = data.getCharges(); + if (charges < data.getMaximumCharges() && inHand != null && inHand.getType() == Material.GLOWSTONE) { + // charge + Actor actor = Actor.actorFromEntity(event.getPlayer()); + RespawnAnchor blockNew = (RespawnAnchor) data.clone(); + blockNew.setCharges(charges + 1); + consumer.queueBlockReplace(actor, block.getState(), blockNew); + } else if (charges > 0 && !block.getWorld().isRespawnAnchorWorks()) { + // explode + Actor actor = Actor.actorFromEntity(event.getPlayer()); + consumer.queueBlockBreak(actor, block.getState()); + lastRespawnAnchorInteractionPlayer = event.getPlayer().getUniqueId(); + lastRespawnAnchorInteractionLocation = block.getLocation(); + new BukkitRunnable() { + @Override + public void run() { + lastRespawnAnchorInteractionPlayer = null; + lastRespawnAnchorInteractionLocation = null; + } + }.runTask(LogBlock.getInstance()); + } } - lastBedInteractionPlayer = event.getPlayer().getUniqueId(); - lastBedInteractionLocation = block.getLocation(); - new BukkitRunnable() { - @Override - public void run() { - lastBedInteractionPlayer = null; - lastBedInteractionLocation = null; - } - }.runTask(LogBlock.getInstance()); } } @@ -150,6 +182,13 @@ public void onBlockExplode(BlockExplodeEvent event) { bedCause = Bukkit.getPlayer(lastBedInteractionPlayer); } } + Player respawnAnchorCause = null; + if (lastRespawnAnchorInteractionPlayer != null && lastRespawnAnchorInteractionLocation != null) { + Location block = event.getBlock().getLocation(); + if (lastRespawnAnchorInteractionLocation.equals(block)) { + respawnAnchorCause = Bukkit.getPlayer(lastRespawnAnchorInteractionPlayer); + } + } for (final Block block : event.blockList()) { final WorldConfig wcfg = getWorldConfig(block.getLocation().getWorld()); @@ -162,6 +201,17 @@ public void onBlockExplode(BlockExplodeEvent event) { } if (Config.logBedExplosionsAsPlayerWhoTriggeredThese) { actor = Actor.actorFromEntity(bedCause); + } else { + actor = new Actor("BedExplosion"); + } + } else if (respawnAnchorCause != null) { + if (!wcfg.isLogging(Logging.RESPAWNANCHOREXPLOSION)) { + return; + } + if (Config.logBedExplosionsAsPlayerWhoTriggeredThese) { + actor = Actor.actorFromEntity(respawnAnchorCause); + } else { + actor = new Actor("RespawnAnchorExplosion"); } } else if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { return; From 0bd211083b2d3f36737799ce57b2a48163435bf7 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 3 Nov 2022 05:56:41 +0100 Subject: [PATCH 328/399] do not log golems by default --- src/main/java/de/diddiz/LogBlock/config/EntityLogging.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/config/EntityLogging.java b/src/main/java/de/diddiz/LogBlock/config/EntityLogging.java index 8e1e75a3..6332250a 100644 --- a/src/main/java/de/diddiz/LogBlock/config/EntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/config/EntityLogging.java @@ -7,8 +7,8 @@ import org.bukkit.entity.EntityType; public enum EntityLogging { - SPAWN(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.IRON_GOLEM.name(), EntityType.SNOWMAN.name() }), - DESTROY(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.VILLAGER.name(), EntityType.IRON_GOLEM.name(), EntityType.SNOWMAN.name(), "ANIMAL" }), + 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; From 7c690c707aac6a8252f6212a115125ba5d6847cf Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 3 Nov 2022 06:01:57 +0100 Subject: [PATCH 329/399] port to exact height when player is in specator mode --- .../java/de/diddiz/LogBlock/CommandsHandler.java | 13 ++++++++----- .../java/de/diddiz/LogBlock/util/BukkitUtils.java | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 0679d9a7..26ae2693 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -15,7 +15,7 @@ import static de.diddiz.LogBlock.config.Config.toolsByName; import static de.diddiz.LogBlock.config.Config.toolsByType; import static de.diddiz.LogBlock.util.BukkitUtils.giveTool; -import static de.diddiz.LogBlock.util.BukkitUtils.saveSpawnHeight; +import static de.diddiz.LogBlock.util.BukkitUtils.safeSpawnHeight; import static de.diddiz.LogBlock.util.TypeColor.DEFAULT; import static de.diddiz.LogBlock.util.TypeColor.ERROR; import static de.diddiz.LogBlock.util.TypeColor.HEADER; @@ -48,6 +48,7 @@ import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.ChatColor; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.command.Command; @@ -373,7 +374,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, if (pos >= 0 && pos < session.lookupCache.length) { final Location loc = session.lookupCache[pos].getLocation(); if (loc != null) { - player.teleport(new Location(loc.getWorld(), loc.getX() + 0.5, saveSpawnHeight(loc), loc.getZ() + 0.5, player.getLocation().getYaw(), 90)); + player.teleport(new Location(loc.getWorld(), loc.getX() + 0.5, player.getGameMode() != GameMode.SPECTATOR ? safeSpawnHeight(loc) : loc.getY(), loc.getZ() + 0.5, player.getLocation().getYaw(), 90)); player.sendMessage(ChatColor.LIGHT_PURPLE + "Teleported to " + loc.getBlockX() + ":" + loc.getBlockY() + ":" + loc.getBlockZ()); } else { sender.sendMessage(ChatColor.RED + "There is no location associated with that. Did you forget coords parameter?"); @@ -699,10 +700,12 @@ public void run() { logblock.getServer().getScheduler().scheduleSyncDelayedTask(logblock, new Runnable() { @Override public void run() { - final int y2 = saveSpawnHeight(loc); - loc.setY(y2); + if (player.getGameMode() != GameMode.SPECTATOR) { + final int y2 = safeSpawnHeight(loc); + loc.setY(y2); + sender.sendMessage(ChatColor.GREEN + "You were teleported " + Math.abs(y2 - y) + " blocks " + (y2 - y > 0 ? "above" : "below")); + } player.teleport(loc); - sender.sendMessage(ChatColor.GREEN + "You were teleported " + Math.abs(y2 - y) + " blocks " + (y2 - y > 0 ? "above" : "below")); } }); } else { diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 4f4cfe2a..6ebc12e1 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -736,7 +736,7 @@ public static void giveTool(Player player, Material type) { } } - public static int saveSpawnHeight(Location loc) { + public static int safeSpawnHeight(Location loc) { final World world = loc.getWorld(); world.getChunkAt(loc); final int x = loc.getBlockX(), z = loc.getBlockZ(); From 5d91d5abb7884b6225b7ab74479ef0e43ba52166 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 3 Nov 2022 06:04:11 +0100 Subject: [PATCH 330/399] "/lb sum entities" should list entities, not blocks --- src/main/java/de/diddiz/LogBlock/QueryParams.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 6d88d8a0..b0bd875c 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -857,6 +857,9 @@ public void parseArgs(CommandSender sender, List args, boolean validate) if (values[0].startsWith("p")) { sum = SummarizationMode.PLAYERS; } else if (values[0].startsWith("b") || values[0].startsWith("e")) { + if (values[0].startsWith("e")) { + bct = BlockChangeType.ENTITIES; + } sum = SummarizationMode.TYPES; } else if (values[0].startsWith("n")) { sum = SummarizationMode.NONE; From c3ae8358ddeaeb43a7859262c162adffda2e863b Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 3 Jan 2023 04:59:42 +0100 Subject: [PATCH 331/399] better log rollback exceptions --- src/main/java/de/diddiz/LogBlock/WorldEditor.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 15fa285a..251965cf 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -185,8 +185,11 @@ public synchronized void run() { final File file = new File("plugins/LogBlock/error/WorldEditor-" + new SimpleDateFormat("yy-MM-dd-HH-mm-ss").format(System.currentTimeMillis()) + ".log"); file.getParentFile().mkdirs(); final PrintWriter writer = new PrintWriter(file); - for (final LookupCacheElement err : errorList) { + for (final WorldEditorException err : errorList) { writer.println(BaseComponent.toPlainText(err.getLogMessage())); + err.printStackTrace(writer); + writer.println(); + writer.println(); } writer.close(); } catch (final Exception ex) { From b3e829d1befacc1833e64fbf54420315d27c369a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 18 Jan 2023 06:09:55 +0100 Subject: [PATCH 332/399] add bamboo blocks (requires 1.19.3) --- pom.xml | 2 +- src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 989f7e15..c541e09a 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ org.spigotmc spigot-api - 1.19-R0.1-SNAPSHOT + 1.19.3-R0.1-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 6ebc12e1..d083fcc6 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -92,6 +92,7 @@ public class BukkitUtils { pressurePlates.add(Material.WARPED_PRESSURE_PLATE); pressurePlates.add(Material.CRIMSON_PRESSURE_PLATE); pressurePlates.add(Material.MANGROVE_PRESSURE_PLATE); + pressurePlates.add(Material.BAMBOO_PRESSURE_PLATE); pressurePlates.add(Material.STONE_PRESSURE_PLATE); pressurePlates.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); pressurePlates.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); @@ -106,6 +107,7 @@ public class BukkitUtils { woodenDoors.add(Material.WARPED_DOOR); woodenDoors.add(Material.CRIMSON_DOOR); woodenDoors.add(Material.MANGROVE_DOOR); + woodenDoors.add(Material.BAMBOO_DOOR); EnumSet saplings = EnumSet.noneOf(Material.class); saplings.add(Material.OAK_SAPLING); @@ -165,6 +167,7 @@ public class BukkitUtils { slabs.add(Material.COBBLED_DEEPSLATE_SLAB); slabs.add(Material.POLISHED_DEEPSLATE_SLAB); slabs.add(Material.MANGROVE_SLAB); + slabs.add(Material.BAMBOO_SLAB); buttons = EnumSet.noneOf(Material.class); buttons.add(Material.STONE_BUTTON); @@ -177,6 +180,7 @@ public class BukkitUtils { buttons.add(Material.WARPED_BUTTON); buttons.add(Material.CRIMSON_BUTTON); buttons.add(Material.MANGROVE_BUTTON); + buttons.add(Material.BAMBOO_BUTTON); buttons.add(Material.POLISHED_BLACKSTONE_BUTTON); signs = EnumSet.noneOf(Material.class); @@ -189,6 +193,7 @@ public class BukkitUtils { signs.add(Material.WARPED_SIGN); signs.add(Material.CRIMSON_SIGN); signs.add(Material.MANGROVE_SIGN); + signs.add(Material.BAMBOO_SIGN); wallSigns = EnumSet.noneOf(Material.class); wallSigns.add(Material.OAK_WALL_SIGN); @@ -200,6 +205,7 @@ public class BukkitUtils { wallSigns.add(Material.WARPED_WALL_SIGN); wallSigns.add(Material.CRIMSON_WALL_SIGN); wallSigns.add(Material.MANGROVE_WALL_SIGN); + wallSigns.add(Material.BAMBOO_WALL_SIGN); allSigns = EnumSet.noneOf(Material.class); allSigns.addAll(signs); @@ -405,6 +411,7 @@ public class BukkitUtils { containerBlocks.add(Material.BARREL); containerBlocks.add(Material.BLAST_FURNACE); containerBlocks.add(Material.SMOKER); + containerBlocks.add(Material.CHISELED_BOOKSHELF); // Doesn't actually have a block inventory // containerBlocks.add(Material.ENDER_CHEST); From d347a25a02d6d4fdfe0a9b6342467f80829499a3 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 7 Feb 2023 04:30:24 +0100 Subject: [PATCH 333/399] Updates for 1.19.3: Log hanging signs and add some missing materials --- .../java/de/diddiz/LogBlock/Consumer.java | 4 +- .../blockstate/BlockStateCodecSign.java | 6 +- .../LogBlock/listeners/InteractLogging.java | 349 ++++++++---------- .../de/diddiz/LogBlock/util/BukkitUtils.java | 81 +++- .../de/diddiz/LogBlock/util/LoggingUtil.java | 2 + 5 files changed, 231 insertions(+), 211 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 23f04248..7e1dbd98 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -36,8 +36,6 @@ import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.Sign; -import org.bukkit.block.data.type.WallSign; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -346,7 +344,7 @@ public void queueKill(Location location, Actor killer, Actor victim, ItemStack w * The four lines on the sign. */ public void queueSignChange(Actor actor, Location loc, BlockData type, String[] lines) { - if ((!(type instanceof Sign) && !(type instanceof WallSign)) || lines == null || lines.length != 4) { + if (!BukkitUtils.getAllSignMaterials().contains(type.getMaterial())) { return; } queueBlock(actor, loc, type, type, null, BlockStateCodecSign.serialize(lines), null); diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index e60c2a89..fb566a97 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -13,7 +13,7 @@ public class BlockStateCodecSign implements BlockStateCodec { @Override public Material[] getApplicableMaterials() { - return BukkitUtils.getAllSignsArray(); + return BukkitUtils.getAllSignMaterials().toArray(new Material[BukkitUtils.getAllSignMaterials().size()]); } @Override @@ -54,7 +54,9 @@ public YamlConfiguration serialize(BlockState state) { */ public static YamlConfiguration serialize(String[] lines) { YamlConfiguration conf = new YamlConfiguration(); - conf.set("lines", Arrays.asList(lines)); + if (lines != null) { + conf.set("lines", Arrays.asList(lines)); + } return conf; } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index e0ade555..0eac4557 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -66,224 +66,165 @@ public void onPlayerInteract(PlayerInteractEvent event) { lastInteractionBlockData = blockData; lastInteractionLocation = loc; - switch (type) { - case OAK_FENCE_GATE: - case SPRUCE_FENCE_GATE: - case BIRCH_FENCE_GATE: - case JUNGLE_FENCE_GATE: - case ACACIA_FENCE_GATE: - case DARK_OAK_FENCE_GATE: - case WARPED_FENCE_GATE: - case CRIMSON_FENCE_GATE: - case OAK_TRAPDOOR: - case SPRUCE_TRAPDOOR: - case BIRCH_TRAPDOOR: - case JUNGLE_TRAPDOOR: - case ACACIA_TRAPDOOR: - case DARK_OAK_TRAPDOOR: - case WARPED_TRAPDOOR: - case CRIMSON_TRAPDOOR: - if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Openable newBlockData = (Openable) blockData.clone(); - newBlockData.setOpen(!newBlockData.isOpen()); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - break; - case CAKE: - if (event.hasItem() && BukkitUtils.isCandle(event.getItem().getType()) && event.useItemInHand() != Result.DENY) { - BlockData newBlockData = Material.valueOf(event.getItem().getType().name() + "_CAKE").createBlockData(); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } else if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20) { - Cake newBlockData = (Cake) blockData.clone(); - if (newBlockData.getBites() < 6) { - newBlockData.setBites(newBlockData.getBites() + 1); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } else { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.AIR.createBlockData()); - } - } - break; - case NOTE_BLOCK: - if (wcfg.isLogging(Logging.NOTEBLOCKINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - NoteBlock newBlockData = (NoteBlock) blockData.clone(); - if (newBlockData.getNote().getOctave() == 2) { - newBlockData.setNote(new Note(0, Tone.F, true)); - } else { - newBlockData.setNote(newBlockData.getNote().sharped()); - } - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - break; - case REPEATER: - if (wcfg.isLogging(Logging.DIODEINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Repeater newBlockData = (Repeater) blockData.clone(); - newBlockData.setDelay((newBlockData.getDelay() % 4) + 1); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - break; - case COMPARATOR: - if (wcfg.isLogging(Logging.COMPARATORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Comparator newBlockData = (Comparator) blockData.clone(); - newBlockData.setMode(newBlockData.getMode() == Mode.COMPARE ? Mode.SUBTRACT : Mode.COMPARE); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - break; - case DAYLIGHT_DETECTOR: - if (wcfg.isLogging(Logging.DAYLIGHTDETECTORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - DaylightDetector newBlockData = (DaylightDetector) blockData.clone(); - newBlockData.setInverted(!newBlockData.isInverted()); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - break; - case OAK_PRESSURE_PLATE: - case SPRUCE_PRESSURE_PLATE: - case BIRCH_PRESSURE_PLATE: - case JUNGLE_PRESSURE_PLATE: - case ACACIA_PRESSURE_PLATE: - case DARK_OAK_PRESSURE_PLATE: - case WARPED_PRESSURE_PLATE: - case CRIMSON_PRESSURE_PLATE: - case STONE_PRESSURE_PLATE: - case HEAVY_WEIGHTED_PRESSURE_PLATE: - case LIGHT_WEIGHTED_PRESSURE_PLATE: - if (wcfg.isLogging(Logging.PRESUREPLATEINTERACT) && event.getAction() == Action.PHYSICAL) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); - } - break; - case TRIPWIRE: - if (wcfg.isLogging(Logging.TRIPWIREINTERACT) && event.getAction() == Action.PHYSICAL) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + if (BukkitUtils.isFenceGate(type) || BukkitUtils.isWoodenTrapdoor(type)) { + if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Openable newBlockData = (Openable) blockData.clone(); + newBlockData.setOpen(!newBlockData.isOpen()); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } else if (BukkitUtils.isPressurePlate(type)) { + if (wcfg.isLogging(Logging.PRESUREPLATEINTERACT) && event.getAction() == Action.PHYSICAL) { + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + } + } else if (BukkitUtils.isWoodenDoor(type)) { + if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Door newBlockData = (Door) blockData.clone(); + newBlockData.setOpen(!newBlockData.isOpen()); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } else if (BukkitUtils.isButton(type) || type == Material.LEVER) { + if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Switch newBlockData = (Switch) blockData.clone(); + if (!newBlockData.isPowered() || type == Material.LEVER) { + newBlockData.setPowered(!newBlockData.isPowered()); } - break; - case FARMLAND: - if (wcfg.isLogging(Logging.CROPTRAMPLE) && event.getAction() == Action.PHYSICAL) { - // 3 = Dirt ID - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.DIRT.createBlockData()); - // Log the crop on top as being broken - Block trampledCrop = clicked.getRelative(BlockFace.UP); - if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) { - consumer.queueBlockBreak(Actor.actorFromEntity(player), trampledCrop.getState()); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } else if (BukkitUtils.isSign(type)) { + if (wcfg.isLogging(Logging.SIGNTEXT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getItem() != null) { + Material itemType = event.getItem().getType(); + if (BukkitUtils.isDye(itemType) || itemType == Material.GLOW_INK_SAC || itemType == Material.INK_SAC) { + final BlockState before = event.getClickedBlock().getState(); + if (before instanceof Sign) { + if (itemType == Material.GLOW_INK_SAC) { + Sign signBefore = (Sign) before; + if (!signBefore.isGlowingText()) { + final Sign signAfter = (Sign) event.getClickedBlock().getState(); + signAfter.setGlowingText(true); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } + } else if (itemType == Material.INK_SAC) { + Sign signBefore = (Sign) before; + if (signBefore.isGlowingText()) { + final Sign signAfter = (Sign) event.getClickedBlock().getState(); + signAfter.setGlowingText(false); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } + } else { + DyeColor newColor = BukkitUtils.dyeToDyeColor(itemType); + Sign signBefore = (Sign) before; + if (newColor != null && signBefore.getColor() != newColor) { + final Sign signAfter = (Sign) event.getClickedBlock().getState(); + signAfter.setColor(newColor); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } + } } } - break; - case TURTLE_EGG: - if (wcfg.isLogging(Logging.BLOCKBREAK) && event.getAction() == Action.PHYSICAL) { - TurtleEgg turtleEggData = (TurtleEgg) blockData; - int eggs = turtleEggData.getEggs(); - if (eggs > 1) { - TurtleEgg turtleEggData2 = (TurtleEgg) turtleEggData.clone(); - turtleEggData2.setEggs(eggs - 1); - consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, turtleEggData2); - } else { - consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, Material.AIR.createBlockData()); + } + } else { + switch (type) { + case CAKE: + if (event.hasItem() && BukkitUtils.isCandle(event.getItem().getType()) && event.useItemInHand() != Result.DENY) { + BlockData newBlockData = Material.valueOf(event.getItem().getType().name() + "_CAKE").createBlockData(); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } else if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20) { + Cake newBlockData = (Cake) blockData.clone(); + if (newBlockData.getBites() < 6) { + newBlockData.setBites(newBlockData.getBites() + 1); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } else { + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.AIR.createBlockData()); + } } - } - break; - case PUMPKIN: - if ((wcfg.isLogging(Logging.BLOCKBREAK) || wcfg.isLogging(Logging.BLOCKPLACE)) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - ItemStack inHand = event.getItem(); - if (inHand != null && inHand.getType() == Material.SHEARS) { - BlockFace clickedFace = event.getBlockFace(); - Directional newBlockData = (Directional) Material.CARVED_PUMPKIN.createBlockData(); - if (clickedFace == BlockFace.NORTH || clickedFace == BlockFace.SOUTH || clickedFace == BlockFace.EAST || clickedFace == BlockFace.WEST) { - newBlockData.setFacing(clickedFace); + break; + case NOTE_BLOCK: + if (wcfg.isLogging(Logging.NOTEBLOCKINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + NoteBlock newBlockData = (NoteBlock) blockData.clone(); + if (newBlockData.getNote().getOctave() == 2) { + newBlockData.setNote(new Note(0, Tone.F, true)); } else { - // use player distance to calculate the facing - Location playerLoc = player.getLocation(); - playerLoc.subtract(0.5, 0, 0.5); - double dx = playerLoc.getX() - loc.getX(); - double dz = playerLoc.getZ() - loc.getZ(); - if (Math.abs(dx) > Math.abs(dz)) { - newBlockData.setFacing(dx > 0 ? BlockFace.EAST : BlockFace.WEST); - } else { - newBlockData.setFacing(dz > 0 ? BlockFace.SOUTH : BlockFace.NORTH); - } + newBlockData.setNote(newBlockData.getNote().sharped()); } consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); } - } - break; - case OAK_DOOR: - case SPRUCE_DOOR: - case BIRCH_DOOR: - case JUNGLE_DOOR: - case ACACIA_DOOR: - case DARK_OAK_DOOR: - case WARPED_DOOR: - case CRIMSON_DOOR: - if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Door newBlockData = (Door) blockData.clone(); - newBlockData.setOpen(!newBlockData.isOpen()); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - break; - case STONE_BUTTON: - case OAK_BUTTON: - case SPRUCE_BUTTON: - case BIRCH_BUTTON: - case JUNGLE_BUTTON: - case ACACIA_BUTTON: - case DARK_OAK_BUTTON: - case WARPED_BUTTON: - case CRIMSON_BUTTON: - case LEVER: - if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Switch newBlockData = (Switch) blockData.clone(); - if (!newBlockData.isPowered() || type == Material.LEVER) { - newBlockData.setPowered(!newBlockData.isPowered()); + break; + case REPEATER: + if (wcfg.isLogging(Logging.DIODEINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Repeater newBlockData = (Repeater) blockData.clone(); + newBlockData.setDelay((newBlockData.getDelay() % 4) + 1); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); } - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - break; - case OAK_SIGN: - case SPRUCE_SIGN: - case BIRCH_SIGN: - case JUNGLE_SIGN: - case ACACIA_SIGN: - case DARK_OAK_SIGN: - case WARPED_SIGN: - case CRIMSON_SIGN: - case OAK_WALL_SIGN: - case SPRUCE_WALL_SIGN: - case BIRCH_WALL_SIGN: - case JUNGLE_WALL_SIGN: - case ACACIA_WALL_SIGN: - case DARK_OAK_WALL_SIGN: - case WARPED_WALL_SIGN: - case CRIMSON_WALL_SIGN: - if (wcfg.isLogging(Logging.SIGNTEXT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getItem() != null) { - Material itemType = event.getItem().getType(); - if (BukkitUtils.isDye(itemType) || itemType == Material.GLOW_INK_SAC || itemType == Material.INK_SAC) { - final BlockState before = event.getClickedBlock().getState(); - if (before instanceof Sign) { - if (itemType == Material.GLOW_INK_SAC) { - Sign signBefore = (Sign) before; - if (!signBefore.isGlowingText()) { - final Sign signAfter = (Sign) event.getClickedBlock().getState(); - signAfter.setGlowingText(true); - consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); - } - } else if (itemType == Material.INK_SAC) { - Sign signBefore = (Sign) before; - if (signBefore.isGlowingText()) { - final Sign signAfter = (Sign) event.getClickedBlock().getState(); - signAfter.setGlowingText(false); - consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); - } + break; + case COMPARATOR: + if (wcfg.isLogging(Logging.COMPARATORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Comparator newBlockData = (Comparator) blockData.clone(); + newBlockData.setMode(newBlockData.getMode() == Mode.COMPARE ? Mode.SUBTRACT : Mode.COMPARE); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + break; + case DAYLIGHT_DETECTOR: + if (wcfg.isLogging(Logging.DAYLIGHTDETECTORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + DaylightDetector newBlockData = (DaylightDetector) blockData.clone(); + newBlockData.setInverted(!newBlockData.isInverted()); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + break; + case TRIPWIRE: + if (wcfg.isLogging(Logging.TRIPWIREINTERACT) && event.getAction() == Action.PHYSICAL) { + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + } + break; + case FARMLAND: + if (wcfg.isLogging(Logging.CROPTRAMPLE) && event.getAction() == Action.PHYSICAL) { + // 3 = Dirt ID + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.DIRT.createBlockData()); + // Log the crop on top as being broken + Block trampledCrop = clicked.getRelative(BlockFace.UP); + if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) { + consumer.queueBlockBreak(Actor.actorFromEntity(player), trampledCrop.getState()); + } + } + break; + case TURTLE_EGG: + if (wcfg.isLogging(Logging.BLOCKBREAK) && event.getAction() == Action.PHYSICAL) { + TurtleEgg turtleEggData = (TurtleEgg) blockData; + int eggs = turtleEggData.getEggs(); + if (eggs > 1) { + TurtleEgg turtleEggData2 = (TurtleEgg) turtleEggData.clone(); + turtleEggData2.setEggs(eggs - 1); + consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, turtleEggData2); + } else { + consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, Material.AIR.createBlockData()); + } + } + break; + case PUMPKIN: + if ((wcfg.isLogging(Logging.BLOCKBREAK) || wcfg.isLogging(Logging.BLOCKPLACE)) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + ItemStack inHand = event.getItem(); + if (inHand != null && inHand.getType() == Material.SHEARS) { + BlockFace clickedFace = event.getBlockFace(); + Directional newBlockData = (Directional) Material.CARVED_PUMPKIN.createBlockData(); + if (clickedFace == BlockFace.NORTH || clickedFace == BlockFace.SOUTH || clickedFace == BlockFace.EAST || clickedFace == BlockFace.WEST) { + newBlockData.setFacing(clickedFace); } else { - DyeColor newColor = BukkitUtils.dyeToDyeColor(itemType); - Sign signBefore = (Sign) before; - if (newColor != null && signBefore.getColor() != newColor) { - final Sign signAfter = (Sign) event.getClickedBlock().getState(); - signAfter.setColor(newColor); - consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + // use player distance to calculate the facing + Location playerLoc = player.getLocation(); + playerLoc.subtract(0.5, 0, 0.5); + double dx = playerLoc.getX() - loc.getX(); + double dz = playerLoc.getZ() - loc.getZ(); + if (Math.abs(dx) > Math.abs(dz)) { + newBlockData.setFacing(dx > 0 ? BlockFace.EAST : BlockFace.WEST); + } else { + newBlockData.setFacing(dz > 0 ? BlockFace.SOUTH : BlockFace.NORTH); } } + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); } } - } - break; - default: + break; + default: + } } } } diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index d083fcc6..4b647eb7 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -7,6 +7,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.EnumMap; import java.util.EnumSet; import java.util.HashMap; @@ -70,7 +71,10 @@ public class BukkitUtils { private static final Map projectileItems; private static final EnumSet signs; private static final EnumSet wallSigns; + private static final EnumSet hangingSigns; + private static final EnumSet hangingWallSigns; private static final EnumSet allSigns; + private static final Set unmodifiableSigns; private static final EnumSet buttons; private static final EnumSet pressurePlates; private static final EnumSet woodenDoors; @@ -80,8 +84,34 @@ public class BukkitUtils { private static final EnumSet alwaysWaterlogged; private static final EnumSet candles; private static final EnumSet candleCakes; + private static final EnumSet fenceGates; + private static final EnumSet woodenTrapdoors; static { + fenceGates = EnumSet.noneOf(Material.class); + fenceGates.add(Material.OAK_FENCE_GATE); + fenceGates.add(Material.SPRUCE_FENCE_GATE); + fenceGates.add(Material.BIRCH_FENCE_GATE); + fenceGates.add(Material.JUNGLE_FENCE_GATE); + fenceGates.add(Material.ACACIA_FENCE_GATE); + fenceGates.add(Material.DARK_OAK_FENCE_GATE); + fenceGates.add(Material.WARPED_FENCE_GATE); + fenceGates.add(Material.CRIMSON_FENCE_GATE); + fenceGates.add(Material.MANGROVE_FENCE_GATE); + fenceGates.add(Material.BAMBOO_FENCE_GATE); + + woodenTrapdoors = EnumSet.noneOf(Material.class); + woodenTrapdoors.add(Material.OAK_TRAPDOOR); + woodenTrapdoors.add(Material.SPRUCE_TRAPDOOR); + woodenTrapdoors.add(Material.BIRCH_TRAPDOOR); + woodenTrapdoors.add(Material.JUNGLE_TRAPDOOR); + woodenTrapdoors.add(Material.ACACIA_TRAPDOOR); + woodenTrapdoors.add(Material.DARK_OAK_TRAPDOOR); + woodenTrapdoors.add(Material.WARPED_TRAPDOOR); + woodenTrapdoors.add(Material.CRIMSON_TRAPDOOR); + woodenTrapdoors.add(Material.MANGROVE_TRAPDOOR); + woodenTrapdoors.add(Material.BAMBOO_TRAPDOOR); + pressurePlates = EnumSet.noneOf(Material.class); pressurePlates.add(Material.OAK_PRESSURE_PLATE); pressurePlates.add(Material.SPRUCE_PRESSURE_PLATE); @@ -207,9 +237,36 @@ public class BukkitUtils { wallSigns.add(Material.MANGROVE_WALL_SIGN); wallSigns.add(Material.BAMBOO_WALL_SIGN); + hangingSigns = EnumSet.noneOf(Material.class); + hangingSigns.add(Material.OAK_HANGING_SIGN); + hangingSigns.add(Material.SPRUCE_HANGING_SIGN); + hangingSigns.add(Material.BIRCH_HANGING_SIGN); + hangingSigns.add(Material.JUNGLE_HANGING_SIGN); + hangingSigns.add(Material.DARK_OAK_HANGING_SIGN); + hangingSigns.add(Material.ACACIA_HANGING_SIGN); + hangingSigns.add(Material.WARPED_HANGING_SIGN); + hangingSigns.add(Material.CRIMSON_HANGING_SIGN); + hangingSigns.add(Material.MANGROVE_HANGING_SIGN); + hangingSigns.add(Material.BAMBOO_HANGING_SIGN); + + hangingWallSigns = EnumSet.noneOf(Material.class); + hangingWallSigns.add(Material.OAK_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.SPRUCE_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.BIRCH_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.JUNGLE_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.DARK_OAK_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.ACACIA_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.WARPED_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.CRIMSON_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.MANGROVE_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.BAMBOO_WALL_HANGING_SIGN); + allSigns = EnumSet.noneOf(Material.class); allSigns.addAll(signs); allSigns.addAll(wallSigns); + allSigns.addAll(hangingSigns); + allSigns.addAll(hangingWallSigns); + unmodifiableSigns = Collections.unmodifiableSet(allSigns); singleBlockPlants = EnumSet.noneOf(Material.class); singleBlockPlants.add(Material.GRASS); @@ -1131,8 +1188,8 @@ public static boolean isSimilarForRollback(Material expected, Material found) { return false; } - public static Material[] getAllSignsArray() { - return allSigns.toArray(new Material[allSigns.size()]); + public static Set getAllSignMaterials() { + return unmodifiableSigns; } public static boolean isAlwaysWaterlogged(Material m) { @@ -1146,4 +1203,24 @@ public static boolean isCandle(Material m) { public static boolean isCandleCake(Material m) { return candleCakes.contains(m); } + + public static boolean isHangingSign(Material m) { + return hangingSigns.contains(m); + } + + public static boolean isFenceGate(Material m) { + return fenceGates.contains(m); + } + + public static boolean isWoodenTrapdoor(Material m) { + return woodenTrapdoors.contains(m); + } + + public static boolean isPressurePlate(Material m) { + return pressurePlates.contains(m); + } + + public static boolean isSign(Material m) { + return allSigns.contains(m); + } } diff --git a/src/main/java/de/diddiz/LogBlock/util/LoggingUtil.java b/src/main/java/de/diddiz/LogBlock/util/LoggingUtil.java index 2c8ede75..5235d944 100644 --- a/src/main/java/de/diddiz/LogBlock/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/LogBlock/util/LoggingUtil.java @@ -228,6 +228,8 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or if (lantern.isHanging()) { consumer.queueBlockBreak(actor, checkBlock.getState()); } + } else if (BukkitUtils.isHangingSign(typeBelow)) { + consumer.queueBlockBreak(actor, checkBlock.getState()); } else if (typeBelow == Material.BELL) { Bell bell = (Bell) checkBlock.getBlockData(); if (bell.getAttachment() == Attachment.CEILING) { From 154de294a497c9fffa6d8ead87d337092f76f2ed Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 7 Feb 2023 04:41:58 +0100 Subject: [PATCH 334/399] use a better method --- src/main/java/de/diddiz/LogBlock/Consumer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 7e1dbd98..a0b16b09 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -344,7 +344,7 @@ public void queueKill(Location location, Actor killer, Actor victim, ItemStack w * The four lines on the sign. */ public void queueSignChange(Actor actor, Location loc, BlockData type, String[] lines) { - if (!BukkitUtils.getAllSignMaterials().contains(type.getMaterial())) { + if (!BukkitUtils.isSign(type.getMaterial())) { return; } queueBlock(actor, loc, type, type, null, BlockStateCodecSign.serialize(lines), null); From e4fb0f38d18ad54a4d34405d324ffdf799b02e83 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 17 Mar 2023 05:30:40 +0100 Subject: [PATCH 335/399] No more enums --- .../LogBlock/blockstate/BlockStateCodecs.java | 4 +- .../diddiz/LogBlock/config/WorldConfig.java | 4 +- .../listeners/BlockSpreadLogging.java | 140 ++++++------- .../LogBlock/listeners/InteractLogging.java | 185 ++++++++---------- .../de/diddiz/LogBlock/util/BukkitUtils.java | 182 ++++++++--------- 5 files changed, 233 insertions(+), 282 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java index 515347b8..a33c7f70 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java @@ -1,6 +1,6 @@ package de.diddiz.LogBlock.blockstate; -import java.util.EnumMap; +import java.util.HashMap; import java.util.Map; import org.bukkit.Material; @@ -8,7 +8,7 @@ import org.bukkit.configuration.file.YamlConfiguration; public class BlockStateCodecs { - private static Map codecs = new EnumMap<>(Material.class); + private static Map codecs = new HashMap<>(); public static void registerCodec(BlockStateCodec codec) { Material[] materials = codec.getApplicableMaterials(); diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index b234b4af..1a9e04e5 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -16,8 +16,8 @@ import java.io.File; import java.io.IOException; import java.util.EnumMap; -import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -97,7 +97,7 @@ public boolean isLoggingAnyEntities() { private class EntityLoggingList { private final EntityLogging entityAction; - private final EnumSet logged = EnumSet.noneOf(EntityType.class); + private final HashSet logged = new HashSet<>(); private final boolean logAll; private final boolean logAnimals; private final boolean logWateranimals; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java index 119f721e..ebcafa60 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java @@ -29,91 +29,71 @@ public void onBlockSpread(BlockSpreadEvent event) { World world = event.getNewState().getWorld(); Material type = event.getNewState().getType(); - switch (type) { - case GRASS: - if (!isLogging(world, Logging.GRASSGROWTH)) { - return; - } - name = "GrassGrowth"; - break; - case MYCELIUM: - if (!isLogging(world, Logging.MYCELIUMSPREAD)) { - return; - } - name = "MyceliumSpread"; - break; - case VINE: - case CAVE_VINES: - case CAVE_VINES_PLANT: - case WEEPING_VINES: - case WEEPING_VINES_PLANT: - case TWISTING_VINES: - case TWISTING_VINES_PLANT: - if (!isLogging(world, Logging.VINEGROWTH)) { - return; - } - name = "VineGrowth"; - break; - case RED_MUSHROOM: - case BROWN_MUSHROOM: - if (!isLogging(world, Logging.MUSHROOMSPREAD)) { - return; - } - name = "MushroomSpread"; - break; - case BAMBOO: - case BAMBOO_SAPLING: - if (!isLogging(world, Logging.BAMBOOGROWTH)) { - return; - } - name = "BambooGrowth"; - if (type == Material.BAMBOO_SAPLING) { - // bamboo sapling gets replaced by bamboo - consumer.queueBlockReplace(new Actor(name), event.getSource().getState(), Material.BAMBOO.createBlockData()); - } - break; - case POINTED_DRIPSTONE: - if (!isLogging(world, Logging.DRIPSTONEGROWTH)) { - return; - } - name = "DripstoneGrowth"; - PointedDripstone pointed = (PointedDripstone) event.getNewState().getBlockData(); - if (pointed.getThickness() != Thickness.TIP_MERGE) { - BlockFace direction = pointed.getVerticalDirection(); - Block previousPart = event.getBlock().getRelative(direction.getOppositeFace()); + if (type == Material.GRASS) { + if (!isLogging(world, Logging.GRASSGROWTH)) { + return; + } + name = "GrassGrowth"; + } else if (type == Material.MYCELIUM) { + if (!isLogging(world, Logging.MYCELIUMSPREAD)) { + return; + } + name = "MyceliumSpread"; + } else if (type == Material.VINE || type == Material.CAVE_VINES || type == Material.CAVE_VINES_PLANT || type == Material.WEEPING_VINES || type == Material.WEEPING_VINES_PLANT || type == Material.TWISTING_VINES || type == Material.TWISTING_VINES_PLANT) { + if (!isLogging(world, Logging.VINEGROWTH)) { + return; + } + name = "VineGrowth"; + } else if (type == Material.RED_MUSHROOM || type == Material.BROWN_MUSHROOM) { + if (!isLogging(world, Logging.MUSHROOMSPREAD)) { + return; + } + name = "MushroomSpread"; + } else if (type == Material.BAMBOO || type == Material.BAMBOO_SAPLING) { + if (!isLogging(world, Logging.BAMBOOGROWTH)) { + return; + } + name = "BambooGrowth"; + if (type == Material.BAMBOO_SAPLING) { + // bamboo sapling gets replaced by bamboo + consumer.queueBlockReplace(new Actor(name), event.getSource().getState(), Material.BAMBOO.createBlockData()); + } + } else if (type == Material.POINTED_DRIPSTONE) { + if (!isLogging(world, Logging.DRIPSTONEGROWTH)) { + return; + } + name = "DripstoneGrowth"; + PointedDripstone pointed = (PointedDripstone) event.getNewState().getBlockData(); + if (pointed.getThickness() != Thickness.TIP_MERGE) { + BlockFace direction = pointed.getVerticalDirection(); + Block previousPart = event.getBlock().getRelative(direction.getOppositeFace()); + if (previousPart.getType() == Material.POINTED_DRIPSTONE) { + PointedDripstone newBelow = (PointedDripstone) previousPart.getBlockData(); + newBelow.setThickness(Thickness.FRUSTUM); + consumer.queueBlockReplace(new Actor(name), previousPart.getState(), newBelow); + + previousPart = previousPart.getRelative(direction.getOppositeFace()); if (previousPart.getType() == Material.POINTED_DRIPSTONE) { - PointedDripstone newBelow = (PointedDripstone) previousPart.getBlockData(); - newBelow.setThickness(Thickness.FRUSTUM); + Block evenMorePrevious = previousPart.getRelative(direction.getOppositeFace()); + newBelow = (PointedDripstone) previousPart.getBlockData(); + newBelow.setThickness(evenMorePrevious.getType() == Material.POINTED_DRIPSTONE ? Thickness.MIDDLE : Thickness.BASE); consumer.queueBlockReplace(new Actor(name), previousPart.getState(), newBelow); - - previousPart = previousPart.getRelative(direction.getOppositeFace()); - if (previousPart.getType() == Material.POINTED_DRIPSTONE) { - Block evenMorePrevious = previousPart.getRelative(direction.getOppositeFace()); - newBelow = (PointedDripstone) previousPart.getBlockData(); - newBelow.setThickness(evenMorePrevious.getType() == Material.POINTED_DRIPSTONE ? Thickness.MIDDLE : Thickness.BASE); - consumer.queueBlockReplace(new Actor(name), previousPart.getState(), newBelow); - } } - } else { - // special case because the old state is already changed (for one half) - PointedDripstone oldState = (PointedDripstone) event.getNewState().getBlockData(); - oldState.setThickness(Thickness.TIP); - consumer.queueBlockReplace(new Actor(name), oldState, event.getNewState()); - return; } - break; - case SCULK: - case SCULK_VEIN: - case SCULK_CATALYST: - case SCULK_SENSOR: - case SCULK_SHRIEKER: - if (!isLogging(world, Logging.SCULKSPREAD)) { - return; - } - name = "SculkSpread"; - break; - default: + } else { + // special case because the old state is already changed (for one half) + PointedDripstone oldState = (PointedDripstone) event.getNewState().getBlockData(); + oldState.setThickness(Thickness.TIP); + consumer.queueBlockReplace(new Actor(name), oldState, event.getNewState()); + return; + } + } else if (type == Material.SCULK || type == Material.SCULK_VEIN || type == Material.SCULK_CATALYST || type == Material.SCULK_SENSOR || type == Material.SCULK_SHRIEKER) { + if (!isLogging(world, Logging.SCULKSPREAD)) { return; + } + name = "SculkSpread"; + } else { + return; } consumer.queueBlockReplace(new Actor(name), event.getBlock().getState(), event.getNewState()); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index 0eac4557..77f1061d 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -122,108 +122,95 @@ public void onPlayerInteract(PlayerInteractEvent event) { } } } - } else { - switch (type) { - case CAKE: - if (event.hasItem() && BukkitUtils.isCandle(event.getItem().getType()) && event.useItemInHand() != Result.DENY) { - BlockData newBlockData = Material.valueOf(event.getItem().getType().name() + "_CAKE").createBlockData(); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } else if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20) { - Cake newBlockData = (Cake) blockData.clone(); - if (newBlockData.getBites() < 6) { - newBlockData.setBites(newBlockData.getBites() + 1); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } else { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.AIR.createBlockData()); - } - } - break; - case NOTE_BLOCK: - if (wcfg.isLogging(Logging.NOTEBLOCKINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - NoteBlock newBlockData = (NoteBlock) blockData.clone(); - if (newBlockData.getNote().getOctave() == 2) { - newBlockData.setNote(new Note(0, Tone.F, true)); - } else { - newBlockData.setNote(newBlockData.getNote().sharped()); - } - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - break; - case REPEATER: - if (wcfg.isLogging(Logging.DIODEINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Repeater newBlockData = (Repeater) blockData.clone(); - newBlockData.setDelay((newBlockData.getDelay() % 4) + 1); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - break; - case COMPARATOR: - if (wcfg.isLogging(Logging.COMPARATORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Comparator newBlockData = (Comparator) blockData.clone(); - newBlockData.setMode(newBlockData.getMode() == Mode.COMPARE ? Mode.SUBTRACT : Mode.COMPARE); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - break; - case DAYLIGHT_DETECTOR: - if (wcfg.isLogging(Logging.DAYLIGHTDETECTORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - DaylightDetector newBlockData = (DaylightDetector) blockData.clone(); - newBlockData.setInverted(!newBlockData.isInverted()); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - break; - case TRIPWIRE: - if (wcfg.isLogging(Logging.TRIPWIREINTERACT) && event.getAction() == Action.PHYSICAL) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); - } - break; - case FARMLAND: - if (wcfg.isLogging(Logging.CROPTRAMPLE) && event.getAction() == Action.PHYSICAL) { - // 3 = Dirt ID - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.DIRT.createBlockData()); - // Log the crop on top as being broken - Block trampledCrop = clicked.getRelative(BlockFace.UP); - if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) { - consumer.queueBlockBreak(Actor.actorFromEntity(player), trampledCrop.getState()); - } - } - break; - case TURTLE_EGG: - if (wcfg.isLogging(Logging.BLOCKBREAK) && event.getAction() == Action.PHYSICAL) { - TurtleEgg turtleEggData = (TurtleEgg) blockData; - int eggs = turtleEggData.getEggs(); - if (eggs > 1) { - TurtleEgg turtleEggData2 = (TurtleEgg) turtleEggData.clone(); - turtleEggData2.setEggs(eggs - 1); - consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, turtleEggData2); + } else if (type == Material.CAKE) { + if (event.hasItem() && BukkitUtils.isCandle(event.getItem().getType()) && event.useItemInHand() != Result.DENY) { + BlockData newBlockData = Material.valueOf(event.getItem().getType().name() + "_CAKE").createBlockData(); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } else if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20) { + Cake newBlockData = (Cake) blockData.clone(); + if (newBlockData.getBites() < 6) { + newBlockData.setBites(newBlockData.getBites() + 1); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } else { + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.AIR.createBlockData()); + } + } + } else if (type == Material.NOTE_BLOCK) { + if (wcfg.isLogging(Logging.NOTEBLOCKINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + NoteBlock newBlockData = (NoteBlock) blockData.clone(); + if (newBlockData.getNote().getOctave() == 2) { + newBlockData.setNote(new Note(0, Tone.F, true)); + } else { + newBlockData.setNote(newBlockData.getNote().sharped()); + } + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } else if (type == Material.REPEATER) { + if (wcfg.isLogging(Logging.DIODEINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Repeater newBlockData = (Repeater) blockData.clone(); + newBlockData.setDelay((newBlockData.getDelay() % 4) + 1); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } else if (type == Material.COMPARATOR) { + if (wcfg.isLogging(Logging.COMPARATORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Comparator newBlockData = (Comparator) blockData.clone(); + newBlockData.setMode(newBlockData.getMode() == Mode.COMPARE ? Mode.SUBTRACT : Mode.COMPARE); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } else if (type == Material.DAYLIGHT_DETECTOR) { + if (wcfg.isLogging(Logging.DAYLIGHTDETECTORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + DaylightDetector newBlockData = (DaylightDetector) blockData.clone(); + newBlockData.setInverted(!newBlockData.isInverted()); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } else if (type == Material.TRIPWIRE) { + if (wcfg.isLogging(Logging.TRIPWIREINTERACT) && event.getAction() == Action.PHYSICAL) { + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + } + } else if (type == Material.FARMLAND) { + if (wcfg.isLogging(Logging.CROPTRAMPLE) && event.getAction() == Action.PHYSICAL) { + // 3 = Dirt ID + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.DIRT.createBlockData()); + // Log the crop on top as being broken + Block trampledCrop = clicked.getRelative(BlockFace.UP); + if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) { + consumer.queueBlockBreak(Actor.actorFromEntity(player), trampledCrop.getState()); + } + } + } else if (type == Material.TURTLE_EGG) { + if (wcfg.isLogging(Logging.BLOCKBREAK) && event.getAction() == Action.PHYSICAL) { + TurtleEgg turtleEggData = (TurtleEgg) blockData; + int eggs = turtleEggData.getEggs(); + if (eggs > 1) { + TurtleEgg turtleEggData2 = (TurtleEgg) turtleEggData.clone(); + turtleEggData2.setEggs(eggs - 1); + consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, turtleEggData2); + } else { + consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, Material.AIR.createBlockData()); + } + } + } else if (type == Material.PUMPKIN) { + if ((wcfg.isLogging(Logging.BLOCKBREAK) || wcfg.isLogging(Logging.BLOCKPLACE)) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + ItemStack inHand = event.getItem(); + if (inHand != null && inHand.getType() == Material.SHEARS) { + BlockFace clickedFace = event.getBlockFace(); + Directional newBlockData = (Directional) Material.CARVED_PUMPKIN.createBlockData(); + if (clickedFace == BlockFace.NORTH || clickedFace == BlockFace.SOUTH || clickedFace == BlockFace.EAST || clickedFace == BlockFace.WEST) { + newBlockData.setFacing(clickedFace); + } else { + // use player distance to calculate the facing + Location playerLoc = player.getLocation(); + playerLoc.subtract(0.5, 0, 0.5); + double dx = playerLoc.getX() - loc.getX(); + double dz = playerLoc.getZ() - loc.getZ(); + if (Math.abs(dx) > Math.abs(dz)) { + newBlockData.setFacing(dx > 0 ? BlockFace.EAST : BlockFace.WEST); } else { - consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, Material.AIR.createBlockData()); + newBlockData.setFacing(dz > 0 ? BlockFace.SOUTH : BlockFace.NORTH); } } - break; - case PUMPKIN: - if ((wcfg.isLogging(Logging.BLOCKBREAK) || wcfg.isLogging(Logging.BLOCKPLACE)) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - ItemStack inHand = event.getItem(); - if (inHand != null && inHand.getType() == Material.SHEARS) { - BlockFace clickedFace = event.getBlockFace(); - Directional newBlockData = (Directional) Material.CARVED_PUMPKIN.createBlockData(); - if (clickedFace == BlockFace.NORTH || clickedFace == BlockFace.SOUTH || clickedFace == BlockFace.EAST || clickedFace == BlockFace.WEST) { - newBlockData.setFacing(clickedFace); - } else { - // use player distance to calculate the facing - Location playerLoc = player.getLocation(); - playerLoc.subtract(0.5, 0, 0.5); - double dx = playerLoc.getX() - loc.getX(); - double dz = playerLoc.getZ() - loc.getZ(); - if (Math.abs(dx) > Math.abs(dz)) { - newBlockData.setFacing(dx > 0 ? BlockFace.EAST : BlockFace.WEST); - } else { - newBlockData.setFacing(dz > 0 ? BlockFace.SOUTH : BlockFace.NORTH); - } - } - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - } - break; - default: + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } } } } diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 4b647eb7..b769d22c 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -8,8 +8,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.EnumMap; -import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -69,26 +67,26 @@ public class BukkitUtils { private static final Set bedBlocks; private static final Map projectileItems; - private static final EnumSet signs; - private static final EnumSet wallSigns; - private static final EnumSet hangingSigns; - private static final EnumSet hangingWallSigns; - private static final EnumSet allSigns; + private static final HashSet signs; + private static final HashSet wallSigns; + private static final HashSet hangingSigns; + private static final HashSet hangingWallSigns; + private static final HashSet allSigns; private static final Set unmodifiableSigns; - private static final EnumSet buttons; - private static final EnumSet pressurePlates; - private static final EnumSet woodenDoors; - private static final EnumSet slabs; - private static final EnumSet concreteBlocks; - private static final EnumMap dyes; - private static final EnumSet alwaysWaterlogged; - private static final EnumSet candles; - private static final EnumSet candleCakes; - private static final EnumSet fenceGates; - private static final EnumSet woodenTrapdoors; + private static final HashSet buttons; + private static final HashSet pressurePlates; + private static final HashSet woodenDoors; + private static final HashSet slabs; + private static final HashSet concreteBlocks; + private static final HashMap dyes; + private static final HashSet alwaysWaterlogged; + private static final HashSet candles; + private static final HashSet candleCakes; + private static final HashSet fenceGates; + private static final HashSet woodenTrapdoors; static { - fenceGates = EnumSet.noneOf(Material.class); + fenceGates = new HashSet<>(); fenceGates.add(Material.OAK_FENCE_GATE); fenceGates.add(Material.SPRUCE_FENCE_GATE); fenceGates.add(Material.BIRCH_FENCE_GATE); @@ -100,7 +98,7 @@ public class BukkitUtils { fenceGates.add(Material.MANGROVE_FENCE_GATE); fenceGates.add(Material.BAMBOO_FENCE_GATE); - woodenTrapdoors = EnumSet.noneOf(Material.class); + woodenTrapdoors = new HashSet<>(); woodenTrapdoors.add(Material.OAK_TRAPDOOR); woodenTrapdoors.add(Material.SPRUCE_TRAPDOOR); woodenTrapdoors.add(Material.BIRCH_TRAPDOOR); @@ -112,7 +110,7 @@ public class BukkitUtils { woodenTrapdoors.add(Material.MANGROVE_TRAPDOOR); woodenTrapdoors.add(Material.BAMBOO_TRAPDOOR); - pressurePlates = EnumSet.noneOf(Material.class); + pressurePlates = new HashSet<>(); pressurePlates.add(Material.OAK_PRESSURE_PLATE); pressurePlates.add(Material.SPRUCE_PRESSURE_PLATE); pressurePlates.add(Material.BIRCH_PRESSURE_PLATE); @@ -127,7 +125,7 @@ public class BukkitUtils { pressurePlates.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); pressurePlates.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); - woodenDoors = EnumSet.noneOf(Material.class); + woodenDoors = new HashSet<>(); woodenDoors.add(Material.OAK_DOOR); woodenDoors.add(Material.SPRUCE_DOOR); woodenDoors.add(Material.BIRCH_DOOR); @@ -139,7 +137,7 @@ public class BukkitUtils { woodenDoors.add(Material.MANGROVE_DOOR); woodenDoors.add(Material.BAMBOO_DOOR); - EnumSet saplings = EnumSet.noneOf(Material.class); + HashSet saplings = new HashSet<>(); saplings.add(Material.OAK_SAPLING); saplings.add(Material.SPRUCE_SAPLING); saplings.add(Material.BIRCH_SAPLING); @@ -150,7 +148,7 @@ public class BukkitUtils { saplings.add(Material.CRIMSON_FUNGUS); saplings.add(Material.MANGROVE_PROPAGULE); - EnumSet carpets = EnumSet.noneOf(Material.class); + HashSet carpets = new HashSet<>(); carpets.add(Material.BLACK_CARPET); carpets.add(Material.BLUE_CARPET); carpets.add(Material.LIGHT_GRAY_CARPET); @@ -168,7 +166,7 @@ public class BukkitUtils { carpets.add(Material.WHITE_CARPET); carpets.add(Material.YELLOW_CARPET); - slabs = EnumSet.noneOf(Material.class); + slabs = new HashSet<>(); slabs.add(Material.OAK_SLAB); slabs.add(Material.SPRUCE_SLAB); slabs.add(Material.BIRCH_SLAB); @@ -199,7 +197,7 @@ public class BukkitUtils { slabs.add(Material.MANGROVE_SLAB); slabs.add(Material.BAMBOO_SLAB); - buttons = EnumSet.noneOf(Material.class); + buttons = new HashSet<>(); buttons.add(Material.STONE_BUTTON); buttons.add(Material.OAK_BUTTON); buttons.add(Material.SPRUCE_BUTTON); @@ -213,7 +211,7 @@ public class BukkitUtils { buttons.add(Material.BAMBOO_BUTTON); buttons.add(Material.POLISHED_BLACKSTONE_BUTTON); - signs = EnumSet.noneOf(Material.class); + signs = new HashSet<>(); signs.add(Material.OAK_SIGN); signs.add(Material.SPRUCE_SIGN); signs.add(Material.BIRCH_SIGN); @@ -225,7 +223,7 @@ public class BukkitUtils { signs.add(Material.MANGROVE_SIGN); signs.add(Material.BAMBOO_SIGN); - wallSigns = EnumSet.noneOf(Material.class); + wallSigns = new HashSet<>(); wallSigns.add(Material.OAK_WALL_SIGN); wallSigns.add(Material.SPRUCE_WALL_SIGN); wallSigns.add(Material.BIRCH_WALL_SIGN); @@ -237,7 +235,7 @@ public class BukkitUtils { wallSigns.add(Material.MANGROVE_WALL_SIGN); wallSigns.add(Material.BAMBOO_WALL_SIGN); - hangingSigns = EnumSet.noneOf(Material.class); + hangingSigns = new HashSet<>(); hangingSigns.add(Material.OAK_HANGING_SIGN); hangingSigns.add(Material.SPRUCE_HANGING_SIGN); hangingSigns.add(Material.BIRCH_HANGING_SIGN); @@ -249,7 +247,7 @@ public class BukkitUtils { hangingSigns.add(Material.MANGROVE_HANGING_SIGN); hangingSigns.add(Material.BAMBOO_HANGING_SIGN); - hangingWallSigns = EnumSet.noneOf(Material.class); + hangingWallSigns = new HashSet<>(); hangingWallSigns.add(Material.OAK_WALL_HANGING_SIGN); hangingWallSigns.add(Material.SPRUCE_WALL_HANGING_SIGN); hangingWallSigns.add(Material.BIRCH_WALL_HANGING_SIGN); @@ -261,14 +259,14 @@ public class BukkitUtils { hangingWallSigns.add(Material.MANGROVE_WALL_HANGING_SIGN); hangingWallSigns.add(Material.BAMBOO_WALL_HANGING_SIGN); - allSigns = EnumSet.noneOf(Material.class); + allSigns = new HashSet<>(); allSigns.addAll(signs); allSigns.addAll(wallSigns); allSigns.addAll(hangingSigns); allSigns.addAll(hangingWallSigns); unmodifiableSigns = Collections.unmodifiableSet(allSigns); - singleBlockPlants = EnumSet.noneOf(Material.class); + singleBlockPlants = new HashSet<>(); singleBlockPlants.add(Material.GRASS); singleBlockPlants.add(Material.FERN); singleBlockPlants.add(Material.DEAD_BUSH); @@ -296,7 +294,7 @@ public class BukkitUtils { singleBlockPlants.add(Material.AZALEA); singleBlockPlants.add(Material.FLOWERING_AZALEA); - doublePlants = EnumSet.noneOf(Material.class); + doublePlants = new HashSet<>(); doublePlants.add(Material.TALL_GRASS); doublePlants.add(Material.LARGE_FERN); doublePlants.add(Material.TALL_SEAGRASS); @@ -316,7 +314,7 @@ public class BukkitUtils { blockEquivalents.add(new HashSet<>(Arrays.asList(93, 94))); // Blocks that break when they are attached to a block - relativeBreakable = EnumSet.noneOf(Material.class); + relativeBreakable = new HashSet<>(); relativeBreakable.addAll(wallSigns); relativeBreakable.add(Material.LADDER); relativeBreakable.addAll(buttons); @@ -332,7 +330,7 @@ public class BukkitUtils { relativeBreakable.add(Material.LARGE_AMETHYST_BUD); // Blocks that break when they are on top of a block - relativeTopBreakable = EnumSet.noneOf(Material.class); + relativeTopBreakable = new HashSet<>(); relativeTopBreakable.addAll(saplings); relativeTopBreakable.addAll(singleBlockPlants); relativeTopBreakable.add(Material.WHEAT); @@ -375,7 +373,7 @@ public class BukkitUtils { } // Blocks that break falling entities - fallingEntityKillers = EnumSet.noneOf(Material.class); + fallingEntityKillers = new HashSet<>(); fallingEntityKillers.addAll(signs); fallingEntityKillers.addAll(wallSigns); fallingEntityKillers.addAll(pressurePlates); @@ -427,7 +425,7 @@ public class BukkitUtils { } // Crop Blocks - cropBlocks = EnumSet.noneOf(Material.class); + cropBlocks = new HashSet<>(); cropBlocks.add(Material.WHEAT); cropBlocks.add(Material.MELON_STEM); cropBlocks.add(Material.PUMPKIN_STEM); @@ -436,7 +434,7 @@ public class BukkitUtils { cropBlocks.add(Material.BEETROOT); // Shulker Boxes - shulkerBoxBlocks = EnumSet.noneOf(Material.class); + shulkerBoxBlocks = new HashSet<>(); shulkerBoxBlocks.add(Material.SHULKER_BOX); shulkerBoxBlocks.add(Material.BLACK_SHULKER_BOX); shulkerBoxBlocks.add(Material.BLUE_SHULKER_BOX); @@ -456,7 +454,7 @@ public class BukkitUtils { shulkerBoxBlocks.add(Material.YELLOW_SHULKER_BOX); // Container Blocks - containerBlocks = EnumSet.noneOf(Material.class); + containerBlocks = new HashSet<>(); containerBlocks.add(Material.CHEST); containerBlocks.add(Material.TRAPPED_CHEST); containerBlocks.add(Material.DISPENSER); @@ -473,7 +471,7 @@ public class BukkitUtils { // containerBlocks.add(Material.ENDER_CHEST); // It doesn't seem like you could injure people with some of these, but they exist, so.... - projectileItems = new EnumMap<>(EntityType.class); + projectileItems = new HashMap<>(); projectileItems.put(EntityType.ARROW, Material.ARROW); projectileItems.put(EntityType.EGG, Material.EGG); projectileItems.put(EntityType.ENDER_PEARL, Material.ENDER_PEARL); @@ -486,7 +484,7 @@ public class BukkitUtils { projectileItems.put(EntityType.WITHER_SKULL, Material.WITHER_SKELETON_SKULL); projectileItems.put(EntityType.FIREWORK, Material.FIREWORK_ROCKET); - nonFluidProofBlocks = EnumSet.noneOf(Material.class); + nonFluidProofBlocks = new HashSet<>(); nonFluidProofBlocks.addAll(singleBlockPlants); nonFluidProofBlocks.addAll(doublePlants); nonFluidProofBlocks.add(Material.REDSTONE_WALL_TORCH); @@ -517,13 +515,13 @@ public class BukkitUtils { nonFluidProofBlocks.add(Material.DAYLIGHT_DETECTOR); nonFluidProofBlocks.addAll(carpets); - alwaysWaterlogged = EnumSet.noneOf(Material.class); + alwaysWaterlogged = new HashSet<>(); alwaysWaterlogged.add(Material.SEAGRASS); alwaysWaterlogged.add(Material.TALL_SEAGRASS); alwaysWaterlogged.add(Material.KELP); alwaysWaterlogged.add(Material.KELP_PLANT); - bedBlocks = EnumSet.noneOf(Material.class); + bedBlocks = new HashSet<>(); bedBlocks.add(Material.BLACK_BED); bedBlocks.add(Material.BLUE_BED); bedBlocks.add(Material.LIGHT_GRAY_BED); @@ -541,7 +539,7 @@ public class BukkitUtils { bedBlocks.add(Material.WHITE_BED); bedBlocks.add(Material.YELLOW_BED); - concreteBlocks = EnumSet.noneOf(Material.class); + concreteBlocks = new HashSet<>(); concreteBlocks.add(Material.BLACK_CONCRETE); concreteBlocks.add(Material.BLUE_CONCRETE); concreteBlocks.add(Material.LIGHT_GRAY_CONCRETE); @@ -559,7 +557,7 @@ public class BukkitUtils { concreteBlocks.add(Material.WHITE_CONCRETE); concreteBlocks.add(Material.YELLOW_CONCRETE); - candles = EnumSet.noneOf(Material.class); + candles = new HashSet<>(); candles.add(Material.CANDLE); candles.add(Material.BLACK_CANDLE); candles.add(Material.BLUE_CANDLE); @@ -578,7 +576,7 @@ public class BukkitUtils { candles.add(Material.WHITE_CANDLE); candles.add(Material.YELLOW_CANDLE); - candleCakes = EnumSet.noneOf(Material.class); + candleCakes = new HashSet<>(); candleCakes.add(Material.CANDLE_CAKE); candleCakes.add(Material.BLACK_CANDLE_CAKE); candleCakes.add(Material.BLUE_CANDLE_CAKE); @@ -597,7 +595,7 @@ public class BukkitUtils { candleCakes.add(Material.WHITE_CANDLE_CAKE); candleCakes.add(Material.YELLOW_CANDLE_CAKE); - dyes = new EnumMap<>(Material.class); + dyes = new HashMap<>(); dyes.put(Material.BLACK_DYE, DyeColor.BLACK); dyes.put(Material.BLUE_DYE, DyeColor.BLUE); dyes.put(Material.LIGHT_GRAY_DYE, DyeColor.LIGHT_GRAY); @@ -1132,58 +1130,44 @@ public static boolean isSimilarForRollback(Material expected, Material found) { if (expected == found) { return true; } - switch (expected) { - case DIRT: - case MYCELIUM: - case FARMLAND: - case GRASS_BLOCK: - case PODZOL: - case DIRT_PATH: - return found == Material.DIRT || found == Material.MYCELIUM || found == Material.FARMLAND || found == Material.GRASS_BLOCK || found == Material.PODZOL || found == Material.DIRT_PATH; - case BAMBOO: - case BAMBOO_SAPLING: - return found == Material.BAMBOO || found == Material.BAMBOO_SAPLING; - case SPONGE: - case WET_SPONGE: - return found == Material.SPONGE || found == Material.WET_SPONGE; - case MELON_STEM: - case ATTACHED_MELON_STEM: - return found == Material.MELON_STEM || found == Material.ATTACHED_MELON_STEM; - case PUMPKIN_STEM: - case ATTACHED_PUMPKIN_STEM: - return found == Material.PUMPKIN_STEM || found == Material.ATTACHED_PUMPKIN_STEM; - case TWISTING_VINES: - case TWISTING_VINES_PLANT: - return found == Material.TWISTING_VINES || found == Material.TWISTING_VINES_PLANT; - case WEEPING_VINES: - case WEEPING_VINES_PLANT: - return found == Material.WEEPING_VINES || found == Material.WEEPING_VINES_PLANT; - case CAVE_VINES: - case CAVE_VINES_PLANT: - return found == Material.CAVE_VINES || found == Material.CAVE_VINES_PLANT; - case BIG_DRIPLEAF: - case BIG_DRIPLEAF_STEM: - return found == Material.BIG_DRIPLEAF || found == Material.BIG_DRIPLEAF_STEM; - case COPPER_BLOCK: - case EXPOSED_COPPER: - case WEATHERED_COPPER: - case OXIDIZED_COPPER: - return found == Material.COPPER_BLOCK || found == Material.EXPOSED_COPPER || found == Material.WEATHERED_COPPER || found == Material.OXIDIZED_COPPER; - case CUT_COPPER: - case EXPOSED_CUT_COPPER: - case WEATHERED_CUT_COPPER: - case OXIDIZED_CUT_COPPER: - return found == Material.CUT_COPPER || found == Material.EXPOSED_CUT_COPPER || found == Material.WEATHERED_CUT_COPPER || found == Material.OXIDIZED_CUT_COPPER; - case CUT_COPPER_STAIRS: - case EXPOSED_CUT_COPPER_STAIRS: - case WEATHERED_CUT_COPPER_STAIRS: - case OXIDIZED_CUT_COPPER_STAIRS: - return found == Material.CUT_COPPER_STAIRS || found == Material.EXPOSED_CUT_COPPER_STAIRS || found == Material.WEATHERED_CUT_COPPER_STAIRS || found == Material.OXIDIZED_CUT_COPPER_STAIRS; - case CUT_COPPER_SLAB: - case EXPOSED_CUT_COPPER_SLAB: - case WEATHERED_CUT_COPPER_SLAB: - case OXIDIZED_CUT_COPPER_SLAB: - return found == Material.CUT_COPPER_SLAB || found == Material.EXPOSED_CUT_COPPER_SLAB || found == Material.WEATHERED_CUT_COPPER_SLAB || found == Material.OXIDIZED_CUT_COPPER_SLAB; + if (expected == Material.DIRT || expected == Material.MYCELIUM || expected == Material.FARMLAND || expected == Material.GRASS_BLOCK || expected == Material.PODZOL || expected == Material.DIRT_PATH) { + return found == Material.DIRT || found == Material.MYCELIUM || found == Material.FARMLAND || found == Material.GRASS_BLOCK || found == Material.PODZOL || found == Material.DIRT_PATH; + } + if (expected == Material.BAMBOO || expected == Material.BAMBOO_SAPLING) { + return found == Material.BAMBOO || found == Material.BAMBOO_SAPLING; + } + if (expected == Material.SPONGE || expected == Material.WET_SPONGE) { + return found == Material.SPONGE || found == Material.WET_SPONGE; + } + if (expected == Material.MELON_STEM || expected == Material.ATTACHED_MELON_STEM) { + return found == Material.MELON_STEM || found == Material.ATTACHED_MELON_STEM; + } + if (expected == Material.PUMPKIN_STEM || expected == Material.ATTACHED_PUMPKIN_STEM) { + return found == Material.PUMPKIN_STEM || found == Material.ATTACHED_PUMPKIN_STEM; + } + if (expected == Material.TWISTING_VINES || expected == Material.TWISTING_VINES_PLANT) { + return found == Material.TWISTING_VINES || found == Material.TWISTING_VINES_PLANT; + } + if (expected == Material.WEEPING_VINES || expected == Material.WEEPING_VINES_PLANT) { + return found == Material.WEEPING_VINES || found == Material.WEEPING_VINES_PLANT; + } + if (expected == Material.CAVE_VINES || expected == Material.CAVE_VINES_PLANT) { + return found == Material.CAVE_VINES || found == Material.CAVE_VINES_PLANT; + } + if (expected == Material.BIG_DRIPLEAF || expected == Material.BIG_DRIPLEAF_STEM) { + return found == Material.BIG_DRIPLEAF || found == Material.BIG_DRIPLEAF_STEM; + } + if (expected == Material.COPPER_BLOCK || expected == Material.EXPOSED_COPPER || expected == Material.WEATHERED_COPPER || expected == Material.OXIDIZED_COPPER) { + return found == Material.COPPER_BLOCK || found == Material.EXPOSED_COPPER || found == Material.WEATHERED_COPPER || found == Material.OXIDIZED_COPPER; + } + if (expected == Material.CUT_COPPER || expected == Material.EXPOSED_CUT_COPPER || expected == Material.WEATHERED_CUT_COPPER || expected == Material.OXIDIZED_CUT_COPPER) { + return found == Material.CUT_COPPER || found == Material.EXPOSED_CUT_COPPER || found == Material.WEATHERED_CUT_COPPER || found == Material.OXIDIZED_CUT_COPPER; + } + if (expected == Material.CUT_COPPER_STAIRS || expected == Material.EXPOSED_CUT_COPPER_STAIRS || expected == Material.WEATHERED_CUT_COPPER_STAIRS || expected == Material.OXIDIZED_CUT_COPPER_STAIRS) { + return found == Material.CUT_COPPER_STAIRS || found == Material.EXPOSED_CUT_COPPER_STAIRS || found == Material.WEATHERED_CUT_COPPER_STAIRS || found == Material.OXIDIZED_CUT_COPPER_STAIRS; + } + if (expected == Material.CUT_COPPER_SLAB || expected == Material.EXPOSED_CUT_COPPER_SLAB || expected == Material.WEATHERED_CUT_COPPER_SLAB || expected == Material.OXIDIZED_CUT_COPPER_SLAB) { + return found == Material.CUT_COPPER_SLAB || found == Material.EXPOSED_CUT_COPPER_SLAB || found == Material.WEATHERED_CUT_COPPER_SLAB || found == Material.OXIDIZED_CUT_COPPER_SLAB; } return false; } From a609c021e6f8fe8c992c6c2775bd49a4be6547e0 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 17 Mar 2023 05:33:58 +0100 Subject: [PATCH 336/399] 1.19.4 --- pom.xml | 2 +- .../java/de/diddiz/LogBlock/util/BukkitUtils.java | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c541e09a..5b23102c 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ org.spigotmc spigot-api - 1.19.3-R0.1-SNAPSHOT + 1.19.4-R0.1-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index b769d22c..bff4a8fa 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -97,6 +97,7 @@ public class BukkitUtils { fenceGates.add(Material.CRIMSON_FENCE_GATE); fenceGates.add(Material.MANGROVE_FENCE_GATE); fenceGates.add(Material.BAMBOO_FENCE_GATE); + fenceGates.add(Material.CHERRY_FENCE_GATE); woodenTrapdoors = new HashSet<>(); woodenTrapdoors.add(Material.OAK_TRAPDOOR); @@ -109,6 +110,7 @@ public class BukkitUtils { woodenTrapdoors.add(Material.CRIMSON_TRAPDOOR); woodenTrapdoors.add(Material.MANGROVE_TRAPDOOR); woodenTrapdoors.add(Material.BAMBOO_TRAPDOOR); + woodenTrapdoors.add(Material.CHERRY_TRAPDOOR); pressurePlates = new HashSet<>(); pressurePlates.add(Material.OAK_PRESSURE_PLATE); @@ -121,6 +123,7 @@ public class BukkitUtils { pressurePlates.add(Material.CRIMSON_PRESSURE_PLATE); pressurePlates.add(Material.MANGROVE_PRESSURE_PLATE); pressurePlates.add(Material.BAMBOO_PRESSURE_PLATE); + pressurePlates.add(Material.CHERRY_PRESSURE_PLATE); pressurePlates.add(Material.STONE_PRESSURE_PLATE); pressurePlates.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); pressurePlates.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); @@ -136,6 +139,7 @@ public class BukkitUtils { woodenDoors.add(Material.CRIMSON_DOOR); woodenDoors.add(Material.MANGROVE_DOOR); woodenDoors.add(Material.BAMBOO_DOOR); + woodenDoors.add(Material.CHERRY_DOOR); HashSet saplings = new HashSet<>(); saplings.add(Material.OAK_SAPLING); @@ -144,6 +148,7 @@ public class BukkitUtils { saplings.add(Material.JUNGLE_SAPLING); saplings.add(Material.ACACIA_SAPLING); saplings.add(Material.DARK_OAK_SAPLING); + saplings.add(Material.CHERRY_SAPLING); saplings.add(Material.WARPED_FUNGUS); saplings.add(Material.CRIMSON_FUNGUS); saplings.add(Material.MANGROVE_PROPAGULE); @@ -196,6 +201,7 @@ public class BukkitUtils { slabs.add(Material.POLISHED_DEEPSLATE_SLAB); slabs.add(Material.MANGROVE_SLAB); slabs.add(Material.BAMBOO_SLAB); + slabs.add(Material.CHERRY_SLAB); buttons = new HashSet<>(); buttons.add(Material.STONE_BUTTON); @@ -209,6 +215,7 @@ public class BukkitUtils { buttons.add(Material.CRIMSON_BUTTON); buttons.add(Material.MANGROVE_BUTTON); buttons.add(Material.BAMBOO_BUTTON); + buttons.add(Material.CHERRY_BUTTON); buttons.add(Material.POLISHED_BLACKSTONE_BUTTON); signs = new HashSet<>(); @@ -222,6 +229,7 @@ public class BukkitUtils { signs.add(Material.CRIMSON_SIGN); signs.add(Material.MANGROVE_SIGN); signs.add(Material.BAMBOO_SIGN); + signs.add(Material.CHERRY_SIGN); wallSigns = new HashSet<>(); wallSigns.add(Material.OAK_WALL_SIGN); @@ -234,6 +242,7 @@ public class BukkitUtils { wallSigns.add(Material.CRIMSON_WALL_SIGN); wallSigns.add(Material.MANGROVE_WALL_SIGN); wallSigns.add(Material.BAMBOO_WALL_SIGN); + wallSigns.add(Material.CHERRY_WALL_SIGN); hangingSigns = new HashSet<>(); hangingSigns.add(Material.OAK_HANGING_SIGN); @@ -246,6 +255,7 @@ public class BukkitUtils { hangingSigns.add(Material.CRIMSON_HANGING_SIGN); hangingSigns.add(Material.MANGROVE_HANGING_SIGN); hangingSigns.add(Material.BAMBOO_HANGING_SIGN); + hangingSigns.add(Material.CHERRY_HANGING_SIGN); hangingWallSigns = new HashSet<>(); hangingWallSigns.add(Material.OAK_WALL_HANGING_SIGN); @@ -258,6 +268,7 @@ public class BukkitUtils { hangingWallSigns.add(Material.CRIMSON_WALL_HANGING_SIGN); hangingWallSigns.add(Material.MANGROVE_WALL_HANGING_SIGN); hangingWallSigns.add(Material.BAMBOO_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.CHERRY_WALL_HANGING_SIGN); allSigns = new HashSet<>(); allSigns.addAll(signs); @@ -293,6 +304,7 @@ public class BukkitUtils { singleBlockPlants.add(Material.NETHER_SPROUTS); singleBlockPlants.add(Material.AZALEA); singleBlockPlants.add(Material.FLOWERING_AZALEA); + singleBlockPlants.add(Material.PINK_PETALS); doublePlants = new HashSet<>(); doublePlants.add(Material.TALL_GRASS); @@ -432,6 +444,7 @@ public class BukkitUtils { cropBlocks.add(Material.CARROT); cropBlocks.add(Material.POTATO); cropBlocks.add(Material.BEETROOT); + cropBlocks.add(Material.TORCHFLOWER_CROP); // Shulker Boxes shulkerBoxBlocks = new HashSet<>(); From 1fce7c7a662cf09964fd6d87b8c928d697cb5dec Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 2 Jun 2023 05:25:12 +0200 Subject: [PATCH 337/399] avoid invalid fluid levels --- .../java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index b5710111..9e85a5b5 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -53,7 +53,7 @@ public void onBlockFromTo(BlockFromToEvent event) { consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData()); } else { Levelled newBlock = (Levelled) blockDataFrom.clone(); - newBlock.setLevel(down ? 1 : levelledFrom.getLevel() + 1); + newBlock.setLevel(down ? 1 : Math.min(levelledFrom.getLevel() + 1, levelledFrom.getMaximumLevel())); if (BukkitUtils.isEmpty(typeTo)) { consumer.queueBlockPlace(new Actor("LavaFlow", source), to.getLocation(), newBlock); } else { @@ -70,7 +70,7 @@ public void onBlockFromTo(BlockFromToEvent event) { } else if ((typeFrom == Material.WATER) && wcfg.isLogging(Logging.WATERFLOW)) { Levelled levelledFrom = fromWaterlogged ? null : (Levelled) blockDataFrom; Levelled newBlock = (Levelled) Material.WATER.createBlockData(); - newBlock.setLevel(fromWaterlogged || down ? 1 : levelledFrom.getLevel() + 1); + newBlock.setLevel(fromWaterlogged || down ? 1 : Math.min(levelledFrom.getLevel() + 1, levelledFrom.getMaximumLevel())); if (BukkitUtils.isEmpty(typeTo)) { consumer.queueBlockPlace(new Actor("WaterFlow", source), to.getLocation(), newBlock); } else if (BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { From 31bef400a670accc1f65f8e29697c4948aa6dea4 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 11 Jun 2023 05:24:15 +0200 Subject: [PATCH 338/399] add 1.20 materials --- pom.xml | 2 +- src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5b23102c..f0a5c712 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ org.spigotmc spigot-api - 1.19.4-R0.1-SNAPSHOT + 1.20-R0.1-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index bff4a8fa..f4babf36 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -305,6 +305,8 @@ public class BukkitUtils { singleBlockPlants.add(Material.AZALEA); singleBlockPlants.add(Material.FLOWERING_AZALEA); singleBlockPlants.add(Material.PINK_PETALS); + singleBlockPlants.add(Material.TORCHFLOWER); + singleBlockPlants.add(Material.PITCHER_CROP); doublePlants = new HashSet<>(); doublePlants.add(Material.TALL_GRASS); @@ -315,6 +317,7 @@ public class BukkitUtils { doublePlants.add(Material.SUNFLOWER); doublePlants.add(Material.PEONY); doublePlants.add(Material.SMALL_DRIPLEAF); + doublePlants.add(Material.PITCHER_PLANT); blockEquivalents = new HashSet<>(7); blockEquivalents.add(new HashSet<>(Arrays.asList(2, 3, 60))); From 419f3530ad36745b15c27993e04071ec027a4d70 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 12 Jun 2023 03:41:12 +0200 Subject: [PATCH 339/399] properly log sign edits --- .../java/de/diddiz/LogBlock/Consumer.java | 7 +- src/main/java/de/diddiz/LogBlock/Updater.java | 3 +- .../blockstate/BlockStateCodecSign.java | 213 +++++++++++------- .../LogBlock/blockstate/BlockStateCodecs.java | 2 +- .../LogBlock/listeners/InteractLogging.java | 51 +++-- .../LogBlock/listeners/SignChangeLogging.java | 2 +- .../de/diddiz/LogBlock/util/BukkitUtils.java | 86 +++++++ .../de/diddiz/LogBlock/util/Reflections.java | 36 +++ .../java/de/diddiz/LogBlock/util/Utils.java | 11 + 9 files changed, 302 insertions(+), 109 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/util/Reflections.java diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index a0b16b09..91a8abff 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -36,6 +36,7 @@ import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Waterlogged; +import org.bukkit.block.sign.Side; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -340,14 +341,16 @@ public void queueKill(Location location, Actor killer, Actor victim, ItemStack w * Location of the placed sign * @param type * BlockData of the sign + * @param side * @param lines * The four lines on the sign. */ - public void queueSignChange(Actor actor, Location loc, BlockData type, String[] lines) { + public void queueSignChange(Actor actor, Location loc, BlockState state, Side side, String[] lines) { + BlockData type = state.getBlockData(); if (!BukkitUtils.isSign(type.getMaterial())) { return; } - queueBlock(actor, loc, type, type, null, BlockStateCodecSign.serialize(lines), null); + queueBlock(actor, loc, type, type, null, BlockStateCodecSign.INSTANCE.serialize(state, side, lines), null); } public void queueChat(Actor player, String message) { diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index d3387369..a1348933 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -9,6 +9,7 @@ import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.data.BlockData; +import org.bukkit.block.sign.Side; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.inventory.ItemStack; @@ -674,7 +675,7 @@ boolean update() { if (!nullBlock && signText != null) { String[] lines = signText.split("\0", 4); - byte[] bytes = Utils.serializeYamlConfiguration(BlockStateCodecSign.serialize(lines)); + byte[] bytes = Utils.serializeYamlConfiguration(BlockStateCodecSign.INSTANCE.serialize(null, Side.FRONT, lines)); Material replacedMaterial = MaterialConverter.getBlockData(replaced, -1).getMaterial(); Material typeMaterial = MaterialConverter.getBlockData(type, -1).getMaterial(); diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index fb566a97..1cc86d3f 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -1,6 +1,7 @@ package de.diddiz.LogBlock.blockstate; import de.diddiz.LogBlock.util.BukkitUtils; +import de.diddiz.LogBlock.util.Reflections; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -8,9 +9,15 @@ import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; +import org.bukkit.block.sign.Side; +import org.bukkit.block.sign.SignSide; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; public class BlockStateCodecSign implements BlockStateCodec { + + public static final BlockStateCodecSign INSTANCE = new BlockStateCodecSign(); + @Override public Material[] getApplicableMaterials() { return BukkitUtils.getAllSignMaterials().toArray(new Material[BukkitUtils.getAllSignMaterials().size()]); @@ -18,44 +25,63 @@ public Material[] getApplicableMaterials() { @Override public YamlConfiguration serialize(BlockState state) { - if (state instanceof Sign) { - Sign sign = (Sign) state; - String[] lines = sign.getLines(); - boolean hasText = false; - for (int i = 0; i < lines.length; i++) { - if (lines[i] != null && lines[i].length() > 0) { - hasText = true; - break; - } - } - DyeColor signColor = sign.getColor(); - if (signColor == null) { - signColor = DyeColor.BLACK; + YamlConfiguration conf = null; + if (state instanceof Sign sign) { + boolean waxed = Reflections.isSignWaxed(sign); + if (waxed) { + conf = new YamlConfiguration(); + conf.set("waxed", waxed); } - if (hasText || signColor != DyeColor.BLACK) { - YamlConfiguration conf = new YamlConfiguration(); - if (hasText) { - conf.set("lines", Arrays.asList(lines)); + for (Side side : Side.values()) { + SignSide signSide = sign.getSide(side); + String[] lines = signSide.getLines(); + boolean hasText = false; + for (int i = 0; i < lines.length; i++) { + if (lines[i] != null && lines[i].length() > 0) { + hasText = true; + break; + } } - if (signColor != DyeColor.BLACK) { - conf.set("color", signColor.name()); + DyeColor signColor = signSide.getColor(); + if (signColor == null) { + signColor = DyeColor.BLACK; } - if (sign.isGlowingText()) { - conf.set("glowing", true); + boolean glowing = signSide.isGlowingText(); + if (hasText || signColor != DyeColor.BLACK || glowing) { + if (conf == null) { + conf = new YamlConfiguration(); + } + ConfigurationSection sideSection = side == Side.FRONT ? conf : conf.createSection(side.name().toLowerCase()); + if (hasText) { + sideSection.set("lines", Arrays.asList(lines)); + } + if (signColor != DyeColor.BLACK) { + sideSection.set("color", signColor.name()); + } + if (glowing) { + sideSection.set("glowing", true); + } } - return conf; } } - return null; + return conf; } /** - * This is required for the SignChangeEvent, because we have no BlockState there. + * This is required for the SignChangeEvent, because we have no updated BlockState there. + * @param state */ - public static YamlConfiguration serialize(String[] lines) { - YamlConfiguration conf = new YamlConfiguration(); + public YamlConfiguration serialize(BlockState state, Side side, String[] lines) { + YamlConfiguration conf = state == null ? null : serialize(state); if (lines != null) { - conf.set("lines", Arrays.asList(lines)); + if (conf == null) { + conf = new YamlConfiguration(); + } + ConfigurationSection sideSection = side == Side.FRONT ? conf : conf.getConfigurationSection(side.name().toLowerCase()); + if (sideSection == null) { + sideSection = conf.createSection(side.name().toLowerCase()); + } + sideSection.set("lines", Arrays.asList(lines)); } return conf; } @@ -64,82 +90,105 @@ public static YamlConfiguration serialize(String[] lines) { public void deserialize(BlockState state, YamlConfiguration conf) { if (state instanceof Sign) { Sign sign = (Sign) state; - DyeColor signColor = DyeColor.BLACK; - boolean glowing = false; - List lines = Collections.emptyList(); if (conf != null) { - if (conf.contains("lines")) { - lines = conf.getStringList("lines"); - } - if (conf.contains("color")) { - try { - signColor = DyeColor.valueOf(conf.getString("color")); - } catch (IllegalArgumentException | NullPointerException e) { - // ignored + sign.setEditable(!conf.getBoolean("waxed")); + for (Side side : Side.values()) { + ConfigurationSection sideSection = side == Side.FRONT ? conf : conf.getConfigurationSection(side.name().toLowerCase()); + DyeColor signColor = DyeColor.BLACK; + boolean glowing = false; + List lines = Collections.emptyList(); + if (sideSection != null) { + if (sideSection.contains("lines")) { + lines = sideSection.getStringList("lines"); + } + if (sideSection.contains("color")) { + try { + signColor = DyeColor.valueOf(sideSection.getString("color")); + } catch (IllegalArgumentException | NullPointerException e) { + // ignored + } + } + glowing = sideSection.getBoolean("glowing", false); } + SignSide signSide = sign.getSide(side); + for (int i = 0; i < 4; i++) { + String line = lines.size() > i && lines.get(i) != null ? lines.get(i) : ""; + signSide.setLine(i, line); + } + signSide.setColor(signColor); + signSide.setGlowingText(glowing); } - glowing = conf.getBoolean("glowing", false); - } - for (int i = 0; i < 4; i++) { - String line = lines.size() > i && lines.get(i) != null ? lines.get(i) : ""; - sign.setLine(i, line); } - sign.setColor(signColor); - sign.setGlowingText(glowing); } } @Override public String toString(YamlConfiguration state, YamlConfiguration oldState) { if (state != null) { - List lines = state.getStringList("lines"); - List oldLines = Collections.emptyList(); - DyeColor signColor = DyeColor.BLACK; - if (state.contains("color")) { - try { - signColor = DyeColor.valueOf(state.getString("color")); - } catch (IllegalArgumentException | NullPointerException e) { - // ignored - } + StringBuilder sb = new StringBuilder(); + boolean isWaxed = state.getBoolean("waxed"); + boolean oldWaxed = oldState != null && oldState.getBoolean("waxed"); + if (isWaxed != oldWaxed) { + sb.append(isWaxed ? "(waxed)" : "(not waxed)"); } - DyeColor oldSignColor = DyeColor.BLACK; - boolean glowing = state.getBoolean("glowing", false); - boolean oldGlowing = false; - if (oldState != null) { - oldLines = oldState.getStringList("lines"); - if (oldState.contains("color")) { + for (Side side : Side.values()) { + ConfigurationSection sideSection = side == Side.FRONT ? state : state.getConfigurationSection(side.name().toLowerCase()); + if (!sb.isEmpty()) { + sb.append(" "); + } + sb.append(side.name()).append(":"); + + List lines = sideSection == null ? Collections.emptyList() : sideSection.getStringList("lines"); + List oldLines = Collections.emptyList(); + DyeColor signColor = DyeColor.BLACK; + if (sideSection != null && sideSection.contains("color")) { try { - oldSignColor = DyeColor.valueOf(oldState.getString("color")); + signColor = DyeColor.valueOf(sideSection.getString("color")); } catch (IllegalArgumentException | NullPointerException e) { // ignored } } - oldGlowing = oldState.getBoolean("glowing", false); - } + DyeColor oldSignColor = DyeColor.BLACK; + boolean glowing = sideSection != null && sideSection.getBoolean("glowing", false); + boolean oldGlowing = false; + if (oldState != null) { + ConfigurationSection oldSideSection = side == Side.FRONT ? oldState : oldState.getConfigurationSection(side.name().toLowerCase()); + if (oldSideSection != null) { + oldLines = oldSideSection.getStringList("lines"); + if (oldSideSection.contains("color")) { + try { + oldSignColor = DyeColor.valueOf(oldSideSection.getString("color")); + } catch (IllegalArgumentException | NullPointerException e) { + // ignored + } + } + oldGlowing = oldSideSection.getBoolean("glowing", false); + } + } - StringBuilder sb = new StringBuilder(); - if (!lines.equals(oldLines)) { - for (String line : lines) { + if (!lines.equals(oldLines)) { + for (String line : lines) { + if (sb.length() > 0) { + sb.append(" "); + } + sb.append("[").append(line).append("]"); + } + } + if (signColor != oldSignColor) { if (sb.length() > 0) { sb.append(" "); } - sb.append("[").append(line).append("]"); + sb.append("(color: " + signColor.name().toLowerCase() + ")"); } - } - if (signColor != oldSignColor) { - if (sb.length() > 0) { - sb.append(" "); - } - sb.append("(color: " + signColor.name().toLowerCase() + ")"); - } - if (glowing != oldGlowing) { - if (sb.length() > 0) { - sb.append(" "); - } - if (glowing) { - sb.append("(glowing)"); - } else { - sb.append("(not glowing)"); + if (glowing != oldGlowing) { + if (sb.length() > 0) { + sb.append(" "); + } + if (glowing) { + sb.append("(glowing)"); + } else { + sb.append("(not glowing)"); + } } } return sb.toString(); diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java index a33c7f70..0f397763 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java @@ -21,7 +21,7 @@ public static void registerCodec(BlockStateCodec codec) { } static { - registerCodec(new BlockStateCodecSign()); + registerCodec(BlockStateCodecSign.INSTANCE); registerCodec(new BlockStateCodecSkull()); registerCodec(new BlockStateCodecBanner()); registerCodec(new BlockStateCodecSpawner()); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index 77f1061d..aacc6035 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -5,6 +5,7 @@ import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.LogBlock.util.BukkitUtils; +import de.diddiz.LogBlock.util.Reflections; import java.util.UUID; import org.bukkit.DyeColor; import org.bukkit.GameEvent; @@ -30,6 +31,8 @@ import org.bukkit.block.data.type.Repeater; import org.bukkit.block.data.type.Switch; import org.bukkit.block.data.type.TurtleEgg; +import org.bukkit.block.sign.Side; +import org.bukkit.block.sign.SignSide; import org.bukkit.entity.Player; import org.bukkit.event.Event.Result; import org.bukkit.event.EventHandler; @@ -93,30 +96,34 @@ public void onPlayerInteract(PlayerInteractEvent event) { } else if (BukkitUtils.isSign(type)) { if (wcfg.isLogging(Logging.SIGNTEXT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getItem() != null) { Material itemType = event.getItem().getType(); - if (BukkitUtils.isDye(itemType) || itemType == Material.GLOW_INK_SAC || itemType == Material.INK_SAC) { + if (BukkitUtils.isDye(itemType) || itemType == Material.GLOW_INK_SAC || itemType == Material.INK_SAC || itemType == Material.HONEYCOMB) { final BlockState before = event.getClickedBlock().getState(); - if (before instanceof Sign) { - if (itemType == Material.GLOW_INK_SAC) { - Sign signBefore = (Sign) before; - if (!signBefore.isGlowingText()) { - final Sign signAfter = (Sign) event.getClickedBlock().getState(); - signAfter.setGlowingText(true); - consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); - } - } else if (itemType == Material.INK_SAC) { - Sign signBefore = (Sign) before; - if (signBefore.isGlowingText()) { - final Sign signAfter = (Sign) event.getClickedBlock().getState(); - signAfter.setGlowingText(false); - consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); - } - } else { - DyeColor newColor = BukkitUtils.dyeToDyeColor(itemType); - Sign signBefore = (Sign) before; - if (newColor != null && signBefore.getColor() != newColor) { - final Sign signAfter = (Sign) event.getClickedBlock().getState(); - signAfter.setColor(newColor); + if (before instanceof Sign signBefore) { + boolean waxed = Reflections.isSignWaxed(signBefore); + if (!waxed) { + final Sign signAfter = (Sign) event.getClickedBlock().getState(); + Side side = BukkitUtils.getFacingSignSide(player, clicked); + SignSide signSideBefore = signBefore.getSide(side); + SignSide signSideAfter = signAfter.getSide(side); + if (itemType == Material.GLOW_INK_SAC) { + if (!signSideBefore.isGlowingText()) { + signSideAfter.setGlowingText(true); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } + } else if (itemType == Material.INK_SAC) { + if (signSideBefore.isGlowingText()) { + signSideAfter.setGlowingText(false); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } + } else if (itemType == Material.HONEYCOMB) { + signAfter.setEditable(false); consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } else if (BukkitUtils.isDye(itemType)) { + DyeColor newColor = BukkitUtils.dyeToDyeColor(itemType); + if (newColor != null && signSideBefore.getColor() != newColor) { + signSideAfter.setColor(newColor); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java index 5622ce50..fe421782 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java @@ -17,7 +17,7 @@ public SignChangeLogging(LogBlock lb) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSignChange(SignChangeEvent event) { if (isLogging(event.getBlock().getWorld(), Logging.SIGNTEXT)) { - consumer.queueSignChange(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getLocation(), event.getBlock().getBlockData(), event.getLines()); + consumer.queueSignChange(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getLocation(), event.getBlock().getState(), event.getSide(), event.getLines()); } } } diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index f4babf36..91d19c0c 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -36,9 +36,16 @@ import org.bukkit.block.data.Bisected; import org.bukkit.block.data.Bisected.Half; import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Directional; +import org.bukkit.block.data.Rotatable; +import org.bukkit.block.data.type.HangingSign; +import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.Slab; import org.bukkit.block.data.type.Slab.Type; import org.bukkit.block.data.type.Stairs; +import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.block.data.type.WallSign; +import org.bukkit.block.sign.Side; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -1223,4 +1230,83 @@ public static boolean isPressurePlate(Material m) { public static boolean isSign(Material m) { return allSigns.contains(m); } + + public static Side getFacingSignSide(Entity entity, Block sign) { + BlockData data = sign.getBlockData(); + Material type = data.getMaterial(); + BlockFace signFace = null; + double centerx = 0.5; + double centerz = 0.5; + double yRotationDegree = 0; + if (type.data == Sign.class || type.data == HangingSign.class) { + Rotatable rotatableData = (Rotatable) data; + signFace = rotatableData.getRotation(); + if (signFace == BlockFace.SOUTH) { + yRotationDegree = 360 * 0.0 / 16.0; + } else if (signFace == BlockFace.SOUTH_SOUTH_WEST) { + yRotationDegree = 360 * 1.0 / 16.0; + } else if (signFace == BlockFace.SOUTH_WEST) { + yRotationDegree = 360 * 2.0 / 16.0; + } else if (signFace == BlockFace.WEST_SOUTH_WEST) { + yRotationDegree = 360 * 3.0 / 16.0; + } else if (signFace == BlockFace.WEST) { + yRotationDegree = 360 * 4.0 / 16.0; + } else if (signFace == BlockFace.WEST_NORTH_WEST) { + yRotationDegree = 360 * 5.0 / 16.0; + } else if (signFace == BlockFace.NORTH_WEST) { + yRotationDegree = 360 * 6.0 / 16.0; + } else if (signFace == BlockFace.NORTH_NORTH_WEST) { + yRotationDegree = 360 * 7.0 / 16.0; + } else if (signFace == BlockFace.NORTH) { + yRotationDegree = 360 * 8.0 / 16.0; + } else if (signFace == BlockFace.NORTH_NORTH_EAST) { + yRotationDegree = 360 * 9.0 / 16.0; + } else if (signFace == BlockFace.NORTH_EAST) { + yRotationDegree = 360 * 10.0 / 16.0; + } else if (signFace == BlockFace.EAST_NORTH_EAST) { + yRotationDegree = 360 * 11.0 / 16.0; + } else if (signFace == BlockFace.EAST) { + yRotationDegree = 360 * 12.0 / 16.0; + } else if (signFace == BlockFace.EAST_SOUTH_EAST) { + yRotationDegree = 360 * 13.0 / 16.0; + } else if (signFace == BlockFace.SOUTH_EAST) { + yRotationDegree = 360 * 14.0 / 16.0; + } else if (signFace == BlockFace.SOUTH_SOUTH_EAST) { + yRotationDegree = 360 * 15.0 / 16.0; + } + } else if (type.data == WallSign.class || type.data == WallHangingSign.class) { + Directional directionalData = (Directional) data; + signFace = directionalData.getFacing(); + if (signFace == BlockFace.SOUTH) { + yRotationDegree = 0; + } else if (signFace == BlockFace.WEST) { + yRotationDegree = 90; + } else if (signFace == BlockFace.NORTH) { + yRotationDegree = 180; + } else if (signFace == BlockFace.EAST) { + yRotationDegree = 270; + } + // wall signs are not centered on the block (but hanging wall signs are) + if (type.data == WallSign.class) { + if (signFace == BlockFace.NORTH) { + centerz = 15.0 / 16.0; + } else if (signFace == BlockFace.SOUTH) { + centerz = 1.0 / 16.0; + } else if (signFace == BlockFace.WEST) { + centerx = 15.0 / 16.0; + } else if (signFace == BlockFace.EAST) { + centerx = 1.0 / 16.0; + } + } + } else { + throw new IllegalArgumentException("block is not a sign"); + } + + Location entityLoc = entity.getLocation(); + double relativeX = entityLoc.getX() - (sign.getX() + centerx); + double relativeZ = entityLoc.getZ() - (sign.getZ() + centerz); + double f = Math.atan2(relativeZ, relativeX) * 180.0 / Math.PI - 90.0; + + return Math.abs(Utils.warpDegrees(f - yRotationDegree)) <= 90.0 ? Side.FRONT : Side.BACK; + } } diff --git a/src/main/java/de/diddiz/LogBlock/util/Reflections.java b/src/main/java/de/diddiz/LogBlock/util/Reflections.java new file mode 100644 index 00000000..5c50cc20 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/util/Reflections.java @@ -0,0 +1,36 @@ +package de.diddiz.LogBlock.util; + +import de.diddiz.LogBlock.LogBlock; +import java.lang.reflect.Field; +import java.util.logging.Level; +import org.bukkit.block.Sign; + +public class Reflections { + private static Field FIELD_CraftBlockEntityState_snapshot; + private static Field FIELD_SignBlockEntity_isWaxed; + + public static boolean isSignWaxed(Sign sign) { + try { + if (FIELD_CraftBlockEntityState_snapshot == null) { + FIELD_CraftBlockEntityState_snapshot = sign.getClass().getSuperclass().getDeclaredField("snapshot"); + FIELD_CraftBlockEntityState_snapshot.setAccessible(true); + } + Object snapshot = FIELD_CraftBlockEntityState_snapshot.get(sign); + if (snapshot == null) { + return false; + } + if (FIELD_SignBlockEntity_isWaxed == null) { + for (Field f : snapshot.getClass().getDeclaredFields()) { + if (f.getType() == boolean.class) { + FIELD_SignBlockEntity_isWaxed = f; + FIELD_SignBlockEntity_isWaxed.setAccessible(true); + } + } + } + return FIELD_SignBlockEntity_isWaxed != null && FIELD_SignBlockEntity_isWaxed.getBoolean(snapshot); + } catch (SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Sign.isWaxed reflection failed", e); + } + return false; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/util/Utils.java b/src/main/java/de/diddiz/LogBlock/util/Utils.java index e84f1f95..2c62a90f 100644 --- a/src/main/java/de/diddiz/LogBlock/util/Utils.java +++ b/src/main/java/de/diddiz/LogBlock/util/Utils.java @@ -284,4 +284,15 @@ public static byte[] serializeYamlConfiguration(YamlConfiguration conf) { public static String serializeForSQL(YamlConfiguration conf) { return mysqlPrepareBytesForInsertAllowNull(serializeYamlConfiguration(conf)); } + + public static double warpDegrees(double degrees) { + double d = degrees % 360.0; + if (d >= 180.0) { + d -= 360.0; + } + if (d < -180.0) { + d += 360.0; + } + return d; + } } From 05269c69788004d4a69e0e29b3651af01f1658a6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 12 Jun 2023 03:43:20 +0200 Subject: [PATCH 340/399] version is now 1.20 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f0a5c712..1eb9c565 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ de.diddiz logblock - 1.19.0.0-SNAPSHOT + 1.20.0.0-SNAPSHOT jar LogBlock From 5fdecb77cdeeefb02c408b3cf5c9f8e0699f4d9f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 12 Jun 2023 05:29:06 +0200 Subject: [PATCH 341/399] improve block state display --- .../java/de/diddiz/LogBlock/BlockChange.java | 20 ++++---- .../LogBlock/blockstate/BlockStateCodec.java | 3 +- .../blockstate/BlockStateCodecBanner.java | 4 +- .../blockstate/BlockStateCodecLectern.java | 10 ++-- .../blockstate/BlockStateCodecShulkerBox.java | 6 ++- .../blockstate/BlockStateCodecSign.java | 47 ++++++++++++------- .../blockstate/BlockStateCodecSkull.java | 15 ++++-- .../blockstate/BlockStateCodecSpawner.java | 6 ++- .../LogBlock/blockstate/BlockStateCodecs.java | 6 +-- .../diddiz/LogBlock/util/MessagingUtil.java | 9 ++++ 10 files changed, 81 insertions(+), 45 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 041e82b9..83ae93e2 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -83,25 +83,27 @@ public BlockChange(ResultSet rs, QueryParams p) throws SQLException { ca = catemp; } - private String getTypeDetails(BlockData type, byte[] typeState) { + private BaseComponent getTypeDetails(BlockData type, byte[] typeState) { return getTypeDetails(type, typeState, null, null); } - private String getTypeDetails(BlockData type, byte[] typeState, BlockData oldType, byte[] oldTypeState) { - String typeDetails = null; + private BaseComponent getTypeDetails(BlockData type, byte[] typeState, BlockData oldType, byte[] oldTypeState) { + BaseComponent typeDetails = null; if (BlockStateCodecs.hasCodec(type.getMaterial())) { try { - typeDetails = BlockStateCodecs.toString(type.getMaterial(), Utils.deserializeYamlConfiguration(typeState), type.equals(oldType) ? Utils.deserializeYamlConfiguration(oldTypeState) : null); + typeDetails = BlockStateCodecs.getChangesAsComponent(type.getMaterial(), Utils.deserializeYamlConfiguration(typeState), type.equals(oldType) ? Utils.deserializeYamlConfiguration(oldTypeState) : null); } catch (Exception e) { LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + type.getMaterial(), e); } } if (typeDetails == null) { - return ""; + return new TextComponent(""); } else { - return " " + typeDetails; + TextComponent component = new TextComponent(" "); + component.addExtra(typeDetails); + return component; } } @@ -129,8 +131,8 @@ public BaseComponent[] getLogMessage(int entry) { } // Process type details once for later use. - String typeDetails = getTypeDetails(type, typeState, replaced, replacedState); - String replacedDetails = getTypeDetails(replaced, replacedState); + BaseComponent typeDetails = getTypeDetails(type, typeState, replaced, replacedState); + BaseComponent replacedDetails = getTypeDetails(replaced, replacedState); if (type.getMaterial().equals(replaced.getMaterial()) || (type.getMaterial() == Material.CAKE && BukkitUtils.isCandleCake(replaced.getMaterial()))) { if (BukkitUtils.isEmpty(type.getMaterial())) { @@ -201,7 +203,7 @@ public BaseComponent[] getLogMessage(int entry) { msg.addExtra(createTextComponentWithColor("changed the book on a ", INTERACT.getColor())); msg.addExtra(prettyMaterial(type)); msg.addExtra(" to"); - msg.addExtra(prettyState(typeDetails.length() == 0 ? " empty" : typeDetails)); + msg.addExtra(prettyState(typeDetails)); } else if (type instanceof Powerable) { msg.addExtra(createTextComponentWithColor("stepped on ", INTERACT.getColor())); msg.addExtra(prettyMaterial(type)); diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java index 28e9e3f6..65ed64b4 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock.blockstate; +import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.configuration.file.YamlConfiguration; @@ -11,5 +12,5 @@ public interface BlockStateCodec { void deserialize(BlockState state, YamlConfiguration conf); - String toString(YamlConfiguration conf, YamlConfiguration oldState); + BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState); } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java index 8cd7a166..e62652c6 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java @@ -1,7 +1,7 @@ package de.diddiz.LogBlock.blockstate; import java.util.List; - +import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.block.Banner; @@ -64,7 +64,7 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public String toString(YamlConfiguration conf, YamlConfiguration oldState) { + public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { return null; } } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java index ab7f764e..6c897bc4 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java @@ -1,5 +1,7 @@ package de.diddiz.LogBlock.blockstate; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.block.Lectern; @@ -43,12 +45,10 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public String toString(YamlConfiguration conf, YamlConfiguration oldState) { + public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { if (conf != null) { - StringBuilder sb = new StringBuilder(); - sb.append("[").append("book").append("]"); - return sb.toString(); + return new TextComponent("[book]"); } - return null; + return new TextComponent("empty"); } } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java index d26c2343..9e632384 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java @@ -5,6 +5,8 @@ import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.LogBlock.util.BukkitUtils; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.block.ShulkerBox; @@ -60,7 +62,7 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public String toString(YamlConfiguration conf, YamlConfiguration oldState) { + public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { if (conf != null) { StringBuilder sb = new StringBuilder(); sb.append("["); @@ -78,7 +80,7 @@ public String toString(YamlConfiguration conf, YamlConfiguration oldState) { } } sb.append("]"); - return anySlot ? sb.toString() : null; + return anySlot ? new TextComponent(sb.toString()) : null; } return null; } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index 1cc86d3f..f97a30b3 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -2,9 +2,13 @@ import de.diddiz.LogBlock.util.BukkitUtils; import de.diddiz.LogBlock.util.Reflections; +import java.awt.Color; import java.util.Arrays; import java.util.Collections; import java.util.List; +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.block.BlockState; @@ -123,20 +127,21 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public String toString(YamlConfiguration state, YamlConfiguration oldState) { + public BaseComponent getChangesAsComponent(YamlConfiguration state, YamlConfiguration oldState) { if (state != null) { - StringBuilder sb = new StringBuilder(); + TextComponent tc = new TextComponent(); + // StringBuilder sb = new StringBuilder(); boolean isWaxed = state.getBoolean("waxed"); boolean oldWaxed = oldState != null && oldState.getBoolean("waxed"); if (isWaxed != oldWaxed) { - sb.append(isWaxed ? "(waxed)" : "(not waxed)"); + tc.addExtra(isWaxed ? "(waxed)" : "(not waxed)"); } for (Side side : Side.values()) { ConfigurationSection sideSection = side == Side.FRONT ? state : state.getConfigurationSection(side.name().toLowerCase()); - if (!sb.isEmpty()) { - sb.append(" "); + if (tc.getExtra() != null && !tc.getExtra().isEmpty()) { + tc.addExtra(" "); } - sb.append(side.name()).append(":"); + tc.addExtra(side.name() + ":"); List lines = sideSection == null ? Collections.emptyList() : sideSection.getStringList("lines"); List oldLines = Collections.emptyList(); @@ -168,30 +173,38 @@ public String toString(YamlConfiguration state, YamlConfiguration oldState) { if (!lines.equals(oldLines)) { for (String line : lines) { - if (sb.length() > 0) { - sb.append(" "); + if (tc.getExtra() != null && !tc.getExtra().isEmpty()) { + tc.addExtra(" "); } - sb.append("[").append(line).append("]"); + tc.addExtra("["); + if (line != null && !line.isEmpty()) { + tc.addExtra(new TextComponent(TextComponent.fromLegacyText(line))); + } + tc.addExtra("]"); } } if (signColor != oldSignColor) { - if (sb.length() > 0) { - sb.append(" "); + if (tc.getExtra() != null && !tc.getExtra().isEmpty()) { + tc.addExtra(" "); } - sb.append("(color: " + signColor.name().toLowerCase() + ")"); + tc.addExtra("(color: "); + TextComponent colorText = new TextComponent(signColor.name().toLowerCase()); + colorText.setColor(ChatColor.of(new Color(signColor.getColor().asARGB()))); + tc.addExtra(colorText); + tc.addExtra(")"); } if (glowing != oldGlowing) { - if (sb.length() > 0) { - sb.append(" "); + if (tc.getExtra() != null && !tc.getExtra().isEmpty()) { + tc.addExtra(" "); } if (glowing) { - sb.append("(glowing)"); + tc.addExtra("(glowing)"); } else { - sb.append("(not glowing)"); + tc.addExtra("(not glowing)"); } } } - return sb.toString(); + return tc; } return null; } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java index d4ad35c8..0f21426d 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java @@ -1,7 +1,10 @@ package de.diddiz.LogBlock.blockstate; import java.util.UUID; - +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.chat.hover.content.Text; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.OfflinePlayer; @@ -65,18 +68,22 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public String toString(YamlConfiguration conf, YamlConfiguration oldState) { + public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { if (HAS_PROFILE_API && conf != null) { PlayerProfile profile = (PlayerProfile) conf.get("profile"); if (profile != null) { - return "[" + (profile.getName() != null ? profile.getName() : (profile.getUniqueId() != null ? profile.getUniqueId().toString() : "~unknown~")) + "]"; + TextComponent tc = new TextComponent("[" + (profile.getName() != null ? profile.getName() : (profile.getUniqueId() != null ? profile.getUniqueId().toString() : "~unknown~")) + "]"); + if (profile.getName() != null) { + tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("UUID: " + profile.getUniqueId().toString()))); + } + return tc; } } String ownerIdString = conf == null ? null : conf.getString("owner"); UUID ownerId = ownerIdString == null ? null : UUID.fromString(ownerIdString); if (ownerId != null) { OfflinePlayer owner = Bukkit.getOfflinePlayer(ownerId); - return "[" + (owner.getName() != null ? owner.getName() : owner.getUniqueId().toString()) + "]"; + return new TextComponent("[" + (owner.getName() != null ? owner.getName() : owner.getUniqueId().toString()) + "]"); } return null; } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java index 0d93fe99..8220b5d8 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java @@ -1,5 +1,7 @@ package de.diddiz.LogBlock.blockstate; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.block.CreatureSpawner; @@ -48,11 +50,11 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public String toString(YamlConfiguration conf, YamlConfiguration oldState) { + public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { if (conf != null) { EntityType entity = EntityType.valueOf(conf.getString("spawnedType")); if (entity != null) { - return "[" + entity + "]"; + return new TextComponent("[" + entity.getKey().getKey() + "]"); } } return null; diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java index 0f397763..b2be20fa 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java @@ -2,7 +2,7 @@ import java.util.HashMap; import java.util.Map; - +import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.configuration.file.YamlConfiguration; @@ -51,10 +51,10 @@ public static void deserialize(BlockState block, YamlConfiguration state) { } } - public static String toString(Material material, YamlConfiguration state, YamlConfiguration oldState) { + public static BaseComponent getChangesAsComponent(Material material, YamlConfiguration state, YamlConfiguration oldState) { BlockStateCodec codec = codecs.get(material); if (codec != null) { - return codec.toString(state, oldState); + return codec.getChangesAsComponent(state, oldState); } return null; } diff --git a/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java b/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java index 3a828945..343f2542 100644 --- a/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java +++ b/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java @@ -49,6 +49,15 @@ public static TextComponent prettyState(String stateName) { return createTextComponentWithColor(stateName, TypeColor.STATE.getColor()); } + public static TextComponent prettyState(BaseComponent stateName) { + TextComponent tc = new TextComponent(); + tc.setColor(TypeColor.STATE.getColor()); + if (stateName != null) { + tc.addExtra(stateName); + } + return tc; + } + public static TextComponent prettyState(int stateValue) { return prettyState(Integer.toString(stateValue)); } From a6e0e72fb6d8c230664307796870dc0c950f3597 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 12 Jun 2023 05:54:46 +0200 Subject: [PATCH 342/399] cleanup sign logging --- .../java/de/diddiz/LogBlock/Consumer.java | 23 ------------------- src/main/java/de/diddiz/LogBlock/Updater.java | 3 ++- .../blockstate/BlockStateCodecSign.java | 13 ++++++++--- .../LogBlock/blockstate/BlockStateCodecs.java | 2 +- .../LogBlock/listeners/SignChangeLogging.java | 12 +++++++++- 5 files changed, 24 insertions(+), 29 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 91a8abff..67e1e2ca 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -36,7 +36,6 @@ import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.sign.Side; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -48,7 +47,6 @@ import org.bukkit.projectiles.ProjectileSource; import de.diddiz.LogBlock.EntityChange.EntityChangeType; -import de.diddiz.LogBlock.blockstate.BlockStateCodecSign; import de.diddiz.LogBlock.blockstate.BlockStateCodecs; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.events.BlockChangePreLogEvent; @@ -332,27 +330,6 @@ public void queueKill(Location location, Actor killer, Actor victim, ItemStack w addQueueLast(new KillRow(location, killer == null ? null : killer, victim, weapon == null ? 0 : MaterialConverter.getOrAddMaterialId(weapon.getType()))); } - /** - * Logs an actor placing a sign along with its contents - * - * @param actor - * Actor placing the sign - * @param loc - * Location of the placed sign - * @param type - * BlockData of the sign - * @param side - * @param lines - * The four lines on the sign. - */ - public void queueSignChange(Actor actor, Location loc, BlockState state, Side side, String[] lines) { - BlockData type = state.getBlockData(); - if (!BukkitUtils.isSign(type.getMaterial())) { - return; - } - queueBlock(actor, loc, type, type, null, BlockStateCodecSign.INSTANCE.serialize(state, side, lines), null); - } - public void queueChat(Actor player, String message) { if (!Config.ignoredChat.isEmpty()) { String lowerCaseMessage = message.toLowerCase(); diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index a1348933..8cf38977 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -638,6 +638,7 @@ boolean update() { if (configVersion.compareTo(new ComparableVersion("1.13.1")) < 0) { logblock.getLogger().info("Updating tables to 1.13.1 ..."); + BlockStateCodecSign signCodec = new BlockStateCodecSign(); try (Connection conn = logblock.getConnection()) { conn.setAutoCommit(false); final Statement st = conn.createStatement(); @@ -675,7 +676,7 @@ boolean update() { if (!nullBlock && signText != null) { String[] lines = signText.split("\0", 4); - byte[] bytes = Utils.serializeYamlConfiguration(BlockStateCodecSign.INSTANCE.serialize(null, Side.FRONT, lines)); + byte[] bytes = Utils.serializeYamlConfiguration(signCodec.serialize(null, Side.FRONT, lines)); Material replacedMaterial = MaterialConverter.getBlockData(replaced, -1).getMaterial(); Material typeMaterial = MaterialConverter.getBlockData(type, -1).getMaterial(); diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index f97a30b3..64c2570c 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -19,9 +19,6 @@ import org.bukkit.configuration.file.YamlConfiguration; public class BlockStateCodecSign implements BlockStateCodec { - - public static final BlockStateCodecSign INSTANCE = new BlockStateCodecSign(); - @Override public Material[] getApplicableMaterials() { return BukkitUtils.getAllSignMaterials().toArray(new Material[BukkitUtils.getAllSignMaterials().size()]); @@ -122,6 +119,16 @@ public void deserialize(BlockState state, YamlConfiguration conf) { signSide.setColor(signColor); signSide.setGlowingText(glowing); } + } else { + sign.setEditable(true); + for (Side side : Side.values()) { + SignSide signSide = sign.getSide(side); + for (int i = 0; i < 4; i++) { + signSide.setLine(i, ""); + } + signSide.setColor(DyeColor.BLACK); + signSide.setGlowingText(false); + } } } } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java index b2be20fa..4f1ed7c8 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java @@ -21,7 +21,7 @@ public static void registerCodec(BlockStateCodec codec) { } static { - registerCodec(BlockStateCodecSign.INSTANCE); + registerCodec(new BlockStateCodecSign()); registerCodec(new BlockStateCodecSkull()); registerCodec(new BlockStateCodecBanner()); registerCodec(new BlockStateCodecSpawner()); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java index fe421782..ce846761 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java @@ -3,6 +3,9 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; +import org.bukkit.block.BlockState; +import org.bukkit.block.Sign; +import org.bukkit.block.sign.SignSide; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.SignChangeEvent; @@ -17,7 +20,14 @@ public SignChangeLogging(LogBlock lb) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSignChange(SignChangeEvent event) { if (isLogging(event.getBlock().getWorld(), Logging.SIGNTEXT)) { - consumer.queueSignChange(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getLocation(), event.getBlock().getState(), event.getSide(), event.getLines()); + BlockState newState = event.getBlock().getState(); + if (newState instanceof Sign sign) { + SignSide signSide = sign.getSide(event.getSide()); + for (int i = 0; i < 4; i++) { + signSide.setLine(i, event.getLine(i)); + } + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getState(), newState); + } } } } From f743347e662bff9199e1fa72504f76f2b9f58f4c Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 12 Jun 2023 05:55:12 +0200 Subject: [PATCH 343/399] sign dyes can only be applied when there is some text on the sign --- .../LogBlock/listeners/InteractLogging.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index aacc6035..88e68fff 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -106,19 +106,19 @@ public void onPlayerInteract(PlayerInteractEvent event) { SignSide signSideBefore = signBefore.getSide(side); SignSide signSideAfter = signAfter.getSide(side); if (itemType == Material.GLOW_INK_SAC) { - if (!signSideBefore.isGlowingText()) { + if (!signSideBefore.isGlowingText() && hasText(signSideBefore)) { signSideAfter.setGlowingText(true); consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); } } else if (itemType == Material.INK_SAC) { - if (signSideBefore.isGlowingText()) { + if (signSideBefore.isGlowingText() && hasText(signSideBefore)) { signSideAfter.setGlowingText(false); consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); } } else if (itemType == Material.HONEYCOMB) { signAfter.setEditable(false); consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); - } else if (BukkitUtils.isDye(itemType)) { + } else if (BukkitUtils.isDye(itemType) && hasText(signSideBefore)) { DyeColor newColor = BukkitUtils.dyeToDyeColor(itemType); if (newColor != null && signSideBefore.getColor() != newColor) { signSideAfter.setColor(newColor); @@ -223,6 +223,15 @@ public void onPlayerInteract(PlayerInteractEvent event) { } } + private boolean hasText(SignSide signSide) { + for (int i = 0; i < 4; i++) { + if (!signSide.getLine(i).isEmpty()) { + return true; + } + } + return false; + } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onGenericGameEvent(GenericGameEvent event) { if (lastInteractionPlayer != null && event.getEntity() != null && event.getEntity().getUniqueId().equals(lastInteractionPlayer) && lastInteractionLocation != null && event.getLocation().equals(lastInteractionLocation)) { From 547aa81063c5427cad65bbf804f397da93c99146 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 12 Jun 2023 06:26:45 +0200 Subject: [PATCH 344/399] improve Reflections.isSignWaxed --- .../de/diddiz/LogBlock/util/Reflections.java | 43 +++++++++++++++---- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/util/Reflections.java b/src/main/java/de/diddiz/LogBlock/util/Reflections.java index 5c50cc20..83f820d3 100644 --- a/src/main/java/de/diddiz/LogBlock/util/Reflections.java +++ b/src/main/java/de/diddiz/LogBlock/util/Reflections.java @@ -12,24 +12,49 @@ public class Reflections { public static boolean isSignWaxed(Sign sign) { try { if (FIELD_CraftBlockEntityState_snapshot == null) { - FIELD_CraftBlockEntityState_snapshot = sign.getClass().getSuperclass().getDeclaredField("snapshot"); - FIELD_CraftBlockEntityState_snapshot.setAccessible(true); + Class superClass = sign.getClass().getSuperclass(); + while (superClass != null) { + try { + FIELD_CraftBlockEntityState_snapshot = superClass.getDeclaredField("snapshot"); + FIELD_CraftBlockEntityState_snapshot.setAccessible(true); + break; + } catch (NoSuchFieldException ignored) { + } + superClass = superClass.getSuperclass(); + } + } + if (FIELD_CraftBlockEntityState_snapshot == null) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Reflections: Sign field 'snapshot' not found"); + return false; } Object snapshot = FIELD_CraftBlockEntityState_snapshot.get(sign); if (snapshot == null) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Reflections: Sign snapshot is null?"); return false; } if (FIELD_SignBlockEntity_isWaxed == null) { - for (Field f : snapshot.getClass().getDeclaredFields()) { - if (f.getType() == boolean.class) { - FIELD_SignBlockEntity_isWaxed = f; - FIELD_SignBlockEntity_isWaxed.setAccessible(true); + Class snapshotClass = snapshot.getClass(); + while (snapshotClass != null) { + for (Field f : snapshotClass.getDeclaredFields()) { + if (f.getType() == boolean.class) { + FIELD_SignBlockEntity_isWaxed = f; + FIELD_SignBlockEntity_isWaxed.setAccessible(true); + break; + } } + if (FIELD_SignBlockEntity_isWaxed != null) { + break; + } + snapshotClass = snapshotClass.getSuperclass(); } } - return FIELD_SignBlockEntity_isWaxed != null && FIELD_SignBlockEntity_isWaxed.getBoolean(snapshot); - } catch (SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) { - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Sign.isWaxed reflection failed", e); + if (FIELD_SignBlockEntity_isWaxed == null) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Reflections: Sign field 'isWaxed' not found"); + return false; + } + return FIELD_SignBlockEntity_isWaxed.getBoolean(snapshot); + } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Reflections: Sign.isWaxed reflection failed", e); } return false; } From 1c0c6c2d8b827c22937129c067dd511c51ae5a0e Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 21 Jul 2023 02:57:05 +0200 Subject: [PATCH 345/399] cauldron no longer has levels --- src/main/resources/blockdata.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/resources/blockdata.txt b/src/main/resources/blockdata.txt index 3f2b8414..97da67d7 100644 --- a/src/main/resources/blockdata.txt +++ b/src/main/resources/blockdata.txt @@ -919,10 +919,10 @@ 115:15,minecraft:air 116:0,minecraft:enchanting_table 117:0,minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false] -118:0,minecraft:cauldron[level=0] -118:1,minecraft:cauldron[level=1] -118:2,minecraft:cauldron[level=2] -118:3,minecraft:cauldron[level=3] +118:0,minecraft:cauldron +118:1,minecraft:cauldron +118:2,minecraft:cauldron +118:3,minecraft:cauldron 118:4,minecraft:air 118:5,minecraft:air 118:6,minecraft:air From 8786dc253ea7b497873160930b666a3b26c81466 Mon Sep 17 00:00:00 2001 From: Joo200 Date: Tue, 15 Aug 2023 16:29:54 +0200 Subject: [PATCH 346/399] add protocol config option to allow mariadb protocol --- src/main/java/de/diddiz/LogBlock/config/Config.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 99fdd86d..924afc25 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -81,6 +81,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti worldNames.add("world_the_end"); } def.put("loggedWorlds", worldNames); + def.put("mysql.protocol", "mysql"); def.put("mysql.host", "localhost"); def.put("mysql.port", 3306); def.put("mysql.database", "minecraft"); @@ -179,7 +180,7 @@ public static void load(LogBlock logblock) throws DataFormatException, IOExcepti boolean oldConfig = configVersion.compareTo(new ComparableVersion(CURRENT_CONFIG_VERSION)) < 0; mysqlDatabase = getStringIncludingInts(config, "mysql.database"); - url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + mysqlDatabase; + url = "jdbc:" + config.getString("mysql.protocol") + "://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + mysqlDatabase; user = getStringIncludingInts(config, "mysql.user"); password = getStringIncludingInts(config, "mysql.password"); mysqlUseSSL = config.getBoolean("mysql.useSSL", true); From 337a0502bfc520cd73ceee6d1e8373870a6c0eca Mon Sep 17 00:00:00 2001 From: KleinCrafter Date: Thu, 28 Sep 2023 18:02:34 +0200 Subject: [PATCH 347/399] Fix #873 Use Bukkit API for plugin Directory --- src/main/java/de/diddiz/LogBlock/Consumer.java | 7 ++++--- src/main/java/de/diddiz/LogBlock/WorldEditor.java | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 67e1e2ca..827b1c49 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -521,8 +521,9 @@ public void writeToFile() throws FileNotFoundException { final long time = System.currentTimeMillis(); final Set insertedPlayers = new HashSet<>(); int counter = 0; - new File("plugins/LogBlock/import/").mkdirs(); - PrintWriter writer = new PrintWriter(new File("plugins/LogBlock/import/queue-" + time + "-0.sql")); + final File importDir = new File(logblock.getDataFolder(), "import"); + importDir.mkdirs(); + PrintWriter writer = new PrintWriter(new File(importDir, "queue-" + time + "-0.sql")); while (!isQueueEmpty()) { final Row r = pollQueueFirst(); if (r == null) { @@ -541,7 +542,7 @@ public void writeToFile() throws FileNotFoundException { counter++; if (counter % 1000 == 0) { writer.close(); - writer = new PrintWriter(new File("plugins/LogBlock/import/queue-" + time + "-" + counter / 1000 + ".sql")); + writer = new PrintWriter(new File(importDir, "queue-" + time + "-" + counter / 1000 + ".sql")); } } writer.close(); diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 251965cf..0c58dd29 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -182,8 +182,9 @@ public synchronized void run() { logblock.getServer().getScheduler().cancelTask(taskID); if (errorList.size() > 0) { try { - final File file = new File("plugins/LogBlock/error/WorldEditor-" + new SimpleDateFormat("yy-MM-dd-HH-mm-ss").format(System.currentTimeMillis()) + ".log"); - file.getParentFile().mkdirs(); + final File errorDir = new File(logblock.getDataFolder(), "error"); + errorDir.mkdir(); + final File file = new File(errorDir, "WorldEditor-" + new SimpleDateFormat("yy-MM-dd-HH-mm-ss").format(System.currentTimeMillis()) + ".log"); final PrintWriter writer = new PrintWriter(file); for (final WorldEditorException err : errorList) { writer.println(BaseComponent.toPlainText(err.getLogMessage())); From 249ab180917ec02b383d15f688a7e6a9e27630d9 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 29 Sep 2023 03:24:18 +0200 Subject: [PATCH 348/399] use mkdirs() instead of mkdir() and fix formatting --- src/main/java/de/diddiz/LogBlock/WorldEditor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 0c58dd29..c77eeaf1 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -182,8 +182,8 @@ public synchronized void run() { logblock.getServer().getScheduler().cancelTask(taskID); if (errorList.size() > 0) { try { - final File errorDir = new File(logblock.getDataFolder(), "error"); - errorDir.mkdir(); + final File errorDir = new File(logblock.getDataFolder(), "error"); + errorDir.mkdirs(); final File file = new File(errorDir, "WorldEditor-" + new SimpleDateFormat("yy-MM-dd-HH-mm-ss").format(System.currentTimeMillis()) + ".log"); final PrintWriter writer = new PrintWriter(file); for (final WorldEditorException err : errorList) { From a3069292d0ebc64938bab59d02dec635faccbe58 Mon Sep 17 00:00:00 2001 From: KleinCrafter Date: Fri, 29 Sep 2023 12:11:47 +0200 Subject: [PATCH 349/399] Bump api-version to 1.20 --- src/main/resources/plugin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 43cee15f..9c9a7930 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -6,7 +6,7 @@ website: http://dev.bukkit.org/server-mods/logblock/ main: de.diddiz.LogBlock.LogBlock description: ${project.description} softdepend: [WorldEdit, WorldGuard] -api-version: 1.17 +api-version: 1.20 commands: lb: description: 'LogBlock plugin commands' From f5ddf9f9ec8772a7e250208ab98ae9120411db7e Mon Sep 17 00:00:00 2001 From: KleinCrafter Date: Sun, 1 Oct 2023 10:50:37 +0200 Subject: [PATCH 350/399] Fix #875 Update HikariCP slf4j is not needed, removed it --- pom.xml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index 1eb9c565..471fba0f 100644 --- a/pom.xml +++ b/pom.xml @@ -68,13 +68,7 @@ com.zaxxer HikariCP - 3.4.1 - compile - - - org.slf4j - slf4j-jdk14 - 1.7.25 + 5.0.1 compile @@ -174,10 +168,6 @@ com.zaxxer.hikari de.diddiz.lib.com.zaxxer.hikari - - org.slf4j - de.diddiz.lib.org.slf4j - From 499cdbca27ace95c4d72f5bdb864a719390a8862 Mon Sep 17 00:00:00 2001 From: KleinCrafter Date: Sun, 1 Oct 2023 20:32:53 +0200 Subject: [PATCH 351/399] Add .editorconfig --- .editorconfig | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..d774813d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 + +[*.java] +indent_style = space +indent_size = 4 + +[*.yml] +indent_style = space +indent_size = 2 \ No newline at end of file From 19cc874db838634ea82bb72c0227c2c1ddaa9865 Mon Sep 17 00:00:00 2001 From: KleinCrafter Date: Mon, 2 Oct 2023 08:17:16 +0200 Subject: [PATCH 352/399] Add trim_trailing_whitespace to .editorconfig --- .editorconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index d774813d..03601399 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,9 +1,10 @@ root = true [*] +charset = utf-8 end_of_line = lf insert_final_newline = true -charset = utf-8 +trim_trailing_whitespace = true [*.java] indent_style = space @@ -11,4 +12,4 @@ indent_size = 4 [*.yml] indent_style = space -indent_size = 2 \ No newline at end of file +indent_size = 2 From 0c21d821d9c10ba9ac0e57170dfb90b02a1e3e3e Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 9 Oct 2023 08:52:12 +0200 Subject: [PATCH 353/399] Fix line endings --- src/main/java/de/diddiz/LogBlock/Actor.java | 364 +-- .../java/de/diddiz/LogBlock/AutoClearLog.java | 64 +- .../java/de/diddiz/LogBlock/BlockChange.java | 544 ++-- .../java/de/diddiz/LogBlock/ChatMessage.java | 118 +- .../java/de/diddiz/LogBlock/ChestAccess.java | 30 +- .../java/de/diddiz/LogBlock/Consumer.java | 2442 +++++++-------- .../de/diddiz/LogBlock/DumpedLogImporter.java | 294 +- .../java/de/diddiz/LogBlock/LogBlock.java | 756 ++--- .../diddiz/LogBlock/LookupCacheElement.java | 36 +- .../LogBlock/LookupCacheElementFactory.java | 80 +- src/main/java/de/diddiz/LogBlock/Session.java | 98 +- .../diddiz/LogBlock/SummedBlockChanges.java | 86 +- src/main/java/de/diddiz/LogBlock/Tool.java | 70 +- .../java/de/diddiz/LogBlock/ToolBehavior.java | 14 +- .../java/de/diddiz/LogBlock/ToolData.java | 30 +- .../java/de/diddiz/LogBlock/ToolMode.java | 36 +- src/main/java/de/diddiz/LogBlock/Updater.java | 2320 +++++++-------- .../diddiz/LogBlock/config/WorldConfig.java | 342 +-- .../LogBlock/listeners/BanListener.java | 96 +- .../LogBlock/listeners/BlockBreakLogging.java | 148 +- .../LogBlock/listeners/BlockBurnLogging.java | 144 +- .../LogBlock/listeners/BlockPlaceLogging.java | 134 +- .../LogBlock/listeners/ChatLogging.java | 116 +- .../listeners/ChestAccessLogging.java | 606 ++-- .../LogBlock/listeners/EndermenLogging.java | 48 +- .../LogBlock/listeners/ExplosionLogging.java | 458 +-- .../LogBlock/listeners/FluidFlowLogging.java | 254 +- .../LogBlock/listeners/InteractLogging.java | 552 ++-- .../LogBlock/listeners/KillLogging.java | 102 +- .../listeners/LeavesDecayLogging.java | 52 +- .../LogBlock/listeners/LoggingListener.java | 26 +- .../LogBlock/listeners/PlayerInfoLogging.java | 86 +- .../LogBlock/listeners/SignChangeLogging.java | 66 +- .../LogBlock/listeners/SnowFadeLogging.java | 56 +- .../LogBlock/listeners/SnowFormLogging.java | 56 +- .../listeners/StructureGrowLogging.java | 68 +- .../LogBlock/listeners/ToolListener.java | 302 +- .../LogBlock/listeners/WitherLogging.java | 48 +- .../de/diddiz/LogBlock/util/BukkitUtils.java | 2624 ++++++++--------- .../LogBlock/util/ComparableVersion.java | 848 +++--- .../LogBlock/util/MySQLConnectionPool.java | 102 +- .../de/diddiz/LogBlock/util/UUIDFetcher.java | 122 +- .../java/de/diddiz/LogBlock/util/Utils.java | 596 ++-- 43 files changed, 7717 insertions(+), 7717 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index 6364ab97..b13a4640 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -1,182 +1,182 @@ -package de.diddiz.LogBlock; - -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.entity.Projectile; -import org.bukkit.projectiles.BlockProjectileSource; -import org.bukkit.projectiles.ProjectileSource; - -import static de.diddiz.LogBlock.util.BukkitUtils.entityName; - -import java.sql.ResultSet; -import java.sql.SQLException; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.block.Block; - -public class Actor { - - @Override - public int hashCode() { - return this.UUID != null ? this.UUID.hashCode() : 0; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || getClass() != obj.getClass()) { - return false; - } - final Actor other = (Actor) obj; - return (this.UUID == null) ? (other.UUID == null) : this.UUID.equals(other.UUID); - } - - final String name; - final String UUID; - final Location blockLocation; - final Entity entity; - - public Actor(String name, String UUID) { - this.name = name; - this.UUID = UUID == null ? "unknown" : (UUID.length() > 36 ? UUID.substring(0, 36) : UUID); - this.blockLocation = null; - this.entity = null; - } - - public Actor(String name, String UUID, Block block) { - this.name = name; - this.UUID = UUID == null ? "unknown" : (UUID.length() > 36 ? UUID.substring(0, 36) : UUID); - this.blockLocation = block == null ? null : block.getLocation(); - this.entity = null; - } - - public Actor(String name, java.util.UUID UUID) { - this.name = name; - this.UUID = UUID.toString(); - this.blockLocation = null; - this.entity = null; - } - - public Actor(String name, java.util.UUID UUID, Block block) { - this.name = name; - this.UUID = UUID.toString(); - this.blockLocation = block == null ? null : block.getLocation(); - this.entity = null; - } - - public Actor(String name, java.util.UUID UUID, Entity entity) { - this.name = name; - this.UUID = UUID.toString(); - this.blockLocation = null; - this.entity = entity; - } - - public Actor(String name) { - this(name, generateUUID(name)); - } - - public Actor(String name, Block block) { - this(name, generateUUID(name), block); - } - - public Actor(String name, Entity entity) { - this.name = name; - this.UUID = generateUUID(name); - this.blockLocation = null; - this.entity = entity; - } - - public Actor(ResultSet rs) throws SQLException { - this(rs.getString("playername"), rs.getString("UUID")); - } - - public String getName() { - return name; - } - - public String getUUID() { - return UUID; - } - - public Location getBlockLocation() { - return blockLocation; - } - - /** - * The acting entity object (if known) - */ - public Entity getEntity() { - return entity; - } - - public static Actor actorFromEntity(Entity entity) { - if (entity instanceof Player) { - return new Actor(entityName(entity), entity.getUniqueId(), entity); - } - if (entity instanceof Projectile) { - ProjectileSource shooter = ((Projectile) entity).getShooter(); - if (shooter != null) { - return actorFromProjectileSource(shooter); - } - } - return new Actor(entityName(entity), entity); - } - - @Deprecated - public static Actor actorFromEntity(EntityType entity) { - return new Actor(entity.name()); - } - - public static Actor actorFromProjectileSource(ProjectileSource psource) { - if (psource instanceof Entity) { - return actorFromEntity((Entity) psource); - } - if (psource instanceof BlockProjectileSource) { - return new Actor(((BlockProjectileSource) psource).getBlock().getType().toString()); - } else { - return new Actor(psource.toString()); - } - - } - - /** - * Generate an Actor object from a String name, trying to guess if it's an online player - * and if so, setting the UUID accordingly. This only checks against currently online - * players and is a "best effort" attempt for use with the pre-UUID API - *

    - * If you know something is an entity (player or otherwise) use the {@link #actorFromEntity(org.bukkit.entity.Entity) } - * or {@link #actorFromEntity(org.bukkit.entity.EntityType) } methods - *

    - * If you know something is a server effect (like gravity) use {@link #Actor(java.lang.String)} - * - * @deprecated Only use this if you have a String of unknown origin - * - * @param actorName - * String of unknown origin - * @return - */ - @Deprecated - public static Actor actorFromString(String actorName) { - Player p = Bukkit.getServer().getPlayerExact(actorName); - if (p != null) { - return actorFromEntity(p); - } - // No player found online with that name, assuming non-player entity/effect - return new Actor(actorName); - } - - public static boolean isValidUUID(String uuid) { - try { - java.util.UUID.fromString(uuid); - return true; - } catch (IllegalArgumentException e) { - return false; - } - } - - public static String generateUUID(String name) { - return "log_" + name; - - } - -} +package de.diddiz.LogBlock; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.projectiles.BlockProjectileSource; +import org.bukkit.projectiles.ProjectileSource; + +import static de.diddiz.LogBlock.util.BukkitUtils.entityName; + +import java.sql.ResultSet; +import java.sql.SQLException; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.block.Block; + +public class Actor { + + @Override + public int hashCode() { + return this.UUID != null ? this.UUID.hashCode() : 0; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final Actor other = (Actor) obj; + return (this.UUID == null) ? (other.UUID == null) : this.UUID.equals(other.UUID); + } + + final String name; + final String UUID; + final Location blockLocation; + final Entity entity; + + public Actor(String name, String UUID) { + this.name = name; + this.UUID = UUID == null ? "unknown" : (UUID.length() > 36 ? UUID.substring(0, 36) : UUID); + this.blockLocation = null; + this.entity = null; + } + + public Actor(String name, String UUID, Block block) { + this.name = name; + this.UUID = UUID == null ? "unknown" : (UUID.length() > 36 ? UUID.substring(0, 36) : UUID); + this.blockLocation = block == null ? null : block.getLocation(); + this.entity = null; + } + + public Actor(String name, java.util.UUID UUID) { + this.name = name; + this.UUID = UUID.toString(); + this.blockLocation = null; + this.entity = null; + } + + public Actor(String name, java.util.UUID UUID, Block block) { + this.name = name; + this.UUID = UUID.toString(); + this.blockLocation = block == null ? null : block.getLocation(); + this.entity = null; + } + + public Actor(String name, java.util.UUID UUID, Entity entity) { + this.name = name; + this.UUID = UUID.toString(); + this.blockLocation = null; + this.entity = entity; + } + + public Actor(String name) { + this(name, generateUUID(name)); + } + + public Actor(String name, Block block) { + this(name, generateUUID(name), block); + } + + public Actor(String name, Entity entity) { + this.name = name; + this.UUID = generateUUID(name); + this.blockLocation = null; + this.entity = entity; + } + + public Actor(ResultSet rs) throws SQLException { + this(rs.getString("playername"), rs.getString("UUID")); + } + + public String getName() { + return name; + } + + public String getUUID() { + return UUID; + } + + public Location getBlockLocation() { + return blockLocation; + } + + /** + * The acting entity object (if known) + */ + public Entity getEntity() { + return entity; + } + + public static Actor actorFromEntity(Entity entity) { + if (entity instanceof Player) { + return new Actor(entityName(entity), entity.getUniqueId(), entity); + } + if (entity instanceof Projectile) { + ProjectileSource shooter = ((Projectile) entity).getShooter(); + if (shooter != null) { + return actorFromProjectileSource(shooter); + } + } + return new Actor(entityName(entity), entity); + } + + @Deprecated + public static Actor actorFromEntity(EntityType entity) { + return new Actor(entity.name()); + } + + public static Actor actorFromProjectileSource(ProjectileSource psource) { + if (psource instanceof Entity) { + return actorFromEntity((Entity) psource); + } + if (psource instanceof BlockProjectileSource) { + return new Actor(((BlockProjectileSource) psource).getBlock().getType().toString()); + } else { + return new Actor(psource.toString()); + } + + } + + /** + * Generate an Actor object from a String name, trying to guess if it's an online player + * and if so, setting the UUID accordingly. This only checks against currently online + * players and is a "best effort" attempt for use with the pre-UUID API + *

    + * If you know something is an entity (player or otherwise) use the {@link #actorFromEntity(org.bukkit.entity.Entity) } + * or {@link #actorFromEntity(org.bukkit.entity.EntityType) } methods + *

    + * If you know something is a server effect (like gravity) use {@link #Actor(java.lang.String)} + * + * @deprecated Only use this if you have a String of unknown origin + * + * @param actorName + * String of unknown origin + * @return + */ + @Deprecated + public static Actor actorFromString(String actorName) { + Player p = Bukkit.getServer().getPlayerExact(actorName); + if (p != null) { + return actorFromEntity(p); + } + // No player found online with that name, assuming non-player entity/effect + return new Actor(actorName); + } + + public static boolean isValidUUID(String uuid) { + try { + java.util.UUID.fromString(uuid); + return true; + } catch (IllegalArgumentException e) { + return false; + } + } + + public static String generateUUID(String name) { + return "log_" + name; + + } + +} diff --git a/src/main/java/de/diddiz/LogBlock/AutoClearLog.java b/src/main/java/de/diddiz/LogBlock/AutoClearLog.java index a57f3576..c7c28cf9 100644 --- a/src/main/java/de/diddiz/LogBlock/AutoClearLog.java +++ b/src/main/java/de/diddiz/LogBlock/AutoClearLog.java @@ -1,32 +1,32 @@ -package de.diddiz.LogBlock; - -import java.util.Arrays; -import java.util.logging.Level; - -import static de.diddiz.LogBlock.config.Config.autoClearLog; -import static org.bukkit.Bukkit.*; - -public class AutoClearLog implements Runnable { - private final LogBlock logblock; - - AutoClearLog(LogBlock logblock) { - this.logblock = logblock; - } - - @Override - public void run() { - final CommandsHandler handler = logblock.getCommandsHandler(); - for (final String paramStr : autoClearLog) { - if (!logblock.isCompletelyEnabled()) { - return; // do not try when plugin is disabled - } - try { - final QueryParams params = new QueryParams(logblock, getConsoleSender(), Arrays.asList(paramStr.split(" "))); - params.noForcedLimit = true; - handler.new CommandClearLog(getServer().getConsoleSender(), params, false); - } catch (final Exception ex) { - getLogger().log(Level.SEVERE, "Failed to schedule auto ClearLog: ", ex); - } - } - } -} +package de.diddiz.LogBlock; + +import java.util.Arrays; +import java.util.logging.Level; + +import static de.diddiz.LogBlock.config.Config.autoClearLog; +import static org.bukkit.Bukkit.*; + +public class AutoClearLog implements Runnable { + private final LogBlock logblock; + + AutoClearLog(LogBlock logblock) { + this.logblock = logblock; + } + + @Override + public void run() { + final CommandsHandler handler = logblock.getCommandsHandler(); + for (final String paramStr : autoClearLog) { + if (!logblock.isCompletelyEnabled()) { + return; // do not try when plugin is disabled + } + try { + final QueryParams params = new QueryParams(logblock, getConsoleSender(), Arrays.asList(paramStr.split(" "))); + params.noForcedLimit = true; + handler.new CommandClearLog(getServer().getConsoleSender(), params, false); + } catch (final Exception ex) { + getLogger().log(Level.SEVERE, "Failed to schedule auto ClearLog: ", ex); + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 83ae93e2..79dcf54a 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -1,272 +1,272 @@ -package de.diddiz.LogBlock; - -import static de.diddiz.LogBlock.util.ActionColor.CREATE; -import static de.diddiz.LogBlock.util.ActionColor.DESTROY; -import static de.diddiz.LogBlock.util.ActionColor.INTERACT; -import static de.diddiz.LogBlock.util.MessagingUtil.createTextComponentWithColor; -import static de.diddiz.LogBlock.util.MessagingUtil.prettyDate; -import static de.diddiz.LogBlock.util.MessagingUtil.prettyLocation; -import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; -import static de.diddiz.LogBlock.util.MessagingUtil.prettyState; -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.Utils; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.logging.Level; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Note; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Lightable; -import org.bukkit.block.data.Openable; -import org.bukkit.block.data.Powerable; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.Candle; -import org.bukkit.block.data.type.Comparator; -import org.bukkit.block.data.type.DaylightDetector; -import org.bukkit.block.data.type.Lectern; -import org.bukkit.block.data.type.NoteBlock; -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; - public final Location loc; - public final Actor actor; - public final String playerName; - public final int replacedMaterial, replacedData, typeMaterial, typeData; - public final byte[] replacedState, typeState; - public final ChestAccess ca; - - public BlockChange(long date, Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { - id = 0; - this.date = date; - this.loc = loc; - this.actor = actor; - this.replacedMaterial = replaced; - this.replacedData = replacedData; - this.replacedState = replacedState; - this.typeMaterial = type; - this.typeData = typeData; - this.typeState = typeState; - this.ca = ca; - this.playerName = actor == null ? null : actor.getName(); - } - - public BlockChange(ResultSet rs, QueryParams p) throws SQLException { - id = p.needId ? rs.getLong("id") : 0; - date = p.needDate ? rs.getTimestamp("date").getTime() : 0; - loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null; - actor = p.needPlayer ? new Actor(rs) : null; - playerName = p.needPlayer ? rs.getString("playername") : null; - replacedMaterial = p.needType ? rs.getInt("replaced") : 0; - replacedData = p.needType ? rs.getInt("replacedData") : -1; - typeMaterial = p.needType ? rs.getInt("type") : 0; - typeData = p.needType ? rs.getInt("typeData") : -1; - replacedState = p.needType ? rs.getBytes("replacedState") : null; - typeState = p.needType ? rs.getBytes("typeState") : null; - ChestAccess catemp = null; - if (p.needChestAccess) { - ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); - if (stack != null) { - catemp = new ChestAccess(stack, rs.getBoolean("itemremove"), rs.getInt("itemtype")); - } - } - ca = catemp; - } - - private BaseComponent getTypeDetails(BlockData type, byte[] typeState) { - return getTypeDetails(type, typeState, null, null); - } - - private BaseComponent getTypeDetails(BlockData type, byte[] typeState, BlockData oldType, byte[] oldTypeState) { - BaseComponent typeDetails = null; - - if (BlockStateCodecs.hasCodec(type.getMaterial())) { - try { - typeDetails = BlockStateCodecs.getChangesAsComponent(type.getMaterial(), Utils.deserializeYamlConfiguration(typeState), type.equals(oldType) ? Utils.deserializeYamlConfiguration(oldTypeState) : null); - } catch (Exception e) { - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + type.getMaterial(), e); - } - } - - if (typeDetails == null) { - return new TextComponent(""); - } else { - TextComponent component = new TextComponent(" "); - component.addExtra(typeDetails); - return component; - } - } - - @Override - public String toString() { - return BaseComponent.toPlainText(getLogMessage(-1)); - } - - @Override - public BaseComponent[] getLogMessage(int entry) { - TextComponent msg = new TextComponent(); - if (date > 0) { - msg.addExtra(prettyDate(date)); - msg.addExtra(" "); - } - if (actor != null) { - msg.addExtra(actor.getName()); - msg.addExtra(" "); - } - BlockData type = getBlockSet(); - BlockData replaced = getBlockReplaced(); - if (type == null || replaced == null) { - msg.addExtra("did an unknown block modification"); - return new BaseComponent[] { msg }; - } - - // Process type details once for later use. - BaseComponent typeDetails = getTypeDetails(type, typeState, replaced, replacedState); - BaseComponent replacedDetails = getTypeDetails(replaced, replacedState); - - if (type.getMaterial().equals(replaced.getMaterial()) || (type.getMaterial() == Material.CAKE && BukkitUtils.isCandleCake(replaced.getMaterial()))) { - if (BukkitUtils.isEmpty(type.getMaterial())) { - msg.addExtra(createTextComponentWithColor("did an unspecified action", INTERACT.getColor())); - } else if (ca != null) { - if (ca.itemStack == null) { - msg.addExtra(createTextComponentWithColor("looked inside ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - } else if (ca.remove) { - msg.addExtra(createTextComponentWithColor("took ", DESTROY.getColor())); - msg.addExtra(BukkitUtils.toString(ca.itemStack)); - msg.addExtra(createTextComponentWithColor(" from ", DESTROY.getColor())); - msg.addExtra(prettyMaterial(type)); - } else { - msg.addExtra(createTextComponentWithColor("put ", CREATE.getColor())); - msg.addExtra(BukkitUtils.toString(ca.itemStack)); - msg.addExtra(createTextComponentWithColor(" into ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); - } - } else if (type instanceof Waterlogged && ((Waterlogged) type).isWaterlogged() != ((Waterlogged) replaced).isWaterlogged()) { - if (((Waterlogged) type).isWaterlogged()) { - msg.addExtra(createTextComponentWithColor("waterlogged ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); - } else { - msg.addExtra(createTextComponentWithColor("dried ", DESTROY.getColor())); - msg.addExtra(prettyMaterial(type)); - } - } else if (BukkitUtils.getContainerBlocks().contains(type.getMaterial())) { - msg.addExtra(createTextComponentWithColor("opened ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - } else if (type instanceof Openable && ((Openable) type).isOpen() != ((Openable) replaced).isOpen()) { - // Door, Trapdoor, Fence gate - msg.addExtra(createTextComponentWithColor(((Openable) type).isOpen() ? "opened " : "closed ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - } else if (type.getMaterial() == Material.LEVER && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) { - msg.addExtra(createTextComponentWithColor("switched ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(prettyState(((Switch) type).isPowered() ? " on" : " off")); - } else if (type instanceof Switch && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) { - msg.addExtra(createTextComponentWithColor("pressed ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - } else if (type.getMaterial() == Material.CAKE) { - msg.addExtra(createTextComponentWithColor("ate a piece of ", DESTROY.getColor())); - msg.addExtra(prettyMaterial(type)); - } else if (type.getMaterial() == Material.NOTE_BLOCK) { - Note note = ((NoteBlock) type).getNote(); - msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(" to "); - msg.addExtra(prettyState(note.getTone().name() + (note.isSharped() ? "#" : ""))); - } else if (type.getMaterial() == Material.REPEATER) { - msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(" to "); - msg.addExtra(prettyState(((Repeater) type).getDelay())); - msg.addExtra(createTextComponentWithColor(" ticks delay", DEFAULT.getColor())); - } else if (type.getMaterial() == Material.COMPARATOR) { - msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(" to "); - msg.addExtra(prettyState(((Comparator) type).getMode())); - } else if (type.getMaterial() == Material.DAYLIGHT_DETECTOR) { - msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(" to "); - msg.addExtra(prettyState(((DaylightDetector) type).isInverted() ? "inverted" : "normal")); - } else if (type instanceof Lectern) { - msg.addExtra(createTextComponentWithColor("changed the book on a ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(" to"); - msg.addExtra(prettyState(typeDetails)); - } else if (type instanceof Powerable) { - msg.addExtra(createTextComponentWithColor("stepped on ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - } else if (type.getMaterial() == Material.TRIPWIRE) { - msg.addExtra(createTextComponentWithColor("ran into ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - } else if (type instanceof Sign || type instanceof WallSign) { - msg.addExtra(createTextComponentWithColor("edited a ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(createTextComponentWithColor(" to", CREATE.getColor())); - msg.addExtra(prettyState(typeDetails)); - } else if (type instanceof Candle && ((Candle) type).getCandles() != ((Candle) replaced).getCandles()) { - msg.addExtra(createTextComponentWithColor("added a candle to ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); - } else if ((type instanceof Candle || BukkitUtils.isCandleCake(type.getMaterial())) && ((Lightable) type).isLit() != ((Lightable) replaced).isLit()) { - if (((Lightable) type).isLit()) { - msg.addExtra(createTextComponentWithColor("lit a ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); - } else { - msg.addExtra(createTextComponentWithColor("extinguished a ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); - } - } else { - msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor())); - msg.addExtra(prettyMaterial(replaced)); - msg.addExtra(prettyState(replacedDetails)); - msg.addExtra(createTextComponentWithColor(" with ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(prettyState(typeDetails)); - } - } else if (BukkitUtils.isEmpty(type.getMaterial())) { - msg.addExtra(createTextComponentWithColor("destroyed ", DESTROY.getColor())); - msg.addExtra(prettyMaterial(replaced)); - msg.addExtra(prettyState(replacedDetails)); - } else if (BukkitUtils.isEmpty(replaced.getMaterial())) { - msg.addExtra(createTextComponentWithColor("created ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(prettyState(typeDetails)); - } else { - msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor())); - msg.addExtra(prettyMaterial(replaced)); - msg.addExtra(prettyState(replacedDetails)); - msg.addExtra(createTextComponentWithColor(" with ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(prettyState(typeDetails)); - } - if (loc != null) { - msg.addExtra(" at "); - msg.addExtra(prettyLocation(loc, entry)); - } - return new BaseComponent[] { msg }; - } - - public BlockData getBlockReplaced() { - return MaterialConverter.getBlockData(replacedMaterial, replacedData); - } - - public BlockData getBlockSet() { - return MaterialConverter.getBlockData(typeMaterial, typeData); - } - - @Override - public Location getLocation() { - return loc; - } -} +package de.diddiz.LogBlock; + +import static de.diddiz.LogBlock.util.ActionColor.CREATE; +import static de.diddiz.LogBlock.util.ActionColor.DESTROY; +import static de.diddiz.LogBlock.util.ActionColor.INTERACT; +import static de.diddiz.LogBlock.util.MessagingUtil.createTextComponentWithColor; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyDate; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyLocation; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyState; +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.Utils; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.logging.Level; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Note; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Lightable; +import org.bukkit.block.data.Openable; +import org.bukkit.block.data.Powerable; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.block.data.type.Candle; +import org.bukkit.block.data.type.Comparator; +import org.bukkit.block.data.type.DaylightDetector; +import org.bukkit.block.data.type.Lectern; +import org.bukkit.block.data.type.NoteBlock; +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; + public final Location loc; + public final Actor actor; + public final String playerName; + public final int replacedMaterial, replacedData, typeMaterial, typeData; + public final byte[] replacedState, typeState; + public final ChestAccess ca; + + public BlockChange(long date, Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { + id = 0; + this.date = date; + this.loc = loc; + this.actor = actor; + this.replacedMaterial = replaced; + this.replacedData = replacedData; + this.replacedState = replacedState; + this.typeMaterial = type; + this.typeData = typeData; + this.typeState = typeState; + this.ca = ca; + this.playerName = actor == null ? null : actor.getName(); + } + + public BlockChange(ResultSet rs, QueryParams p) throws SQLException { + id = p.needId ? rs.getLong("id") : 0; + date = p.needDate ? rs.getTimestamp("date").getTime() : 0; + loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null; + actor = p.needPlayer ? new Actor(rs) : null; + playerName = p.needPlayer ? rs.getString("playername") : null; + replacedMaterial = p.needType ? rs.getInt("replaced") : 0; + replacedData = p.needType ? rs.getInt("replacedData") : -1; + typeMaterial = p.needType ? rs.getInt("type") : 0; + typeData = p.needType ? rs.getInt("typeData") : -1; + replacedState = p.needType ? rs.getBytes("replacedState") : null; + typeState = p.needType ? rs.getBytes("typeState") : null; + ChestAccess catemp = null; + if (p.needChestAccess) { + ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); + if (stack != null) { + catemp = new ChestAccess(stack, rs.getBoolean("itemremove"), rs.getInt("itemtype")); + } + } + ca = catemp; + } + + private BaseComponent getTypeDetails(BlockData type, byte[] typeState) { + return getTypeDetails(type, typeState, null, null); + } + + private BaseComponent getTypeDetails(BlockData type, byte[] typeState, BlockData oldType, byte[] oldTypeState) { + BaseComponent typeDetails = null; + + if (BlockStateCodecs.hasCodec(type.getMaterial())) { + try { + typeDetails = BlockStateCodecs.getChangesAsComponent(type.getMaterial(), Utils.deserializeYamlConfiguration(typeState), type.equals(oldType) ? Utils.deserializeYamlConfiguration(oldTypeState) : null); + } catch (Exception e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + type.getMaterial(), e); + } + } + + if (typeDetails == null) { + return new TextComponent(""); + } else { + TextComponent component = new TextComponent(" "); + component.addExtra(typeDetails); + return component; + } + } + + @Override + public String toString() { + return BaseComponent.toPlainText(getLogMessage(-1)); + } + + @Override + public BaseComponent[] getLogMessage(int entry) { + TextComponent msg = new TextComponent(); + if (date > 0) { + msg.addExtra(prettyDate(date)); + msg.addExtra(" "); + } + if (actor != null) { + msg.addExtra(actor.getName()); + msg.addExtra(" "); + } + BlockData type = getBlockSet(); + BlockData replaced = getBlockReplaced(); + if (type == null || replaced == null) { + msg.addExtra("did an unknown block modification"); + return new BaseComponent[] { msg }; + } + + // Process type details once for later use. + BaseComponent typeDetails = getTypeDetails(type, typeState, replaced, replacedState); + BaseComponent replacedDetails = getTypeDetails(replaced, replacedState); + + if (type.getMaterial().equals(replaced.getMaterial()) || (type.getMaterial() == Material.CAKE && BukkitUtils.isCandleCake(replaced.getMaterial()))) { + if (BukkitUtils.isEmpty(type.getMaterial())) { + msg.addExtra(createTextComponentWithColor("did an unspecified action", INTERACT.getColor())); + } else if (ca != null) { + if (ca.itemStack == null) { + msg.addExtra(createTextComponentWithColor("looked inside ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type)); + } else if (ca.remove) { + msg.addExtra(createTextComponentWithColor("took ", DESTROY.getColor())); + msg.addExtra(BukkitUtils.toString(ca.itemStack)); + msg.addExtra(createTextComponentWithColor(" from ", DESTROY.getColor())); + msg.addExtra(prettyMaterial(type)); + } else { + msg.addExtra(createTextComponentWithColor("put ", CREATE.getColor())); + msg.addExtra(BukkitUtils.toString(ca.itemStack)); + msg.addExtra(createTextComponentWithColor(" into ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type)); + } + } else if (type instanceof Waterlogged && ((Waterlogged) type).isWaterlogged() != ((Waterlogged) replaced).isWaterlogged()) { + if (((Waterlogged) type).isWaterlogged()) { + msg.addExtra(createTextComponentWithColor("waterlogged ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type)); + } else { + msg.addExtra(createTextComponentWithColor("dried ", DESTROY.getColor())); + msg.addExtra(prettyMaterial(type)); + } + } else if (BukkitUtils.getContainerBlocks().contains(type.getMaterial())) { + msg.addExtra(createTextComponentWithColor("opened ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type)); + } else if (type instanceof Openable && ((Openable) type).isOpen() != ((Openable) replaced).isOpen()) { + // Door, Trapdoor, Fence gate + msg.addExtra(createTextComponentWithColor(((Openable) type).isOpen() ? "opened " : "closed ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type)); + } else if (type.getMaterial() == Material.LEVER && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) { + msg.addExtra(createTextComponentWithColor("switched ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type)); + msg.addExtra(prettyState(((Switch) type).isPowered() ? " on" : " off")); + } else if (type instanceof Switch && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) { + msg.addExtra(createTextComponentWithColor("pressed ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type)); + } else if (type.getMaterial() == Material.CAKE) { + msg.addExtra(createTextComponentWithColor("ate a piece of ", DESTROY.getColor())); + msg.addExtra(prettyMaterial(type)); + } else if (type.getMaterial() == Material.NOTE_BLOCK) { + Note note = ((NoteBlock) type).getNote(); + msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type)); + msg.addExtra(" to "); + msg.addExtra(prettyState(note.getTone().name() + (note.isSharped() ? "#" : ""))); + } else if (type.getMaterial() == Material.REPEATER) { + msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type)); + msg.addExtra(" to "); + msg.addExtra(prettyState(((Repeater) type).getDelay())); + msg.addExtra(createTextComponentWithColor(" ticks delay", DEFAULT.getColor())); + } else if (type.getMaterial() == Material.COMPARATOR) { + msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type)); + msg.addExtra(" to "); + msg.addExtra(prettyState(((Comparator) type).getMode())); + } else if (type.getMaterial() == Material.DAYLIGHT_DETECTOR) { + msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type)); + msg.addExtra(" to "); + msg.addExtra(prettyState(((DaylightDetector) type).isInverted() ? "inverted" : "normal")); + } else if (type instanceof Lectern) { + msg.addExtra(createTextComponentWithColor("changed the book on a ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type)); + msg.addExtra(" to"); + msg.addExtra(prettyState(typeDetails)); + } else if (type instanceof Powerable) { + msg.addExtra(createTextComponentWithColor("stepped on ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type)); + } else if (type.getMaterial() == Material.TRIPWIRE) { + msg.addExtra(createTextComponentWithColor("ran into ", INTERACT.getColor())); + msg.addExtra(prettyMaterial(type)); + } else if (type instanceof Sign || type instanceof WallSign) { + msg.addExtra(createTextComponentWithColor("edited a ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type)); + msg.addExtra(createTextComponentWithColor(" to", CREATE.getColor())); + msg.addExtra(prettyState(typeDetails)); + } else if (type instanceof Candle && ((Candle) type).getCandles() != ((Candle) replaced).getCandles()) { + msg.addExtra(createTextComponentWithColor("added a candle to ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type)); + } else if ((type instanceof Candle || BukkitUtils.isCandleCake(type.getMaterial())) && ((Lightable) type).isLit() != ((Lightable) replaced).isLit()) { + if (((Lightable) type).isLit()) { + msg.addExtra(createTextComponentWithColor("lit a ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type)); + } else { + msg.addExtra(createTextComponentWithColor("extinguished a ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type)); + } + } else { + msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor())); + msg.addExtra(prettyMaterial(replaced)); + msg.addExtra(prettyState(replacedDetails)); + msg.addExtra(createTextComponentWithColor(" with ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type)); + msg.addExtra(prettyState(typeDetails)); + } + } else if (BukkitUtils.isEmpty(type.getMaterial())) { + msg.addExtra(createTextComponentWithColor("destroyed ", DESTROY.getColor())); + msg.addExtra(prettyMaterial(replaced)); + msg.addExtra(prettyState(replacedDetails)); + } else if (BukkitUtils.isEmpty(replaced.getMaterial())) { + msg.addExtra(createTextComponentWithColor("created ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type)); + msg.addExtra(prettyState(typeDetails)); + } else { + msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor())); + msg.addExtra(prettyMaterial(replaced)); + msg.addExtra(prettyState(replacedDetails)); + msg.addExtra(createTextComponentWithColor(" with ", CREATE.getColor())); + msg.addExtra(prettyMaterial(type)); + msg.addExtra(prettyState(typeDetails)); + } + if (loc != null) { + msg.addExtra(" at "); + msg.addExtra(prettyLocation(loc, entry)); + } + return new BaseComponent[] { msg }; + } + + public BlockData getBlockReplaced() { + return MaterialConverter.getBlockData(replacedMaterial, replacedData); + } + + public BlockData getBlockSet() { + return MaterialConverter.getBlockData(typeMaterial, typeData); + } + + @Override + public Location getLocation() { + return loc; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/ChatMessage.java b/src/main/java/de/diddiz/LogBlock/ChatMessage.java index 7f940276..43d93586 100644 --- a/src/main/java/de/diddiz/LogBlock/ChatMessage.java +++ b/src/main/java/de/diddiz/LogBlock/ChatMessage.java @@ -1,59 +1,59 @@ -package de.diddiz.LogBlock; - -import static de.diddiz.LogBlock.util.LoggingUtil.checkText; -import static de.diddiz.LogBlock.util.MessagingUtil.brackets; -import static de.diddiz.LogBlock.util.MessagingUtil.prettyDate; - -import de.diddiz.LogBlock.util.MessagingUtil; -import de.diddiz.LogBlock.util.MessagingUtil.BracketType; -import java.sql.ResultSet; -import java.sql.SQLException; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; -import org.bukkit.Location; - -public class ChatMessage implements LookupCacheElement { - final long id, date; - final String playerName, message; - final Actor player; - - public ChatMessage(Actor player, String message) { - id = 0; - date = System.currentTimeMillis() / 1000; - this.player = player; - this.message = checkText(message); - this.playerName = player == null ? null : player.getName(); - } - - public ChatMessage(ResultSet rs, QueryParams p) throws SQLException { - id = p.needId ? rs.getLong("id") : 0; - date = p.needDate ? rs.getTimestamp("date").getTime() : 0; - player = p.needPlayer ? new Actor(rs) : null; - playerName = p.needPlayer ? rs.getString("playername") : null; - message = p.needMessage ? rs.getString("message") : null; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - public BaseComponent[] getLogMessage(int entry) { - TextComponent msg = new TextComponent(); - if (date > 0) { - msg.addExtra(prettyDate(date)); - msg.addExtra(" "); - } - if (playerName != null) { - msg.addExtra(brackets(BracketType.ANGLE, MessagingUtil.createTextComponentWithColor(playerName, net.md_5.bungee.api.ChatColor.WHITE))); - msg.addExtra(" "); - } - if (message != null) { - for (BaseComponent messageComponent : TextComponent.fromLegacyText(message)) { - msg.addExtra(messageComponent); - } - } - return new BaseComponent[] { msg }; - } -} +package de.diddiz.LogBlock; + +import static de.diddiz.LogBlock.util.LoggingUtil.checkText; +import static de.diddiz.LogBlock.util.MessagingUtil.brackets; +import static de.diddiz.LogBlock.util.MessagingUtil.prettyDate; + +import de.diddiz.LogBlock.util.MessagingUtil; +import de.diddiz.LogBlock.util.MessagingUtil.BracketType; +import java.sql.ResultSet; +import java.sql.SQLException; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.Location; + +public class ChatMessage implements LookupCacheElement { + final long id, date; + final String playerName, message; + final Actor player; + + public ChatMessage(Actor player, String message) { + id = 0; + date = System.currentTimeMillis() / 1000; + this.player = player; + this.message = checkText(message); + this.playerName = player == null ? null : player.getName(); + } + + public ChatMessage(ResultSet rs, QueryParams p) throws SQLException { + id = p.needId ? rs.getLong("id") : 0; + date = p.needDate ? rs.getTimestamp("date").getTime() : 0; + player = p.needPlayer ? new Actor(rs) : null; + playerName = p.needPlayer ? rs.getString("playername") : null; + message = p.needMessage ? rs.getString("message") : null; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + public BaseComponent[] getLogMessage(int entry) { + TextComponent msg = new TextComponent(); + if (date > 0) { + msg.addExtra(prettyDate(date)); + msg.addExtra(" "); + } + if (playerName != null) { + msg.addExtra(brackets(BracketType.ANGLE, MessagingUtil.createTextComponentWithColor(playerName, net.md_5.bungee.api.ChatColor.WHITE))); + msg.addExtra(" "); + } + if (message != null) { + for (BaseComponent messageComponent : TextComponent.fromLegacyText(message)) { + msg.addExtra(messageComponent); + } + } + return new BaseComponent[] { msg }; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/ChestAccess.java b/src/main/java/de/diddiz/LogBlock/ChestAccess.java index c9d78828..71575161 100644 --- a/src/main/java/de/diddiz/LogBlock/ChestAccess.java +++ b/src/main/java/de/diddiz/LogBlock/ChestAccess.java @@ -1,15 +1,15 @@ -package de.diddiz.LogBlock; - -import org.bukkit.inventory.ItemStack; - -public class ChestAccess { - public final ItemStack itemStack; - public final boolean remove; - public final int itemType; - - public ChestAccess(ItemStack itemStack, boolean remove, int itemType) { - this.itemStack = itemStack; - this.remove = remove; - this.itemType = itemType; - } -} +package de.diddiz.LogBlock; + +import org.bukkit.inventory.ItemStack; + +public class ChestAccess { + public final ItemStack itemStack; + public final boolean remove; + public final int itemType; + + public ChestAccess(ItemStack itemStack, boolean remove, int itemType) { + this.itemStack = itemStack; + this.remove = remove; + this.itemType = itemType; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 827b1c49..c07db642 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -1,1221 +1,1221 @@ -package de.diddiz.LogBlock; - -import static de.diddiz.LogBlock.config.Config.getWorldConfig; -import static de.diddiz.LogBlock.config.Config.hiddenBlocks; -import static de.diddiz.LogBlock.config.Config.hiddenPlayers; -import static de.diddiz.LogBlock.config.Config.isLogged; -import static de.diddiz.LogBlock.config.Config.logPlayerInfo; -import static de.diddiz.LogBlock.util.BukkitUtils.compressInventory; -import static de.diddiz.LogBlock.util.BukkitUtils.itemIDfromProjectileEntity; -import static de.diddiz.LogBlock.util.Utils.mysqlTextEscape; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintWriter; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Deque; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.UUID; -import java.util.logging.Level; - -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.entity.Projectile; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryHolder; -import org.bukkit.inventory.ItemStack; -import org.bukkit.projectiles.ProjectileSource; - -import de.diddiz.LogBlock.EntityChange.EntityChangeType; -import de.diddiz.LogBlock.blockstate.BlockStateCodecs; -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.Utils; - -public class Consumer extends Thread { - private static final int MAX_SHUTDOWN_TIME_MILLIS = 20000; - private static final int WAIT_FOR_CONNECTION_TIME_MILLIS = 10000; - private static final int RETURN_IDLE_CONNECTION_TIME_MILLIS = 120000; - private static final int RETRIES_ON_UNKNOWN_CONNECTION_ERROR = 2; - - private final Deque queue = new ArrayDeque<>(); - private final LogBlock logblock; - private final Map playerIds = new HashMap<>(); - private final Map uncommitedPlayerIds = new HashMap<>(); - private final Map> uncommitedEntityIds = new HashMap<>(); - - private long addEntryCounter; - private long nextWarnCounter; - - private boolean shutdown; - private long shutdownInitialized; - - Consumer(LogBlock logblock) { - this.logblock = logblock; - PlayerLeaveRow.class.getName(); // preload this class - setName("Logblock-Consumer"); - } - - public LogBlock getLogblock() { - return logblock; - } - - /** - * Logs any block change. Don't try to combine broken and placed blocks. Queue two block changes or use the queueBLockReplace methods. - * - * @param actor - * Actor responsible for making the change - * @param loc - * Location of the block change - * @param typeBefore - * BlockData of the block before the change - * @param typeAfter - * BlockData of the block after the change - */ - public void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter) { - queueBlock(actor, loc, typeBefore, typeAfter, null, null, null); - } - - /** - * Logs a block break. The type afterwards is assumed to be air. - * - * @param actor - * Actor responsible for breaking the block - * @param before - * BlockState of the block before actually being destroyed. - */ - public void queueBlockBreak(Actor actor, BlockState before) { - queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), null, BlockStateCodecs.serialize(before), null, null); - } - - /** - * Logs a block break. The block type afterwards is assumed to be air. - * - * @param actor - * Actor responsible for the block break - * @param loc - * Location of the broken block - * @param typeBefore - * BlockData of the block before the break - */ - public void queueBlockBreak(Actor actor, Location loc, BlockData typeBefore) { - queueBlock(actor, loc, typeBefore, null); - } - - /** - * Logs a block place. The block type before is assumed to be air. - * - * @param actor - * Actor responsible for placing the block - * @param after - * BlockState of the block after actually being placed. - */ - public void queueBlockPlace(Actor actor, BlockState after) { - queueBlock(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), null, after.getBlockData(), null, BlockStateCodecs.serialize(after), null); - } - - /** - * Logs a block place. The block type before is assumed to be air. - * - * @param actor - * Actor responsible for placing the block - * @param loc - * Location of the placed block - * @param type - * BlockData of the placed block - */ - public void queueBlockPlace(Actor actor, Location loc, BlockData type) { - queueBlock(actor, loc, null, type); - } - - /** - * Logs a block being replaced from the before and after {@link org.bukkit.block.BlockState}s - * - * @param actor - * Actor responsible for replacing the block - * @param before - * BlockState of the block before actually being destroyed. - * @param after - * BlockState of the block after actually being placed. - */ - public void queueBlockReplace(Actor actor, BlockState before, BlockState after) { - queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), after.getBlockData(), BlockStateCodecs.serialize(before), BlockStateCodecs.serialize(after), null); - } - - /** - * Logs a block being replaced from the before {@link org.bukkit.block.BlockState} and the type and data after - * - * @param actor - * Actor responsible for replacing the block - * @param before - * BlockState of the block before being replaced. - * @param typeAfter - * BlockData of the block after being replaced - */ - public void queueBlockReplace(Actor actor, BlockState before, BlockData typeAfter) { - queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), typeAfter, BlockStateCodecs.serialize(before), null, null); - } - - /** - * Logs a block being replaced from the type and data before and the {@link org.bukkit.block.BlockState} after - * - * @param actor - * Actor responsible for replacing the block - * @param typeBefore - * BlockData of the block before being replaced - * @param after - * BlockState of the block after actually being placed. - */ - public void queueBlockReplace(Actor actor, BlockData typeBefore, BlockState after) { - queueBlock(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), typeBefore, after.getBlockData(), null, BlockStateCodecs.serialize(after), null); - } - - public void queueBlockReplace(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter) { - queueBlock(actor, loc, typeBefore, typeAfter, null, null, null); - } - - /** - * Logs an actor interacting with a container block's inventory - * - * @param actor - * The actor interacting with the container - * @param container - * The respective container. Must be an instance of an InventoryHolder. - * @param itemStack - * Item taken/stored, including amount - * @param remove - * true if the item was removed - */ - public void queueChestAccess(Actor actor, BlockState container, ItemStack itemStack, boolean remove) { - if (!(container instanceof InventoryHolder)) { - throw new IllegalArgumentException("Container must be instanceof InventoryHolder"); - } - queueChestAccess(actor, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getBlockData(), itemStack, remove); - } - - /** - * Logs an actor interacting with a container block's inventory - * - * @param actor - * The actor interacting with the container - * @param loc - * The location of the container block - * @param type - * BlockData of the container. - * @param itemStack - * Item taken/stored, including amount - * @param remove - * true if the item was removed - */ - 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()))); - } - - /** - * Logs a container block break. The block type before is assumed to be air. All content is assumed to be taken. - * - * @param actor - * The actor breaking the container - * @param container - * Must be an instance of InventoryHolder - */ - public void queueContainerBreak(Actor actor, BlockState container) { - if (!(container instanceof InventoryHolder)) { - return; - } - queueContainerBreak(actor, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getBlockData(), ((InventoryHolder) container).getInventory()); - } - - /** - * Logs a container block break. The block type before is assumed to be air. All content is assumed to be taken. - * - * @param actor - * The actor responsible for breaking the container - * @param loc - * The location of the inventory block - * @param type - * BlockData of the container block - * @param inv - * The inventory of the container block - */ - public void queueContainerBreak(Actor actor, Location loc, BlockData type, Inventory inv) { - final ItemStack[] items = compressInventory(inv.getContents()); - for (final ItemStack item : items) { - queueChestAccess(actor, loc, type, item, true); - } - queueBlockBreak(actor, loc, type); - } - - /** - * @param killer - * Can't be null - * @param victim - * Can't be null - */ - public void queueKill(Entity killer, Entity victim) { - if (killer == null || victim == null) { - return; - } - ItemStack weapon = null; - Actor killerActor = Actor.actorFromEntity(killer); - // If it's a projectile kill we want to manually assign the weapon, so check for player before converting a projectile to its source - if (killer instanceof Player && ((Player) killer).getInventory().getItemInMainHand() != null) { - weapon = ((Player) killer).getInventory().getItemInMainHand(); - } - if (killer instanceof Projectile) { - Material projectileMaterial = itemIDfromProjectileEntity(killer); - weapon = projectileMaterial == null ? null : new ItemStack(projectileMaterial); - ProjectileSource ps = ((Projectile) killer).getShooter(); - if (ps == null) { - killerActor = Actor.actorFromEntity(killer); - } else { - killerActor = Actor.actorFromProjectileSource(ps); - } - } - - queueKill(victim.getLocation(), killerActor, Actor.actorFromEntity(victim), weapon); - } - - /** - * This form should only be used when the killer is not an entity e.g. for fall or suffocation damage - * - * @param killer - * Can't be null - * @param victim - * Can't be null - */ - public void queueKill(Actor killer, Entity victim) { - if (killer == null || victim == null) { - return; - } - queueKill(victim.getLocation(), killer, Actor.actorFromEntity(victim), null); - } - - /** - * @param location - * Location of the victim. - * @param killer - * Killer Actor. Can be null. - * @param victim - * Victim Actor. Can't be null. - * @param weapon - * Item of the weapon. null for no weapon. - */ - public void queueKill(Location location, Actor killer, Actor victim, ItemStack weapon) { - if (victim == null || !isLogged(location.getWorld())) { - return; - } - addQueueLast(new KillRow(location, killer == null ? null : killer, victim, weapon == null ? 0 : MaterialConverter.getOrAddMaterialId(weapon.getType()))); - } - - public void queueChat(Actor player, String message) { - if (!Config.ignoredChat.isEmpty()) { - String lowerCaseMessage = message.toLowerCase(); - for (String ignored : Config.ignoredChat) { - if (lowerCaseMessage.startsWith(ignored)) { - return; - } - } - } - if (hiddenPlayers.contains(player.getName().toLowerCase())) { - return; - } - while (message.length() > 256) { - addQueueLast(new ChatRow(player, message.substring(0, 256))); - message = message.substring(256); - } - addQueueLast(new ChatRow(player, message)); - } - - public void queueJoin(Player player) { - addQueueLast(new PlayerJoinRow(player)); - } - - public void queueLeave(Player player, long onlineTime) { - addQueueLast(new PlayerLeaveRow(player, onlineTime)); - } - - public void shutdown() { - synchronized (queue) { - shutdown = true; - shutdownInitialized = System.currentTimeMillis(); - queue.notifyAll(); - } - while (isAlive()) { - try { - join(); - } catch (InterruptedException e) { - // ignore - } - } - } - - @Override - public void run() { - ArrayList currentRows = new ArrayList<>(); - Connection conn = null; - BatchHelper batchHelper = new BatchHelper(); - int lastCommitsFailed = 0; - while (true) { - try { - if (conn == null) { - batchHelper.reset(); - conn = logblock.getConnection(); - if (conn != null) { - // initialize connection - conn.setAutoCommit(false); - } else { - // we did not get a connection - boolean wantsShutdown; - synchronized (queue) { - wantsShutdown = shutdown; - } - if (wantsShutdown) { - // lets give up - break; - } - // wait for a connection - logblock.getLogger().severe("[Consumer] Could not connect to the database!"); - try { - Thread.sleep(WAIT_FOR_CONNECTION_TIME_MILLIS); - } catch (InterruptedException e) { - // ignore - } - continue; - } - } - Row r; - boolean processBatch = false; - synchronized (queue) { - if (shutdown) { - // Give this thread some time to process the remaining entries - if (queue.isEmpty() || System.currentTimeMillis() - shutdownInitialized > MAX_SHUTDOWN_TIME_MILLIS) { - if (currentRows.isEmpty()) { - break; - } else { - processBatch = true; - } - } - } - r = queue.pollFirst(); - if (r == null) { - try { - if (currentRows.isEmpty() && !shutdown) { - // nothing to do for us - // wait some time before closing the connection - queue.wait(RETURN_IDLE_CONNECTION_TIME_MILLIS); - // if there is still nothing to do, close the connection and go to sleep - if (queue.isEmpty() && !shutdown) { - try { - conn.close(); - } catch (Exception e) { - // ignored - } - conn = null; - queue.wait(); - } - } else { - processBatch = true; - } - } catch (InterruptedException e) { - // ignore - } - } - } - if (r != null) { - boolean failOnActors = false; - for (final Actor actor : r.getActors()) { - if (playerIDAsIntIncludeUncommited(actor) == null) { - if (!addPlayer(conn, actor)) { - failOnActors = true; // skip this row - } - } - } - if (!failOnActors) { - currentRows.add(r); - r.process(conn, batchHelper); - } - } - if (currentRows.size() >= Math.max((processBatch ? 1 : (Config.forceToProcessAtLeast * 10)), 1)) { - batchHelper.processStatements(conn); - conn.commit(); - currentRows.clear(); - playerIds.putAll(uncommitedPlayerIds); - uncommitedPlayerIds.clear(); - uncommitedEntityIds.clear(); - lastCommitsFailed = 0; - } - } catch (Exception e) { - boolean retry = lastCommitsFailed < RETRIES_ON_UNKNOWN_CONNECTION_ERROR; - String state = "unknown"; - if (e instanceof SQLException) { - // Retry on network errors: SQLSTATE = 08S01 08001 08004 HY000 40001 - state = ((SQLException) e).getSQLState(); - retry = retry || (state != null && (state.equals("08S01") || state.equals("08001") || state.equals("08004") || state.equals("HY000") || state.equals("40001"))); - } - lastCommitsFailed += 1; - if (retry) { - logblock.getLogger().log(Level.WARNING, "[Consumer] Database connection lost, reconnecting! SQLState: " + state); - // readd rows to the queue - synchronized (queue) { - while (!currentRows.isEmpty()) { - queue.addFirst(currentRows.remove(currentRows.size() - 1)); - } - } - } else { - logblock.getLogger().log(Level.SEVERE, "[Consumer] Could not insert entries! SQLState: " + state, e); - } - currentRows.clear(); - batchHelper.reset(); - uncommitedPlayerIds.clear(); - uncommitedEntityIds.clear(); - if (conn != null) { - try { - conn.close(); - } catch (SQLException e1) { - // ignore - } - } - conn = null; - } - } - if (conn != null) { - try { - conn.close(); - } catch (SQLException e1) { - // ignore - } - } - - // readd to queue - this can be saved later - synchronized (queue) { - while (!currentRows.isEmpty()) { - queue.addFirst(currentRows.remove(currentRows.size() - 1)); - } - } - } - - public void writeToFile() throws FileNotFoundException { - final long time = System.currentTimeMillis(); - final Set insertedPlayers = new HashSet<>(); - int counter = 0; - final File importDir = new File(logblock.getDataFolder(), "import"); - importDir.mkdirs(); - PrintWriter writer = new PrintWriter(new File(importDir, "queue-" + time + "-0.sql")); - while (!isQueueEmpty()) { - final Row r = pollQueueFirst(); - if (r == null) { - continue; - } - for (final Actor actor : r.getActors()) { - if (!playerIds.containsKey(actor) && !insertedPlayers.contains(actor)) { - // Odd query contruction is to work around innodb auto increment behaviour - bug #492 - writer.println("INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + mysqlTextEscape(actor.getName()) + "','" + mysqlTextEscape(actor.getUUID()) + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(actor.getUUID()) + "') LIMIT 1;"); - insertedPlayers.add(actor); - } - } - for (final String insert : r.getInserts()) { - writer.println(insert); - } - counter++; - if (counter % 1000 == 0) { - writer.close(); - writer = new PrintWriter(new File(importDir, "queue-" + time + "-" + counter / 1000 + ".sql")); - } - } - writer.close(); - } - - int getQueueSize() { - synchronized (queue) { - return queue.size(); - } - } - - private boolean isQueueEmpty() { - synchronized (queue) { - return queue.isEmpty(); - } - } - - private void addQueueLast(Row row) { - synchronized (queue) { - boolean wasEmpty = queue.isEmpty(); - queue.addLast(row); - addEntryCounter++; - if (Config.queueWarningSize > 0 && queue.size() >= Config.queueWarningSize && addEntryCounter >= nextWarnCounter) { - logblock.getLogger().warning("[Consumer] Queue overloaded. Size: " + queue.size()); - nextWarnCounter = addEntryCounter + 1000; - } - if (wasEmpty) { - queue.notifyAll(); - } - } - } - - private Row pollQueueFirst() { - synchronized (queue) { - return queue.pollFirst(); - } - } - - static void hide(Player player) { - hiddenPlayers.add(player.getName().toLowerCase()); - } - - static void unHide(Player player) { - hiddenPlayers.remove(player.getName().toLowerCase()); - } - - static boolean toggleHide(Player player) { - final String playerName = player.getName().toLowerCase(); - if (hiddenPlayers.contains(playerName)) { - hiddenPlayers.remove(playerName); - return false; - } - hiddenPlayers.add(playerName); - return true; - } - - private boolean addPlayer(Connection conn, Actor actor) throws SQLException { - // Odd query contruction is to work around innodb auto increment behaviour - bug #492 - String name = actor.getName(); - String uuid = actor.getUUID(); - Statement state = conn.createStatement(); - String q1 = "INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + mysqlTextEscape(name) + "','" + mysqlTextEscape(uuid) + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(uuid) + "') LIMIT 1"; - String q2 = "SELECT playerid FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(uuid) + "'"; - int q1Result = state.executeUpdate(q1); - ResultSet rs = state.executeQuery(q2); - if (rs.next()) { - uncommitedPlayerIds.put(actor, rs.getInt(1)); - } - rs.close(); - if (!uncommitedPlayerIds.containsKey(actor)) { - state.executeUpdate("INSERT IGNORE INTO `lb-players` (playername,UUID) VALUES ('" + mysqlTextEscape(name) + "','" + mysqlTextEscape(uuid) + "')"); - rs = state.executeQuery(q2); - if (rs.next()) { - uncommitedPlayerIds.put(actor, rs.getInt(1)); - } else { - logblock.getLogger().warning("[Consumer] Failed to add player " + actor.getName()); - logblock.getLogger().warning("[Consumer-Debug] Query 1: " + q1); - logblock.getLogger().warning("[Consumer-Debug] Query 1 - Result: " + q1Result); - logblock.getLogger().warning("[Consumer-Debug] Query 2: " + q2); - } - rs.close(); - } - state.close(); - return uncommitedPlayerIds.containsKey(actor); - } - - private long getEntityUUID(Connection conn, World world, UUID uuid) throws SQLException { - Map uncommitedEntityIdsHere = uncommitedEntityIds.get(world); - if (uncommitedEntityIdsHere == null) { - uncommitedEntityIdsHere = new HashMap<>(); - uncommitedEntityIds.put(world, uncommitedEntityIdsHere); - } - Long existing = uncommitedEntityIdsHere.get(uuid); - if (existing != null) { - return existing; - } - - // Odd query contruction is to work around innodb auto increment behaviour - bug #492 - final String table = getWorldConfig(world).table; - String uuidString = uuid.toString(); - Statement state = conn.createStatement(); - String q1 = "INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) SELECT '" + mysqlTextEscape(uuidString) + "' FROM `" + table + "-entityids` WHERE NOT EXISTS (SELECT NULL FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(uuidString) + "') LIMIT 1"; - String q2 = "SELECT entityid FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(uuidString) + "'"; - int q1Result = state.executeUpdate(q1); - ResultSet rs = state.executeQuery(q2); - if (rs.next()) { - uncommitedEntityIdsHere.put(uuid, rs.getLong(1)); - } - rs.close(); - // if there was not any row in the table the query above does not work, so we need to try this one - if (!uncommitedEntityIdsHere.containsKey(uuid)) { - state.executeUpdate("INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) VALUES ('" + mysqlTextEscape(uuidString) + "')"); - rs = state.executeQuery(q2); - if (rs.next()) { - uncommitedEntityIdsHere.put(uuid, rs.getLong(1)); - } else { - logblock.getLogger().warning("[Consumer] Failed to add entity uuid " + uuidString.toString()); - logblock.getLogger().warning("[Consumer-Debug] World: " + world.getName()); - logblock.getLogger().warning("[Consumer-Debug] Query 1: " + q1); - logblock.getLogger().warning("[Consumer-Debug] Query 1 - Result: " + q1Result); - logblock.getLogger().warning("[Consumer-Debug] Query 2: " + q2); - } - rs.close(); - } - state.close(); - return uncommitedEntityIdsHere.get(uuid); - } - - private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter, YamlConfiguration stateBefore, YamlConfiguration stateAfter, ChestAccess ca) { - if (typeBefore == null || typeBefore.getMaterial() == Material.CAVE_AIR || typeBefore.getMaterial() == Material.VOID_AIR) { - typeBefore = Bukkit.createBlockData(Material.AIR); - } - if (typeAfter == null && ((typeBefore instanceof Waterlogged && ((Waterlogged) typeBefore).isWaterlogged()) || BukkitUtils.isAlwaysWaterlogged(typeBefore.getMaterial()))) { - typeAfter = Bukkit.createBlockData(Material.WATER); - } - if (typeAfter == null || typeAfter.getMaterial() == Material.CAVE_AIR || typeAfter.getMaterial() == Material.VOID_AIR) { - typeAfter = Bukkit.createBlockData(Material.AIR); - } - if (BlockChangePreLogEvent.getHandlerList().getRegisteredListeners().length > 0) { - // Create and call the event - BlockChangePreLogEvent event = new BlockChangePreLogEvent(actor, loc, typeBefore, typeAfter, stateBefore, stateAfter, ca); - logblock.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - - // Update variables - actor = event.getOwnerActor(); - loc = event.getLocation(); - typeBefore = event.getTypeBefore(); - typeAfter = event.getTypeAfter(); - stateBefore = event.getStateBefore(); - stateAfter = event.getStateAfter(); - ca = event.getChestAccess(); - } - // Do this last so LogBlock still has final say in what is being added - if (actor == null || loc == null || typeBefore == null || typeAfter == null || hiddenPlayers.contains(actor.getName().toLowerCase()) || !isLogged(loc.getWorld()) || typeBefore != typeAfter && hiddenBlocks.contains(typeBefore.getMaterial()) && hiddenBlocks.contains(typeAfter.getMaterial())) { - return; - } - - int replacedMaterialId = MaterialConverter.getOrAddMaterialId(typeBefore); - int replacedStateId = MaterialConverter.getOrAddBlockStateId(typeBefore); - int typeMaterialId = MaterialConverter.getOrAddMaterialId(typeAfter); - int typeStateId = MaterialConverter.getOrAddBlockStateId(typeAfter); - - addQueueLast(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, Utils.serializeYamlConfiguration(stateBefore), typeMaterialId, typeStateId, Utils.serializeYamlConfiguration(stateAfter), ca)); - } - - public void queueEntityModification(Actor actor, Entity entity, EntityChangeType changeType, YamlConfiguration data) { - if (actor == null || changeType == null || entity == null || hiddenPlayers.contains(actor.getName().toLowerCase()) || !isLogged(entity.getWorld())) { - return; - } - UUID entityId = entity.getUniqueId(); - EntityType entityType = entity.getType(); - Location loc = entity.getLocation(); - - if (EntityChangePreLogEvent.getHandlerList().getRegisteredListeners().length > 0) { - // Create and call the event - EntityChangePreLogEvent event = new EntityChangePreLogEvent(actor, loc, entity, changeType, data); - logblock.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - - // Update variables - actor = event.getOwnerActor(); - loc = event.getLocation(); - } - // Do this last so LogBlock still has final say in what is being added - if (actor == null || loc == null || hiddenPlayers.contains(actor.getName().toLowerCase()) || !isLogged(loc.getWorld())) { - return; - } - - addQueueLast(new EntityRow(loc, actor, entityType, entityId, changeType, Utils.serializeYamlConfiguration(data))); - } - - /** - * Change the UUID that is stored for an entity in the database. This is needed when an entity is respawned - * and now has a different UUID. - * - * @param world the world that contains the entity - * @param entityId the database id of the entity - * @param entityUUID the new UUID of the entity - */ - public void queueEntityUUIDChange(World world, int entityId, UUID entityUUID) { - addQueueLast(new EntityUUIDChange(world, entityId, entityUUID)); - } - - private String playerID(Actor actor) { - if (actor == null) { - return "NULL"; - } - final Integer id = playerIds.get(actor); - if (id != null) { - return id.toString(); - } - return "(SELECT playerid FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(actor.getUUID()) + "')"; - } - - private Integer playerIDAsIntIncludeUncommited(Actor actor) { - if (actor == null) { - return null; - } - Integer id = playerIds.get(actor); - if (id != null) { - return id; - } - return uncommitedPlayerIds.get(actor); - } - - private static interface Row { - String[] getInserts(); - - void process(Connection conn, BatchHelper batchHelper) throws SQLException; - - Actor[] getActors(); - } - - private class BlockRow extends BlockChange implements Row { - final String statementString; - final String selectActorIdStatementString; - - public BlockRow(Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { - super(System.currentTimeMillis() / 1000, loc, actor, replaced, replacedData, replacedState, type, typeData, typeState, ca); - - statementString = getWorldConfig(loc.getWorld()).insertBlockStatementString; - selectActorIdStatementString = getWorldConfig(loc.getWorld()).selectBlockActorIdStatementString; - } - - @Override - public String[] getInserts() { - final String table = getWorldConfig(loc.getWorld()).table; - final String[] inserts = new String[ca != null || replacedState != null || typeState != null ? 2 : 1]; - - inserts[0] = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(actor) + ", " + replacedMaterial + ", " + replacedData + ", " + typeMaterial + ", " + typeData + ", '" + loc.getBlockX() - + "', " + safeY(loc) + ", '" + loc.getBlockZ() + "');"; - if (replacedState != null || typeState != null) { - inserts[1] = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(" + Utils.mysqlPrepareBytesForInsertAllowNull(replacedState) + ", " + Utils.mysqlPrepareBytesForInsertAllowNull(typeState) + ", LAST_INSERT_ID());"; - } else if (ca != null) { - try { - inserts[1] = "INSERT INTO `" + table + "-chestdata` (id, item, itemremove, itemtype) values (LAST_INSERT_ID(), '" + Utils.mysqlEscapeBytes(Utils.saveItemStack(ca.itemStack)) + "', " + (ca.remove ? 1 : 0) + ", " + ca.itemType + ");"; - } catch (Exception e) { - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not serialize ItemStack " + e.getMessage(), e); - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Problematic row: " + toString()); - return new String[0]; - } - } - return inserts; - } - - @Override - public Actor[] getActors() { - return new Actor[] { actor }; - } - - @Override - public void process(Connection conn, BatchHelper batchHelper) throws SQLException { - byte[] serializedItemStack = null; - if (ca != null) { - try { - serializedItemStack = Utils.saveItemStack(ca.itemStack); - } catch (Exception e) { - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not serialize ItemStack " + e.getMessage(), e); - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Problematic row: " + toString()); - return; - } - } - final byte[] finalSerializedItemStack = serializedItemStack; - int sourceActor = playerIDAsIntIncludeUncommited(actor); - Location actorBlockLocation = actor.getBlockLocation(); - if (actorBlockLocation != null) { - Integer tempSourceActor = batchHelper.getUncommitedBlockActor(actorBlockLocation); - if (tempSourceActor != null) { - sourceActor = tempSourceActor; - } else { - PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, selectActorIdStatementString, Statement.NO_GENERATED_KEYS); - smt.setInt(1, actorBlockLocation.getBlockX()); - smt.setInt(2, safeY(actorBlockLocation)); - smt.setInt(3, actorBlockLocation.getBlockZ()); - ResultSet rs = smt.executeQuery(); - if (rs.next()) { - sourceActor = rs.getInt(1); - } - rs.close(); - } - } - PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.RETURN_GENERATED_KEYS); - smt.setLong(1, date); - smt.setInt(2, sourceActor); - smt.setInt(3, replacedMaterial); - smt.setInt(4, replacedData); - smt.setInt(5, typeMaterial); - smt.setInt(6, typeData); - smt.setInt(7, loc.getBlockX()); - smt.setInt(8, safeY(loc)); - smt.setInt(9, loc.getBlockZ()); - batchHelper.addUncommitedBlockActorId(loc, sourceActor); - batchHelper.addBatch(smt, new LongCallback() { - @Override - public void call(long id) throws SQLException { - PreparedStatement ps; - if (typeState != null || replacedState != null) { - ps = batchHelper.getOrPrepareStatement(conn, getWorldConfig(loc.getWorld()).insertBlockStateStatementString, Statement.NO_GENERATED_KEYS); - ps.setBytes(1, replacedState); - ps.setBytes(2, typeState); - ps.setLong(3, id); - batchHelper.addBatch(ps, null); - } - if (ca != null) { - ps = batchHelper.getOrPrepareStatement(conn, getWorldConfig(loc.getWorld()).insertBlockChestDataStatementString, Statement.NO_GENERATED_KEYS); - ps.setBytes(1, finalSerializedItemStack); - ps.setInt(2, ca.remove ? 1 : 0); - ps.setLong(3, id); - ps.setInt(4, ca.itemType); - batchHelper.addBatch(ps, null); - } - } - }); - } - } - - private class KillRow implements Row { - final long date; - final Actor killer, victim; - final int weapon; - final Location loc; - final String statementString; - - KillRow(Location loc, Actor attacker, Actor defender, int weapon) { - date = System.currentTimeMillis() / 1000; - this.loc = loc; - killer = attacker; - victim = defender; - this.weapon = weapon; - - statementString = "INSERT INTO `" + getWorldConfig(loc.getWorld()).table + "-kills` (date, killer, victim, weapon, x, y, z) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?)"; - } - - @Override - public String[] getInserts() { - return new String[] { "INSERT INTO `" + getWorldConfig(loc.getWorld()).table + "-kills` (date, killer, victim, weapon, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(killer) + ", " + playerID(victim) + ", " + weapon + ", " + loc.getBlockX() + ", " + safeY(loc) + ", " - + loc.getBlockZ() + ");" }; - } - - @Override - public Actor[] getActors() { - return new Actor[] { killer, victim }; - } - - @Override - public void process(Connection conn, BatchHelper batchHelper) throws SQLException { - PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); - smt.setLong(1, date); - smt.setInt(2, playerIDAsIntIncludeUncommited(killer)); - smt.setInt(3, playerIDAsIntIncludeUncommited(victim)); - smt.setInt(4, weapon); - smt.setInt(5, loc.getBlockX()); - smt.setInt(6, safeY(loc)); - smt.setInt(7, loc.getBlockZ()); - batchHelper.addBatch(smt, null); - } - } - - private class ChatRow extends ChatMessage implements Row { - private String statementString; - - ChatRow(Actor player, String message) { - super(player, message); - - statementString = "INSERT INTO `lb-chat` (date, playerid, message) VALUES (FROM_UNIXTIME(?), ?, ?)"; - } - - @Override - public String[] getInserts() { - return new String[] { "INSERT INTO `lb-chat` (date, playerid, message) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(player) + ", '" + mysqlTextEscape(message) + "');" }; - } - - @Override - public Actor[] getActors() { - return new Actor[] { player }; - } - - @Override - public void process(Connection conn, BatchHelper batchHelper) throws SQLException { - PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); - smt.setLong(1, date); - smt.setInt(2, playerIDAsIntIncludeUncommited(player)); - smt.setString(3, message); - batchHelper.addBatch(smt, null); - } - } - - private class PlayerJoinRow implements Row { - private final Actor player; - private final long lastLogin; - private final String ip; - private String statementString; - - PlayerJoinRow(Player player) { - this.player = Actor.actorFromEntity(player); - lastLogin = System.currentTimeMillis() / 1000; - ip = player.getAddress().toString().replace("'", "\\'"); - - if (logPlayerInfo) { - statementString = "UPDATE `lb-players` SET lastlogin = FROM_UNIXTIME(?), firstlogin = IF(firstlogin = 0, FROM_UNIXTIME(?), firstlogin), ip = ?, playername = ? WHERE UUID = ?"; - } else { - statementString = "UPDATE `lb-players` SET playername = ? WHERE UUID = ?"; - } - } - - @Override - public String[] getInserts() { - if (logPlayerInfo) { - return new String[] { - "UPDATE `lb-players` SET lastlogin = FROM_UNIXTIME(" + lastLogin + "), firstlogin = IF(firstlogin = 0, FROM_UNIXTIME(" + lastLogin + "), firstlogin), ip = '" + ip + "', playername = '" + mysqlTextEscape(player.getName()) + "' WHERE UUID = '" + player.getUUID() + "';" }; - } - return new String[] { "UPDATE `lb-players` SET playername = '" + mysqlTextEscape(player.getName()) + "' WHERE UUID = '" + mysqlTextEscape(player.getUUID()) + "';" }; - } - - @Override - public Actor[] getActors() { - return new Actor[] { player }; - } - - @Override - public void process(Connection conn, BatchHelper batchHelper) throws SQLException { - PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); - if (logPlayerInfo) { - smt.setLong(1, lastLogin); - smt.setLong(2, lastLogin); - smt.setString(3, ip); - smt.setString(4, player.getName()); - smt.setString(5, player.getUUID()); - } else { - smt.setString(1, player.getName()); - smt.setString(2, player.getUUID()); - } - batchHelper.addBatch(smt, null); - } - } - - private class PlayerLeaveRow implements Row { - private final long onlineTime; - private final Actor actor; - private String statementString; - - PlayerLeaveRow(Player player, long onlineTime) { - this.onlineTime = onlineTime; - actor = Actor.actorFromEntity(player); - statementString = "UPDATE `lb-players` SET onlinetime = onlinetime + ? WHERE lastlogin > 0 && UUID = ?"; - } - - @Override - public String[] getInserts() { - if (logPlayerInfo) { - return new String[] { "UPDATE `lb-players` SET onlinetime = onlinetime + " + onlineTime + " WHERE lastlogin > 0 && UUID = '" + mysqlTextEscape(actor.getUUID()) + "';" }; - } - return new String[0]; - } - - @Override - public Actor[] getActors() { - return new Actor[] { actor }; - } - - @Override - public void process(Connection conn, BatchHelper batchHelper) throws SQLException { - PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); - smt.setLong(1, onlineTime); - smt.setString(2, actor.getUUID()); - batchHelper.addBatch(smt, null); - } - } - - private class EntityRow extends EntityChange implements Row { - final String statementString; - final String selectActorIdStatementString; - - public EntityRow(Location loc, Actor actor, EntityType type, UUID entityid, EntityChangeType changeType, byte[] data) { - super(System.currentTimeMillis() / 1000, loc, actor, type, entityid, changeType, data); - statementString = getWorldConfig(loc.getWorld()).insertEntityStatementString; - selectActorIdStatementString = getWorldConfig(loc.getWorld()).selectBlockActorIdStatementString; - } - - @Override - public String[] getInserts() { - final String table = getWorldConfig(loc.getWorld()).table; - final String[] inserts = new String[2]; - - inserts[0] = "INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) SELECT '" + mysqlTextEscape(entityUUID.toString()) + "' FROM `" + table + "-entityids` WHERE NOT EXISTS (SELECT NULL FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(entityUUID.toString()) + "') LIMIT 1"; - int entityTypeId = EntityTypeConverter.getOrAddEntityTypeId(type); - inserts[1] = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(actor) + ", " + "(SELECT entityid FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(entityUUID.toString()) + "')" - + ", " + entityTypeId + ", '" + loc.getBlockX() + "', " + safeY(loc) + ", '" + loc.getBlockZ() + "', " + changeType.ordinal() + ", " + Utils.mysqlPrepareBytesForInsertAllowNull(data) + ");"; - return inserts; - } - - @Override - public Actor[] getActors() { - return new Actor[] { actor }; - } - - @Override - public void process(Connection conn, BatchHelper batchHelper) throws SQLException { - int sourceActor = playerIDAsIntIncludeUncommited(actor); - Location actorBlockLocation = actor.getBlockLocation(); - if (actorBlockLocation != null) { - Integer tempSourceActor = batchHelper.getUncommitedBlockActor(actorBlockLocation); - if (tempSourceActor != null) { - sourceActor = tempSourceActor; - } else { - PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, selectActorIdStatementString, Statement.NO_GENERATED_KEYS); - smt.setInt(1, actorBlockLocation.getBlockX()); - smt.setInt(2, safeY(actorBlockLocation)); - smt.setInt(3, actorBlockLocation.getBlockZ()); - ResultSet rs = smt.executeQuery(); - if (rs.next()) { - sourceActor = rs.getInt(1); - } - rs.close(); - } - } - PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); - smt.setLong(1, date); - smt.setInt(2, sourceActor); - smt.setLong(3, getEntityUUID(conn, loc.getWorld(), entityUUID)); - smt.setInt(4, EntityTypeConverter.getOrAddEntityTypeId(type)); - smt.setInt(5, loc.getBlockX()); - smt.setInt(6, safeY(loc)); - smt.setInt(7, loc.getBlockZ()); - smt.setInt(8, changeType.ordinal()); - smt.setBytes(9, data); - batchHelper.addBatch(smt, null); - } - } - - private class EntityUUIDChange implements Row { - private final World world; - private final long entityId; - private final UUID entityUUID; - final String updateEntityUUIDString; - - public EntityUUIDChange(World world, long entityId, UUID entityUUID) { - this.world = world; - this.entityId = entityId; - this.entityUUID = entityUUID; - updateEntityUUIDString = getWorldConfig(world).updateEntityUUIDString; - } - - @Override - public String[] getInserts() { - final String table = getWorldConfig(world).table; - final String[] inserts = new String[1]; - - inserts[0] = "UPDATE `" + table + "-entityids` SET entityuuid = '" + mysqlTextEscape(entityUUID.toString()) + "' WHERE entityid = " + entityId; - return inserts; - } - - @Override - public Actor[] getActors() { - return new Actor[0]; - } - - @Override - public void process(Connection conn, BatchHelper batchHelper) throws SQLException { - PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, updateEntityUUIDString, Statement.NO_GENERATED_KEYS); - smt.setString(1, entityUUID.toString()); - smt.setLong(2, entityId); - smt.executeUpdate(); - } - } - - private int safeY(Location loc) { - int safeY = loc.getBlockY(); - if (safeY < Short.MIN_VALUE) { - safeY = Short.MIN_VALUE; - } - if (safeY > Short.MAX_VALUE) { - safeY = Short.MAX_VALUE; - } - return safeY; - } - - private class BatchHelper { - private HashMap preparedStatements = new HashMap<>(); - private HashSet preparedStatementsWithGeneratedKeys = new HashSet<>(); - private LinkedHashMap> generatedKeyHandler = new LinkedHashMap<>(); - private HashMap uncommitedBlockActors = new HashMap<>(); - - public void reset() { - preparedStatements.clear(); - preparedStatementsWithGeneratedKeys.clear(); - generatedKeyHandler.clear(); - uncommitedBlockActors.clear(); - } - - public void addUncommitedBlockActorId(Location loc, int actorId) { - uncommitedBlockActors.put(loc, actorId); - } - - public Integer getUncommitedBlockActor(Location loc) { - return uncommitedBlockActors.get(loc); - } - - public void processStatements(Connection conn) throws SQLException { - while (!generatedKeyHandler.isEmpty()) { - Entry> entry = generatedKeyHandler.entrySet().iterator().next(); - PreparedStatement smt = entry.getKey(); - ArrayList callbackList = entry.getValue(); - generatedKeyHandler.remove(smt); - smt.executeBatch(); - if (preparedStatementsWithGeneratedKeys.contains(smt)) { - ResultSet keys = smt.getGeneratedKeys(); - long[] results = new long[callbackList.size()]; - int pos = 0; - while (keys.next() && pos < results.length) { - results[pos++] = keys.getLong(1); - } - keys.close(); - for (int i = 0; i < results.length; i++) { - LongCallback callback = callbackList.get(i); - if (callback != null) { - callback.call(results[i]); - } - } - } - } - uncommitedBlockActors.clear(); - } - - public PreparedStatement getOrPrepareStatement(Connection conn, String sql, int autoGeneratedKeys) throws SQLException { - PreparedStatement smt = preparedStatements.get(sql); - if (smt == null) { - smt = conn.prepareStatement(sql, autoGeneratedKeys); - preparedStatements.put(sql, smt); - if (autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS) { - preparedStatementsWithGeneratedKeys.add(smt); - } - } - return smt; - } - - public void addBatch(PreparedStatement smt, LongCallback generatedKeysCallback) throws SQLException { - smt.addBatch(); - ArrayList callbackList = generatedKeyHandler.get(smt); - if (callbackList == null) { - callbackList = new ArrayList<>(); - generatedKeyHandler.put(smt, callbackList); - } - callbackList.add(generatedKeysCallback); - } - } - - protected interface LongCallback { - public void call(long value) throws SQLException; - } -} +package de.diddiz.LogBlock; + +import static de.diddiz.LogBlock.config.Config.getWorldConfig; +import static de.diddiz.LogBlock.config.Config.hiddenBlocks; +import static de.diddiz.LogBlock.config.Config.hiddenPlayers; +import static de.diddiz.LogBlock.config.Config.isLogged; +import static de.diddiz.LogBlock.config.Config.logPlayerInfo; +import static de.diddiz.LogBlock.util.BukkitUtils.compressInventory; +import static de.diddiz.LogBlock.util.BukkitUtils.itemIDfromProjectileEntity; +import static de.diddiz.LogBlock.util.Utils.mysqlTextEscape; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; +import java.util.logging.Level; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.projectiles.ProjectileSource; + +import de.diddiz.LogBlock.EntityChange.EntityChangeType; +import de.diddiz.LogBlock.blockstate.BlockStateCodecs; +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.Utils; + +public class Consumer extends Thread { + private static final int MAX_SHUTDOWN_TIME_MILLIS = 20000; + private static final int WAIT_FOR_CONNECTION_TIME_MILLIS = 10000; + private static final int RETURN_IDLE_CONNECTION_TIME_MILLIS = 120000; + private static final int RETRIES_ON_UNKNOWN_CONNECTION_ERROR = 2; + + private final Deque queue = new ArrayDeque<>(); + private final LogBlock logblock; + private final Map playerIds = new HashMap<>(); + private final Map uncommitedPlayerIds = new HashMap<>(); + private final Map> uncommitedEntityIds = new HashMap<>(); + + private long addEntryCounter; + private long nextWarnCounter; + + private boolean shutdown; + private long shutdownInitialized; + + Consumer(LogBlock logblock) { + this.logblock = logblock; + PlayerLeaveRow.class.getName(); // preload this class + setName("Logblock-Consumer"); + } + + public LogBlock getLogblock() { + return logblock; + } + + /** + * Logs any block change. Don't try to combine broken and placed blocks. Queue two block changes or use the queueBLockReplace methods. + * + * @param actor + * Actor responsible for making the change + * @param loc + * Location of the block change + * @param typeBefore + * BlockData of the block before the change + * @param typeAfter + * BlockData of the block after the change + */ + public void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter) { + queueBlock(actor, loc, typeBefore, typeAfter, null, null, null); + } + + /** + * Logs a block break. The type afterwards is assumed to be air. + * + * @param actor + * Actor responsible for breaking the block + * @param before + * BlockState of the block before actually being destroyed. + */ + public void queueBlockBreak(Actor actor, BlockState before) { + queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), null, BlockStateCodecs.serialize(before), null, null); + } + + /** + * Logs a block break. The block type afterwards is assumed to be air. + * + * @param actor + * Actor responsible for the block break + * @param loc + * Location of the broken block + * @param typeBefore + * BlockData of the block before the break + */ + public void queueBlockBreak(Actor actor, Location loc, BlockData typeBefore) { + queueBlock(actor, loc, typeBefore, null); + } + + /** + * Logs a block place. The block type before is assumed to be air. + * + * @param actor + * Actor responsible for placing the block + * @param after + * BlockState of the block after actually being placed. + */ + public void queueBlockPlace(Actor actor, BlockState after) { + queueBlock(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), null, after.getBlockData(), null, BlockStateCodecs.serialize(after), null); + } + + /** + * Logs a block place. The block type before is assumed to be air. + * + * @param actor + * Actor responsible for placing the block + * @param loc + * Location of the placed block + * @param type + * BlockData of the placed block + */ + public void queueBlockPlace(Actor actor, Location loc, BlockData type) { + queueBlock(actor, loc, null, type); + } + + /** + * Logs a block being replaced from the before and after {@link org.bukkit.block.BlockState}s + * + * @param actor + * Actor responsible for replacing the block + * @param before + * BlockState of the block before actually being destroyed. + * @param after + * BlockState of the block after actually being placed. + */ + public void queueBlockReplace(Actor actor, BlockState before, BlockState after) { + queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), after.getBlockData(), BlockStateCodecs.serialize(before), BlockStateCodecs.serialize(after), null); + } + + /** + * Logs a block being replaced from the before {@link org.bukkit.block.BlockState} and the type and data after + * + * @param actor + * Actor responsible for replacing the block + * @param before + * BlockState of the block before being replaced. + * @param typeAfter + * BlockData of the block after being replaced + */ + public void queueBlockReplace(Actor actor, BlockState before, BlockData typeAfter) { + queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), typeAfter, BlockStateCodecs.serialize(before), null, null); + } + + /** + * Logs a block being replaced from the type and data before and the {@link org.bukkit.block.BlockState} after + * + * @param actor + * Actor responsible for replacing the block + * @param typeBefore + * BlockData of the block before being replaced + * @param after + * BlockState of the block after actually being placed. + */ + public void queueBlockReplace(Actor actor, BlockData typeBefore, BlockState after) { + queueBlock(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), typeBefore, after.getBlockData(), null, BlockStateCodecs.serialize(after), null); + } + + public void queueBlockReplace(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter) { + queueBlock(actor, loc, typeBefore, typeAfter, null, null, null); + } + + /** + * Logs an actor interacting with a container block's inventory + * + * @param actor + * The actor interacting with the container + * @param container + * The respective container. Must be an instance of an InventoryHolder. + * @param itemStack + * Item taken/stored, including amount + * @param remove + * true if the item was removed + */ + public void queueChestAccess(Actor actor, BlockState container, ItemStack itemStack, boolean remove) { + if (!(container instanceof InventoryHolder)) { + throw new IllegalArgumentException("Container must be instanceof InventoryHolder"); + } + queueChestAccess(actor, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getBlockData(), itemStack, remove); + } + + /** + * Logs an actor interacting with a container block's inventory + * + * @param actor + * The actor interacting with the container + * @param loc + * The location of the container block + * @param type + * BlockData of the container. + * @param itemStack + * Item taken/stored, including amount + * @param remove + * true if the item was removed + */ + 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()))); + } + + /** + * Logs a container block break. The block type before is assumed to be air. All content is assumed to be taken. + * + * @param actor + * The actor breaking the container + * @param container + * Must be an instance of InventoryHolder + */ + public void queueContainerBreak(Actor actor, BlockState container) { + if (!(container instanceof InventoryHolder)) { + return; + } + queueContainerBreak(actor, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getBlockData(), ((InventoryHolder) container).getInventory()); + } + + /** + * Logs a container block break. The block type before is assumed to be air. All content is assumed to be taken. + * + * @param actor + * The actor responsible for breaking the container + * @param loc + * The location of the inventory block + * @param type + * BlockData of the container block + * @param inv + * The inventory of the container block + */ + public void queueContainerBreak(Actor actor, Location loc, BlockData type, Inventory inv) { + final ItemStack[] items = compressInventory(inv.getContents()); + for (final ItemStack item : items) { + queueChestAccess(actor, loc, type, item, true); + } + queueBlockBreak(actor, loc, type); + } + + /** + * @param killer + * Can't be null + * @param victim + * Can't be null + */ + public void queueKill(Entity killer, Entity victim) { + if (killer == null || victim == null) { + return; + } + ItemStack weapon = null; + Actor killerActor = Actor.actorFromEntity(killer); + // If it's a projectile kill we want to manually assign the weapon, so check for player before converting a projectile to its source + if (killer instanceof Player && ((Player) killer).getInventory().getItemInMainHand() != null) { + weapon = ((Player) killer).getInventory().getItemInMainHand(); + } + if (killer instanceof Projectile) { + Material projectileMaterial = itemIDfromProjectileEntity(killer); + weapon = projectileMaterial == null ? null : new ItemStack(projectileMaterial); + ProjectileSource ps = ((Projectile) killer).getShooter(); + if (ps == null) { + killerActor = Actor.actorFromEntity(killer); + } else { + killerActor = Actor.actorFromProjectileSource(ps); + } + } + + queueKill(victim.getLocation(), killerActor, Actor.actorFromEntity(victim), weapon); + } + + /** + * This form should only be used when the killer is not an entity e.g. for fall or suffocation damage + * + * @param killer + * Can't be null + * @param victim + * Can't be null + */ + public void queueKill(Actor killer, Entity victim) { + if (killer == null || victim == null) { + return; + } + queueKill(victim.getLocation(), killer, Actor.actorFromEntity(victim), null); + } + + /** + * @param location + * Location of the victim. + * @param killer + * Killer Actor. Can be null. + * @param victim + * Victim Actor. Can't be null. + * @param weapon + * Item of the weapon. null for no weapon. + */ + public void queueKill(Location location, Actor killer, Actor victim, ItemStack weapon) { + if (victim == null || !isLogged(location.getWorld())) { + return; + } + addQueueLast(new KillRow(location, killer == null ? null : killer, victim, weapon == null ? 0 : MaterialConverter.getOrAddMaterialId(weapon.getType()))); + } + + public void queueChat(Actor player, String message) { + if (!Config.ignoredChat.isEmpty()) { + String lowerCaseMessage = message.toLowerCase(); + for (String ignored : Config.ignoredChat) { + if (lowerCaseMessage.startsWith(ignored)) { + return; + } + } + } + if (hiddenPlayers.contains(player.getName().toLowerCase())) { + return; + } + while (message.length() > 256) { + addQueueLast(new ChatRow(player, message.substring(0, 256))); + message = message.substring(256); + } + addQueueLast(new ChatRow(player, message)); + } + + public void queueJoin(Player player) { + addQueueLast(new PlayerJoinRow(player)); + } + + public void queueLeave(Player player, long onlineTime) { + addQueueLast(new PlayerLeaveRow(player, onlineTime)); + } + + public void shutdown() { + synchronized (queue) { + shutdown = true; + shutdownInitialized = System.currentTimeMillis(); + queue.notifyAll(); + } + while (isAlive()) { + try { + join(); + } catch (InterruptedException e) { + // ignore + } + } + } + + @Override + public void run() { + ArrayList currentRows = new ArrayList<>(); + Connection conn = null; + BatchHelper batchHelper = new BatchHelper(); + int lastCommitsFailed = 0; + while (true) { + try { + if (conn == null) { + batchHelper.reset(); + conn = logblock.getConnection(); + if (conn != null) { + // initialize connection + conn.setAutoCommit(false); + } else { + // we did not get a connection + boolean wantsShutdown; + synchronized (queue) { + wantsShutdown = shutdown; + } + if (wantsShutdown) { + // lets give up + break; + } + // wait for a connection + logblock.getLogger().severe("[Consumer] Could not connect to the database!"); + try { + Thread.sleep(WAIT_FOR_CONNECTION_TIME_MILLIS); + } catch (InterruptedException e) { + // ignore + } + continue; + } + } + Row r; + boolean processBatch = false; + synchronized (queue) { + if (shutdown) { + // Give this thread some time to process the remaining entries + if (queue.isEmpty() || System.currentTimeMillis() - shutdownInitialized > MAX_SHUTDOWN_TIME_MILLIS) { + if (currentRows.isEmpty()) { + break; + } else { + processBatch = true; + } + } + } + r = queue.pollFirst(); + if (r == null) { + try { + if (currentRows.isEmpty() && !shutdown) { + // nothing to do for us + // wait some time before closing the connection + queue.wait(RETURN_IDLE_CONNECTION_TIME_MILLIS); + // if there is still nothing to do, close the connection and go to sleep + if (queue.isEmpty() && !shutdown) { + try { + conn.close(); + } catch (Exception e) { + // ignored + } + conn = null; + queue.wait(); + } + } else { + processBatch = true; + } + } catch (InterruptedException e) { + // ignore + } + } + } + if (r != null) { + boolean failOnActors = false; + for (final Actor actor : r.getActors()) { + if (playerIDAsIntIncludeUncommited(actor) == null) { + if (!addPlayer(conn, actor)) { + failOnActors = true; // skip this row + } + } + } + if (!failOnActors) { + currentRows.add(r); + r.process(conn, batchHelper); + } + } + if (currentRows.size() >= Math.max((processBatch ? 1 : (Config.forceToProcessAtLeast * 10)), 1)) { + batchHelper.processStatements(conn); + conn.commit(); + currentRows.clear(); + playerIds.putAll(uncommitedPlayerIds); + uncommitedPlayerIds.clear(); + uncommitedEntityIds.clear(); + lastCommitsFailed = 0; + } + } catch (Exception e) { + boolean retry = lastCommitsFailed < RETRIES_ON_UNKNOWN_CONNECTION_ERROR; + String state = "unknown"; + if (e instanceof SQLException) { + // Retry on network errors: SQLSTATE = 08S01 08001 08004 HY000 40001 + state = ((SQLException) e).getSQLState(); + retry = retry || (state != null && (state.equals("08S01") || state.equals("08001") || state.equals("08004") || state.equals("HY000") || state.equals("40001"))); + } + lastCommitsFailed += 1; + if (retry) { + logblock.getLogger().log(Level.WARNING, "[Consumer] Database connection lost, reconnecting! SQLState: " + state); + // readd rows to the queue + synchronized (queue) { + while (!currentRows.isEmpty()) { + queue.addFirst(currentRows.remove(currentRows.size() - 1)); + } + } + } else { + logblock.getLogger().log(Level.SEVERE, "[Consumer] Could not insert entries! SQLState: " + state, e); + } + currentRows.clear(); + batchHelper.reset(); + uncommitedPlayerIds.clear(); + uncommitedEntityIds.clear(); + if (conn != null) { + try { + conn.close(); + } catch (SQLException e1) { + // ignore + } + } + conn = null; + } + } + if (conn != null) { + try { + conn.close(); + } catch (SQLException e1) { + // ignore + } + } + + // readd to queue - this can be saved later + synchronized (queue) { + while (!currentRows.isEmpty()) { + queue.addFirst(currentRows.remove(currentRows.size() - 1)); + } + } + } + + public void writeToFile() throws FileNotFoundException { + final long time = System.currentTimeMillis(); + final Set insertedPlayers = new HashSet<>(); + int counter = 0; + final File importDir = new File(logblock.getDataFolder(), "import"); + importDir.mkdirs(); + PrintWriter writer = new PrintWriter(new File(importDir, "queue-" + time + "-0.sql")); + while (!isQueueEmpty()) { + final Row r = pollQueueFirst(); + if (r == null) { + continue; + } + for (final Actor actor : r.getActors()) { + if (!playerIds.containsKey(actor) && !insertedPlayers.contains(actor)) { + // Odd query contruction is to work around innodb auto increment behaviour - bug #492 + writer.println("INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + mysqlTextEscape(actor.getName()) + "','" + mysqlTextEscape(actor.getUUID()) + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(actor.getUUID()) + "') LIMIT 1;"); + insertedPlayers.add(actor); + } + } + for (final String insert : r.getInserts()) { + writer.println(insert); + } + counter++; + if (counter % 1000 == 0) { + writer.close(); + writer = new PrintWriter(new File(importDir, "queue-" + time + "-" + counter / 1000 + ".sql")); + } + } + writer.close(); + } + + int getQueueSize() { + synchronized (queue) { + return queue.size(); + } + } + + private boolean isQueueEmpty() { + synchronized (queue) { + return queue.isEmpty(); + } + } + + private void addQueueLast(Row row) { + synchronized (queue) { + boolean wasEmpty = queue.isEmpty(); + queue.addLast(row); + addEntryCounter++; + if (Config.queueWarningSize > 0 && queue.size() >= Config.queueWarningSize && addEntryCounter >= nextWarnCounter) { + logblock.getLogger().warning("[Consumer] Queue overloaded. Size: " + queue.size()); + nextWarnCounter = addEntryCounter + 1000; + } + if (wasEmpty) { + queue.notifyAll(); + } + } + } + + private Row pollQueueFirst() { + synchronized (queue) { + return queue.pollFirst(); + } + } + + static void hide(Player player) { + hiddenPlayers.add(player.getName().toLowerCase()); + } + + static void unHide(Player player) { + hiddenPlayers.remove(player.getName().toLowerCase()); + } + + static boolean toggleHide(Player player) { + final String playerName = player.getName().toLowerCase(); + if (hiddenPlayers.contains(playerName)) { + hiddenPlayers.remove(playerName); + return false; + } + hiddenPlayers.add(playerName); + return true; + } + + private boolean addPlayer(Connection conn, Actor actor) throws SQLException { + // Odd query contruction is to work around innodb auto increment behaviour - bug #492 + String name = actor.getName(); + String uuid = actor.getUUID(); + Statement state = conn.createStatement(); + String q1 = "INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + mysqlTextEscape(name) + "','" + mysqlTextEscape(uuid) + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(uuid) + "') LIMIT 1"; + String q2 = "SELECT playerid FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(uuid) + "'"; + int q1Result = state.executeUpdate(q1); + ResultSet rs = state.executeQuery(q2); + if (rs.next()) { + uncommitedPlayerIds.put(actor, rs.getInt(1)); + } + rs.close(); + if (!uncommitedPlayerIds.containsKey(actor)) { + state.executeUpdate("INSERT IGNORE INTO `lb-players` (playername,UUID) VALUES ('" + mysqlTextEscape(name) + "','" + mysqlTextEscape(uuid) + "')"); + rs = state.executeQuery(q2); + if (rs.next()) { + uncommitedPlayerIds.put(actor, rs.getInt(1)); + } else { + logblock.getLogger().warning("[Consumer] Failed to add player " + actor.getName()); + logblock.getLogger().warning("[Consumer-Debug] Query 1: " + q1); + logblock.getLogger().warning("[Consumer-Debug] Query 1 - Result: " + q1Result); + logblock.getLogger().warning("[Consumer-Debug] Query 2: " + q2); + } + rs.close(); + } + state.close(); + return uncommitedPlayerIds.containsKey(actor); + } + + private long getEntityUUID(Connection conn, World world, UUID uuid) throws SQLException { + Map uncommitedEntityIdsHere = uncommitedEntityIds.get(world); + if (uncommitedEntityIdsHere == null) { + uncommitedEntityIdsHere = new HashMap<>(); + uncommitedEntityIds.put(world, uncommitedEntityIdsHere); + } + Long existing = uncommitedEntityIdsHere.get(uuid); + if (existing != null) { + return existing; + } + + // Odd query contruction is to work around innodb auto increment behaviour - bug #492 + final String table = getWorldConfig(world).table; + String uuidString = uuid.toString(); + Statement state = conn.createStatement(); + String q1 = "INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) SELECT '" + mysqlTextEscape(uuidString) + "' FROM `" + table + "-entityids` WHERE NOT EXISTS (SELECT NULL FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(uuidString) + "') LIMIT 1"; + String q2 = "SELECT entityid FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(uuidString) + "'"; + int q1Result = state.executeUpdate(q1); + ResultSet rs = state.executeQuery(q2); + if (rs.next()) { + uncommitedEntityIdsHere.put(uuid, rs.getLong(1)); + } + rs.close(); + // if there was not any row in the table the query above does not work, so we need to try this one + if (!uncommitedEntityIdsHere.containsKey(uuid)) { + state.executeUpdate("INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) VALUES ('" + mysqlTextEscape(uuidString) + "')"); + rs = state.executeQuery(q2); + if (rs.next()) { + uncommitedEntityIdsHere.put(uuid, rs.getLong(1)); + } else { + logblock.getLogger().warning("[Consumer] Failed to add entity uuid " + uuidString.toString()); + logblock.getLogger().warning("[Consumer-Debug] World: " + world.getName()); + logblock.getLogger().warning("[Consumer-Debug] Query 1: " + q1); + logblock.getLogger().warning("[Consumer-Debug] Query 1 - Result: " + q1Result); + logblock.getLogger().warning("[Consumer-Debug] Query 2: " + q2); + } + rs.close(); + } + state.close(); + return uncommitedEntityIdsHere.get(uuid); + } + + private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter, YamlConfiguration stateBefore, YamlConfiguration stateAfter, ChestAccess ca) { + if (typeBefore == null || typeBefore.getMaterial() == Material.CAVE_AIR || typeBefore.getMaterial() == Material.VOID_AIR) { + typeBefore = Bukkit.createBlockData(Material.AIR); + } + if (typeAfter == null && ((typeBefore instanceof Waterlogged && ((Waterlogged) typeBefore).isWaterlogged()) || BukkitUtils.isAlwaysWaterlogged(typeBefore.getMaterial()))) { + typeAfter = Bukkit.createBlockData(Material.WATER); + } + if (typeAfter == null || typeAfter.getMaterial() == Material.CAVE_AIR || typeAfter.getMaterial() == Material.VOID_AIR) { + typeAfter = Bukkit.createBlockData(Material.AIR); + } + if (BlockChangePreLogEvent.getHandlerList().getRegisteredListeners().length > 0) { + // Create and call the event + BlockChangePreLogEvent event = new BlockChangePreLogEvent(actor, loc, typeBefore, typeAfter, stateBefore, stateAfter, ca); + logblock.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + + // Update variables + actor = event.getOwnerActor(); + loc = event.getLocation(); + typeBefore = event.getTypeBefore(); + typeAfter = event.getTypeAfter(); + stateBefore = event.getStateBefore(); + stateAfter = event.getStateAfter(); + ca = event.getChestAccess(); + } + // Do this last so LogBlock still has final say in what is being added + if (actor == null || loc == null || typeBefore == null || typeAfter == null || hiddenPlayers.contains(actor.getName().toLowerCase()) || !isLogged(loc.getWorld()) || typeBefore != typeAfter && hiddenBlocks.contains(typeBefore.getMaterial()) && hiddenBlocks.contains(typeAfter.getMaterial())) { + return; + } + + int replacedMaterialId = MaterialConverter.getOrAddMaterialId(typeBefore); + int replacedStateId = MaterialConverter.getOrAddBlockStateId(typeBefore); + int typeMaterialId = MaterialConverter.getOrAddMaterialId(typeAfter); + int typeStateId = MaterialConverter.getOrAddBlockStateId(typeAfter); + + addQueueLast(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, Utils.serializeYamlConfiguration(stateBefore), typeMaterialId, typeStateId, Utils.serializeYamlConfiguration(stateAfter), ca)); + } + + public void queueEntityModification(Actor actor, Entity entity, EntityChangeType changeType, YamlConfiguration data) { + if (actor == null || changeType == null || entity == null || hiddenPlayers.contains(actor.getName().toLowerCase()) || !isLogged(entity.getWorld())) { + return; + } + UUID entityId = entity.getUniqueId(); + EntityType entityType = entity.getType(); + Location loc = entity.getLocation(); + + if (EntityChangePreLogEvent.getHandlerList().getRegisteredListeners().length > 0) { + // Create and call the event + EntityChangePreLogEvent event = new EntityChangePreLogEvent(actor, loc, entity, changeType, data); + logblock.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + + // Update variables + actor = event.getOwnerActor(); + loc = event.getLocation(); + } + // Do this last so LogBlock still has final say in what is being added + if (actor == null || loc == null || hiddenPlayers.contains(actor.getName().toLowerCase()) || !isLogged(loc.getWorld())) { + return; + } + + addQueueLast(new EntityRow(loc, actor, entityType, entityId, changeType, Utils.serializeYamlConfiguration(data))); + } + + /** + * Change the UUID that is stored for an entity in the database. This is needed when an entity is respawned + * and now has a different UUID. + * + * @param world the world that contains the entity + * @param entityId the database id of the entity + * @param entityUUID the new UUID of the entity + */ + public void queueEntityUUIDChange(World world, int entityId, UUID entityUUID) { + addQueueLast(new EntityUUIDChange(world, entityId, entityUUID)); + } + + private String playerID(Actor actor) { + if (actor == null) { + return "NULL"; + } + final Integer id = playerIds.get(actor); + if (id != null) { + return id.toString(); + } + return "(SELECT playerid FROM `lb-players` WHERE UUID = '" + mysqlTextEscape(actor.getUUID()) + "')"; + } + + private Integer playerIDAsIntIncludeUncommited(Actor actor) { + if (actor == null) { + return null; + } + Integer id = playerIds.get(actor); + if (id != null) { + return id; + } + return uncommitedPlayerIds.get(actor); + } + + private static interface Row { + String[] getInserts(); + + void process(Connection conn, BatchHelper batchHelper) throws SQLException; + + Actor[] getActors(); + } + + private class BlockRow extends BlockChange implements Row { + final String statementString; + final String selectActorIdStatementString; + + public BlockRow(Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { + super(System.currentTimeMillis() / 1000, loc, actor, replaced, replacedData, replacedState, type, typeData, typeState, ca); + + statementString = getWorldConfig(loc.getWorld()).insertBlockStatementString; + selectActorIdStatementString = getWorldConfig(loc.getWorld()).selectBlockActorIdStatementString; + } + + @Override + public String[] getInserts() { + final String table = getWorldConfig(loc.getWorld()).table; + final String[] inserts = new String[ca != null || replacedState != null || typeState != null ? 2 : 1]; + + inserts[0] = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(actor) + ", " + replacedMaterial + ", " + replacedData + ", " + typeMaterial + ", " + typeData + ", '" + loc.getBlockX() + + "', " + safeY(loc) + ", '" + loc.getBlockZ() + "');"; + if (replacedState != null || typeState != null) { + inserts[1] = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(" + Utils.mysqlPrepareBytesForInsertAllowNull(replacedState) + ", " + Utils.mysqlPrepareBytesForInsertAllowNull(typeState) + ", LAST_INSERT_ID());"; + } else if (ca != null) { + try { + inserts[1] = "INSERT INTO `" + table + "-chestdata` (id, item, itemremove, itemtype) values (LAST_INSERT_ID(), '" + Utils.mysqlEscapeBytes(Utils.saveItemStack(ca.itemStack)) + "', " + (ca.remove ? 1 : 0) + ", " + ca.itemType + ");"; + } catch (Exception e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not serialize ItemStack " + e.getMessage(), e); + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Problematic row: " + toString()); + return new String[0]; + } + } + return inserts; + } + + @Override + public Actor[] getActors() { + return new Actor[] { actor }; + } + + @Override + public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + byte[] serializedItemStack = null; + if (ca != null) { + try { + serializedItemStack = Utils.saveItemStack(ca.itemStack); + } catch (Exception e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not serialize ItemStack " + e.getMessage(), e); + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Problematic row: " + toString()); + return; + } + } + final byte[] finalSerializedItemStack = serializedItemStack; + int sourceActor = playerIDAsIntIncludeUncommited(actor); + Location actorBlockLocation = actor.getBlockLocation(); + if (actorBlockLocation != null) { + Integer tempSourceActor = batchHelper.getUncommitedBlockActor(actorBlockLocation); + if (tempSourceActor != null) { + sourceActor = tempSourceActor; + } else { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, selectActorIdStatementString, Statement.NO_GENERATED_KEYS); + smt.setInt(1, actorBlockLocation.getBlockX()); + smt.setInt(2, safeY(actorBlockLocation)); + smt.setInt(3, actorBlockLocation.getBlockZ()); + ResultSet rs = smt.executeQuery(); + if (rs.next()) { + sourceActor = rs.getInt(1); + } + rs.close(); + } + } + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.RETURN_GENERATED_KEYS); + smt.setLong(1, date); + smt.setInt(2, sourceActor); + smt.setInt(3, replacedMaterial); + smt.setInt(4, replacedData); + smt.setInt(5, typeMaterial); + smt.setInt(6, typeData); + smt.setInt(7, loc.getBlockX()); + smt.setInt(8, safeY(loc)); + smt.setInt(9, loc.getBlockZ()); + batchHelper.addUncommitedBlockActorId(loc, sourceActor); + batchHelper.addBatch(smt, new LongCallback() { + @Override + public void call(long id) throws SQLException { + PreparedStatement ps; + if (typeState != null || replacedState != null) { + ps = batchHelper.getOrPrepareStatement(conn, getWorldConfig(loc.getWorld()).insertBlockStateStatementString, Statement.NO_GENERATED_KEYS); + ps.setBytes(1, replacedState); + ps.setBytes(2, typeState); + ps.setLong(3, id); + batchHelper.addBatch(ps, null); + } + if (ca != null) { + ps = batchHelper.getOrPrepareStatement(conn, getWorldConfig(loc.getWorld()).insertBlockChestDataStatementString, Statement.NO_GENERATED_KEYS); + ps.setBytes(1, finalSerializedItemStack); + ps.setInt(2, ca.remove ? 1 : 0); + ps.setLong(3, id); + ps.setInt(4, ca.itemType); + batchHelper.addBatch(ps, null); + } + } + }); + } + } + + private class KillRow implements Row { + final long date; + final Actor killer, victim; + final int weapon; + final Location loc; + final String statementString; + + KillRow(Location loc, Actor attacker, Actor defender, int weapon) { + date = System.currentTimeMillis() / 1000; + this.loc = loc; + killer = attacker; + victim = defender; + this.weapon = weapon; + + statementString = "INSERT INTO `" + getWorldConfig(loc.getWorld()).table + "-kills` (date, killer, victim, weapon, x, y, z) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?)"; + } + + @Override + public String[] getInserts() { + return new String[] { "INSERT INTO `" + getWorldConfig(loc.getWorld()).table + "-kills` (date, killer, victim, weapon, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(killer) + ", " + playerID(victim) + ", " + weapon + ", " + loc.getBlockX() + ", " + safeY(loc) + ", " + + loc.getBlockZ() + ");" }; + } + + @Override + public Actor[] getActors() { + return new Actor[] { killer, victim }; + } + + @Override + public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); + smt.setLong(1, date); + smt.setInt(2, playerIDAsIntIncludeUncommited(killer)); + smt.setInt(3, playerIDAsIntIncludeUncommited(victim)); + smt.setInt(4, weapon); + smt.setInt(5, loc.getBlockX()); + smt.setInt(6, safeY(loc)); + smt.setInt(7, loc.getBlockZ()); + batchHelper.addBatch(smt, null); + } + } + + private class ChatRow extends ChatMessage implements Row { + private String statementString; + + ChatRow(Actor player, String message) { + super(player, message); + + statementString = "INSERT INTO `lb-chat` (date, playerid, message) VALUES (FROM_UNIXTIME(?), ?, ?)"; + } + + @Override + public String[] getInserts() { + return new String[] { "INSERT INTO `lb-chat` (date, playerid, message) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(player) + ", '" + mysqlTextEscape(message) + "');" }; + } + + @Override + public Actor[] getActors() { + return new Actor[] { player }; + } + + @Override + public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); + smt.setLong(1, date); + smt.setInt(2, playerIDAsIntIncludeUncommited(player)); + smt.setString(3, message); + batchHelper.addBatch(smt, null); + } + } + + private class PlayerJoinRow implements Row { + private final Actor player; + private final long lastLogin; + private final String ip; + private String statementString; + + PlayerJoinRow(Player player) { + this.player = Actor.actorFromEntity(player); + lastLogin = System.currentTimeMillis() / 1000; + ip = player.getAddress().toString().replace("'", "\\'"); + + if (logPlayerInfo) { + statementString = "UPDATE `lb-players` SET lastlogin = FROM_UNIXTIME(?), firstlogin = IF(firstlogin = 0, FROM_UNIXTIME(?), firstlogin), ip = ?, playername = ? WHERE UUID = ?"; + } else { + statementString = "UPDATE `lb-players` SET playername = ? WHERE UUID = ?"; + } + } + + @Override + public String[] getInserts() { + if (logPlayerInfo) { + return new String[] { + "UPDATE `lb-players` SET lastlogin = FROM_UNIXTIME(" + lastLogin + "), firstlogin = IF(firstlogin = 0, FROM_UNIXTIME(" + lastLogin + "), firstlogin), ip = '" + ip + "', playername = '" + mysqlTextEscape(player.getName()) + "' WHERE UUID = '" + player.getUUID() + "';" }; + } + return new String[] { "UPDATE `lb-players` SET playername = '" + mysqlTextEscape(player.getName()) + "' WHERE UUID = '" + mysqlTextEscape(player.getUUID()) + "';" }; + } + + @Override + public Actor[] getActors() { + return new Actor[] { player }; + } + + @Override + public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); + if (logPlayerInfo) { + smt.setLong(1, lastLogin); + smt.setLong(2, lastLogin); + smt.setString(3, ip); + smt.setString(4, player.getName()); + smt.setString(5, player.getUUID()); + } else { + smt.setString(1, player.getName()); + smt.setString(2, player.getUUID()); + } + batchHelper.addBatch(smt, null); + } + } + + private class PlayerLeaveRow implements Row { + private final long onlineTime; + private final Actor actor; + private String statementString; + + PlayerLeaveRow(Player player, long onlineTime) { + this.onlineTime = onlineTime; + actor = Actor.actorFromEntity(player); + statementString = "UPDATE `lb-players` SET onlinetime = onlinetime + ? WHERE lastlogin > 0 && UUID = ?"; + } + + @Override + public String[] getInserts() { + if (logPlayerInfo) { + return new String[] { "UPDATE `lb-players` SET onlinetime = onlinetime + " + onlineTime + " WHERE lastlogin > 0 && UUID = '" + mysqlTextEscape(actor.getUUID()) + "';" }; + } + return new String[0]; + } + + @Override + public Actor[] getActors() { + return new Actor[] { actor }; + } + + @Override + public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); + smt.setLong(1, onlineTime); + smt.setString(2, actor.getUUID()); + batchHelper.addBatch(smt, null); + } + } + + private class EntityRow extends EntityChange implements Row { + final String statementString; + final String selectActorIdStatementString; + + public EntityRow(Location loc, Actor actor, EntityType type, UUID entityid, EntityChangeType changeType, byte[] data) { + super(System.currentTimeMillis() / 1000, loc, actor, type, entityid, changeType, data); + statementString = getWorldConfig(loc.getWorld()).insertEntityStatementString; + selectActorIdStatementString = getWorldConfig(loc.getWorld()).selectBlockActorIdStatementString; + } + + @Override + public String[] getInserts() { + final String table = getWorldConfig(loc.getWorld()).table; + final String[] inserts = new String[2]; + + inserts[0] = "INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) SELECT '" + mysqlTextEscape(entityUUID.toString()) + "' FROM `" + table + "-entityids` WHERE NOT EXISTS (SELECT NULL FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(entityUUID.toString()) + "') LIMIT 1"; + int entityTypeId = EntityTypeConverter.getOrAddEntityTypeId(type); + inserts[1] = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(actor) + ", " + "(SELECT entityid FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(entityUUID.toString()) + "')" + + ", " + entityTypeId + ", '" + loc.getBlockX() + "', " + safeY(loc) + ", '" + loc.getBlockZ() + "', " + changeType.ordinal() + ", " + Utils.mysqlPrepareBytesForInsertAllowNull(data) + ");"; + return inserts; + } + + @Override + public Actor[] getActors() { + return new Actor[] { actor }; + } + + @Override + public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + int sourceActor = playerIDAsIntIncludeUncommited(actor); + Location actorBlockLocation = actor.getBlockLocation(); + if (actorBlockLocation != null) { + Integer tempSourceActor = batchHelper.getUncommitedBlockActor(actorBlockLocation); + if (tempSourceActor != null) { + sourceActor = tempSourceActor; + } else { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, selectActorIdStatementString, Statement.NO_GENERATED_KEYS); + smt.setInt(1, actorBlockLocation.getBlockX()); + smt.setInt(2, safeY(actorBlockLocation)); + smt.setInt(3, actorBlockLocation.getBlockZ()); + ResultSet rs = smt.executeQuery(); + if (rs.next()) { + sourceActor = rs.getInt(1); + } + rs.close(); + } + } + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.NO_GENERATED_KEYS); + smt.setLong(1, date); + smt.setInt(2, sourceActor); + smt.setLong(3, getEntityUUID(conn, loc.getWorld(), entityUUID)); + smt.setInt(4, EntityTypeConverter.getOrAddEntityTypeId(type)); + smt.setInt(5, loc.getBlockX()); + smt.setInt(6, safeY(loc)); + smt.setInt(7, loc.getBlockZ()); + smt.setInt(8, changeType.ordinal()); + smt.setBytes(9, data); + batchHelper.addBatch(smt, null); + } + } + + private class EntityUUIDChange implements Row { + private final World world; + private final long entityId; + private final UUID entityUUID; + final String updateEntityUUIDString; + + public EntityUUIDChange(World world, long entityId, UUID entityUUID) { + this.world = world; + this.entityId = entityId; + this.entityUUID = entityUUID; + updateEntityUUIDString = getWorldConfig(world).updateEntityUUIDString; + } + + @Override + public String[] getInserts() { + final String table = getWorldConfig(world).table; + final String[] inserts = new String[1]; + + inserts[0] = "UPDATE `" + table + "-entityids` SET entityuuid = '" + mysqlTextEscape(entityUUID.toString()) + "' WHERE entityid = " + entityId; + return inserts; + } + + @Override + public Actor[] getActors() { + return new Actor[0]; + } + + @Override + public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, updateEntityUUIDString, Statement.NO_GENERATED_KEYS); + smt.setString(1, entityUUID.toString()); + smt.setLong(2, entityId); + smt.executeUpdate(); + } + } + + private int safeY(Location loc) { + int safeY = loc.getBlockY(); + if (safeY < Short.MIN_VALUE) { + safeY = Short.MIN_VALUE; + } + if (safeY > Short.MAX_VALUE) { + safeY = Short.MAX_VALUE; + } + return safeY; + } + + private class BatchHelper { + private HashMap preparedStatements = new HashMap<>(); + private HashSet preparedStatementsWithGeneratedKeys = new HashSet<>(); + private LinkedHashMap> generatedKeyHandler = new LinkedHashMap<>(); + private HashMap uncommitedBlockActors = new HashMap<>(); + + public void reset() { + preparedStatements.clear(); + preparedStatementsWithGeneratedKeys.clear(); + generatedKeyHandler.clear(); + uncommitedBlockActors.clear(); + } + + public void addUncommitedBlockActorId(Location loc, int actorId) { + uncommitedBlockActors.put(loc, actorId); + } + + public Integer getUncommitedBlockActor(Location loc) { + return uncommitedBlockActors.get(loc); + } + + public void processStatements(Connection conn) throws SQLException { + while (!generatedKeyHandler.isEmpty()) { + Entry> entry = generatedKeyHandler.entrySet().iterator().next(); + PreparedStatement smt = entry.getKey(); + ArrayList callbackList = entry.getValue(); + generatedKeyHandler.remove(smt); + smt.executeBatch(); + if (preparedStatementsWithGeneratedKeys.contains(smt)) { + ResultSet keys = smt.getGeneratedKeys(); + long[] results = new long[callbackList.size()]; + int pos = 0; + while (keys.next() && pos < results.length) { + results[pos++] = keys.getLong(1); + } + keys.close(); + for (int i = 0; i < results.length; i++) { + LongCallback callback = callbackList.get(i); + if (callback != null) { + callback.call(results[i]); + } + } + } + } + uncommitedBlockActors.clear(); + } + + public PreparedStatement getOrPrepareStatement(Connection conn, String sql, int autoGeneratedKeys) throws SQLException { + PreparedStatement smt = preparedStatements.get(sql); + if (smt == null) { + smt = conn.prepareStatement(sql, autoGeneratedKeys); + preparedStatements.put(sql, smt); + if (autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS) { + preparedStatementsWithGeneratedKeys.add(smt); + } + } + return smt; + } + + public void addBatch(PreparedStatement smt, LongCallback generatedKeysCallback) throws SQLException { + smt.addBatch(); + ArrayList callbackList = generatedKeyHandler.get(smt); + if (callbackList == null) { + callbackList = new ArrayList<>(); + generatedKeyHandler.put(smt, callbackList); + } + callbackList.add(generatedKeysCallback); + } + } + + protected interface LongCallback { + public void call(long value) throws SQLException; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java b/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java index f430bb42..0a0d9d29 100644 --- a/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java +++ b/src/main/java/de/diddiz/LogBlock/DumpedLogImporter.java @@ -1,147 +1,147 @@ -package de.diddiz.LogBlock; - -import static de.diddiz.LogBlock.util.Utils.newline; - -import de.diddiz.LogBlock.util.Utils.ExtensionFilenameFilter; -import java.io.*; -import java.sql.Connection; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Arrays; -import java.util.Comparator; -import java.util.logging.Level; -import java.util.regex.Pattern; - -public class DumpedLogImporter implements Runnable { - private final LogBlock logblock; - - DumpedLogImporter(LogBlock logblock) { - this.logblock = logblock; - } - - @Override - public void run() { - final File[] imports = new File(logblock.getDataFolder(), "import").listFiles(new ExtensionFilenameFilter("sql")); - if (imports != null && imports.length > 0) { - logblock.getLogger().info("Found " + imports.length + " imports."); - Arrays.sort(imports, new ImportsComparator()); - Connection conn = null; - try { - conn = logblock.getConnection(); - if (conn == null) { - return; - } - conn.setAutoCommit(false); - final Statement st = conn.createStatement(); - final BufferedWriter writer = new BufferedWriter(new FileWriter(new File(logblock.getDataFolder(), "import/failed.txt"))); - int successes = 0, errors = 0; - try { - for (final File sqlFile : imports) { - String line = null; - try { - logblock.getLogger().info("Trying to import " + sqlFile.getName() + " ..."); - // first try batch import the whole file - final BufferedReader reader = new BufferedReader(new FileReader(sqlFile)); - int statements = 0; - while ((line = reader.readLine()) != null) { - if (line.endsWith(";")) { - line = line.substring(0, line.length() - 1); - } - if (!line.isEmpty()) { - statements++; - st.addBatch(line); - } - } - st.executeBatch(); - conn.commit(); - reader.close(); - sqlFile.delete(); - successes += statements; - logblock.getLogger().info("Successfully imported " + sqlFile.getName() + "."); - } catch (final Exception ignored) { - // if the batch import did not work, retry line by line - try { - final BufferedReader reader = new BufferedReader(new FileReader(sqlFile)); - while ((line = reader.readLine()) != null) { - if (line.endsWith(";")) { - line = line.substring(0, line.length() - 1); - } - if (!line.isEmpty()) { - try { - st.execute(line); - successes++; - } catch (final SQLException ex) { - logblock.getLogger().severe("Error while importing: '" + line + "': " + ex.getMessage()); - writer.write(line + newline); - errors++; - } - } - } - conn.commit(); - reader.close(); - sqlFile.delete(); - logblock.getLogger().info("Successfully imported " + sqlFile.getName() + "."); - } catch (final Exception ex) { - logblock.getLogger().severe("Error while importing " + sqlFile.getName() + ": " + ex.getMessage()); - errors++; - } - } - } - } finally { - writer.close(); - } - st.close(); - logblock.getLogger().info("Successfully imported stored queue. (" + successes + " rows imported, " + errors + " errors)"); - } catch (final Exception ex) { - logblock.getLogger().log(Level.WARNING, "Error while importing: ", ex); - } finally { - if (conn != null) { - try { - conn.close(); - } catch (final SQLException ex) { - } - } - } - } - } - - private static class ImportsComparator implements Comparator { - private final Pattern splitPattern = Pattern.compile("[\\-\\.]"); - - @Override - public int compare(File o1, File o2) { - String[] name1 = splitPattern.split(o1.getName()); - String[] name2 = splitPattern.split(o2.getName()); - if (name1.length > name2.length) { - return 1; - } else if (name1.length < name2.length) { - return -1; - } - for (int i = 0; i < name1.length; i++) { - String part1 = name1[i]; - String part2 = name2[i]; - if (part1.length() > 0 && part2.length() > 0) { - char first1 = part1.charAt(0); - char first2 = part2.charAt(0); - if (first1 >= '0' && first1 <= '9' && first2 >= '0' && first2 <= '9') { - try { - long long1 = Long.parseLong(part1); - long long2 = Long.parseLong(part2); - if (long1 == long2) { - continue; - } - return long1 > long2 ? 1 : -1; - } catch (NumberFormatException e) { - // fallthrough to string compare - } - } - } - int compareString = part1.compareTo(part2); - if (compareString != 0) { - return compareString; - } - } - return 0; - } - } -} +package de.diddiz.LogBlock; + +import static de.diddiz.LogBlock.util.Utils.newline; + +import de.diddiz.LogBlock.util.Utils.ExtensionFilenameFilter; +import java.io.*; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Arrays; +import java.util.Comparator; +import java.util.logging.Level; +import java.util.regex.Pattern; + +public class DumpedLogImporter implements Runnable { + private final LogBlock logblock; + + DumpedLogImporter(LogBlock logblock) { + this.logblock = logblock; + } + + @Override + public void run() { + final File[] imports = new File(logblock.getDataFolder(), "import").listFiles(new ExtensionFilenameFilter("sql")); + if (imports != null && imports.length > 0) { + logblock.getLogger().info("Found " + imports.length + " imports."); + Arrays.sort(imports, new ImportsComparator()); + Connection conn = null; + try { + conn = logblock.getConnection(); + if (conn == null) { + return; + } + conn.setAutoCommit(false); + final Statement st = conn.createStatement(); + final BufferedWriter writer = new BufferedWriter(new FileWriter(new File(logblock.getDataFolder(), "import/failed.txt"))); + int successes = 0, errors = 0; + try { + for (final File sqlFile : imports) { + String line = null; + try { + logblock.getLogger().info("Trying to import " + sqlFile.getName() + " ..."); + // first try batch import the whole file + final BufferedReader reader = new BufferedReader(new FileReader(sqlFile)); + int statements = 0; + while ((line = reader.readLine()) != null) { + if (line.endsWith(";")) { + line = line.substring(0, line.length() - 1); + } + if (!line.isEmpty()) { + statements++; + st.addBatch(line); + } + } + st.executeBatch(); + conn.commit(); + reader.close(); + sqlFile.delete(); + successes += statements; + logblock.getLogger().info("Successfully imported " + sqlFile.getName() + "."); + } catch (final Exception ignored) { + // if the batch import did not work, retry line by line + try { + final BufferedReader reader = new BufferedReader(new FileReader(sqlFile)); + while ((line = reader.readLine()) != null) { + if (line.endsWith(";")) { + line = line.substring(0, line.length() - 1); + } + if (!line.isEmpty()) { + try { + st.execute(line); + successes++; + } catch (final SQLException ex) { + logblock.getLogger().severe("Error while importing: '" + line + "': " + ex.getMessage()); + writer.write(line + newline); + errors++; + } + } + } + conn.commit(); + reader.close(); + sqlFile.delete(); + logblock.getLogger().info("Successfully imported " + sqlFile.getName() + "."); + } catch (final Exception ex) { + logblock.getLogger().severe("Error while importing " + sqlFile.getName() + ": " + ex.getMessage()); + errors++; + } + } + } + } finally { + writer.close(); + } + st.close(); + logblock.getLogger().info("Successfully imported stored queue. (" + successes + " rows imported, " + errors + " errors)"); + } catch (final Exception ex) { + logblock.getLogger().log(Level.WARNING, "Error while importing: ", ex); + } finally { + if (conn != null) { + try { + conn.close(); + } catch (final SQLException ex) { + } + } + } + } + } + + private static class ImportsComparator implements Comparator { + private final Pattern splitPattern = Pattern.compile("[\\-\\.]"); + + @Override + public int compare(File o1, File o2) { + String[] name1 = splitPattern.split(o1.getName()); + String[] name2 = splitPattern.split(o2.getName()); + if (name1.length > name2.length) { + return 1; + } else if (name1.length < name2.length) { + return -1; + } + for (int i = 0; i < name1.length; i++) { + String part1 = name1[i]; + String part2 = name2[i]; + if (part1.length() > 0 && part2.length() > 0) { + char first1 = part1.charAt(0); + char first2 = part2.charAt(0); + if (first1 >= '0' && first1 <= '9' && first2 >= '0' && first2 <= '9') { + try { + long long1 = Long.parseLong(part1); + long long2 = Long.parseLong(part2); + if (long1 == long2) { + continue; + } + return long1 > long2 ? 1 : -1; + } catch (NumberFormatException e) { + // fallthrough to string compare + } + } + } + int compareString = part1.compareTo(part2); + if (compareString != 0) { + return compareString; + } + } + return 0; + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 4ea95c66..212129fc 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -1,378 +1,378 @@ -package de.diddiz.LogBlock; - -import de.diddiz.LogBlock.addons.worldguard.WorldGuardLoggingFlagsAddon; -import de.diddiz.LogBlock.config.Config; -import de.diddiz.LogBlock.listeners.*; -import de.diddiz.LogBlock.questioner.Questioner; -import de.diddiz.LogBlock.util.BukkitUtils; -import de.diddiz.LogBlock.util.MySQLConnectionPool; -import de.diddiz.LogBlock.worldedit.WorldEditHelper; -import de.diddiz.LogBlock.worldedit.WorldEditLoggingHook; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.permissions.Permission; -import org.bukkit.plugin.PluginManager; -import org.bukkit.plugin.java.JavaPlugin; - -import java.io.File; -import java.io.FileNotFoundException; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; - -import static de.diddiz.LogBlock.config.Config.*; -import static org.bukkit.Bukkit.getPluginManager; - -public class LogBlock extends JavaPlugin { - private static LogBlock logblock = null; - private MySQLConnectionPool pool; - private Consumer consumer = null; - private CommandsHandler commandsHandler; - private boolean noDb = false, connected = true; - private PlayerInfoLogging playerInfoLogging; - private ScaffoldingLogging scaffoldingLogging; - private Questioner questioner; - private WorldGuardLoggingFlagsAddon worldGuardLoggingFlagsAddon; - private boolean isConfigLoaded; - private volatile boolean isCompletelyEnabled; - - public static LogBlock getInstance() { - return logblock; - } - - public boolean isCompletelyEnabled() { - return isCompletelyEnabled; - } - - public Consumer getConsumer() { - return consumer; - } - - public CommandsHandler getCommandsHandler() { - return commandsHandler; - } - - @Override - public void onLoad() { - logblock = this; - BukkitUtils.isDoublePlant(Material.AIR); // Force static code to run - try { - Config.load(this); - isConfigLoaded = true; - } catch (final Exception ex) { - getLogger().log(Level.SEVERE, "Could not load LogBlock config! " + ex.getMessage(), ex); - } - if (Config.worldGuardLoggingFlags) { - if (getServer().getPluginManager().getPlugin("WorldGuard") == null) { - getLogger().log(Level.SEVERE, "Invalid config! addons.worldguardLoggingFlags is set to true, but WorldGuard is not loaded."); - } else { - worldGuardLoggingFlagsAddon = new WorldGuardLoggingFlagsAddon(this); - worldGuardLoggingFlagsAddon.onPluginLoad(); - } - } - } - - @Override - public void onEnable() { - final PluginManager pm = getPluginManager(); - if (!isConfigLoaded) { - pm.disablePlugin(this); - return; - } - consumer = new Consumer(this); - try { - getLogger().info("Connecting to " + user + "@" + url + "..."); - try { - Class.forName("com.mysql.cj.jdbc.Driver"); - } catch (ClassNotFoundException ignored) { - Class.forName("com.mysql.jdbc.Driver"); - } - pool = new MySQLConnectionPool(url, user, password, mysqlUseSSL, mysqlRequireSSL); - final Connection conn = getConnection(true); - if (conn == null) { - noDb = true; - 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;"); - } - conn.close(); - Updater updater = new Updater(this); - updater.checkTables(); - MaterialConverter.initializeMaterials(getConnection()); - MaterialConverter.getOrAddMaterialId(Material.AIR); // AIR must be the first entry - EntityTypeConverter.initializeEntityTypes(getConnection()); - if (updater.update()) { - load(this); - } - } catch (final NullPointerException ex) { - getLogger().log(Level.SEVERE, "Error while loading: ", ex); - } catch (final Exception ex) { - getLogger().log(Level.SEVERE, "Error while loading: " + ex.getMessage(), ex); - pm.disablePlugin(this); - return; - } - - if (WorldEditHelper.hasWorldEdit()) { - new WorldEditLoggingHook(this).hook(); - } - commandsHandler = new CommandsHandler(this); - getCommand("lb").setExecutor(commandsHandler); - if (enableAutoClearLog && autoClearLogDelay > 0) { - getServer().getScheduler().runTaskTimerAsynchronously(this, new AutoClearLog(this), 6000, autoClearLogDelay * 60 * 20); - } - new DumpedLogImporter(this).run(); - registerEvents(); - consumer.start(); - for (final Tool tool : toolsByType.values()) { - if (pm.getPermission("logblock.tools." + tool.name) == null) { - final Permission perm = new Permission("logblock.tools." + tool.name, tool.permissionDefault); - pm.addPermission(perm); - } - } - questioner = new Questioner(this); - if (worldGuardLoggingFlagsAddon != null) { - worldGuardLoggingFlagsAddon.onPluginEnable(); - } - isCompletelyEnabled = true; - getServer().getScheduler().runTaskAsynchronously(this, new Updater.PlayerCountChecker(this)); - } - - private void registerEvents() { - final PluginManager pm = getPluginManager(); - pm.registerEvents(new ToolListener(this), this); - pm.registerEvents(playerInfoLogging = new PlayerInfoLogging(this), this); - if (askRollbackAfterBan) { - pm.registerEvents(new BanListener(this), this); - } - if (isLogging(Logging.BLOCKPLACE)) { - pm.registerEvents(new BlockPlaceLogging(this), this); - } - if (isLogging(Logging.LAVAFLOW) || isLogging(Logging.WATERFLOW)) { - pm.registerEvents(new FluidFlowLogging(this), this); - } - if (isLogging(Logging.BLOCKBREAK)) { - pm.registerEvents(new BlockBreakLogging(this), this); - } - if (isLogging(Logging.SIGNTEXT)) { - pm.registerEvents(new SignChangeLogging(this), this); - } - if (isLogging(Logging.FIRE)) { - pm.registerEvents(new BlockBurnLogging(this), this); - } - if (isLogging(Logging.SNOWFORM)) { - pm.registerEvents(new SnowFormLogging(this), this); - } - if (isLogging(Logging.SNOWFADE)) { - pm.registerEvents(new SnowFadeLogging(this), this); - } - if (isLogging(Logging.SCAFFOLDING)) { - pm.registerEvents(scaffoldingLogging = new ScaffoldingLogging(this), this); - } - if (isLogging(Logging.CAULDRONINTERACT)) { - pm.registerEvents(new CauldronLogging(this), this); - } - if (isLogging(Logging.CREEPEREXPLOSION) || isLogging(Logging.TNTEXPLOSION) || isLogging(Logging.GHASTFIREBALLEXPLOSION) || isLogging(Logging.ENDERDRAGON) || isLogging(Logging.MISCEXPLOSION)) { - pm.registerEvents(new ExplosionLogging(this), this); - } - if (isLogging(Logging.LEAVESDECAY)) { - pm.registerEvents(new LeavesDecayLogging(this), this); - } - if (isLogging(Logging.CHESTACCESS)) { - pm.registerEvents(new ChestAccessLogging(this), this); - } - if (isLogging(Logging.BLOCKBREAK) || isLogging(Logging.BLOCKPLACE) || isLogging(Logging.SWITCHINTERACT) || isLogging(Logging.DOORINTERACT) || isLogging(Logging.CAKEEAT) || isLogging(Logging.DIODEINTERACT) || isLogging(Logging.COMPARATORINTERACT) || isLogging(Logging.NOTEBLOCKINTERACT) - || isLogging(Logging.PRESUREPLATEINTERACT) || isLogging(Logging.TRIPWIREINTERACT) || isLogging(Logging.CROPTRAMPLE)) { - pm.registerEvents(new InteractLogging(this), this); - } - if (isLogging(Logging.CREATURECROPTRAMPLE)) { - pm.registerEvents(new CreatureInteractLogging(this), this); - } - if (isLogging(Logging.KILL)) { - pm.registerEvents(new KillLogging(this), this); - } - if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { - pm.registerEvents(new ChatLogging(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); - } - if (isLogging(Logging.BONEMEALSTRUCTUREGROW)) { - pm.registerEvents(new BlockFertilizeLogging(this), this); - } - if (isLogging(Logging.GRASSGROWTH) || isLogging(Logging.MYCELIUMSPREAD) || isLogging(Logging.VINEGROWTH) || isLogging(Logging.MUSHROOMSPREAD) || isLogging(Logging.BAMBOOGROWTH) || isLogging(Logging.DRIPSTONEGROWTH) || isLogging(Logging.SCULKSPREAD)) { - pm.registerEvents(new BlockSpreadLogging(this), this); - } - if (isLogging(Logging.DRAGONEGGTELEPORT)) { - pm.registerEvents(new DragonEggLogging(this), this); - } - if (isLogging(Logging.LECTERNBOOKCHANGE)) { - pm.registerEvents(new LecternLogging(this), this); - } - if (isLogging(Logging.OXIDIZATION)) { - pm.registerEvents(new OxidizationLogging(this), this); - } - if (Config.isLoggingAnyEntities()) { - if (!WorldEditHelper.hasFullWorldEdit()) { - getLogger().severe("No compatible WorldEdit found, entity logging will not work!"); - } else { - pm.registerEvents(new AdvancedEntityLogging(this), this); - getLogger().info("Entity logging enabled!"); - } - } - } - - @Override - public void onDisable() { - isCompletelyEnabled = false; - getServer().getScheduler().cancelTasks(this); - if (consumer != null) { - if (logPlayerInfo && playerInfoLogging != null) { - for (final Player player : getServer().getOnlinePlayers()) { - playerInfoLogging.onPlayerQuit(player); - } - } - getLogger().info("Waiting for consumer ..."); - consumer.shutdown(); - if (consumer.getQueueSize() > 0) { - getLogger().info("Remaining queue size: " + consumer.getQueueSize() + ". Trying to write to a local file."); - try { - consumer.writeToFile(); - getLogger().info("Successfully dumped queue."); - } catch (final FileNotFoundException ex) { - getLogger().info("Failed to write. Given up."); - } - } - } - if (pool != null) { - pool.close(); - } - } - - @Override - public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { - if (noDb) { - sender.sendMessage(ChatColor.RED + "No database connected. Check your MySQL user/pw and database for typos. Start/restart your MySQL server."); - } - return true; - } - - public boolean hasPermission(CommandSender sender, String permission) { - return sender.hasPermission(permission); - } - - public Connection getConnection() { - return getConnection(false); - } - - public Connection getConnection(boolean testConnection) { - try { - final Connection conn = pool.getConnection(); - if (!connected) { - getLogger().info("MySQL connection rebuild"); - connected = true; - } - return conn; - } catch (final Exception ex) { - if (testConnection) { - getLogger().log(Level.SEVERE, "Could not connect to the Database! Please check your config! " + ex.getMessage()); - } else if (connected) { - getLogger().log(Level.SEVERE, "Error while fetching connection: ", ex); - connected = false; - } else { - getLogger().log(Level.SEVERE, "MySQL connection lost", ex); - } - return null; - } - } - - /** - * Returns a list of block changes based on the given query parameters, the query parameters - * are essentially programmatic versions of the parameters a player would pass - * to the logblock lookup command i.e /lb lookup query-parameters - * - * Note: this method directly calls a SQL query and is hence a slow blocking function, avoid running - * it on the main game thread - * - * @param params QueryParams that contains the needed columns (all other will be filled with default values) and the params. World is required. - * @return Returns a list of block changes based on the given query parameters - * @throws SQLException if a sql exception occurs while looking up the block changes - */ - public List getBlockChanges(QueryParams params) throws SQLException { - final Connection conn = getConnection(); - Statement state = null; - if (conn == null) { - throw new SQLException("No connection"); - } - try { - state = conn.createStatement(); - final ResultSet rs = state.executeQuery(params.getQuery()); - final List blockchanges = new ArrayList<>(); - while (rs.next()) { - blockchanges.add(new BlockChange(rs, params)); - } - return blockchanges; - } finally { - if (state != null) { - state.close(); - } - conn.close(); - } - } - - public int getCount(QueryParams params) throws SQLException { - if (params == null || params.world == null || !Config.isLogged(params.world)) { - throw new IllegalArgumentException("World is not logged: " + ((params == null || params.world == null) ? "null" : params.world.getName())); - } - final Connection conn = getConnection(); - Statement state = null; - if (conn == null) { - throw new SQLException("No connection"); - } - try { - state = conn.createStatement(); - final QueryParams p = params.clone(); - p.needCount = true; - final ResultSet rs = state.executeQuery(p.getQuery()); - if (!rs.next()) { - return 0; - } - return rs.getInt(1); - } finally { - if (state != null) { - state.close(); - } - conn.close(); - } - } - - @Override - public File getFile() { - return super.getFile(); - } - - public Questioner getQuestioner() { - return questioner; - } - - public ScaffoldingLogging getScaffoldingLogging() { - return scaffoldingLogging; - } -} +package de.diddiz.LogBlock; + +import de.diddiz.LogBlock.addons.worldguard.WorldGuardLoggingFlagsAddon; +import de.diddiz.LogBlock.config.Config; +import de.diddiz.LogBlock.listeners.*; +import de.diddiz.LogBlock.questioner.Questioner; +import de.diddiz.LogBlock.util.BukkitUtils; +import de.diddiz.LogBlock.util.MySQLConnectionPool; +import de.diddiz.LogBlock.worldedit.WorldEditHelper; +import de.diddiz.LogBlock.worldedit.WorldEditLoggingHook; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.permissions.Permission; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.io.FileNotFoundException; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; + +import static de.diddiz.LogBlock.config.Config.*; +import static org.bukkit.Bukkit.getPluginManager; + +public class LogBlock extends JavaPlugin { + private static LogBlock logblock = null; + private MySQLConnectionPool pool; + private Consumer consumer = null; + private CommandsHandler commandsHandler; + private boolean noDb = false, connected = true; + private PlayerInfoLogging playerInfoLogging; + private ScaffoldingLogging scaffoldingLogging; + private Questioner questioner; + private WorldGuardLoggingFlagsAddon worldGuardLoggingFlagsAddon; + private boolean isConfigLoaded; + private volatile boolean isCompletelyEnabled; + + public static LogBlock getInstance() { + return logblock; + } + + public boolean isCompletelyEnabled() { + return isCompletelyEnabled; + } + + public Consumer getConsumer() { + return consumer; + } + + public CommandsHandler getCommandsHandler() { + return commandsHandler; + } + + @Override + public void onLoad() { + logblock = this; + BukkitUtils.isDoublePlant(Material.AIR); // Force static code to run + try { + Config.load(this); + isConfigLoaded = true; + } catch (final Exception ex) { + getLogger().log(Level.SEVERE, "Could not load LogBlock config! " + ex.getMessage(), ex); + } + if (Config.worldGuardLoggingFlags) { + if (getServer().getPluginManager().getPlugin("WorldGuard") == null) { + getLogger().log(Level.SEVERE, "Invalid config! addons.worldguardLoggingFlags is set to true, but WorldGuard is not loaded."); + } else { + worldGuardLoggingFlagsAddon = new WorldGuardLoggingFlagsAddon(this); + worldGuardLoggingFlagsAddon.onPluginLoad(); + } + } + } + + @Override + public void onEnable() { + final PluginManager pm = getPluginManager(); + if (!isConfigLoaded) { + pm.disablePlugin(this); + return; + } + consumer = new Consumer(this); + try { + getLogger().info("Connecting to " + user + "@" + url + "..."); + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException ignored) { + Class.forName("com.mysql.jdbc.Driver"); + } + pool = new MySQLConnectionPool(url, user, password, mysqlUseSSL, mysqlRequireSSL); + final Connection conn = getConnection(true); + if (conn == null) { + noDb = true; + 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;"); + } + conn.close(); + Updater updater = new Updater(this); + updater.checkTables(); + MaterialConverter.initializeMaterials(getConnection()); + MaterialConverter.getOrAddMaterialId(Material.AIR); // AIR must be the first entry + EntityTypeConverter.initializeEntityTypes(getConnection()); + if (updater.update()) { + load(this); + } + } catch (final NullPointerException ex) { + getLogger().log(Level.SEVERE, "Error while loading: ", ex); + } catch (final Exception ex) { + getLogger().log(Level.SEVERE, "Error while loading: " + ex.getMessage(), ex); + pm.disablePlugin(this); + return; + } + + if (WorldEditHelper.hasWorldEdit()) { + new WorldEditLoggingHook(this).hook(); + } + commandsHandler = new CommandsHandler(this); + getCommand("lb").setExecutor(commandsHandler); + if (enableAutoClearLog && autoClearLogDelay > 0) { + getServer().getScheduler().runTaskTimerAsynchronously(this, new AutoClearLog(this), 6000, autoClearLogDelay * 60 * 20); + } + new DumpedLogImporter(this).run(); + registerEvents(); + consumer.start(); + for (final Tool tool : toolsByType.values()) { + if (pm.getPermission("logblock.tools." + tool.name) == null) { + final Permission perm = new Permission("logblock.tools." + tool.name, tool.permissionDefault); + pm.addPermission(perm); + } + } + questioner = new Questioner(this); + if (worldGuardLoggingFlagsAddon != null) { + worldGuardLoggingFlagsAddon.onPluginEnable(); + } + isCompletelyEnabled = true; + getServer().getScheduler().runTaskAsynchronously(this, new Updater.PlayerCountChecker(this)); + } + + private void registerEvents() { + final PluginManager pm = getPluginManager(); + pm.registerEvents(new ToolListener(this), this); + pm.registerEvents(playerInfoLogging = new PlayerInfoLogging(this), this); + if (askRollbackAfterBan) { + pm.registerEvents(new BanListener(this), this); + } + if (isLogging(Logging.BLOCKPLACE)) { + pm.registerEvents(new BlockPlaceLogging(this), this); + } + if (isLogging(Logging.LAVAFLOW) || isLogging(Logging.WATERFLOW)) { + pm.registerEvents(new FluidFlowLogging(this), this); + } + if (isLogging(Logging.BLOCKBREAK)) { + pm.registerEvents(new BlockBreakLogging(this), this); + } + if (isLogging(Logging.SIGNTEXT)) { + pm.registerEvents(new SignChangeLogging(this), this); + } + if (isLogging(Logging.FIRE)) { + pm.registerEvents(new BlockBurnLogging(this), this); + } + if (isLogging(Logging.SNOWFORM)) { + pm.registerEvents(new SnowFormLogging(this), this); + } + if (isLogging(Logging.SNOWFADE)) { + pm.registerEvents(new SnowFadeLogging(this), this); + } + if (isLogging(Logging.SCAFFOLDING)) { + pm.registerEvents(scaffoldingLogging = new ScaffoldingLogging(this), this); + } + if (isLogging(Logging.CAULDRONINTERACT)) { + pm.registerEvents(new CauldronLogging(this), this); + } + if (isLogging(Logging.CREEPEREXPLOSION) || isLogging(Logging.TNTEXPLOSION) || isLogging(Logging.GHASTFIREBALLEXPLOSION) || isLogging(Logging.ENDERDRAGON) || isLogging(Logging.MISCEXPLOSION)) { + pm.registerEvents(new ExplosionLogging(this), this); + } + if (isLogging(Logging.LEAVESDECAY)) { + pm.registerEvents(new LeavesDecayLogging(this), this); + } + if (isLogging(Logging.CHESTACCESS)) { + pm.registerEvents(new ChestAccessLogging(this), this); + } + if (isLogging(Logging.BLOCKBREAK) || isLogging(Logging.BLOCKPLACE) || isLogging(Logging.SWITCHINTERACT) || isLogging(Logging.DOORINTERACT) || isLogging(Logging.CAKEEAT) || isLogging(Logging.DIODEINTERACT) || isLogging(Logging.COMPARATORINTERACT) || isLogging(Logging.NOTEBLOCKINTERACT) + || isLogging(Logging.PRESUREPLATEINTERACT) || isLogging(Logging.TRIPWIREINTERACT) || isLogging(Logging.CROPTRAMPLE)) { + pm.registerEvents(new InteractLogging(this), this); + } + if (isLogging(Logging.CREATURECROPTRAMPLE)) { + pm.registerEvents(new CreatureInteractLogging(this), this); + } + if (isLogging(Logging.KILL)) { + pm.registerEvents(new KillLogging(this), this); + } + if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { + pm.registerEvents(new ChatLogging(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); + } + if (isLogging(Logging.BONEMEALSTRUCTUREGROW)) { + pm.registerEvents(new BlockFertilizeLogging(this), this); + } + if (isLogging(Logging.GRASSGROWTH) || isLogging(Logging.MYCELIUMSPREAD) || isLogging(Logging.VINEGROWTH) || isLogging(Logging.MUSHROOMSPREAD) || isLogging(Logging.BAMBOOGROWTH) || isLogging(Logging.DRIPSTONEGROWTH) || isLogging(Logging.SCULKSPREAD)) { + pm.registerEvents(new BlockSpreadLogging(this), this); + } + if (isLogging(Logging.DRAGONEGGTELEPORT)) { + pm.registerEvents(new DragonEggLogging(this), this); + } + if (isLogging(Logging.LECTERNBOOKCHANGE)) { + pm.registerEvents(new LecternLogging(this), this); + } + if (isLogging(Logging.OXIDIZATION)) { + pm.registerEvents(new OxidizationLogging(this), this); + } + if (Config.isLoggingAnyEntities()) { + if (!WorldEditHelper.hasFullWorldEdit()) { + getLogger().severe("No compatible WorldEdit found, entity logging will not work!"); + } else { + pm.registerEvents(new AdvancedEntityLogging(this), this); + getLogger().info("Entity logging enabled!"); + } + } + } + + @Override + public void onDisable() { + isCompletelyEnabled = false; + getServer().getScheduler().cancelTasks(this); + if (consumer != null) { + if (logPlayerInfo && playerInfoLogging != null) { + for (final Player player : getServer().getOnlinePlayers()) { + playerInfoLogging.onPlayerQuit(player); + } + } + getLogger().info("Waiting for consumer ..."); + consumer.shutdown(); + if (consumer.getQueueSize() > 0) { + getLogger().info("Remaining queue size: " + consumer.getQueueSize() + ". Trying to write to a local file."); + try { + consumer.writeToFile(); + getLogger().info("Successfully dumped queue."); + } catch (final FileNotFoundException ex) { + getLogger().info("Failed to write. Given up."); + } + } + } + if (pool != null) { + pool.close(); + } + } + + @Override + public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { + if (noDb) { + sender.sendMessage(ChatColor.RED + "No database connected. Check your MySQL user/pw and database for typos. Start/restart your MySQL server."); + } + return true; + } + + public boolean hasPermission(CommandSender sender, String permission) { + return sender.hasPermission(permission); + } + + public Connection getConnection() { + return getConnection(false); + } + + public Connection getConnection(boolean testConnection) { + try { + final Connection conn = pool.getConnection(); + if (!connected) { + getLogger().info("MySQL connection rebuild"); + connected = true; + } + return conn; + } catch (final Exception ex) { + if (testConnection) { + getLogger().log(Level.SEVERE, "Could not connect to the Database! Please check your config! " + ex.getMessage()); + } else if (connected) { + getLogger().log(Level.SEVERE, "Error while fetching connection: ", ex); + connected = false; + } else { + getLogger().log(Level.SEVERE, "MySQL connection lost", ex); + } + return null; + } + } + + /** + * Returns a list of block changes based on the given query parameters, the query parameters + * are essentially programmatic versions of the parameters a player would pass + * to the logblock lookup command i.e /lb lookup query-parameters + * + * Note: this method directly calls a SQL query and is hence a slow blocking function, avoid running + * it on the main game thread + * + * @param params QueryParams that contains the needed columns (all other will be filled with default values) and the params. World is required. + * @return Returns a list of block changes based on the given query parameters + * @throws SQLException if a sql exception occurs while looking up the block changes + */ + public List getBlockChanges(QueryParams params) throws SQLException { + final Connection conn = getConnection(); + Statement state = null; + if (conn == null) { + throw new SQLException("No connection"); + } + try { + state = conn.createStatement(); + final ResultSet rs = state.executeQuery(params.getQuery()); + final List blockchanges = new ArrayList<>(); + while (rs.next()) { + blockchanges.add(new BlockChange(rs, params)); + } + return blockchanges; + } finally { + if (state != null) { + state.close(); + } + conn.close(); + } + } + + public int getCount(QueryParams params) throws SQLException { + if (params == null || params.world == null || !Config.isLogged(params.world)) { + throw new IllegalArgumentException("World is not logged: " + ((params == null || params.world == null) ? "null" : params.world.getName())); + } + final Connection conn = getConnection(); + Statement state = null; + if (conn == null) { + throw new SQLException("No connection"); + } + try { + state = conn.createStatement(); + final QueryParams p = params.clone(); + p.needCount = true; + final ResultSet rs = state.executeQuery(p.getQuery()); + if (!rs.next()) { + return 0; + } + return rs.getInt(1); + } finally { + if (state != null) { + state.close(); + } + conn.close(); + } + } + + @Override + public File getFile() { + return super.getFile(); + } + + public Questioner getQuestioner() { + return questioner; + } + + public ScaffoldingLogging getScaffoldingLogging() { + return scaffoldingLogging; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java b/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java index 0bffb6b2..ba3c55c4 100644 --- a/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java +++ b/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java @@ -1,18 +1,18 @@ -package de.diddiz.LogBlock; - -import net.md_5.bungee.api.chat.BaseComponent; -import org.bukkit.Location; - -public interface LookupCacheElement { - public Location getLocation(); - - public default BaseComponent[] getLogMessage() { - return getLogMessage(-1); - } - - public BaseComponent[] getLogMessage(int entry); - - public default int getNumChanges() { - return 1; - } -} +package de.diddiz.LogBlock; + +import net.md_5.bungee.api.chat.BaseComponent; +import org.bukkit.Location; + +public interface LookupCacheElement { + public Location getLocation(); + + public default BaseComponent[] getLogMessage() { + return getLogMessage(-1); + } + + public BaseComponent[] getLogMessage(int entry); + + public default int getNumChanges() { + return 1; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/LookupCacheElementFactory.java b/src/main/java/de/diddiz/LogBlock/LookupCacheElementFactory.java index cc579e28..6bbbc456 100755 --- a/src/main/java/de/diddiz/LogBlock/LookupCacheElementFactory.java +++ b/src/main/java/de/diddiz/LogBlock/LookupCacheElementFactory.java @@ -1,40 +1,40 @@ -package de.diddiz.LogBlock; - -import de.diddiz.LogBlock.QueryParams.BlockChangeType; -import de.diddiz.LogBlock.QueryParams.SummarizationMode; - -import java.sql.ResultSet; -import java.sql.SQLException; - -public class LookupCacheElementFactory { - private final QueryParams params; - private final float spaceFactor; - - public LookupCacheElementFactory(QueryParams params, float spaceFactor) { - this.params = params; - this.spaceFactor = spaceFactor; - } - - public LookupCacheElement getLookupCacheElement(ResultSet rs) throws SQLException { - if (params.bct == BlockChangeType.CHAT) { - return new ChatMessage(rs, params); - } - if (params.bct == BlockChangeType.KILLS) { - if (params.sum == SummarizationMode.NONE) { - return new Kill(rs, params); - } else if (params.sum == SummarizationMode.PLAYERS) { - return new SummedKills(rs, params, spaceFactor); - } - } - if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) { - if (params.sum == SummarizationMode.NONE) { - return new EntityChange(rs, params); - } - return new SummedEntityChanges(rs, params, spaceFactor); - } - if (params.sum == SummarizationMode.NONE) { - return new BlockChange(rs, params); - } - return new SummedBlockChanges(rs, params, spaceFactor); - } -} +package de.diddiz.LogBlock; + +import de.diddiz.LogBlock.QueryParams.BlockChangeType; +import de.diddiz.LogBlock.QueryParams.SummarizationMode; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class LookupCacheElementFactory { + private final QueryParams params; + private final float spaceFactor; + + public LookupCacheElementFactory(QueryParams params, float spaceFactor) { + this.params = params; + this.spaceFactor = spaceFactor; + } + + public LookupCacheElement getLookupCacheElement(ResultSet rs) throws SQLException { + if (params.bct == BlockChangeType.CHAT) { + return new ChatMessage(rs, params); + } + if (params.bct == BlockChangeType.KILLS) { + if (params.sum == SummarizationMode.NONE) { + return new Kill(rs, params); + } else if (params.sum == SummarizationMode.PLAYERS) { + return new SummedKills(rs, params, spaceFactor); + } + } + if (params.bct == BlockChangeType.ENTITIES || params.bct == BlockChangeType.ENTITIES_CREATED || params.bct == BlockChangeType.ENTITIES_KILLED) { + if (params.sum == SummarizationMode.NONE) { + return new EntityChange(rs, params); + } + return new SummedEntityChanges(rs, params, spaceFactor); + } + if (params.sum == SummarizationMode.NONE) { + return new BlockChange(rs, params); + } + return new SummedBlockChanges(rs, params, spaceFactor); + } +} diff --git a/src/main/java/de/diddiz/LogBlock/Session.java b/src/main/java/de/diddiz/LogBlock/Session.java index d13ff785..b145d4e9 100644 --- a/src/main/java/de/diddiz/LogBlock/Session.java +++ b/src/main/java/de/diddiz/LogBlock/Session.java @@ -1,49 +1,49 @@ -package de.diddiz.LogBlock; - -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.HashMap; -import java.util.Map; - -import static de.diddiz.LogBlock.config.Config.toolsByType; -import static org.bukkit.Bukkit.getServer; - -public class Session { - private static final Map sessions = new HashMap<>(); - public QueryParams lastQuery = null; - public LookupCacheElement[] lookupCache = null; - public int page = 1; - public Map toolData; - - private Session(Player player) { - toolData = new HashMap<>(); - final LogBlock logblock = LogBlock.getInstance(); - if (player != null) { - for (final Tool tool : toolsByType.values()) { - toolData.put(tool, new ToolData(tool, logblock, player)); - } - } - } - - public static boolean hasSession(CommandSender sender) { - return sessions.containsKey(sender.getName().toLowerCase()); - } - - public static boolean hasSession(String playerName) { - return sessions.containsKey(playerName.toLowerCase()); - } - - public static Session getSession(CommandSender sender) { - return getSession(sender.getName()); - } - - public static Session getSession(String playerName) { - Session session = sessions.get(playerName.toLowerCase()); - if (session == null) { - session = new Session(getServer().getPlayer(playerName)); - sessions.put(playerName.toLowerCase(), session); - } - return session; - } -} +package de.diddiz.LogBlock; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.HashMap; +import java.util.Map; + +import static de.diddiz.LogBlock.config.Config.toolsByType; +import static org.bukkit.Bukkit.getServer; + +public class Session { + private static final Map sessions = new HashMap<>(); + public QueryParams lastQuery = null; + public LookupCacheElement[] lookupCache = null; + public int page = 1; + public Map toolData; + + private Session(Player player) { + toolData = new HashMap<>(); + final LogBlock logblock = LogBlock.getInstance(); + if (player != null) { + for (final Tool tool : toolsByType.values()) { + toolData.put(tool, new ToolData(tool, logblock, player)); + } + } + } + + public static boolean hasSession(CommandSender sender) { + return sessions.containsKey(sender.getName().toLowerCase()); + } + + public static boolean hasSession(String playerName) { + return sessions.containsKey(playerName.toLowerCase()); + } + + public static Session getSession(CommandSender sender) { + return getSession(sender.getName()); + } + + public static Session getSession(String playerName) { + Session session = sessions.get(playerName.toLowerCase()); + if (session == null) { + session = new Session(getServer().getPlayer(playerName)); + sessions.put(playerName.toLowerCase(), session); + } + return session; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java index 2e357c16..871666d5 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java @@ -1,43 +1,43 @@ -package de.diddiz.LogBlock; - -import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; - -import de.diddiz.LogBlock.QueryParams.SummarizationMode; -import de.diddiz.LogBlock.util.MessagingUtil; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Objects; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; -import org.bukkit.Location; - -public class SummedBlockChanges implements LookupCacheElement { - private final int type; - private final int created, destroyed; - private final float spaceFactor; - private final Actor actor; - - public SummedBlockChanges(ResultSet rs, QueryParams p, float spaceFactor) throws SQLException { - // Actor currently useless here as we don't yet output UUID in results anywhere - actor = p.sum == SummarizationMode.PLAYERS ? new Actor(rs) : null; - type = p.sum == SummarizationMode.TYPES ? rs.getInt("type") : 0; - created = rs.getInt("created"); - destroyed = rs.getInt("destroyed"); - this.spaceFactor = spaceFactor; - } - - @Override - public Location getLocation() { - return null; - } - - @Override - 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); - } - - @Override - public int getNumChanges() { - return created + destroyed; - } -} +package de.diddiz.LogBlock; + +import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; + +import de.diddiz.LogBlock.QueryParams.SummarizationMode; +import de.diddiz.LogBlock.util.MessagingUtil; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Objects; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.Location; + +public class SummedBlockChanges implements LookupCacheElement { + private final int type; + private final int created, destroyed; + private final float spaceFactor; + private final Actor actor; + + public SummedBlockChanges(ResultSet rs, QueryParams p, float spaceFactor) throws SQLException { + // Actor currently useless here as we don't yet output UUID in results anywhere + actor = p.sum == SummarizationMode.PLAYERS ? new Actor(rs) : null; + type = p.sum == SummarizationMode.TYPES ? rs.getInt("type") : 0; + created = rs.getInt("created"); + destroyed = rs.getInt("destroyed"); + this.spaceFactor = spaceFactor; + } + + @Override + public Location getLocation() { + return null; + } + + @Override + 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); + } + + @Override + public int getNumChanges() { + return created + destroyed; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/Tool.java b/src/main/java/de/diddiz/LogBlock/Tool.java index 7a9c8282..51234091 100644 --- a/src/main/java/de/diddiz/LogBlock/Tool.java +++ b/src/main/java/de/diddiz/LogBlock/Tool.java @@ -1,35 +1,35 @@ -package de.diddiz.LogBlock; - -import org.bukkit.Material; -import org.bukkit.permissions.PermissionDefault; - -import java.util.List; - -public class Tool { - public final String name; - public final List aliases; - public final ToolBehavior leftClickBehavior, rightClickBehavior; - public final boolean defaultEnabled; - public final Material item; - public final boolean canDrop; - public final QueryParams params; - public final ToolMode mode; - public final PermissionDefault permissionDefault; - public final boolean removeOnDisable; - public final boolean dropToDisable; - - public Tool(String name, List aliases, ToolBehavior leftClickBehavior, ToolBehavior rightClickBehavior, boolean defaultEnabled, Material item, boolean canDrop, QueryParams params, ToolMode mode, PermissionDefault permissionDefault, boolean removeOnDisable, boolean dropToDisable) { - this.name = name; - this.aliases = aliases; - this.leftClickBehavior = leftClickBehavior; - this.rightClickBehavior = rightClickBehavior; - this.defaultEnabled = defaultEnabled; - this.item = item; - this.canDrop = canDrop; - this.params = params; - this.mode = mode; - this.permissionDefault = permissionDefault; - this.removeOnDisable = removeOnDisable; - this.dropToDisable = dropToDisable; - } -} +package de.diddiz.LogBlock; + +import org.bukkit.Material; +import org.bukkit.permissions.PermissionDefault; + +import java.util.List; + +public class Tool { + public final String name; + public final List aliases; + public final ToolBehavior leftClickBehavior, rightClickBehavior; + public final boolean defaultEnabled; + public final Material item; + public final boolean canDrop; + public final QueryParams params; + public final ToolMode mode; + public final PermissionDefault permissionDefault; + public final boolean removeOnDisable; + public final boolean dropToDisable; + + public Tool(String name, List aliases, ToolBehavior leftClickBehavior, ToolBehavior rightClickBehavior, boolean defaultEnabled, Material item, boolean canDrop, QueryParams params, ToolMode mode, PermissionDefault permissionDefault, boolean removeOnDisable, boolean dropToDisable) { + this.name = name; + this.aliases = aliases; + this.leftClickBehavior = leftClickBehavior; + this.rightClickBehavior = rightClickBehavior; + this.defaultEnabled = defaultEnabled; + this.item = item; + this.canDrop = canDrop; + this.params = params; + this.mode = mode; + this.permissionDefault = permissionDefault; + this.removeOnDisable = removeOnDisable; + this.dropToDisable = dropToDisable; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/ToolBehavior.java b/src/main/java/de/diddiz/LogBlock/ToolBehavior.java index bbeac793..5c75895d 100644 --- a/src/main/java/de/diddiz/LogBlock/ToolBehavior.java +++ b/src/main/java/de/diddiz/LogBlock/ToolBehavior.java @@ -1,7 +1,7 @@ -package de.diddiz.LogBlock; - -public enum ToolBehavior { - TOOL, - BLOCK, - NONE -} +package de.diddiz.LogBlock; + +public enum ToolBehavior { + TOOL, + BLOCK, + NONE +} diff --git a/src/main/java/de/diddiz/LogBlock/ToolData.java b/src/main/java/de/diddiz/LogBlock/ToolData.java index f5243937..ee75dcc0 100644 --- a/src/main/java/de/diddiz/LogBlock/ToolData.java +++ b/src/main/java/de/diddiz/LogBlock/ToolData.java @@ -1,15 +1,15 @@ -package de.diddiz.LogBlock; - -import org.bukkit.entity.Player; - -public class ToolData { - public boolean enabled; - public QueryParams params; - public ToolMode mode; - - public ToolData(Tool tool, LogBlock logblock, Player player) { - enabled = tool.defaultEnabled && logblock.hasPermission(player, "logblock.tools." + tool.name); - params = tool.params.clone(); - mode = tool.mode; - } -} +package de.diddiz.LogBlock; + +import org.bukkit.entity.Player; + +public class ToolData { + public boolean enabled; + public QueryParams params; + public ToolMode mode; + + public ToolData(Tool tool, LogBlock logblock, Player player) { + enabled = tool.defaultEnabled && logblock.hasPermission(player, "logblock.tools." + tool.name); + params = tool.params.clone(); + mode = tool.mode; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/ToolMode.java b/src/main/java/de/diddiz/LogBlock/ToolMode.java index 25fc2496..3a901375 100644 --- a/src/main/java/de/diddiz/LogBlock/ToolMode.java +++ b/src/main/java/de/diddiz/LogBlock/ToolMode.java @@ -1,18 +1,18 @@ -package de.diddiz.LogBlock; - -public enum ToolMode { - CLEARLOG("logblock.clearlog"), - LOOKUP("logblock.lookup"), - REDO("logblock.rollback"), - ROLLBACK("logblock.rollback"), - WRITELOGFILE("logblock.rollback"); - private final String permission; - - private ToolMode(String permission) { - this.permission = permission; - } - - public String getPermission() { - return permission; - } -} +package de.diddiz.LogBlock; + +public enum ToolMode { + CLEARLOG("logblock.clearlog"), + LOOKUP("logblock.lookup"), + REDO("logblock.rollback"), + ROLLBACK("logblock.rollback"), + WRITELOGFILE("logblock.rollback"); + private final String permission; + + private ToolMode(String permission) { + this.permission = permission; + } + + public String getPermission() { + return permission; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 8cf38977..34653c0f 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -1,1160 +1,1160 @@ -package de.diddiz.LogBlock; - -import de.diddiz.LogBlock.blockstate.BlockStateCodecSign; -import de.diddiz.LogBlock.config.Config; -import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.LogBlock.util.ComparableVersion; -import de.diddiz.LogBlock.util.UUIDFetcher; -import de.diddiz.LogBlock.util.Utils; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.sign.Side; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.inventory.ItemStack; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.sql.*; -import java.util.*; -import java.util.jar.JarFile; -import java.util.logging.Level; - -import static de.diddiz.LogBlock.config.Config.getLoggedWorlds; -import static de.diddiz.LogBlock.config.Config.isLogging; -import static de.diddiz.LogBlock.util.BukkitUtils.friendlyWorldname; - -class Updater { - private final LogBlock logblock; - final int UUID_CONVERT_BATCH_SIZE = 100; - final int BLOCKS_CONVERT_BATCH_SIZE = 100000; - final int OTHER_CONVERT_BATCH_SIZE = 20000; - - Updater(LogBlock logblock) { - this.logblock = logblock; - } - - boolean update() { - final ConfigurationSection config = logblock.getConfig(); - String versionString = config.getString("version"); - ComparableVersion configVersion = new ComparableVersion(versionString); - // if (configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion().replace(" (manually compiled)", ""))) >= 0) { - // return false; - // } - if (configVersion.compareTo(new ComparableVersion("1.2.7")) < 0) { - logblock.getLogger().info("Updating tables to 1.2.7 ..."); - if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - st.execute("ALTER TABLE `lb-chat` ADD FULLTEXT message (message)"); - st.close(); - conn.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - } - config.set("version", "1.2.7"); - } - if (configVersion.compareTo(new ComparableVersion("1.3")) < 0) { - logblock.getLogger().info("Updating config to 1.3.0 ..."); - for (final String tool : config.getConfigurationSection("tools").getKeys(false)) { - if (config.get("tools." + tool + ".permissionDefault") == null) { - config.set("tools." + tool + ".permissionDefault", "OP"); - } - } - config.set("version", "1.3.0"); - } - if (configVersion.compareTo(new ComparableVersion("1.3.1")) < 0) { - logblock.getLogger().info("Updating tables to 1.3.1 ..."); - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - st.execute("ALTER TABLE `lb-players` ADD COLUMN lastlogin DATETIME NOT NULL, ADD COLUMN onlinetime TIME NOT NULL, ADD COLUMN ip VARCHAR(255) NOT NULL"); - st.close(); - conn.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - config.set("version", "1.3.1"); - } - if (configVersion.compareTo(new ComparableVersion("1.3.2")) < 0) { - logblock.getLogger().info("Updating tables to 1.3.2 ..."); - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - st.execute("ALTER TABLE `lb-players` ADD COLUMN firstlogin DATETIME NOT NULL AFTER playername"); - st.close(); - conn.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - config.set("version", "1.3.2"); - } - if (configVersion.compareTo(new ComparableVersion("1.4")) < 0) { - logblock.getLogger().info("Updating config to 1.4.0 ..."); - config.set("clearlog.keepLogDays", null); - config.set("version", "1.4.0"); - } - if (configVersion.compareTo(new ComparableVersion("1.4.2")) < 0) { - logblock.getLogger().info("Updating config to 1.4.2 ..."); - for (final String world : config.getStringList("loggedWorlds")) { - final File file = new File(logblock.getDataFolder(), friendlyWorldname(world) + ".yml"); - final YamlConfiguration wcfg = YamlConfiguration.loadConfiguration(file); - if (wcfg.contains("logBlockCreations")) { - wcfg.set("logging.BLOCKPLACE", wcfg.getBoolean("logBlockCreations")); - } - if (wcfg.contains("logBlockDestroyings")) { - wcfg.set("logging.BLOCKBREAK", wcfg.getBoolean("logBlockDestroyings")); - } - if (wcfg.contains("logSignTexts")) { - wcfg.set("logging.SIGNTEXT", wcfg.getBoolean("logSignTexts")); - } - if (wcfg.contains("logFire")) { - wcfg.set("logging.FIRE", wcfg.getBoolean("logFire")); - } - if (wcfg.contains("logLeavesDecay")) { - wcfg.set("logging.LEAVESDECAY", wcfg.getBoolean("logLeavesDecay")); - } - if (wcfg.contains("logLavaFlow")) { - wcfg.set("logging.LAVAFLOW", wcfg.getBoolean("logLavaFlow")); - } - if (wcfg.contains("logWaterFlow")) { - wcfg.set("logging.WATERFLOW", wcfg.getBoolean("logWaterFlow")); - } - if (wcfg.contains("logChestAccess")) { - wcfg.set("logging.CHESTACCESS", wcfg.getBoolean("logChestAccess")); - } - if (wcfg.contains("logButtonsAndLevers")) { - wcfg.set("logging.SWITCHINTERACT", wcfg.getBoolean("logButtonsAndLevers")); - } - if (wcfg.contains("logKills")) { - wcfg.set("logging.KILL", wcfg.getBoolean("logKills")); - } - if (wcfg.contains("logChat")) { - wcfg.set("logging.CHAT", wcfg.getBoolean("logChat")); - } - if (wcfg.contains("logSnowForm")) { - wcfg.set("logging.SNOWFORM", wcfg.getBoolean("logSnowForm")); - } - if (wcfg.contains("logSnowFade")) { - wcfg.set("logging.SNOWFADE", wcfg.getBoolean("logSnowFade")); - } - if (wcfg.contains("logDoors")) { - wcfg.set("logging.DOORINTERACT", wcfg.getBoolean("logDoors")); - } - if (wcfg.contains("logCakes")) { - wcfg.set("logging.CAKEEAT", wcfg.getBoolean("logCakes")); - } - if (wcfg.contains("logEndermen")) { - wcfg.set("logging.ENDERMEN", wcfg.getBoolean("logEndermen")); - } - if (wcfg.contains("logExplosions")) { - final boolean logExplosions = wcfg.getBoolean("logExplosions"); - wcfg.set("logging.TNTEXPLOSION", logExplosions); - wcfg.set("logging.MISCEXPLOSION", logExplosions); - wcfg.set("logging.CREEPEREXPLOSION", logExplosions); - wcfg.set("logging.GHASTFIREBALLEXPLOSION", logExplosions); - } - wcfg.set("logBlockCreations", null); - wcfg.set("logBlockDestroyings", null); - wcfg.set("logSignTexts", null); - wcfg.set("logExplosions", null); - wcfg.set("logFire", null); - wcfg.set("logLeavesDecay", null); - wcfg.set("logLavaFlow", null); - wcfg.set("logWaterFlow", null); - wcfg.set("logChestAccess", null); - wcfg.set("logButtonsAndLevers", null); - wcfg.set("logKills", null); - wcfg.set("logChat", null); - wcfg.set("logSnowForm", null); - wcfg.set("logSnowFade", null); - wcfg.set("logDoors", null); - wcfg.set("logCakes", null); - wcfg.set("logEndermen", null); - try { - wcfg.save(file); - } catch (final IOException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - } - } - config.set("clearlog.keepLogDays", null); - config.set("version", "1.4.2"); - } - if (configVersion.compareTo(new ComparableVersion("1.5.1")) < 0) { - logblock.getLogger().info("Updating tables to 1.5.1 ..."); - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - for (final WorldConfig wcfg : getLoggedWorlds()) { - if (wcfg.isLogging(Logging.KILL)) { - st.execute("ALTER TABLE `" + wcfg.table + "-kills` ADD (x MEDIUMINT NOT NULL DEFAULT 0, y SMALLINT NOT NULL DEFAULT 0, z MEDIUMINT NOT NULL DEFAULT 0)"); - } - } - st.close(); - conn.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - config.set("version", "1.5.1"); - } - if (configVersion.compareTo(new ComparableVersion("1.5.2")) < 0) { - logblock.getLogger().info("Updating tables to 1.5.2 ..."); - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - final ResultSet rs = st.executeQuery("SHOW COLUMNS FROM `lb-players` WHERE field = 'onlinetime'"); - if (rs.next() && rs.getString("Type").equalsIgnoreCase("time")) { - st.execute("ALTER TABLE `lb-players` ADD onlinetime2 INT UNSIGNED NOT NULL"); - st.execute("UPDATE `lb-players` SET onlinetime2 = HOUR(onlinetime) * 3600 + MINUTE(onlinetime) * 60 + SECOND(onlinetime)"); - st.execute("ALTER TABLE `lb-players` DROP onlinetime"); - st.execute("ALTER TABLE `lb-players` CHANGE onlinetime2 onlinetime INT UNSIGNED NOT NULL"); - } else { - logblock.getLogger().info("Column lb-players was already modified, skipping it."); - } - st.close(); - conn.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - config.set("version", "1.5.2"); - } - if (configVersion.compareTo(new ComparableVersion("1.8.1")) < 0) { - logblock.getLogger().info("Updating tables to 1.8.1 ..."); - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - for (final WorldConfig wcfg : getLoggedWorlds()) { - if (wcfg.isLogging(Logging.CHESTACCESS)) { - st.execute("ALTER TABLE `" + wcfg.table + "-chest` CHANGE itemdata itemdata SMALLINT NOT NULL"); - logblock.getLogger().info("Table " + wcfg.table + "-chest modified"); - } - } - st.close(); - conn.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - config.set("version", "1.8.1"); - } - - if (configVersion.compareTo(new ComparableVersion("1.9")) < 0) { - logblock.getLogger().info("Updating tables to 1.9.0 ..."); - logblock.getLogger().info("Importing UUIDs for large databases may take some time"); - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - st.execute("ALTER TABLE `lb-players` ADD `UUID` VARCHAR(36) NOT NULL"); - } catch (final SQLException ex) { - // Error 1060 is MySQL error "column already exists". We want to continue with import if we get that error - if (ex.getErrorCode() != 1060) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - } - try { - String unimportedPrefix = "noimport_"; - ResultSet rs; - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - if (config.getBoolean("logging.logPlayerInfo")) { - // Start by assuming anything with no onlinetime is not a player - st.execute("UPDATE `lb-players` SET UUID = CONCAT ('log_',playername) WHERE onlinetime=0 AND LENGTH(UUID) = 0"); - } else { - // If we can't assume that, we must assume anything we can't look up is not a player - unimportedPrefix = "log_"; - } - // Tell people how many are needing converted - rs = st.executeQuery("SELECT COUNT(playername) FROM `lb-players` WHERE LENGTH(UUID)=0"); - rs.next(); - String total = Integer.toString(rs.getInt(1)); - logblock.getLogger().info(total + " players to convert"); - int done = 0; - - conn.setAutoCommit(false); - Map players = new HashMap<>(); - List names = new ArrayList<>(UUID_CONVERT_BATCH_SIZE); - Map response; - rs = st.executeQuery("SELECT playerid,playername FROM `lb-players` WHERE LENGTH(UUID)=0 LIMIT " + Integer.toString(UUID_CONVERT_BATCH_SIZE)); - while (rs.next()) { - do { - players.put(rs.getString(2), rs.getInt(1)); - names.add(rs.getString(2)); - } while (rs.next()); - if (names.size() > 0) { - String theUUID; - response = UUIDFetcher.getUUIDs(names); - for (Map.Entry entry : players.entrySet()) { - if (response.get(entry.getKey()) == null) { - theUUID = unimportedPrefix + entry.getKey(); - logblock.getLogger().warning(entry.getKey() + " not found - giving UUID of " + theUUID); - } else { - theUUID = response.get(entry.getKey()).toString(); - } - String thePID = entry.getValue().toString(); - st.execute("UPDATE `lb-players` SET UUID = '" + theUUID + "' WHERE playerid = " + thePID); - done++; - } - conn.commit(); - players.clear(); - names.clear(); - logblock.getLogger().info("Processed " + Integer.toString(done) + " out of " + total); - rs.close(); - rs = st.executeQuery("SELECT playerid,playername FROM `lb-players` WHERE LENGTH(UUID)=0 LIMIT " + Integer.toString(UUID_CONVERT_BATCH_SIZE)); - } - } - rs.close(); - st.close(); - conn.close(); - - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } catch (Exception ex) { - logblock.getLogger().log(Level.SEVERE, "[UUID importer]", ex); - return false; - } - config.set("version", "1.9.0"); - } - if (configVersion.compareTo(new ComparableVersion("1.9.4")) < 0) { - logblock.getLogger().info("Updating tables to 1.9.4 ..."); - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - // Need to wrap both these next two inside individual try/catch statements in case index does not exist - try { - st.execute("DROP INDEX UUID ON `lb-players`"); - } catch (final SQLException ex) { - if (ex.getErrorCode() != 1091) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - } - try { - st.execute("DROP INDEX playername ON `lb-players`"); - } catch (final SQLException ex) { - if (ex.getErrorCode() != 1091) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - } - st.execute("CREATE INDEX UUID ON `lb-players` (UUID);"); - st.execute("CREATE INDEX playername ON `lb-players` (playername);"); - st.close(); - conn.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - config.set("version", "1.9.4"); - } - // Ensure charset for free-text fields is UTF-8, or UTF8-mb4 if possible - // As this may be an expensive operation and the database default may already be this, check on a table-by-table basis before converting - if (configVersion.compareTo(new ComparableVersion("1.10.0")) < 0) { - logblock.getLogger().info("Updating tables to 1.10.0 ..."); - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - checkCharset("lb-players", "name", st, false); - if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { - checkCharset("lb-chat", "message", st, false); - } - for (final WorldConfig wcfg : getLoggedWorlds()) { - if (wcfg.isLogging(Logging.SIGNTEXT)) { - // checkCharset(wcfg.table + "-sign","signtext",st); - } - } - st.close(); - conn.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - config.set("version", "1.10.0"); - } - - if (configVersion.compareTo(new ComparableVersion("1.12.0")) < 0) { - logblock.getLogger().info("Updating tables to 1.12.0 ..."); - if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - st.execute("ALTER TABLE `lb-chat` MODIFY COLUMN `message` VARCHAR(256) NOT NULL"); - st.close(); - conn.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - } - config.set("version", "1.12.0"); - } - if (configVersion.compareTo(new ComparableVersion("1.13.0")) < 0) { - logblock.getLogger().info("Updating tables to 1.13.0 ..."); - try { - MaterialUpdater1_13 materialUpdater = new MaterialUpdater1_13(logblock); - logblock.getLogger().info("Convertig BlockId to BlockData. This can take a while ..."); - final Connection conn = logblock.getConnection(); - conn.setAutoCommit(false); - final Statement st = conn.createStatement(); - for (final WorldConfig wcfg : getLoggedWorlds()) { - logblock.getLogger().info("Processing world " + wcfg.world + "..."); - logblock.getLogger().info("Processing block changes..."); - boolean hadRow = true; - long rowsToConvert = 0; - long done = 0; - try { - ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "`"); - if (rs.next()) { - rowsToConvert = rs.getLong(1); - logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table); - } - rs.close(); - - PreparedStatement deleteStatement = conn.prepareStatement("DELETE FROM `" + wcfg.table + "` WHERE id = ?"); - PreparedStatement insertStatement = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-blocks` (id, date, playerid, replaced, replacedData, type, typeData, x, y, z) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); - - while (hadRow) { - hadRow = false; - ResultSet entries = st.executeQuery("SELECT id, date, playerid, replaced, type, data, x, y, z FROM `" + wcfg.table + "` ORDER BY id ASC LIMIT " + BLOCKS_CONVERT_BATCH_SIZE); - while (entries.next()) { - hadRow = true; - long id = entries.getLong("id"); - Timestamp date = entries.getTimestamp("date"); - int playerid = entries.getInt("playerid"); - int replaced = entries.getInt("replaced"); - int type = entries.getInt("type"); - int data = entries.getInt("data"); - int x = entries.getInt("x"); - int y = entries.getInt("y"); - int z = entries.getInt("z"); - if (data == 16) { - data = 0; - } - - try { - BlockData replacedBlockData = materialUpdater.getBlockData(replaced, data); - BlockData setBlockData = materialUpdater.getBlockData(type, data); - - int newReplacedId = MaterialConverter.getOrAddMaterialId(replacedBlockData); - int newReplacedData = MaterialConverter.getOrAddBlockStateId(replacedBlockData); - - int newSetId = MaterialConverter.getOrAddMaterialId(setBlockData); - int newSetData = MaterialConverter.getOrAddBlockStateId(setBlockData); - - insertStatement.setLong(1, id); - insertStatement.setTimestamp(2, date); - insertStatement.setInt(3, playerid); - insertStatement.setInt(4, newReplacedId); - insertStatement.setInt(5, newReplacedData); - insertStatement.setInt(6, newSetId); - insertStatement.setInt(7, newSetData); - insertStatement.setInt(8, x); - insertStatement.setInt(9, y); - insertStatement.setInt(10, z); - insertStatement.addBatch(); - } catch (Exception e) { - logblock.getLogger().info("Exception in entry " + id + " (" + replaced + ":" + data + "->" + type + ":" + data + "): " + e.getMessage()); - } - deleteStatement.setLong(1, id); - deleteStatement.addBatch(); - - done++; - } - entries.close(); - int failedRows = 0; - if (hadRow) { - try { - insertStatement.executeBatch(); - } catch (BatchUpdateException e) { - for (int result : e.getUpdateCounts()) { - if (result == Statement.EXECUTE_FAILED) { - failedRows++; - } - } - } - deleteStatement.executeBatch(); - } - conn.commit(); - logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " " + (failedRows > 0 ? "Duplicates: " + failedRows + " " : "") + "(" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); - } - insertStatement.close(); - deleteStatement.close(); - } catch (SQLException e) { - logblock.getLogger().info("Could not convert " + wcfg.table + ": " + e.getMessage()); - } - - logblock.getLogger().info("Processing chests..."); - rowsToConvert = 0; - done = 0; - try { - ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-chest`"); - if (rs.next()) { - rowsToConvert = rs.getLong(1); - logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-chest"); - } - rs.close(); - - PreparedStatement insertChestData = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-chestdata` (id, item, itemremove, itemtype) VALUES (?, ?, ?, ?)"); - PreparedStatement deleteChest = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-chest` WHERE id = ?"); - while (true) { - rs = st.executeQuery("SELECT id, itemtype, itemamount, itemdata FROM `" + wcfg.table + "-chest` ORDER BY id ASC LIMIT " + OTHER_CONVERT_BATCH_SIZE); - boolean anyRow = false; - while (rs.next()) { - anyRow = true; - long id = rs.getLong("id"); - int itemtype = rs.getInt("itemtype"); - int itemdata = rs.getInt("itemdata"); - int amount = rs.getInt("itemamount"); - Material weaponMaterial = materialUpdater.getMaterial(itemtype, itemdata); - if (weaponMaterial == null) { - weaponMaterial = Material.AIR; - } - @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(stack)); - insertChestData.setInt(3, amount >= 0 ? 0 : 1); - insertChestData.setInt(4, MaterialConverter.getOrAddMaterialId(weaponMaterial)); - insertChestData.addBatch(); - - deleteChest.setLong(1, id); - deleteChest.addBatch(); - done++; - } - rs.close(); - if (!anyRow) { - break; - } - int failedRows = 0; - try { - insertChestData.executeBatch(); - } catch (BatchUpdateException e) { - for (int result : e.getUpdateCounts()) { - if (result == Statement.EXECUTE_FAILED) { - failedRows++; - } - } - } - deleteChest.executeBatch(); - conn.commit(); - logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " " + (failedRows > 0 ? "Duplicates: " + failedRows + " " : "") + "(" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); - } - insertChestData.close(); - deleteChest.close(); - } catch (SQLException e) { - logblock.getLogger().info("Could not convert " + wcfg.table + "-chest: " + e.getMessage()); - } - - if (wcfg.isLogging(Logging.KILL)) { - logblock.getLogger().info("Processing kills..."); - rowsToConvert = 0; - done = 0; - try { - ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-kills`"); - if (rs.next()) { - rowsToConvert = rs.getLong(1); - logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-kills"); - } - rs.close(); - - PreparedStatement updateWeaponStatement = conn.prepareStatement("UPDATE `" + wcfg.table + "-kills` SET weapon = ? WHERE id = ?"); - for (int start = 0;; start += OTHER_CONVERT_BATCH_SIZE) { - rs = st.executeQuery("SELECT id, weapon FROM `" + wcfg.table + "-kills` ORDER BY id ASC LIMIT " + start + "," + OTHER_CONVERT_BATCH_SIZE); - boolean anyUpdate = false; - boolean anyRow = false; - while (rs.next()) { - anyRow = true; - long id = rs.getLong("id"); - int weapon = rs.getInt("weapon"); - Material weaponMaterial = materialUpdater.getMaterial(weapon, 0); - if (weaponMaterial == null) { - weaponMaterial = Material.AIR; - } - int newWeapon = MaterialConverter.getOrAddMaterialId(weaponMaterial); - if (newWeapon != weapon) { - anyUpdate = true; - updateWeaponStatement.setInt(1, newWeapon); - updateWeaponStatement.setLong(2, id); - updateWeaponStatement.addBatch(); - } - done++; - } - rs.close(); - if (anyUpdate) { - updateWeaponStatement.executeBatch(); - conn.commit(); - } - logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); - if (!anyRow) { - break; - } - } - updateWeaponStatement.close(); - } catch (SQLException e) { - logblock.getLogger().info("Could not convert " + wcfg.table + "-kills: " + e.getMessage()); - } - } - } - st.close(); - conn.close(); - - logblock.getLogger().info("Updating config to 1.13.0 ..."); - config.set("logging.hiddenBlocks", materialUpdater.convertMaterials(config.getStringList("logging.hiddenBlocks"))); - config.set("rollback.dontRollback", materialUpdater.convertMaterials(config.getStringList("rollback.dontRollback"))); - config.set("rollback.replaceAnyway", materialUpdater.convertMaterials(config.getStringList("rollback.replaceAnyway"))); - final ConfigurationSection toolsSec = config.getConfigurationSection("tools"); - for (final String toolName : toolsSec.getKeys(false)) { - final ConfigurationSection tSec = toolsSec.getConfigurationSection(toolName); - tSec.set("item", materialUpdater.convertMaterial(tSec.getString("item", "OAK_LOG"))); - } - } catch (final SQLException | IOException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - config.set("version", "1.13.0"); - } - - if (configVersion.compareTo(new ComparableVersion("1.13.1")) < 0) { - logblock.getLogger().info("Updating tables to 1.13.1 ..."); - BlockStateCodecSign signCodec = new BlockStateCodecSign(); - try (Connection conn = logblock.getConnection()) { - conn.setAutoCommit(false); - final Statement st = conn.createStatement(); - for (final WorldConfig wcfg : getLoggedWorlds()) { - logblock.getLogger().info("Processing world " + wcfg.world + "..."); - ResultSet rsCol = st.executeQuery("SHOW COLUMNS FROM `" + wcfg.table + "-chestdata` LIKE 'itemtype'"); - if (!rsCol.next()) { - st.execute("ALTER TABLE `" + wcfg.table + "-chestdata` ADD COLUMN `itemtype` SMALLINT NOT NULL DEFAULT '0'"); - } - rsCol.close(); - conn.commit(); - if (wcfg.isLogging(Logging.SIGNTEXT)) { - long rowsToConvert = 0; - long done = 0; - try { - ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-sign`"); - if (rs.next()) { - rowsToConvert = rs.getLong(1); - logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-sign"); - } - rs.close(); - - PreparedStatement insertSignState = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-state` (id, replacedState, typeState) VALUES (?, ?, ?)"); - PreparedStatement deleteSign = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-sign` WHERE id = ?"); - while (true) { - rs = st.executeQuery("SELECT id, signtext, replaced, type FROM `" + wcfg.table + "-sign` LEFT JOIN `" + wcfg.table + "-blocks` USING (id) ORDER BY id ASC LIMIT " + OTHER_CONVERT_BATCH_SIZE); - boolean anyRow = false; - while (rs.next()) { - anyRow = true; - long id = rs.getLong("id"); - String signText = rs.getString("signtext"); - int replaced = rs.getInt("replaced"); - boolean nullBlock = rs.wasNull(); - int type = rs.getInt("type"); - - if (!nullBlock && signText != null) { - String[] lines = signText.split("\0", 4); - byte[] bytes = Utils.serializeYamlConfiguration(signCodec.serialize(null, Side.FRONT, lines)); - - Material replacedMaterial = MaterialConverter.getBlockData(replaced, -1).getMaterial(); - Material typeMaterial = MaterialConverter.getBlockData(type, -1).getMaterial(); - boolean wasSign = replacedMaterial == Material.OAK_SIGN || replacedMaterial == Material.OAK_WALL_SIGN; - boolean isSign = typeMaterial == Material.OAK_SIGN || typeMaterial == Material.OAK_WALL_SIGN; - - insertSignState.setLong(1, id); - insertSignState.setBytes(2, wasSign ? bytes : null); - insertSignState.setBytes(3, isSign ? bytes : null); - insertSignState.addBatch(); - } - - deleteSign.setLong(1, id); - deleteSign.addBatch(); - done++; - } - rs.close(); - if (!anyRow) { - break; - } - int failedRows = 0; - try { - insertSignState.executeBatch(); - } catch (BatchUpdateException e) { - for (int result : e.getUpdateCounts()) { - if (result == Statement.EXECUTE_FAILED) { - failedRows++; - } - } - } - deleteSign.executeBatch(); - conn.commit(); - logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " " + (failedRows > 0 ? "Duplicates: " + failedRows + " " : "") + "(" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); - } - insertSignState.close(); - deleteSign.close(); - } catch (SQLException e) { - logblock.getLogger().info("Could not convert " + wcfg.table + "-sign: " + e.getMessage()); - } - } - } - - st.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - - config.set("version", "1.13.1"); - } - - if (configVersion.compareTo(new ComparableVersion("1.16.0")) < 0) { - logblock.getLogger().info("Updating tables to 1.16.0 ..."); - try (Connection conn = logblock.getConnection()) { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - for (final WorldConfig wcfg : getLoggedWorlds()) { - createIndexIfDoesNotExist(wcfg.table + "-entities", "entityid", "KEY `entityid` (entityid)", st, false); - } - st.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Warning: Could not add index", ex); - } - config.set("version", "1.16.0"); - } - if (configVersion.compareTo(new ComparableVersion("1.17.0")) < 0) { - logblock.getLogger().info("Updating tables to 1.17.0 ..."); - logblock.getLogger().warning("The updating process might take several minutes if you have a huge log table! Please do not shutdown your server until it is completed."); - try (Connection conn = logblock.getConnection()) { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - for (final WorldConfig wcfg : getLoggedWorlds()) { - st.executeUpdate("ALTER TABLE `" + wcfg.table + "-blocks` CHANGE `y` `y` SMALLINT(5) NOT NULL"); - } - st.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Warning: Could not alter table", ex); - } - logblock.getLogger().info("Update to 1.17.0 completed."); - config.set("version", "1.17.0"); - } - - if (configVersion.compareTo(new ComparableVersion(Config.CURRENT_CONFIG_VERSION)) < 0) { - config.set("version", Config.CURRENT_CONFIG_VERSION); - } - - // this can always be checked - try (Connection conn = logblock.getConnection()) { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - checkCharset("lb-players", "name", st, true); - if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { - checkCharset("lb-chat", "message", st, true); - } - createIndexIfDoesNotExist("lb-materials", "name", "UNIQUE KEY `name` (`name`(150))", st, true); - createIndexIfDoesNotExist("lb-blockstates", "name", "UNIQUE KEY `name` (`name`(150))", st, true); - - st.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - try (Connection conn = logblock.getConnection()) { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - PreparedStatement stSelectColumnType = conn.prepareStatement("SELECT `TABLE_NAME`, `COLUMN_TYPE` FROM information_schema.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `COLUMN_NAME` = ?"); - stSelectColumnType.setString(1, Config.mysqlDatabase); - stSelectColumnType.setString(2, "y"); - HashMap tablesAndYColumnType = new HashMap<>(); - try (ResultSet rs = stSelectColumnType.executeQuery()) { - while (rs.next()) { - String table = rs.getString("TABLE_NAME").toLowerCase(); - String type = rs.getString("COLUMN_TYPE").toLowerCase(); - tablesAndYColumnType.put(table, type); - } - } - for (final WorldConfig wcfg : getLoggedWorlds()) { - String type = tablesAndYColumnType.get((wcfg.table + "-blocks").toLowerCase()); - if (type != null) { - if (type.contains("tinyint") || type.contains("unsigned")) { - logblock.getLogger().info("Fixing y column type for table " + wcfg.table + "-blocks ..."); - logblock.getLogger().warning("The updating process might take several minutes if you have a huge log table! Please do not shutdown your server until it is completed."); - st.executeUpdate("ALTER TABLE `" + wcfg.table + "-blocks` CHANGE `y` `y` SMALLINT(5) NOT NULL"); - } - } - type = tablesAndYColumnType.get((wcfg.table + "-entities").toLowerCase()); - if (type != null) { - if (type.contains("tinyint") || type.contains("unsigned")) { - logblock.getLogger().info("Fixing y column type for table " + wcfg.table + "-entities ..."); - logblock.getLogger().warning("The updating process might take several minutes if you have a huge log table! Please do not shutdown your server until it is completed."); - st.executeUpdate("ALTER TABLE `" + wcfg.table + "-entities` CHANGE `y` `y` SMALLINT(5) NOT NULL"); - } - } - type = tablesAndYColumnType.get((wcfg.table + "-kills").toLowerCase()); - if (type != null) { - if (type.contains("tinyint") || type.contains("unsigned")) { - logblock.getLogger().info("Fixing y column type for table " + wcfg.table + "-kills ..."); - logblock.getLogger().warning("The updating process might take several minutes if you have a huge log table! Please do not shutdown your server until it is completed."); - st.executeUpdate("ALTER TABLE `" + wcfg.table + "-kills` CHANGE `y` `y` SMALLINT(5) NOT NULL"); - } - } - } - st.close(); - conn.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - - updateMaterialsPost1_13(); - - logblock.saveConfig(); - return true; - } - - void createIndexIfDoesNotExist(String table, String indexName, String definition, Statement st, boolean silent) throws SQLException { - final ResultSet rs = st.executeQuery("SHOW INDEX FROM `" + table + "` WHERE Key_name = '" + indexName + "'"); - if (!rs.next()) { - st.execute("ALTER TABLE `" + table + "` ADD " + definition); - logblock.getLogger().info("Add index " + indexName + " to table " + table + ": Table modified"); - } else if (!silent) { - logblock.getLogger().info("Add index " + indexName + " to table " + table + ": Already fine, skipping it"); - } - rs.close(); - } - - void checkCharset(String table, String column, Statement st, boolean silent) throws SQLException { - final ResultSet rs = st.executeQuery("SHOW FULL COLUMNS FROM `" + table + "` WHERE field = '" + column + "'"); - String charset = "utf8"; - if (Config.mb4) { - charset = "utf8mb4"; - } - if (rs.next() && !rs.getString("Collation").substring(0, charset.length()).equalsIgnoreCase(charset)) { - st.execute("ALTER TABLE `" + table + "` CONVERT TO CHARSET " + charset); - logblock.getLogger().info("Table " + table + " modified"); - } else if (!silent) { - logblock.getLogger().info("Table " + table + " already fine, skipping it"); - } - rs.close(); - } - - void checkTables() throws SQLException { - String charset = "utf8"; - if (Config.mb4) { - charset = "utf8mb4"; - } - final Connection conn = logblock.getConnection(); - if (conn == null) { - throw new SQLException("No connection"); - } - 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); - // 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;"); - if (!rs.next()) { - state.execute("INSERT IGNORE INTO `lb-players` (UUID,playername) VALUES ('log_dummy_record','dummy_record')"); - } - 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); - } 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-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))"); - 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 + "-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"); - } - } - } - } - } - - /** - * Update materials that were renamed - */ - private void updateMaterialsPost1_13() { - final ConfigurationSection config = logblock.getConfig(); - String previousMinecraftVersion = config.getString("previousMinecraftVersion"); - if (previousMinecraftVersion == null) { - previousMinecraftVersion = "1.13"; - } - ComparableVersion comparablePreviousMinecraftVersion = new ComparableVersion(previousMinecraftVersion); - String currentMinecraftVersion = logblock.getServer().getVersion(); - currentMinecraftVersion = currentMinecraftVersion.substring(currentMinecraftVersion.indexOf("(MC: ") + 5); - int currentVersionEnd = currentMinecraftVersion.indexOf(" "); - int currentVersionEnd2 = currentMinecraftVersion.indexOf(")"); - if (currentVersionEnd2 >= 0 && (currentVersionEnd < 0 || currentVersionEnd2 < currentVersionEnd)) { - currentVersionEnd = currentVersionEnd2; - } - currentMinecraftVersion = currentMinecraftVersion.substring(0, currentVersionEnd); - logblock.getLogger().info("[Updater] Current Minecraft Version: '" + currentMinecraftVersion + "'"); - ComparableVersion comparableCurrentMinecraftVersion = new ComparableVersion(currentMinecraftVersion); - - if (comparablePreviousMinecraftVersion.compareTo("1.14") < 0 && comparableCurrentMinecraftVersion.compareTo("1.14") >= 0) { - logblock.getLogger().info("[Updater] Upgrading Materials to 1.14"); - renameMaterial("minecraft:sign", Material.OAK_SIGN); - renameMaterial("minecraft:wall_sign", Material.OAK_WALL_SIGN); - renameMaterial("minecraft:stone_slab", Material.SMOOTH_STONE_SLAB); - renameMaterial("minecraft:rose_red", Material.RED_DYE); - renameMaterial("minecraft:dandelion_yellow", Material.YELLOW_DYE); - renameMaterial("minecraft:cactus_green", Material.GREEN_DYE); - } - - if (comparablePreviousMinecraftVersion.compareTo("1.17") < 0 && comparableCurrentMinecraftVersion.compareTo("1.17") >= 0) { - logblock.getLogger().info("[Updater] Upgrading Materials to 1.17"); - renameMaterial("minecraft:grass_path", Material.DIRT_PATH); - } - - config.set("previousMinecraftVersion", currentMinecraftVersion); - logblock.saveConfig(); - } - - private void renameMaterial(String oldName, Material newName) { - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(false); - PreparedStatement stSelectMaterial = conn.prepareStatement("SELECT id FROM `lb-materials` WHERE name = ?"); - stSelectMaterial.setString(1, oldName); - ResultSet rs = stSelectMaterial.executeQuery(); - if (rs.next()) { - logblock.getLogger().info("[Updater] Updating " + oldName + " to " + newName); - int oldId = rs.getInt(1); - int newId = MaterialConverter.getOrAddMaterialId(newName); - - Statement st = conn.createStatement(); - int rows = 0; - for (final WorldConfig wcfg : getLoggedWorlds()) { - rows += st.executeUpdate("UPDATE `" + wcfg.table + "-blocks` SET replaced = " + newId + " WHERE replaced = " + oldId); - rows += st.executeUpdate("UPDATE `" + wcfg.table + "-blocks` SET type = " + newId + " WHERE type = " + oldId); - rows += st.executeUpdate("UPDATE `" + wcfg.table + "-chestdata` SET itemtype = " + newId + " WHERE itemtype = " + oldId); - if (wcfg.isLogging(Logging.KILL)) { - rows += st.executeUpdate("UPDATE `" + wcfg.table + "-kills` SET weapon = " + newId + " WHERE weapon = " + oldId); - } - } - st.close(); - if (rows > 0) { - logblock.getLogger().info("[Updater] Successfully updated " + rows + " entries.."); - } - } - stSelectMaterial.close(); - conn.commit(); - conn.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: " + ex.getMessage(), ex); - } - } - - public static class PlayerCountChecker implements Runnable { - - private LogBlock logblock; - - public PlayerCountChecker(LogBlock logblock) { - this.logblock = logblock; - } - - @Override - public void run() { - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - ResultSet rs = st.executeQuery("SELECT auto_increment FROM information_schema.columns AS col join information_schema.tables AS tab ON (col.table_schema=tab.table_schema AND col.table_name=tab.table_name) WHERE col.table_name = 'lb-players' AND col.column_name = 'playerid' AND col.data_type = 'smallint' AND col.table_schema = DATABASE() AND auto_increment > 65000;"); - if (rs.next()) { - for (int i = 0; i < 6; i++) { - logblock.getLogger().warning("Your server reached 65000 players. You should soon update your database table schema - see FAQ: https://github.com/LogBlock/LogBlock/wiki/FAQ#logblock-your-server-reached-65000-players-"); - } - } - st.close(); - conn.close(); - } catch (final SQLException ex) { - if (logblock.isCompletelyEnabled()) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - } - } - } - } - - public static class MaterialUpdater1_13 { - BlockData[][] blockDataMapping; - Material[][] itemMapping = new Material[10][]; - - public MaterialUpdater1_13(LogBlock plugin) throws IOException { - blockDataMapping = new BlockData[256][16]; - try (JarFile file = new JarFile(plugin.getFile())) { - BufferedReader reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(file.getInputStream(file.getJarEntry("blockdata.txt"))), "UTF-8")); - while (true) { - String line = reader.readLine(); - if (line == null) { - break; - } - int splitter1 = line.indexOf(":"); - int splitter2 = line.indexOf(","); - if (splitter1 >= 0 && splitter2 >= 0) { - int blockid = Integer.parseInt(line.substring(0, splitter1)); - int blockdata = Integer.parseInt(line.substring(splitter1 + 1, splitter2)); - BlockData newBlockData = Bukkit.createBlockData(line.substring(splitter2 + 1)); - - if (blockdata == 0) { - for (int i = 0; i < 16; i++) { - if (blockDataMapping[blockid][i] == null) { - blockDataMapping[blockid][i] = newBlockData; - } - } - } else { - blockDataMapping[blockid][blockdata] = newBlockData; - } - } - } - reader.close(); - - HashMap materialKeysToMaterial = new HashMap<>(); - for (Material material : Material.values()) { - materialKeysToMaterial.put(material.getKey().toString(), material); - } - - reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(file.getInputStream(file.getJarEntry("itemdata.txt"))), "UTF-8")); - while (true) { - String line = reader.readLine(); - if (line == null) { - break; - } - int splitter1 = line.indexOf(":"); - int splitter2 = line.indexOf(","); - if (splitter1 >= 0 && splitter2 >= 0) { - int itemid = Integer.parseInt(line.substring(0, splitter1)); - int itemdata = Integer.parseInt(line.substring(splitter1 + 1, splitter2)); - Material newMaterial = materialKeysToMaterial.get(line.substring(splitter2 + 1)); - if (newMaterial == null) { - throw new IOException("Unknown item: " + line.substring(splitter2 + 1)); - } - if (itemid >= itemMapping.length) { - itemMapping = Arrays.copyOf(itemMapping, Math.max(itemMapping.length * 3 / 2, itemid + 1)); - } - - Material[] itemValues = itemMapping[itemid]; - if (itemValues == null) { - itemValues = new Material[itemdata + 1]; - itemMapping[itemid] = itemValues; - } else if (itemValues.length <= itemdata) { - itemValues = Arrays.copyOf(itemValues, itemdata + 1); - itemMapping[itemid] = itemValues; - } - itemValues[itemdata] = newMaterial; - } - } - reader.close(); - } - } - - public BlockData getBlockData(int id, int data) { - return id >= 0 && id < 256 && data >= 0 && data < 16 ? blockDataMapping[id][data] : null; - } - - public Material getMaterial(int id, int data) { - Material[] materials = id >= 0 && id < itemMapping.length ? itemMapping[id] : null; - if (materials != null && materials.length > 0) { - if (materials[0] != null && materials[0].getMaxDurability() == 0 && data >= 0 && data < materials.length && materials[data] != null) { - return materials[data]; - } - return materials[0]; - } - return null; - } - - public Material getMaterial(String id) { - int item = 0; - int data = 0; - int seperator = id.indexOf(':'); - if (seperator < 0) { - item = Integer.parseInt(id); - } else { - item = Integer.parseInt(id.substring(0, seperator)); - data = Integer.parseInt(id.substring(seperator + 1)); - } - return getMaterial(item, data); - } - - public String convertMaterial(String oldEntry) { - if (oldEntry == null) { - return null; - } - try { - Material newMaterial = getMaterial(oldEntry); - if (newMaterial != null) { - return newMaterial.name(); - } - } catch (Exception e) { - Material newMaterial = Material.matchMaterial(oldEntry, true); - if (newMaterial != null) { - return newMaterial.name(); - } else { - newMaterial = Material.matchMaterial(oldEntry); - if (newMaterial != null) { - return newMaterial.name(); - } - } - } - return null; - } - - public List convertMaterials(Collection oldEntries) { - Set newEntries = new LinkedHashSet<>(); - for (String oldEntry : oldEntries) { - String newEntry = convertMaterial(oldEntry); - if (newEntry != null) { - newEntries.add(newEntry); - if (newEntry.equals(Material.AIR.name())) { - newEntries.add(Material.CAVE_AIR.name()); - newEntries.add(Material.VOID_AIR.name()); - } - } - } - return new ArrayList<>(newEntries); - } - } -} +package de.diddiz.LogBlock; + +import de.diddiz.LogBlock.blockstate.BlockStateCodecSign; +import de.diddiz.LogBlock.config.Config; +import de.diddiz.LogBlock.config.WorldConfig; +import de.diddiz.LogBlock.util.ComparableVersion; +import de.diddiz.LogBlock.util.UUIDFetcher; +import de.diddiz.LogBlock.util.Utils; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.sign.Side; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemStack; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.sql.*; +import java.util.*; +import java.util.jar.JarFile; +import java.util.logging.Level; + +import static de.diddiz.LogBlock.config.Config.getLoggedWorlds; +import static de.diddiz.LogBlock.config.Config.isLogging; +import static de.diddiz.LogBlock.util.BukkitUtils.friendlyWorldname; + +class Updater { + private final LogBlock logblock; + final int UUID_CONVERT_BATCH_SIZE = 100; + final int BLOCKS_CONVERT_BATCH_SIZE = 100000; + final int OTHER_CONVERT_BATCH_SIZE = 20000; + + Updater(LogBlock logblock) { + this.logblock = logblock; + } + + boolean update() { + final ConfigurationSection config = logblock.getConfig(); + String versionString = config.getString("version"); + ComparableVersion configVersion = new ComparableVersion(versionString); + // if (configVersion.compareTo(new ComparableVersion(logblock.getDescription().getVersion().replace(" (manually compiled)", ""))) >= 0) { + // return false; + // } + if (configVersion.compareTo(new ComparableVersion("1.2.7")) < 0) { + logblock.getLogger().info("Updating tables to 1.2.7 ..."); + if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + st.execute("ALTER TABLE `lb-chat` ADD FULLTEXT message (message)"); + st.close(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + } + config.set("version", "1.2.7"); + } + if (configVersion.compareTo(new ComparableVersion("1.3")) < 0) { + logblock.getLogger().info("Updating config to 1.3.0 ..."); + for (final String tool : config.getConfigurationSection("tools").getKeys(false)) { + if (config.get("tools." + tool + ".permissionDefault") == null) { + config.set("tools." + tool + ".permissionDefault", "OP"); + } + } + config.set("version", "1.3.0"); + } + if (configVersion.compareTo(new ComparableVersion("1.3.1")) < 0) { + logblock.getLogger().info("Updating tables to 1.3.1 ..."); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + st.execute("ALTER TABLE `lb-players` ADD COLUMN lastlogin DATETIME NOT NULL, ADD COLUMN onlinetime TIME NOT NULL, ADD COLUMN ip VARCHAR(255) NOT NULL"); + st.close(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.3.1"); + } + if (configVersion.compareTo(new ComparableVersion("1.3.2")) < 0) { + logblock.getLogger().info("Updating tables to 1.3.2 ..."); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + st.execute("ALTER TABLE `lb-players` ADD COLUMN firstlogin DATETIME NOT NULL AFTER playername"); + st.close(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.3.2"); + } + if (configVersion.compareTo(new ComparableVersion("1.4")) < 0) { + logblock.getLogger().info("Updating config to 1.4.0 ..."); + config.set("clearlog.keepLogDays", null); + config.set("version", "1.4.0"); + } + if (configVersion.compareTo(new ComparableVersion("1.4.2")) < 0) { + logblock.getLogger().info("Updating config to 1.4.2 ..."); + for (final String world : config.getStringList("loggedWorlds")) { + final File file = new File(logblock.getDataFolder(), friendlyWorldname(world) + ".yml"); + final YamlConfiguration wcfg = YamlConfiguration.loadConfiguration(file); + if (wcfg.contains("logBlockCreations")) { + wcfg.set("logging.BLOCKPLACE", wcfg.getBoolean("logBlockCreations")); + } + if (wcfg.contains("logBlockDestroyings")) { + wcfg.set("logging.BLOCKBREAK", wcfg.getBoolean("logBlockDestroyings")); + } + if (wcfg.contains("logSignTexts")) { + wcfg.set("logging.SIGNTEXT", wcfg.getBoolean("logSignTexts")); + } + if (wcfg.contains("logFire")) { + wcfg.set("logging.FIRE", wcfg.getBoolean("logFire")); + } + if (wcfg.contains("logLeavesDecay")) { + wcfg.set("logging.LEAVESDECAY", wcfg.getBoolean("logLeavesDecay")); + } + if (wcfg.contains("logLavaFlow")) { + wcfg.set("logging.LAVAFLOW", wcfg.getBoolean("logLavaFlow")); + } + if (wcfg.contains("logWaterFlow")) { + wcfg.set("logging.WATERFLOW", wcfg.getBoolean("logWaterFlow")); + } + if (wcfg.contains("logChestAccess")) { + wcfg.set("logging.CHESTACCESS", wcfg.getBoolean("logChestAccess")); + } + if (wcfg.contains("logButtonsAndLevers")) { + wcfg.set("logging.SWITCHINTERACT", wcfg.getBoolean("logButtonsAndLevers")); + } + if (wcfg.contains("logKills")) { + wcfg.set("logging.KILL", wcfg.getBoolean("logKills")); + } + if (wcfg.contains("logChat")) { + wcfg.set("logging.CHAT", wcfg.getBoolean("logChat")); + } + if (wcfg.contains("logSnowForm")) { + wcfg.set("logging.SNOWFORM", wcfg.getBoolean("logSnowForm")); + } + if (wcfg.contains("logSnowFade")) { + wcfg.set("logging.SNOWFADE", wcfg.getBoolean("logSnowFade")); + } + if (wcfg.contains("logDoors")) { + wcfg.set("logging.DOORINTERACT", wcfg.getBoolean("logDoors")); + } + if (wcfg.contains("logCakes")) { + wcfg.set("logging.CAKEEAT", wcfg.getBoolean("logCakes")); + } + if (wcfg.contains("logEndermen")) { + wcfg.set("logging.ENDERMEN", wcfg.getBoolean("logEndermen")); + } + if (wcfg.contains("logExplosions")) { + final boolean logExplosions = wcfg.getBoolean("logExplosions"); + wcfg.set("logging.TNTEXPLOSION", logExplosions); + wcfg.set("logging.MISCEXPLOSION", logExplosions); + wcfg.set("logging.CREEPEREXPLOSION", logExplosions); + wcfg.set("logging.GHASTFIREBALLEXPLOSION", logExplosions); + } + wcfg.set("logBlockCreations", null); + wcfg.set("logBlockDestroyings", null); + wcfg.set("logSignTexts", null); + wcfg.set("logExplosions", null); + wcfg.set("logFire", null); + wcfg.set("logLeavesDecay", null); + wcfg.set("logLavaFlow", null); + wcfg.set("logWaterFlow", null); + wcfg.set("logChestAccess", null); + wcfg.set("logButtonsAndLevers", null); + wcfg.set("logKills", null); + wcfg.set("logChat", null); + wcfg.set("logSnowForm", null); + wcfg.set("logSnowFade", null); + wcfg.set("logDoors", null); + wcfg.set("logCakes", null); + wcfg.set("logEndermen", null); + try { + wcfg.save(file); + } catch (final IOException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + } + } + config.set("clearlog.keepLogDays", null); + config.set("version", "1.4.2"); + } + if (configVersion.compareTo(new ComparableVersion("1.5.1")) < 0) { + logblock.getLogger().info("Updating tables to 1.5.1 ..."); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + for (final WorldConfig wcfg : getLoggedWorlds()) { + if (wcfg.isLogging(Logging.KILL)) { + st.execute("ALTER TABLE `" + wcfg.table + "-kills` ADD (x MEDIUMINT NOT NULL DEFAULT 0, y SMALLINT NOT NULL DEFAULT 0, z MEDIUMINT NOT NULL DEFAULT 0)"); + } + } + st.close(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.5.1"); + } + if (configVersion.compareTo(new ComparableVersion("1.5.2")) < 0) { + logblock.getLogger().info("Updating tables to 1.5.2 ..."); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + final ResultSet rs = st.executeQuery("SHOW COLUMNS FROM `lb-players` WHERE field = 'onlinetime'"); + if (rs.next() && rs.getString("Type").equalsIgnoreCase("time")) { + st.execute("ALTER TABLE `lb-players` ADD onlinetime2 INT UNSIGNED NOT NULL"); + st.execute("UPDATE `lb-players` SET onlinetime2 = HOUR(onlinetime) * 3600 + MINUTE(onlinetime) * 60 + SECOND(onlinetime)"); + st.execute("ALTER TABLE `lb-players` DROP onlinetime"); + st.execute("ALTER TABLE `lb-players` CHANGE onlinetime2 onlinetime INT UNSIGNED NOT NULL"); + } else { + logblock.getLogger().info("Column lb-players was already modified, skipping it."); + } + st.close(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.5.2"); + } + if (configVersion.compareTo(new ComparableVersion("1.8.1")) < 0) { + logblock.getLogger().info("Updating tables to 1.8.1 ..."); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + for (final WorldConfig wcfg : getLoggedWorlds()) { + if (wcfg.isLogging(Logging.CHESTACCESS)) { + st.execute("ALTER TABLE `" + wcfg.table + "-chest` CHANGE itemdata itemdata SMALLINT NOT NULL"); + logblock.getLogger().info("Table " + wcfg.table + "-chest modified"); + } + } + st.close(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.8.1"); + } + + if (configVersion.compareTo(new ComparableVersion("1.9")) < 0) { + logblock.getLogger().info("Updating tables to 1.9.0 ..."); + logblock.getLogger().info("Importing UUIDs for large databases may take some time"); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + st.execute("ALTER TABLE `lb-players` ADD `UUID` VARCHAR(36) NOT NULL"); + } catch (final SQLException ex) { + // Error 1060 is MySQL error "column already exists". We want to continue with import if we get that error + if (ex.getErrorCode() != 1060) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + } + try { + String unimportedPrefix = "noimport_"; + ResultSet rs; + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + if (config.getBoolean("logging.logPlayerInfo")) { + // Start by assuming anything with no onlinetime is not a player + st.execute("UPDATE `lb-players` SET UUID = CONCAT ('log_',playername) WHERE onlinetime=0 AND LENGTH(UUID) = 0"); + } else { + // If we can't assume that, we must assume anything we can't look up is not a player + unimportedPrefix = "log_"; + } + // Tell people how many are needing converted + rs = st.executeQuery("SELECT COUNT(playername) FROM `lb-players` WHERE LENGTH(UUID)=0"); + rs.next(); + String total = Integer.toString(rs.getInt(1)); + logblock.getLogger().info(total + " players to convert"); + int done = 0; + + conn.setAutoCommit(false); + Map players = new HashMap<>(); + List names = new ArrayList<>(UUID_CONVERT_BATCH_SIZE); + Map response; + rs = st.executeQuery("SELECT playerid,playername FROM `lb-players` WHERE LENGTH(UUID)=0 LIMIT " + Integer.toString(UUID_CONVERT_BATCH_SIZE)); + while (rs.next()) { + do { + players.put(rs.getString(2), rs.getInt(1)); + names.add(rs.getString(2)); + } while (rs.next()); + if (names.size() > 0) { + String theUUID; + response = UUIDFetcher.getUUIDs(names); + for (Map.Entry entry : players.entrySet()) { + if (response.get(entry.getKey()) == null) { + theUUID = unimportedPrefix + entry.getKey(); + logblock.getLogger().warning(entry.getKey() + " not found - giving UUID of " + theUUID); + } else { + theUUID = response.get(entry.getKey()).toString(); + } + String thePID = entry.getValue().toString(); + st.execute("UPDATE `lb-players` SET UUID = '" + theUUID + "' WHERE playerid = " + thePID); + done++; + } + conn.commit(); + players.clear(); + names.clear(); + logblock.getLogger().info("Processed " + Integer.toString(done) + " out of " + total); + rs.close(); + rs = st.executeQuery("SELECT playerid,playername FROM `lb-players` WHERE LENGTH(UUID)=0 LIMIT " + Integer.toString(UUID_CONVERT_BATCH_SIZE)); + } + } + rs.close(); + st.close(); + conn.close(); + + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } catch (Exception ex) { + logblock.getLogger().log(Level.SEVERE, "[UUID importer]", ex); + return false; + } + config.set("version", "1.9.0"); + } + if (configVersion.compareTo(new ComparableVersion("1.9.4")) < 0) { + logblock.getLogger().info("Updating tables to 1.9.4 ..."); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + // Need to wrap both these next two inside individual try/catch statements in case index does not exist + try { + st.execute("DROP INDEX UUID ON `lb-players`"); + } catch (final SQLException ex) { + if (ex.getErrorCode() != 1091) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + } + try { + st.execute("DROP INDEX playername ON `lb-players`"); + } catch (final SQLException ex) { + if (ex.getErrorCode() != 1091) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + } + st.execute("CREATE INDEX UUID ON `lb-players` (UUID);"); + st.execute("CREATE INDEX playername ON `lb-players` (playername);"); + st.close(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.9.4"); + } + // Ensure charset for free-text fields is UTF-8, or UTF8-mb4 if possible + // As this may be an expensive operation and the database default may already be this, check on a table-by-table basis before converting + if (configVersion.compareTo(new ComparableVersion("1.10.0")) < 0) { + logblock.getLogger().info("Updating tables to 1.10.0 ..."); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + checkCharset("lb-players", "name", st, false); + if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { + checkCharset("lb-chat", "message", st, false); + } + for (final WorldConfig wcfg : getLoggedWorlds()) { + if (wcfg.isLogging(Logging.SIGNTEXT)) { + // checkCharset(wcfg.table + "-sign","signtext",st); + } + } + st.close(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.10.0"); + } + + if (configVersion.compareTo(new ComparableVersion("1.12.0")) < 0) { + logblock.getLogger().info("Updating tables to 1.12.0 ..."); + if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + st.execute("ALTER TABLE `lb-chat` MODIFY COLUMN `message` VARCHAR(256) NOT NULL"); + st.close(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + } + config.set("version", "1.12.0"); + } + if (configVersion.compareTo(new ComparableVersion("1.13.0")) < 0) { + logblock.getLogger().info("Updating tables to 1.13.0 ..."); + try { + MaterialUpdater1_13 materialUpdater = new MaterialUpdater1_13(logblock); + logblock.getLogger().info("Convertig BlockId to BlockData. This can take a while ..."); + final Connection conn = logblock.getConnection(); + conn.setAutoCommit(false); + final Statement st = conn.createStatement(); + for (final WorldConfig wcfg : getLoggedWorlds()) { + logblock.getLogger().info("Processing world " + wcfg.world + "..."); + logblock.getLogger().info("Processing block changes..."); + boolean hadRow = true; + long rowsToConvert = 0; + long done = 0; + try { + ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "`"); + if (rs.next()) { + rowsToConvert = rs.getLong(1); + logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table); + } + rs.close(); + + PreparedStatement deleteStatement = conn.prepareStatement("DELETE FROM `" + wcfg.table + "` WHERE id = ?"); + PreparedStatement insertStatement = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-blocks` (id, date, playerid, replaced, replacedData, type, typeData, x, y, z) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); + + while (hadRow) { + hadRow = false; + ResultSet entries = st.executeQuery("SELECT id, date, playerid, replaced, type, data, x, y, z FROM `" + wcfg.table + "` ORDER BY id ASC LIMIT " + BLOCKS_CONVERT_BATCH_SIZE); + while (entries.next()) { + hadRow = true; + long id = entries.getLong("id"); + Timestamp date = entries.getTimestamp("date"); + int playerid = entries.getInt("playerid"); + int replaced = entries.getInt("replaced"); + int type = entries.getInt("type"); + int data = entries.getInt("data"); + int x = entries.getInt("x"); + int y = entries.getInt("y"); + int z = entries.getInt("z"); + if (data == 16) { + data = 0; + } + + try { + BlockData replacedBlockData = materialUpdater.getBlockData(replaced, data); + BlockData setBlockData = materialUpdater.getBlockData(type, data); + + int newReplacedId = MaterialConverter.getOrAddMaterialId(replacedBlockData); + int newReplacedData = MaterialConverter.getOrAddBlockStateId(replacedBlockData); + + int newSetId = MaterialConverter.getOrAddMaterialId(setBlockData); + int newSetData = MaterialConverter.getOrAddBlockStateId(setBlockData); + + insertStatement.setLong(1, id); + insertStatement.setTimestamp(2, date); + insertStatement.setInt(3, playerid); + insertStatement.setInt(4, newReplacedId); + insertStatement.setInt(5, newReplacedData); + insertStatement.setInt(6, newSetId); + insertStatement.setInt(7, newSetData); + insertStatement.setInt(8, x); + insertStatement.setInt(9, y); + insertStatement.setInt(10, z); + insertStatement.addBatch(); + } catch (Exception e) { + logblock.getLogger().info("Exception in entry " + id + " (" + replaced + ":" + data + "->" + type + ":" + data + "): " + e.getMessage()); + } + deleteStatement.setLong(1, id); + deleteStatement.addBatch(); + + done++; + } + entries.close(); + int failedRows = 0; + if (hadRow) { + try { + insertStatement.executeBatch(); + } catch (BatchUpdateException e) { + for (int result : e.getUpdateCounts()) { + if (result == Statement.EXECUTE_FAILED) { + failedRows++; + } + } + } + deleteStatement.executeBatch(); + } + conn.commit(); + logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " " + (failedRows > 0 ? "Duplicates: " + failedRows + " " : "") + "(" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + } + insertStatement.close(); + deleteStatement.close(); + } catch (SQLException e) { + logblock.getLogger().info("Could not convert " + wcfg.table + ": " + e.getMessage()); + } + + logblock.getLogger().info("Processing chests..."); + rowsToConvert = 0; + done = 0; + try { + ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-chest`"); + if (rs.next()) { + rowsToConvert = rs.getLong(1); + logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-chest"); + } + rs.close(); + + PreparedStatement insertChestData = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-chestdata` (id, item, itemremove, itemtype) VALUES (?, ?, ?, ?)"); + PreparedStatement deleteChest = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-chest` WHERE id = ?"); + while (true) { + rs = st.executeQuery("SELECT id, itemtype, itemamount, itemdata FROM `" + wcfg.table + "-chest` ORDER BY id ASC LIMIT " + OTHER_CONVERT_BATCH_SIZE); + boolean anyRow = false; + while (rs.next()) { + anyRow = true; + long id = rs.getLong("id"); + int itemtype = rs.getInt("itemtype"); + int itemdata = rs.getInt("itemdata"); + int amount = rs.getInt("itemamount"); + Material weaponMaterial = materialUpdater.getMaterial(itemtype, itemdata); + if (weaponMaterial == null) { + weaponMaterial = Material.AIR; + } + @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(stack)); + insertChestData.setInt(3, amount >= 0 ? 0 : 1); + insertChestData.setInt(4, MaterialConverter.getOrAddMaterialId(weaponMaterial)); + insertChestData.addBatch(); + + deleteChest.setLong(1, id); + deleteChest.addBatch(); + done++; + } + rs.close(); + if (!anyRow) { + break; + } + int failedRows = 0; + try { + insertChestData.executeBatch(); + } catch (BatchUpdateException e) { + for (int result : e.getUpdateCounts()) { + if (result == Statement.EXECUTE_FAILED) { + failedRows++; + } + } + } + deleteChest.executeBatch(); + conn.commit(); + logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " " + (failedRows > 0 ? "Duplicates: " + failedRows + " " : "") + "(" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + } + insertChestData.close(); + deleteChest.close(); + } catch (SQLException e) { + logblock.getLogger().info("Could not convert " + wcfg.table + "-chest: " + e.getMessage()); + } + + if (wcfg.isLogging(Logging.KILL)) { + logblock.getLogger().info("Processing kills..."); + rowsToConvert = 0; + done = 0; + try { + ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-kills`"); + if (rs.next()) { + rowsToConvert = rs.getLong(1); + logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-kills"); + } + rs.close(); + + PreparedStatement updateWeaponStatement = conn.prepareStatement("UPDATE `" + wcfg.table + "-kills` SET weapon = ? WHERE id = ?"); + for (int start = 0;; start += OTHER_CONVERT_BATCH_SIZE) { + rs = st.executeQuery("SELECT id, weapon FROM `" + wcfg.table + "-kills` ORDER BY id ASC LIMIT " + start + "," + OTHER_CONVERT_BATCH_SIZE); + boolean anyUpdate = false; + boolean anyRow = false; + while (rs.next()) { + anyRow = true; + long id = rs.getLong("id"); + int weapon = rs.getInt("weapon"); + Material weaponMaterial = materialUpdater.getMaterial(weapon, 0); + if (weaponMaterial == null) { + weaponMaterial = Material.AIR; + } + int newWeapon = MaterialConverter.getOrAddMaterialId(weaponMaterial); + if (newWeapon != weapon) { + anyUpdate = true; + updateWeaponStatement.setInt(1, newWeapon); + updateWeaponStatement.setLong(2, id); + updateWeaponStatement.addBatch(); + } + done++; + } + rs.close(); + if (anyUpdate) { + updateWeaponStatement.executeBatch(); + conn.commit(); + } + logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + if (!anyRow) { + break; + } + } + updateWeaponStatement.close(); + } catch (SQLException e) { + logblock.getLogger().info("Could not convert " + wcfg.table + "-kills: " + e.getMessage()); + } + } + } + st.close(); + conn.close(); + + logblock.getLogger().info("Updating config to 1.13.0 ..."); + config.set("logging.hiddenBlocks", materialUpdater.convertMaterials(config.getStringList("logging.hiddenBlocks"))); + config.set("rollback.dontRollback", materialUpdater.convertMaterials(config.getStringList("rollback.dontRollback"))); + config.set("rollback.replaceAnyway", materialUpdater.convertMaterials(config.getStringList("rollback.replaceAnyway"))); + final ConfigurationSection toolsSec = config.getConfigurationSection("tools"); + for (final String toolName : toolsSec.getKeys(false)) { + final ConfigurationSection tSec = toolsSec.getConfigurationSection(toolName); + tSec.set("item", materialUpdater.convertMaterial(tSec.getString("item", "OAK_LOG"))); + } + } catch (final SQLException | IOException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.13.0"); + } + + if (configVersion.compareTo(new ComparableVersion("1.13.1")) < 0) { + logblock.getLogger().info("Updating tables to 1.13.1 ..."); + BlockStateCodecSign signCodec = new BlockStateCodecSign(); + try (Connection conn = logblock.getConnection()) { + conn.setAutoCommit(false); + final Statement st = conn.createStatement(); + for (final WorldConfig wcfg : getLoggedWorlds()) { + logblock.getLogger().info("Processing world " + wcfg.world + "..."); + ResultSet rsCol = st.executeQuery("SHOW COLUMNS FROM `" + wcfg.table + "-chestdata` LIKE 'itemtype'"); + if (!rsCol.next()) { + st.execute("ALTER TABLE `" + wcfg.table + "-chestdata` ADD COLUMN `itemtype` SMALLINT NOT NULL DEFAULT '0'"); + } + rsCol.close(); + conn.commit(); + if (wcfg.isLogging(Logging.SIGNTEXT)) { + long rowsToConvert = 0; + long done = 0; + try { + ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-sign`"); + if (rs.next()) { + rowsToConvert = rs.getLong(1); + logblock.getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-sign"); + } + rs.close(); + + PreparedStatement insertSignState = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-state` (id, replacedState, typeState) VALUES (?, ?, ?)"); + PreparedStatement deleteSign = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-sign` WHERE id = ?"); + while (true) { + rs = st.executeQuery("SELECT id, signtext, replaced, type FROM `" + wcfg.table + "-sign` LEFT JOIN `" + wcfg.table + "-blocks` USING (id) ORDER BY id ASC LIMIT " + OTHER_CONVERT_BATCH_SIZE); + boolean anyRow = false; + while (rs.next()) { + anyRow = true; + long id = rs.getLong("id"); + String signText = rs.getString("signtext"); + int replaced = rs.getInt("replaced"); + boolean nullBlock = rs.wasNull(); + int type = rs.getInt("type"); + + if (!nullBlock && signText != null) { + String[] lines = signText.split("\0", 4); + byte[] bytes = Utils.serializeYamlConfiguration(signCodec.serialize(null, Side.FRONT, lines)); + + Material replacedMaterial = MaterialConverter.getBlockData(replaced, -1).getMaterial(); + Material typeMaterial = MaterialConverter.getBlockData(type, -1).getMaterial(); + boolean wasSign = replacedMaterial == Material.OAK_SIGN || replacedMaterial == Material.OAK_WALL_SIGN; + boolean isSign = typeMaterial == Material.OAK_SIGN || typeMaterial == Material.OAK_WALL_SIGN; + + insertSignState.setLong(1, id); + insertSignState.setBytes(2, wasSign ? bytes : null); + insertSignState.setBytes(3, isSign ? bytes : null); + insertSignState.addBatch(); + } + + deleteSign.setLong(1, id); + deleteSign.addBatch(); + done++; + } + rs.close(); + if (!anyRow) { + break; + } + int failedRows = 0; + try { + insertSignState.executeBatch(); + } catch (BatchUpdateException e) { + for (int result : e.getUpdateCounts()) { + if (result == Statement.EXECUTE_FAILED) { + failedRows++; + } + } + } + deleteSign.executeBatch(); + conn.commit(); + logblock.getLogger().info("Done: " + done + "/" + rowsToConvert + " " + (failedRows > 0 ? "Duplicates: " + failedRows + " " : "") + "(" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)"); + } + insertSignState.close(); + deleteSign.close(); + } catch (SQLException e) { + logblock.getLogger().info("Could not convert " + wcfg.table + "-sign: " + e.getMessage()); + } + } + } + + st.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + + config.set("version", "1.13.1"); + } + + if (configVersion.compareTo(new ComparableVersion("1.16.0")) < 0) { + logblock.getLogger().info("Updating tables to 1.16.0 ..."); + try (Connection conn = logblock.getConnection()) { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + for (final WorldConfig wcfg : getLoggedWorlds()) { + createIndexIfDoesNotExist(wcfg.table + "-entities", "entityid", "KEY `entityid` (entityid)", st, false); + } + st.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Warning: Could not add index", ex); + } + config.set("version", "1.16.0"); + } + if (configVersion.compareTo(new ComparableVersion("1.17.0")) < 0) { + logblock.getLogger().info("Updating tables to 1.17.0 ..."); + logblock.getLogger().warning("The updating process might take several minutes if you have a huge log table! Please do not shutdown your server until it is completed."); + try (Connection conn = logblock.getConnection()) { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + for (final WorldConfig wcfg : getLoggedWorlds()) { + st.executeUpdate("ALTER TABLE `" + wcfg.table + "-blocks` CHANGE `y` `y` SMALLINT(5) NOT NULL"); + } + st.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Warning: Could not alter table", ex); + } + logblock.getLogger().info("Update to 1.17.0 completed."); + config.set("version", "1.17.0"); + } + + if (configVersion.compareTo(new ComparableVersion(Config.CURRENT_CONFIG_VERSION)) < 0) { + config.set("version", Config.CURRENT_CONFIG_VERSION); + } + + // this can always be checked + try (Connection conn = logblock.getConnection()) { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + checkCharset("lb-players", "name", st, true); + if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { + checkCharset("lb-chat", "message", st, true); + } + createIndexIfDoesNotExist("lb-materials", "name", "UNIQUE KEY `name` (`name`(150))", st, true); + createIndexIfDoesNotExist("lb-blockstates", "name", "UNIQUE KEY `name` (`name`(150))", st, true); + + st.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + try (Connection conn = logblock.getConnection()) { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + PreparedStatement stSelectColumnType = conn.prepareStatement("SELECT `TABLE_NAME`, `COLUMN_TYPE` FROM information_schema.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `COLUMN_NAME` = ?"); + stSelectColumnType.setString(1, Config.mysqlDatabase); + stSelectColumnType.setString(2, "y"); + HashMap tablesAndYColumnType = new HashMap<>(); + try (ResultSet rs = stSelectColumnType.executeQuery()) { + while (rs.next()) { + String table = rs.getString("TABLE_NAME").toLowerCase(); + String type = rs.getString("COLUMN_TYPE").toLowerCase(); + tablesAndYColumnType.put(table, type); + } + } + for (final WorldConfig wcfg : getLoggedWorlds()) { + String type = tablesAndYColumnType.get((wcfg.table + "-blocks").toLowerCase()); + if (type != null) { + if (type.contains("tinyint") || type.contains("unsigned")) { + logblock.getLogger().info("Fixing y column type for table " + wcfg.table + "-blocks ..."); + logblock.getLogger().warning("The updating process might take several minutes if you have a huge log table! Please do not shutdown your server until it is completed."); + st.executeUpdate("ALTER TABLE `" + wcfg.table + "-blocks` CHANGE `y` `y` SMALLINT(5) NOT NULL"); + } + } + type = tablesAndYColumnType.get((wcfg.table + "-entities").toLowerCase()); + if (type != null) { + if (type.contains("tinyint") || type.contains("unsigned")) { + logblock.getLogger().info("Fixing y column type for table " + wcfg.table + "-entities ..."); + logblock.getLogger().warning("The updating process might take several minutes if you have a huge log table! Please do not shutdown your server until it is completed."); + st.executeUpdate("ALTER TABLE `" + wcfg.table + "-entities` CHANGE `y` `y` SMALLINT(5) NOT NULL"); + } + } + type = tablesAndYColumnType.get((wcfg.table + "-kills").toLowerCase()); + if (type != null) { + if (type.contains("tinyint") || type.contains("unsigned")) { + logblock.getLogger().info("Fixing y column type for table " + wcfg.table + "-kills ..."); + logblock.getLogger().warning("The updating process might take several minutes if you have a huge log table! Please do not shutdown your server until it is completed."); + st.executeUpdate("ALTER TABLE `" + wcfg.table + "-kills` CHANGE `y` `y` SMALLINT(5) NOT NULL"); + } + } + } + st.close(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + + updateMaterialsPost1_13(); + + logblock.saveConfig(); + return true; + } + + void createIndexIfDoesNotExist(String table, String indexName, String definition, Statement st, boolean silent) throws SQLException { + final ResultSet rs = st.executeQuery("SHOW INDEX FROM `" + table + "` WHERE Key_name = '" + indexName + "'"); + if (!rs.next()) { + st.execute("ALTER TABLE `" + table + "` ADD " + definition); + logblock.getLogger().info("Add index " + indexName + " to table " + table + ": Table modified"); + } else if (!silent) { + logblock.getLogger().info("Add index " + indexName + " to table " + table + ": Already fine, skipping it"); + } + rs.close(); + } + + void checkCharset(String table, String column, Statement st, boolean silent) throws SQLException { + final ResultSet rs = st.executeQuery("SHOW FULL COLUMNS FROM `" + table + "` WHERE field = '" + column + "'"); + String charset = "utf8"; + if (Config.mb4) { + charset = "utf8mb4"; + } + if (rs.next() && !rs.getString("Collation").substring(0, charset.length()).equalsIgnoreCase(charset)) { + st.execute("ALTER TABLE `" + table + "` CONVERT TO CHARSET " + charset); + logblock.getLogger().info("Table " + table + " modified"); + } else if (!silent) { + logblock.getLogger().info("Table " + table + " already fine, skipping it"); + } + rs.close(); + } + + void checkTables() throws SQLException { + String charset = "utf8"; + if (Config.mb4) { + charset = "utf8mb4"; + } + final Connection conn = logblock.getConnection(); + if (conn == null) { + throw new SQLException("No connection"); + } + 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); + // 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;"); + if (!rs.next()) { + state.execute("INSERT IGNORE INTO `lb-players` (UUID,playername) VALUES ('log_dummy_record','dummy_record')"); + } + 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); + } 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-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))"); + 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 + "-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"); + } + } + } + } + } + + /** + * Update materials that were renamed + */ + private void updateMaterialsPost1_13() { + final ConfigurationSection config = logblock.getConfig(); + String previousMinecraftVersion = config.getString("previousMinecraftVersion"); + if (previousMinecraftVersion == null) { + previousMinecraftVersion = "1.13"; + } + ComparableVersion comparablePreviousMinecraftVersion = new ComparableVersion(previousMinecraftVersion); + String currentMinecraftVersion = logblock.getServer().getVersion(); + currentMinecraftVersion = currentMinecraftVersion.substring(currentMinecraftVersion.indexOf("(MC: ") + 5); + int currentVersionEnd = currentMinecraftVersion.indexOf(" "); + int currentVersionEnd2 = currentMinecraftVersion.indexOf(")"); + if (currentVersionEnd2 >= 0 && (currentVersionEnd < 0 || currentVersionEnd2 < currentVersionEnd)) { + currentVersionEnd = currentVersionEnd2; + } + currentMinecraftVersion = currentMinecraftVersion.substring(0, currentVersionEnd); + logblock.getLogger().info("[Updater] Current Minecraft Version: '" + currentMinecraftVersion + "'"); + ComparableVersion comparableCurrentMinecraftVersion = new ComparableVersion(currentMinecraftVersion); + + if (comparablePreviousMinecraftVersion.compareTo("1.14") < 0 && comparableCurrentMinecraftVersion.compareTo("1.14") >= 0) { + logblock.getLogger().info("[Updater] Upgrading Materials to 1.14"); + renameMaterial("minecraft:sign", Material.OAK_SIGN); + renameMaterial("minecraft:wall_sign", Material.OAK_WALL_SIGN); + renameMaterial("minecraft:stone_slab", Material.SMOOTH_STONE_SLAB); + renameMaterial("minecraft:rose_red", Material.RED_DYE); + renameMaterial("minecraft:dandelion_yellow", Material.YELLOW_DYE); + renameMaterial("minecraft:cactus_green", Material.GREEN_DYE); + } + + if (comparablePreviousMinecraftVersion.compareTo("1.17") < 0 && comparableCurrentMinecraftVersion.compareTo("1.17") >= 0) { + logblock.getLogger().info("[Updater] Upgrading Materials to 1.17"); + renameMaterial("minecraft:grass_path", Material.DIRT_PATH); + } + + config.set("previousMinecraftVersion", currentMinecraftVersion); + logblock.saveConfig(); + } + + private void renameMaterial(String oldName, Material newName) { + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(false); + PreparedStatement stSelectMaterial = conn.prepareStatement("SELECT id FROM `lb-materials` WHERE name = ?"); + stSelectMaterial.setString(1, oldName); + ResultSet rs = stSelectMaterial.executeQuery(); + if (rs.next()) { + logblock.getLogger().info("[Updater] Updating " + oldName + " to " + newName); + int oldId = rs.getInt(1); + int newId = MaterialConverter.getOrAddMaterialId(newName); + + Statement st = conn.createStatement(); + int rows = 0; + for (final WorldConfig wcfg : getLoggedWorlds()) { + rows += st.executeUpdate("UPDATE `" + wcfg.table + "-blocks` SET replaced = " + newId + " WHERE replaced = " + oldId); + rows += st.executeUpdate("UPDATE `" + wcfg.table + "-blocks` SET type = " + newId + " WHERE type = " + oldId); + rows += st.executeUpdate("UPDATE `" + wcfg.table + "-chestdata` SET itemtype = " + newId + " WHERE itemtype = " + oldId); + if (wcfg.isLogging(Logging.KILL)) { + rows += st.executeUpdate("UPDATE `" + wcfg.table + "-kills` SET weapon = " + newId + " WHERE weapon = " + oldId); + } + } + st.close(); + if (rows > 0) { + logblock.getLogger().info("[Updater] Successfully updated " + rows + " entries.."); + } + } + stSelectMaterial.close(); + conn.commit(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: " + ex.getMessage(), ex); + } + } + + public static class PlayerCountChecker implements Runnable { + + private LogBlock logblock; + + public PlayerCountChecker(LogBlock logblock) { + this.logblock = logblock; + } + + @Override + public void run() { + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + ResultSet rs = st.executeQuery("SELECT auto_increment FROM information_schema.columns AS col join information_schema.tables AS tab ON (col.table_schema=tab.table_schema AND col.table_name=tab.table_name) WHERE col.table_name = 'lb-players' AND col.column_name = 'playerid' AND col.data_type = 'smallint' AND col.table_schema = DATABASE() AND auto_increment > 65000;"); + if (rs.next()) { + for (int i = 0; i < 6; i++) { + logblock.getLogger().warning("Your server reached 65000 players. You should soon update your database table schema - see FAQ: https://github.com/LogBlock/LogBlock/wiki/FAQ#logblock-your-server-reached-65000-players-"); + } + } + st.close(); + conn.close(); + } catch (final SQLException ex) { + if (logblock.isCompletelyEnabled()) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + } + } + } + } + + public static class MaterialUpdater1_13 { + BlockData[][] blockDataMapping; + Material[][] itemMapping = new Material[10][]; + + public MaterialUpdater1_13(LogBlock plugin) throws IOException { + blockDataMapping = new BlockData[256][16]; + try (JarFile file = new JarFile(plugin.getFile())) { + BufferedReader reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(file.getInputStream(file.getJarEntry("blockdata.txt"))), "UTF-8")); + while (true) { + String line = reader.readLine(); + if (line == null) { + break; + } + int splitter1 = line.indexOf(":"); + int splitter2 = line.indexOf(","); + if (splitter1 >= 0 && splitter2 >= 0) { + int blockid = Integer.parseInt(line.substring(0, splitter1)); + int blockdata = Integer.parseInt(line.substring(splitter1 + 1, splitter2)); + BlockData newBlockData = Bukkit.createBlockData(line.substring(splitter2 + 1)); + + if (blockdata == 0) { + for (int i = 0; i < 16; i++) { + if (blockDataMapping[blockid][i] == null) { + blockDataMapping[blockid][i] = newBlockData; + } + } + } else { + blockDataMapping[blockid][blockdata] = newBlockData; + } + } + } + reader.close(); + + HashMap materialKeysToMaterial = new HashMap<>(); + for (Material material : Material.values()) { + materialKeysToMaterial.put(material.getKey().toString(), material); + } + + reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(file.getInputStream(file.getJarEntry("itemdata.txt"))), "UTF-8")); + while (true) { + String line = reader.readLine(); + if (line == null) { + break; + } + int splitter1 = line.indexOf(":"); + int splitter2 = line.indexOf(","); + if (splitter1 >= 0 && splitter2 >= 0) { + int itemid = Integer.parseInt(line.substring(0, splitter1)); + int itemdata = Integer.parseInt(line.substring(splitter1 + 1, splitter2)); + Material newMaterial = materialKeysToMaterial.get(line.substring(splitter2 + 1)); + if (newMaterial == null) { + throw new IOException("Unknown item: " + line.substring(splitter2 + 1)); + } + if (itemid >= itemMapping.length) { + itemMapping = Arrays.copyOf(itemMapping, Math.max(itemMapping.length * 3 / 2, itemid + 1)); + } + + Material[] itemValues = itemMapping[itemid]; + if (itemValues == null) { + itemValues = new Material[itemdata + 1]; + itemMapping[itemid] = itemValues; + } else if (itemValues.length <= itemdata) { + itemValues = Arrays.copyOf(itemValues, itemdata + 1); + itemMapping[itemid] = itemValues; + } + itemValues[itemdata] = newMaterial; + } + } + reader.close(); + } + } + + public BlockData getBlockData(int id, int data) { + return id >= 0 && id < 256 && data >= 0 && data < 16 ? blockDataMapping[id][data] : null; + } + + public Material getMaterial(int id, int data) { + Material[] materials = id >= 0 && id < itemMapping.length ? itemMapping[id] : null; + if (materials != null && materials.length > 0) { + if (materials[0] != null && materials[0].getMaxDurability() == 0 && data >= 0 && data < materials.length && materials[data] != null) { + return materials[data]; + } + return materials[0]; + } + return null; + } + + public Material getMaterial(String id) { + int item = 0; + int data = 0; + int seperator = id.indexOf(':'); + if (seperator < 0) { + item = Integer.parseInt(id); + } else { + item = Integer.parseInt(id.substring(0, seperator)); + data = Integer.parseInt(id.substring(seperator + 1)); + } + return getMaterial(item, data); + } + + public String convertMaterial(String oldEntry) { + if (oldEntry == null) { + return null; + } + try { + Material newMaterial = getMaterial(oldEntry); + if (newMaterial != null) { + return newMaterial.name(); + } + } catch (Exception e) { + Material newMaterial = Material.matchMaterial(oldEntry, true); + if (newMaterial != null) { + return newMaterial.name(); + } else { + newMaterial = Material.matchMaterial(oldEntry); + if (newMaterial != null) { + return newMaterial.name(); + } + } + } + return null; + } + + public List convertMaterials(Collection oldEntries) { + Set newEntries = new LinkedHashSet<>(); + for (String oldEntry : oldEntries) { + String newEntry = convertMaterial(oldEntry); + if (newEntry != null) { + newEntries.add(newEntry); + if (newEntry.equals(Material.AIR.name())) { + newEntries.add(Material.CAVE_AIR.name()); + newEntries.add(Material.VOID_AIR.name()); + } + } + } + return new ArrayList<>(newEntries); + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index 1a9e04e5..06a6e90b 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -1,171 +1,171 @@ -package de.diddiz.LogBlock.config; - -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import de.diddiz.LogBlock.util.BukkitUtils; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Animals; -import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Monster; -import org.bukkit.entity.Player; -import org.bukkit.entity.WaterMob; - -import java.io.File; -import java.io.IOException; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.logging.Level; - -public class WorldConfig extends LoggingEnabledMapping { - public final String world; - public final String table; - public final String insertBlockStatementString; - public final String selectBlockActorIdStatementString; - public final String insertBlockStateStatementString; - public final String insertBlockChestDataStatementString; - public final String insertEntityStatementString; - public final String updateEntityUUIDString; - - private final EnumMap entityLogging = new EnumMap<>(EntityLogging.class); - public final boolean logNaturalEntitySpawns; - public final boolean logAllNamedEntityKills; - - public WorldConfig(String world, File file) throws IOException { - this.world = world; - final Map def = new HashMap<>(); - // "Before MySQL 5.1.6, database and table names cannot contain "/", "\", ".", or characters that are not permitted in file names" - MySQL manual - // They _can_ contain spaces, but replace them as well - def.put("table", "lb-" + file.getName().substring(0, file.getName().length() - 4).replaceAll("[ ./\\\\]", "_")); - for (final Logging l : Logging.values()) { - def.put("logging." + l.toString(), l.isDefaultEnabled()); - } - final YamlConfiguration config = YamlConfiguration.loadConfiguration(file); - for (final Entry e : def.entrySet()) { - if (config.get(e.getKey()) == null) { - config.set(e.getKey(), e.getValue()); - } - } - for (EntityLogging el : EntityLogging.values()) { - if (!(config.get("entity." + el.name().toLowerCase()) instanceof List)) { - config.set("entity." + el.name().toLowerCase(), el.getDefaultEnabled()); - } - entityLogging.put(el, new EntityLoggingList(el, config.getStringList("entity." + el.name().toLowerCase()))); - } - if (!config.isBoolean("entity.logNaturalSpawns")) { - config.set("entity.logNaturalSpawns", false); - } - logNaturalEntitySpawns = config.getBoolean("entity.logNaturalSpawns"); - - if (!config.isBoolean("entity.logAllNamedEntityKills")) { - config.set("entity.logAllNamedEntityKills", true); - } - logAllNamedEntityKills = config.getBoolean("entity.logAllNamedEntityKills"); - - config.save(file); - table = config.getString("table"); - for (final Logging l : Logging.values()) { - setLogging(l, config.getBoolean("logging." + l.toString())); - } - - insertBlockStatementString = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"; - selectBlockActorIdStatementString = "SELECT playerid FROM `" + table + "-blocks` WHERE x = ? AND y = ? AND z = ? ORDER BY date DESC LIMIT 1"; - insertBlockStateStatementString = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(?, ?, ?)"; - insertBlockChestDataStatementString = "INSERT INTO `" + table + "-chestdata` (item, itemremove, id, itemtype) values (?, ?, ?, ?)"; - insertEntityStatementString = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"; - updateEntityUUIDString = "UPDATE `" + table + "-entityids` SET entityuuid = ? WHERE entityid = ?"; - } - - public boolean isLogging(EntityLogging logging, Entity entity) { - return entityLogging.get(logging).isLogging(entity); - } - - public boolean isLoggingAnyEntities() { - for (EntityLoggingList list : entityLogging.values()) { - if (list.isLoggingAnyEntities()) { - return true; - } - } - return false; - } - - private class EntityLoggingList { - private final EntityLogging entityAction; - private final HashSet logged = new HashSet<>(); - private final boolean logAll; - private final boolean logAnimals; - private final boolean logWateranimals; - private final boolean logMonsters; - private final boolean logLiving; - - public EntityLoggingList(EntityLogging entityAction, List types) { - this.entityAction = entityAction; - boolean all = false; - boolean animals = false; - boolean wateranimals = false; - boolean monsters = false; - boolean living = false; - for (String type : types) { - EntityType et = BukkitUtils.matchEntityType(type); - if (et != null) { - logged.add(et); - } else { - if (type.equalsIgnoreCase("all")) { - all = true; - } else if (type.equalsIgnoreCase("animal") || type.equalsIgnoreCase("animals")) { - animals = true; - } else if (type.equalsIgnoreCase("wateranimal") || type.equalsIgnoreCase("wateranimals")) { - wateranimals = true; - } else if (type.equalsIgnoreCase("monster") || type.equalsIgnoreCase("monsters")) { - monsters = true; - } else if (type.equalsIgnoreCase("living")) { - living = true; - } else { - LogBlock.getInstance().getLogger().log(Level.WARNING, "Unkown entity type in config for " + world + ": " + type); - } - } - } - logAll = all; - logAnimals = animals; - logWateranimals = wateranimals; - logMonsters = monsters; - logLiving = living; - } - - public boolean isLogging(Entity entity) { - if (entity == null || (entity instanceof Player)) { - return false; - } - EntityType type = entity.getType(); - if (logAll || logged.contains(type)) { - return true; - } - if (logLiving && LivingEntity.class.isAssignableFrom(entity.getClass()) && !(entity instanceof ArmorStand)) { - return true; - } - if (logAnimals && Animals.class.isAssignableFrom(entity.getClass())) { - return true; - } - if (logWateranimals && WaterMob.class.isAssignableFrom(entity.getClass())) { - return true; - } - if (logMonsters && (Monster.class.isAssignableFrom(entity.getClass()) || entity.getType() == EntityType.SLIME || entity.getType() == EntityType.WITHER || entity.getType() == EntityType.ENDER_DRAGON || entity.getType() == EntityType.SHULKER || entity.getType() == EntityType.GHAST)) { - return true; - } - if (entityAction == EntityLogging.DESTROY && logAllNamedEntityKills && entity.getCustomName() != null) { - return true; - } - return false; - } - - public boolean isLoggingAnyEntities() { - return logAll || logAnimals || logLiving || logMonsters || !logged.isEmpty() || (entityAction == EntityLogging.DESTROY && logAllNamedEntityKills); - } - } -} +package de.diddiz.LogBlock.config; + +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.util.BukkitUtils; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Animals; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Player; +import org.bukkit.entity.WaterMob; + +import java.io.File; +import java.io.IOException; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; + +public class WorldConfig extends LoggingEnabledMapping { + public final String world; + public final String table; + public final String insertBlockStatementString; + public final String selectBlockActorIdStatementString; + public final String insertBlockStateStatementString; + public final String insertBlockChestDataStatementString; + public final String insertEntityStatementString; + public final String updateEntityUUIDString; + + private final EnumMap entityLogging = new EnumMap<>(EntityLogging.class); + public final boolean logNaturalEntitySpawns; + public final boolean logAllNamedEntityKills; + + public WorldConfig(String world, File file) throws IOException { + this.world = world; + final Map def = new HashMap<>(); + // "Before MySQL 5.1.6, database and table names cannot contain "/", "\", ".", or characters that are not permitted in file names" - MySQL manual + // They _can_ contain spaces, but replace them as well + def.put("table", "lb-" + file.getName().substring(0, file.getName().length() - 4).replaceAll("[ ./\\\\]", "_")); + for (final Logging l : Logging.values()) { + def.put("logging." + l.toString(), l.isDefaultEnabled()); + } + final YamlConfiguration config = YamlConfiguration.loadConfiguration(file); + for (final Entry e : def.entrySet()) { + if (config.get(e.getKey()) == null) { + config.set(e.getKey(), e.getValue()); + } + } + for (EntityLogging el : EntityLogging.values()) { + if (!(config.get("entity." + el.name().toLowerCase()) instanceof List)) { + config.set("entity." + el.name().toLowerCase(), el.getDefaultEnabled()); + } + entityLogging.put(el, new EntityLoggingList(el, config.getStringList("entity." + el.name().toLowerCase()))); + } + if (!config.isBoolean("entity.logNaturalSpawns")) { + config.set("entity.logNaturalSpawns", false); + } + logNaturalEntitySpawns = config.getBoolean("entity.logNaturalSpawns"); + + if (!config.isBoolean("entity.logAllNamedEntityKills")) { + config.set("entity.logAllNamedEntityKills", true); + } + logAllNamedEntityKills = config.getBoolean("entity.logAllNamedEntityKills"); + + config.save(file); + table = config.getString("table"); + for (final Logging l : Logging.values()) { + setLogging(l, config.getBoolean("logging." + l.toString())); + } + + insertBlockStatementString = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"; + selectBlockActorIdStatementString = "SELECT playerid FROM `" + table + "-blocks` WHERE x = ? AND y = ? AND z = ? ORDER BY date DESC LIMIT 1"; + insertBlockStateStatementString = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(?, ?, ?)"; + insertBlockChestDataStatementString = "INSERT INTO `" + table + "-chestdata` (item, itemremove, id, itemtype) values (?, ?, ?, ?)"; + insertEntityStatementString = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"; + updateEntityUUIDString = "UPDATE `" + table + "-entityids` SET entityuuid = ? WHERE entityid = ?"; + } + + public boolean isLogging(EntityLogging logging, Entity entity) { + return entityLogging.get(logging).isLogging(entity); + } + + public boolean isLoggingAnyEntities() { + for (EntityLoggingList list : entityLogging.values()) { + if (list.isLoggingAnyEntities()) { + return true; + } + } + return false; + } + + private class EntityLoggingList { + private final EntityLogging entityAction; + private final HashSet logged = new HashSet<>(); + private final boolean logAll; + private final boolean logAnimals; + private final boolean logWateranimals; + private final boolean logMonsters; + private final boolean logLiving; + + public EntityLoggingList(EntityLogging entityAction, List types) { + this.entityAction = entityAction; + boolean all = false; + boolean animals = false; + boolean wateranimals = false; + boolean monsters = false; + boolean living = false; + for (String type : types) { + EntityType et = BukkitUtils.matchEntityType(type); + if (et != null) { + logged.add(et); + } else { + if (type.equalsIgnoreCase("all")) { + all = true; + } else if (type.equalsIgnoreCase("animal") || type.equalsIgnoreCase("animals")) { + animals = true; + } else if (type.equalsIgnoreCase("wateranimal") || type.equalsIgnoreCase("wateranimals")) { + wateranimals = true; + } else if (type.equalsIgnoreCase("monster") || type.equalsIgnoreCase("monsters")) { + monsters = true; + } else if (type.equalsIgnoreCase("living")) { + living = true; + } else { + LogBlock.getInstance().getLogger().log(Level.WARNING, "Unkown entity type in config for " + world + ": " + type); + } + } + } + logAll = all; + logAnimals = animals; + logWateranimals = wateranimals; + logMonsters = monsters; + logLiving = living; + } + + public boolean isLogging(Entity entity) { + if (entity == null || (entity instanceof Player)) { + return false; + } + EntityType type = entity.getType(); + if (logAll || logged.contains(type)) { + return true; + } + if (logLiving && LivingEntity.class.isAssignableFrom(entity.getClass()) && !(entity instanceof ArmorStand)) { + return true; + } + if (logAnimals && Animals.class.isAssignableFrom(entity.getClass())) { + return true; + } + if (logWateranimals && WaterMob.class.isAssignableFrom(entity.getClass())) { + return true; + } + if (logMonsters && (Monster.class.isAssignableFrom(entity.getClass()) || entity.getType() == EntityType.SLIME || entity.getType() == EntityType.WITHER || entity.getType() == EntityType.ENDER_DRAGON || entity.getType() == EntityType.SHULKER || entity.getType() == EntityType.GHAST)) { + return true; + } + if (entityAction == EntityLogging.DESTROY && logAllNamedEntityKills && entity.getCustomName() != null) { + return true; + } + return false; + } + + public boolean isLoggingAnyEntities() { + return logAll || logAnimals || logLiving || logMonsters || !logged.isEmpty() || (entityAction == EntityLogging.DESTROY && logAllNamedEntityKills); + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BanListener.java b/src/main/java/de/diddiz/LogBlock/listeners/BanListener.java index 9f50afb2..63ab4acd 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BanListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BanListener.java @@ -1,48 +1,48 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.CommandsHandler; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.QueryParams; -import org.bukkit.World; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; - -import static de.diddiz.LogBlock.config.Config.banPermission; -import static de.diddiz.LogBlock.config.Config.isLogged; -import static org.bukkit.Bukkit.getScheduler; - -public class BanListener implements Listener { - private final CommandsHandler handler; - private final LogBlock logblock; - - public BanListener(LogBlock logblock) { - this.logblock = logblock; - handler = logblock.getCommandsHandler(); - } - - @EventHandler - public void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event) { - final String[] split = event.getMessage().split(" "); - if (split.length > 1 && split[0].equalsIgnoreCase("/ban") && logblock.hasPermission(event.getPlayer(), banPermission)) { - final QueryParams p = new QueryParams(logblock); - p.setPlayer(split[1].equalsIgnoreCase("g") ? split[2] : split[1]); - p.since = 0; - p.silent = false; - getScheduler().runTaskAsynchronously(logblock, new Runnable() { - @Override - public void run() { - for (final World world : logblock.getServer().getWorlds()) { - if (isLogged(world)) { - p.world = world; - try { - handler.new CommandRollback(event.getPlayer(), p, false); - } catch (final Exception ex) { - } - } - } - } - }); - } - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.CommandsHandler; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.QueryParams; +import org.bukkit.World; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; + +import static de.diddiz.LogBlock.config.Config.banPermission; +import static de.diddiz.LogBlock.config.Config.isLogged; +import static org.bukkit.Bukkit.getScheduler; + +public class BanListener implements Listener { + private final CommandsHandler handler; + private final LogBlock logblock; + + public BanListener(LogBlock logblock) { + this.logblock = logblock; + handler = logblock.getCommandsHandler(); + } + + @EventHandler + public void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event) { + final String[] split = event.getMessage().split(" "); + if (split.length > 1 && split[0].equalsIgnoreCase("/ban") && logblock.hasPermission(event.getPlayer(), banPermission)) { + final QueryParams p = new QueryParams(logblock); + p.setPlayer(split[1].equalsIgnoreCase("g") ? split[2] : split[1]); + p.since = 0; + p.silent = false; + getScheduler().runTaskAsynchronously(logblock, new Runnable() { + @Override + public void run() { + for (final World world : logblock.getServer().getWorlds()) { + if (isLogged(world)) { + p.world = world; + try { + handler.new CommandRollback(event.getPlayer(), p, false); + } catch (final Exception ex) { + } + } + } + } + }); + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java index c5614560..12c0b2b6 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java @@ -1,74 +1,74 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.Actor; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.LogBlock.util.BukkitUtils; -import org.bukkit.Bukkit; -import org.bukkit.GameMode; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.player.PlayerBucketFillEvent; - -import static de.diddiz.LogBlock.config.Config.getWorldConfig; -import static de.diddiz.LogBlock.config.Config.isLogging; -import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockBreak; -import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockReplace; -import static de.diddiz.LogBlock.util.LoggingUtil.smartLogFallables; - -public class BlockBreakLogging extends LoggingListener { - public BlockBreakLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockBreak(BlockBreakEvent event) { - if (isLogging(event.getBlock().getWorld(), Logging.BLOCKBREAK)) { - WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld()); - if (wcfg == null) { - return; - } - - final Actor actor = Actor.actorFromEntity(event.getPlayer()); - final Block origin = event.getBlock(); - final Material type = origin.getType(); - - if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) { - consumer.queueContainerBreak(actor, origin.getState()); - } else if (type == Material.ICE) { - // When in creative mode ice doesn't form water - if (event.getPlayer().getGameMode().equals(GameMode.CREATIVE)) { - smartLogBlockBreak(consumer, actor, origin); - } else { - smartLogBlockReplace(consumer, actor, origin, Bukkit.createBlockData(Material.WATER)); - } - } else { - smartLogBlockBreak(consumer, actor, origin); - } - smartLogFallables(consumer, actor, origin); - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onPlayerBucketFill(PlayerBucketFillEvent event) { - if (isLogging(event.getBlockClicked().getWorld(), Logging.BLOCKBREAK)) { - BlockData clickedBlockData = event.getBlockClicked().getBlockData(); - if (clickedBlockData instanceof Waterlogged) { - Waterlogged clickedWaterlogged = (Waterlogged) clickedBlockData; - if (clickedWaterlogged.isWaterlogged()) { - Waterlogged clickedWaterloggedWithoutWater = (Waterlogged) clickedWaterlogged.clone(); - clickedWaterloggedWithoutWater.setWaterlogged(false); - consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), clickedWaterlogged, clickedWaterloggedWithoutWater); - } - } else { - consumer.queueBlockBreak(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getState()); - } - } - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.WorldConfig; +import de.diddiz.LogBlock.util.BukkitUtils; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.player.PlayerBucketFillEvent; + +import static de.diddiz.LogBlock.config.Config.getWorldConfig; +import static de.diddiz.LogBlock.config.Config.isLogging; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockBreak; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockReplace; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogFallables; + +public class BlockBreakLogging extends LoggingListener { + public BlockBreakLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockBreak(BlockBreakEvent event) { + if (isLogging(event.getBlock().getWorld(), Logging.BLOCKBREAK)) { + WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld()); + if (wcfg == null) { + return; + } + + final Actor actor = Actor.actorFromEntity(event.getPlayer()); + final Block origin = event.getBlock(); + final Material type = origin.getType(); + + if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) { + consumer.queueContainerBreak(actor, origin.getState()); + } else if (type == Material.ICE) { + // When in creative mode ice doesn't form water + if (event.getPlayer().getGameMode().equals(GameMode.CREATIVE)) { + smartLogBlockBreak(consumer, actor, origin); + } else { + smartLogBlockReplace(consumer, actor, origin, Bukkit.createBlockData(Material.WATER)); + } + } else { + smartLogBlockBreak(consumer, actor, origin); + } + smartLogFallables(consumer, actor, origin); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerBucketFill(PlayerBucketFillEvent event) { + if (isLogging(event.getBlockClicked().getWorld(), Logging.BLOCKBREAK)) { + BlockData clickedBlockData = event.getBlockClicked().getBlockData(); + if (clickedBlockData instanceof Waterlogged) { + Waterlogged clickedWaterlogged = (Waterlogged) clickedBlockData; + if (clickedWaterlogged.isWaterlogged()) { + Waterlogged clickedWaterloggedWithoutWater = (Waterlogged) clickedWaterlogged.clone(); + clickedWaterloggedWithoutWater.setWaterlogged(false); + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), clickedWaterlogged, clickedWaterloggedWithoutWater); + } + } else { + consumer.queueBlockBreak(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getState()); + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java index 5ba55c63..1ee7ed1f 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java @@ -1,72 +1,72 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.Actor; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import de.diddiz.LogBlock.config.Config; - -import org.bukkit.Material; -import org.bukkit.block.Block; -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.block.BlockBurnEvent; -import org.bukkit.event.block.BlockIgniteEvent; -import org.bukkit.event.block.BlockIgniteEvent.IgniteCause; -import org.bukkit.event.player.PlayerInteractEvent; - -import static de.diddiz.LogBlock.config.Config.isLogging; -import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockBreak; -import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockReplace; -import static de.diddiz.LogBlock.util.LoggingUtil.smartLogFallables; - -public class BlockBurnLogging extends LoggingListener { - public BlockBurnLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockBurn(BlockBurnEvent event) { - if (isLogging(event.getBlock().getWorld(), Logging.FIRE)) { - smartLogBlockReplace(consumer, new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null), event.getBlock(), Material.FIRE.createBlockData()); - smartLogFallables(consumer, new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null), event.getBlock()); - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockIgnite(BlockIgniteEvent event) { - Actor actor = new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null); - if (event.getCause() == IgniteCause.FLINT_AND_STEEL) { - if (event.getIgnitingEntity() != null) { - return; // handled in block place - } else { - actor = new Actor("Dispenser"); - } - } else if (event.getCause() == IgniteCause.LIGHTNING) { - actor = new Actor("Lightning"); - } else if (event.getCause() == IgniteCause.EXPLOSION) { - actor = new Actor("Explosion"); - } else if (event.getCause() == IgniteCause.LAVA) { - actor = new Actor("Lava"); - } else if (event.getCause() == IgniteCause.ENDER_CRYSTAL) { - actor = new Actor("EnderCrystal"); - } - if (isLogging(event.getBlock().getWorld(), Logging.FIRE)) { - consumer.queueBlockPlace(actor, event.getBlock().getLocation(), Material.FIRE.createBlockData()); - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onExtinguish(PlayerInteractEvent event) { - if (event.getAction().equals(Action.LEFT_CLICK_BLOCK)) { - Player player = event.getPlayer(); - Block block = event.getClickedBlock().getRelative(event.getBlockFace()); - if (block.getType().equals(Material.FIRE) && isLogging(player.getWorld(), Logging.FIRE)) { - Actor actor = Actor.actorFromEntity(player); - smartLogBlockBreak(consumer, actor, block); - smartLogFallables(consumer, actor, block); - } - } - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.Config; + +import org.bukkit.Material; +import org.bukkit.block.Block; +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.block.BlockBurnEvent; +import org.bukkit.event.block.BlockIgniteEvent; +import org.bukkit.event.block.BlockIgniteEvent.IgniteCause; +import org.bukkit.event.player.PlayerInteractEvent; + +import static de.diddiz.LogBlock.config.Config.isLogging; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockBreak; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockReplace; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogFallables; + +public class BlockBurnLogging extends LoggingListener { + public BlockBurnLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockBurn(BlockBurnEvent event) { + if (isLogging(event.getBlock().getWorld(), Logging.FIRE)) { + smartLogBlockReplace(consumer, new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null), event.getBlock(), Material.FIRE.createBlockData()); + smartLogFallables(consumer, new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null), event.getBlock()); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockIgnite(BlockIgniteEvent event) { + Actor actor = new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null); + if (event.getCause() == IgniteCause.FLINT_AND_STEEL) { + if (event.getIgnitingEntity() != null) { + return; // handled in block place + } else { + actor = new Actor("Dispenser"); + } + } else if (event.getCause() == IgniteCause.LIGHTNING) { + actor = new Actor("Lightning"); + } else if (event.getCause() == IgniteCause.EXPLOSION) { + actor = new Actor("Explosion"); + } else if (event.getCause() == IgniteCause.LAVA) { + actor = new Actor("Lava"); + } else if (event.getCause() == IgniteCause.ENDER_CRYSTAL) { + actor = new Actor("EnderCrystal"); + } + if (isLogging(event.getBlock().getWorld(), Logging.FIRE)) { + consumer.queueBlockPlace(actor, event.getBlock().getLocation(), Material.FIRE.createBlockData()); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onExtinguish(PlayerInteractEvent event) { + if (event.getAction().equals(Action.LEFT_CLICK_BLOCK)) { + Player player = event.getPlayer(); + Block block = event.getClickedBlock().getRelative(event.getBlockFace()); + if (block.getType().equals(Material.FIRE) && isLogging(player.getWorld(), Logging.FIRE)) { + Actor actor = Actor.actorFromEntity(player); + smartLogBlockBreak(consumer, actor, block); + smartLogFallables(consumer, actor, block); + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java index b24cfcf8..e6f72610 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java @@ -1,67 +1,67 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.Actor; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import de.diddiz.LogBlock.config.Config; -import de.diddiz.LogBlock.util.LoggingUtil; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.player.PlayerBucketEmptyEvent; - -import static de.diddiz.LogBlock.config.Config.isLogging; - -public class BlockPlaceLogging extends LoggingListener { - public BlockPlaceLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockPlace(BlockPlaceEvent event) { - if (Config.isLogging(event.getBlock().getWorld(), Logging.BLOCKPLACE)) { - final BlockState before = event.getBlockReplacedState(); - final BlockState after = event.getBlockPlaced().getState(); - final Actor actor = Actor.actorFromEntity(event.getPlayer()); - if (before.getType() == Material.LECTERN && after.getType() == Material.LECTERN) { - return; - } - LoggingUtil.smartLogBlockPlace(consumer, actor, before, after); - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) { - if (isLogging(event.getPlayer().getWorld(), Logging.BLOCKPLACE)) { - Material placedMaterial = event.getBucket() == Material.LAVA_BUCKET ? Material.LAVA : Material.WATER; - BlockData clickedBlockData = event.getBlockClicked().getBlockData(); - if (placedMaterial == Material.WATER && clickedBlockData instanceof Waterlogged) { - Waterlogged clickedWaterlogged = (Waterlogged) clickedBlockData; - if (!clickedWaterlogged.isWaterlogged()) { - Waterlogged clickedWaterloggedWithWater = (Waterlogged) clickedWaterlogged.clone(); - clickedWaterloggedWithWater.setWaterlogged(true); - consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), clickedWaterlogged, clickedWaterloggedWithWater); - return; - } - } - Block placedAt = event.getBlockClicked().getRelative(event.getBlockFace()); - if (placedAt.isEmpty()) { - consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedMaterial.createBlockData()); - } else { - BlockData placedAtBlock = placedAt.getBlockData(); - if (placedAtBlock instanceof Waterlogged && !(((Waterlogged) placedAtBlock).isWaterlogged())) { - Waterlogged clickedWaterloggedWithWater = (Waterlogged) placedAtBlock.clone(); - clickedWaterloggedWithWater.setWaterlogged(true); - consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedAtBlock, clickedWaterloggedWithWater); - } else { - consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedAtBlock, placedMaterial.createBlockData()); - } - } - } - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.Config; +import de.diddiz.LogBlock.util.LoggingUtil; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.player.PlayerBucketEmptyEvent; + +import static de.diddiz.LogBlock.config.Config.isLogging; + +public class BlockPlaceLogging extends LoggingListener { + public BlockPlaceLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent event) { + if (Config.isLogging(event.getBlock().getWorld(), Logging.BLOCKPLACE)) { + final BlockState before = event.getBlockReplacedState(); + final BlockState after = event.getBlockPlaced().getState(); + final Actor actor = Actor.actorFromEntity(event.getPlayer()); + if (before.getType() == Material.LECTERN && after.getType() == Material.LECTERN) { + return; + } + LoggingUtil.smartLogBlockPlace(consumer, actor, before, after); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) { + if (isLogging(event.getPlayer().getWorld(), Logging.BLOCKPLACE)) { + Material placedMaterial = event.getBucket() == Material.LAVA_BUCKET ? Material.LAVA : Material.WATER; + BlockData clickedBlockData = event.getBlockClicked().getBlockData(); + if (placedMaterial == Material.WATER && clickedBlockData instanceof Waterlogged) { + Waterlogged clickedWaterlogged = (Waterlogged) clickedBlockData; + if (!clickedWaterlogged.isWaterlogged()) { + Waterlogged clickedWaterloggedWithWater = (Waterlogged) clickedWaterlogged.clone(); + clickedWaterloggedWithWater.setWaterlogged(true); + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getLocation(), clickedWaterlogged, clickedWaterloggedWithWater); + return; + } + } + Block placedAt = event.getBlockClicked().getRelative(event.getBlockFace()); + if (placedAt.isEmpty()) { + consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedMaterial.createBlockData()); + } else { + BlockData placedAtBlock = placedAt.getBlockData(); + if (placedAtBlock instanceof Waterlogged && !(((Waterlogged) placedAtBlock).isWaterlogged())) { + Waterlogged clickedWaterloggedWithWater = (Waterlogged) placedAtBlock.clone(); + clickedWaterloggedWithWater.setWaterlogged(true); + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedAtBlock, clickedWaterloggedWithWater); + } else { + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), placedAt.getLocation(), placedAtBlock, placedMaterial.createBlockData()); + } + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChatLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChatLogging.java index baafe636..11b1a75c 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChatLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChatLogging.java @@ -1,58 +1,58 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.Actor; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import org.bukkit.command.BlockCommandSender; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.minecart.CommandMinecart; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.server.ServerCommandEvent; - -import static de.diddiz.LogBlock.config.Config.isLogging; - -public class ChatLogging extends LoggingListener { - public ChatLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { - if (isLogging(event.getPlayer().getWorld(), Logging.PLAYER_COMMANDS)) { - consumer.queueChat(Actor.actorFromEntity(event.getPlayer()), event.getMessage()); - } - } - - @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerChat(AsyncPlayerChatEvent event) { - if (isLogging(event.getPlayer().getWorld(), Logging.CHAT)) { - consumer.queueChat(Actor.actorFromEntity(event.getPlayer()), event.getMessage()); - } - } - - @EventHandler(priority = EventPriority.MONITOR) - public void onServerCommand(ServerCommandEvent event) { - CommandSender sender = event.getSender(); - Actor actor; - if (sender instanceof BlockCommandSender) { - if (!isLogging(((BlockCommandSender) sender).getBlock().getWorld(), Logging.COMMANDBLOCK_COMMANDS)) { - return; - } - actor = new Actor("CommandBlock"); - } else if (sender instanceof CommandMinecart) { - if (!isLogging(((CommandMinecart) sender).getWorld(), Logging.COMMANDBLOCK_COMMANDS)) { - return; - } - actor = new Actor("CommandMinecart"); - } else { - if (!isLogging(Logging.CONSOLE_COMMANDS)) { - return; - } - actor = new Actor("Console"); - } - consumer.queueChat(actor, "/" + event.getCommand()); - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import org.bukkit.command.BlockCommandSender; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.minecart.CommandMinecart; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.server.ServerCommandEvent; + +import static de.diddiz.LogBlock.config.Config.isLogging; + +public class ChatLogging extends LoggingListener { + public ChatLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { + if (isLogging(event.getPlayer().getWorld(), Logging.PLAYER_COMMANDS)) { + consumer.queueChat(Actor.actorFromEntity(event.getPlayer()), event.getMessage()); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerChat(AsyncPlayerChatEvent event) { + if (isLogging(event.getPlayer().getWorld(), Logging.CHAT)) { + consumer.queueChat(Actor.actorFromEntity(event.getPlayer()), event.getMessage()); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onServerCommand(ServerCommandEvent event) { + CommandSender sender = event.getSender(); + Actor actor; + if (sender instanceof BlockCommandSender) { + if (!isLogging(((BlockCommandSender) sender).getBlock().getWorld(), Logging.COMMANDBLOCK_COMMANDS)) { + return; + } + actor = new Actor("CommandBlock"); + } else if (sender instanceof CommandMinecart) { + if (!isLogging(((CommandMinecart) sender).getWorld(), Logging.COMMANDBLOCK_COMMANDS)) { + return; + } + actor = new Actor("CommandMinecart"); + } else { + if (!isLogging(Logging.CONSOLE_COMMANDS)) { + return; + } + actor = new Actor("Console"); + } + consumer.queueChat(actor, "/" + event.getCommand()); + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index 15606ecf..319b66ba 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -1,303 +1,303 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.Actor; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.BlockState; -import org.bukkit.block.DoubleChest; -import org.bukkit.entity.HumanEntity; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -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.inventory.Inventory; -import org.bukkit.inventory.InventoryHolder; -import org.bukkit.inventory.ItemStack; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import static de.diddiz.LogBlock.config.Config.isLogging; -import static de.diddiz.LogBlock.util.BukkitUtils.*; - -public class ChestAccessLogging extends LoggingListener { - private class PlayerActiveInventoryModifications { - private final HumanEntity actor; - private final Location location; - private final HashMap modifications; - - public PlayerActiveInventoryModifications(HumanEntity actor, Location location) { - this.actor = actor; - this.location = location; - this.modifications = new HashMap<>(); - } - - public void addModification(ItemStack stack, int amount) { - if (amount == 0) { - return; - } - // if we have other viewers, we have to flush their changes - ArrayList allViewers = containersByLocation.get(location); - if (allViewers.size() > 1) { - for (PlayerActiveInventoryModifications other : allViewers) { - if (other != this) { - other.flush(); - } - } - } - - // consumer.getLogblock().getLogger().info("Modify container: " + stack + " change: " + amount); - stack = new ItemStack(stack); - stack.setAmount(1); - Integer existing = modifications.get(stack); - int newTotal = amount + (existing == null ? 0 : existing); - if (newTotal == 0) { - modifications.remove(stack); - } else { - modifications.put(stack, newTotal); - } - } - - public void flush() { - if (!modifications.isEmpty()) { - for (Entry e : modifications.entrySet()) { - ItemStack stack = e.getKey(); - int amount = e.getValue(); - 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(); - } - } - - public HumanEntity getActor() { - return actor; - } - - public Location getLocation() { - return location; - } - } - - private final Map containersByOwner = new HashMap<>(); - private final Map> containersByLocation = new HashMap<>(); - - public ChestAccessLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onInventoryClose(InventoryCloseEvent event) { - final HumanEntity player = event.getPlayer(); - if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) { - return; - } - InventoryHolder holder = event.getInventory().getHolder(); - if (holder instanceof BlockState || holder instanceof DoubleChest) { - final PlayerActiveInventoryModifications modifications = containersByOwner.remove(player); - if (modifications != null) { - final Location loc = modifications.getLocation(); - ArrayList atLocation = containersByLocation.get(loc); - atLocation.remove(modifications); - if (atLocation.isEmpty()) { - containersByLocation.remove(loc); - } - modifications.flush(); - } - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onInventoryOpen(InventoryOpenEvent event) { - final HumanEntity player = event.getPlayer(); - if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) { - return; - } - if (event.getInventory() != null) { - InventoryHolder holder = event.getInventory().getHolder(); - if (holder instanceof BlockState || holder instanceof DoubleChest) { - if (getInventoryHolderType(holder) != Material.CRAFTING_TABLE) { - PlayerActiveInventoryModifications modifications = new PlayerActiveInventoryModifications(event.getPlayer(), getInventoryHolderLocation(holder)); - containersByOwner.put(modifications.getActor(), modifications); - containersByLocation.compute(modifications.getLocation(), (k, v) -> { - if (v == null) { - v = new ArrayList<>(); - } - v.add(modifications); - return v; - }); - } - } - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onInventoryClick(InventoryClickEvent event) { - final HumanEntity player = event.getWhoClicked(); - if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) { - return; - } - InventoryHolder holder = event.getInventory().getHolder(); - if (holder instanceof BlockState || holder instanceof DoubleChest) { - final PlayerActiveInventoryModifications modifications = containersByOwner.get(player); - if (modifications != null) { - switch (event.getAction()) { - case PICKUP_ONE: - case DROP_ONE_SLOT: - if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { - modifications.addModification(event.getCurrentItem(), -1); - } - break; - case PICKUP_HALF: - // server behaviour: round up - if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { - modifications.addModification(event.getCurrentItem(), -(event.getCurrentItem().getAmount() + 1) / 2); - } - break; - case PICKUP_SOME: // oversized stack - can not take all when clicking - // server behaviour: leave a full stack in the slot, take everything else - if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { - int taken = event.getCurrentItem().getAmount() - event.getCurrentItem().getMaxStackSize(); - modifications.addModification(event.getCursor(), -taken); - } - break; - case PICKUP_ALL: - case DROP_ALL_SLOT: - if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { - modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount()); - } - break; - case PLACE_ONE: - if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { - modifications.addModification(event.getCursor(), 1); - } - break; - case PLACE_SOME: // not enough free place in target slot - // server behaviour: place as much as possible - if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { - int placeable = event.getCurrentItem().getMaxStackSize() - event.getCurrentItem().getAmount(); - modifications.addModification(event.getCursor(), placeable); - } - break; - case PLACE_ALL: - if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { - modifications.addModification(event.getCursor(), event.getCursor().getAmount()); - } - break; - case SWAP_WITH_CURSOR: - if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { - modifications.addModification(event.getCursor(), event.getCursor().getAmount()); - modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount()); - } - break; - case MOVE_TO_OTHER_INVENTORY: // shift + click - boolean removed = event.getRawSlot() < event.getView().getTopInventory().getSize(); - modifications.addModification(event.getCurrentItem(), event.getCurrentItem().getAmount() * (removed ? -1 : 1)); - break; - case COLLECT_TO_CURSOR: // double click - // server behaviour: first collect all with an amount != maxstacksize, then others, starting from slot 0 (container) - ItemStack cursor = event.getCursor(); - if (cursor == null) { - return; - } - int toPickUp = cursor.getMaxStackSize() - cursor.getAmount(); - int takenFromContainer = 0; - boolean takeFromFullStacks = false; - Inventory top = event.getView().getTopInventory(); - Inventory bottom = event.getView().getBottomInventory(); - while (toPickUp > 0) { - for (ItemStack stack : top.getStorageContents()) { - if (cursor.isSimilar(stack)) { - if (takeFromFullStacks == (stack.getAmount() == stack.getMaxStackSize())) { - int take = Math.min(toPickUp, stack.getAmount()); - toPickUp -= take; - takenFromContainer += take; - if (toPickUp <= 0) { - break; - } - } - } - } - if (toPickUp <= 0) { - break; - } - for (ItemStack stack : bottom.getStorageContents()) { - if (cursor.isSimilar(stack)) { - if (takeFromFullStacks == (stack.getAmount() == stack.getMaxStackSize())) { - int take = Math.min(toPickUp, stack.getAmount()); - toPickUp -= take; - if (toPickUp <= 0) { - break; - } - } - } - } - if (takeFromFullStacks) { - break; - } else { - takeFromFullStacks = true; - } - } - if (takenFromContainer > 0) { - modifications.addModification(event.getCursor(), -takenFromContainer); - } - break; - case HOTBAR_SWAP: // number key or offhand key - case HOTBAR_MOVE_AND_READD: // something was in the other slot - if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { - ItemStack otherSlot = (event.getClick() == ClickType.SWAP_OFFHAND) ? event.getWhoClicked().getInventory().getItemInOffHand() : event.getWhoClicked().getInventory().getItem(event.getHotbarButton()); - if (event.getCurrentItem() != null && event.getCurrentItem().getType() != Material.AIR) { - modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount()); - } - if (otherSlot != null && otherSlot.getType() != Material.AIR) { - modifications.addModification(otherSlot, otherSlot.getAmount()); - } - } - break; - case DROP_ALL_CURSOR: - case DROP_ONE_CURSOR: - case CLONE_STACK: - case NOTHING: - // only the cursor or nothing (but not the inventory) was modified - break; - case UNKNOWN: - default: - // unable to log something we don't know - consumer.getLogblock().getLogger().warning("Unknown inventory action by " + event.getWhoClicked().getName() + ": " + event.getAction() + " Slot: " + event.getSlot() + " Slot type: " + event.getSlotType()); - break; - } - } - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onInventoryDrag(InventoryDragEvent event) { - final HumanEntity player = event.getWhoClicked(); - if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) { - return; - } - InventoryHolder holder = event.getInventory().getHolder(); - if (holder instanceof BlockState || holder instanceof DoubleChest) { - final PlayerActiveInventoryModifications modifications = containersByOwner.get(player); - if (modifications != null) { - Inventory container = event.getView().getTopInventory(); - int containerSize = container.getSize(); - for (Entry e : event.getNewItems().entrySet()) { - int slot = e.getKey(); - if (slot < containerSize) { - ItemStack old = container.getItem(slot); - int oldAmount = (old == null || old.getType() == Material.AIR) ? 0 : old.getAmount(); - modifications.addModification(e.getValue(), e.getValue().getAmount() - oldAmount); - } - } - } - } - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.BlockState; +import org.bukkit.block.DoubleChest; +import org.bukkit.entity.HumanEntity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +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.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import static de.diddiz.LogBlock.config.Config.isLogging; +import static de.diddiz.LogBlock.util.BukkitUtils.*; + +public class ChestAccessLogging extends LoggingListener { + private class PlayerActiveInventoryModifications { + private final HumanEntity actor; + private final Location location; + private final HashMap modifications; + + public PlayerActiveInventoryModifications(HumanEntity actor, Location location) { + this.actor = actor; + this.location = location; + this.modifications = new HashMap<>(); + } + + public void addModification(ItemStack stack, int amount) { + if (amount == 0) { + return; + } + // if we have other viewers, we have to flush their changes + ArrayList allViewers = containersByLocation.get(location); + if (allViewers.size() > 1) { + for (PlayerActiveInventoryModifications other : allViewers) { + if (other != this) { + other.flush(); + } + } + } + + // consumer.getLogblock().getLogger().info("Modify container: " + stack + " change: " + amount); + stack = new ItemStack(stack); + stack.setAmount(1); + Integer existing = modifications.get(stack); + int newTotal = amount + (existing == null ? 0 : existing); + if (newTotal == 0) { + modifications.remove(stack); + } else { + modifications.put(stack, newTotal); + } + } + + public void flush() { + if (!modifications.isEmpty()) { + for (Entry e : modifications.entrySet()) { + ItemStack stack = e.getKey(); + int amount = e.getValue(); + 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(); + } + } + + public HumanEntity getActor() { + return actor; + } + + public Location getLocation() { + return location; + } + } + + private final Map containersByOwner = new HashMap<>(); + private final Map> containersByLocation = new HashMap<>(); + + public ChestAccessLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onInventoryClose(InventoryCloseEvent event) { + final HumanEntity player = event.getPlayer(); + if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) { + return; + } + InventoryHolder holder = event.getInventory().getHolder(); + if (holder instanceof BlockState || holder instanceof DoubleChest) { + final PlayerActiveInventoryModifications modifications = containersByOwner.remove(player); + if (modifications != null) { + final Location loc = modifications.getLocation(); + ArrayList atLocation = containersByLocation.get(loc); + atLocation.remove(modifications); + if (atLocation.isEmpty()) { + containersByLocation.remove(loc); + } + modifications.flush(); + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onInventoryOpen(InventoryOpenEvent event) { + final HumanEntity player = event.getPlayer(); + if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) { + return; + } + if (event.getInventory() != null) { + InventoryHolder holder = event.getInventory().getHolder(); + if (holder instanceof BlockState || holder instanceof DoubleChest) { + if (getInventoryHolderType(holder) != Material.CRAFTING_TABLE) { + PlayerActiveInventoryModifications modifications = new PlayerActiveInventoryModifications(event.getPlayer(), getInventoryHolderLocation(holder)); + containersByOwner.put(modifications.getActor(), modifications); + containersByLocation.compute(modifications.getLocation(), (k, v) -> { + if (v == null) { + v = new ArrayList<>(); + } + v.add(modifications); + return v; + }); + } + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onInventoryClick(InventoryClickEvent event) { + final HumanEntity player = event.getWhoClicked(); + if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) { + return; + } + InventoryHolder holder = event.getInventory().getHolder(); + if (holder instanceof BlockState || holder instanceof DoubleChest) { + final PlayerActiveInventoryModifications modifications = containersByOwner.get(player); + if (modifications != null) { + switch (event.getAction()) { + case PICKUP_ONE: + case DROP_ONE_SLOT: + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + modifications.addModification(event.getCurrentItem(), -1); + } + break; + case PICKUP_HALF: + // server behaviour: round up + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + modifications.addModification(event.getCurrentItem(), -(event.getCurrentItem().getAmount() + 1) / 2); + } + break; + case PICKUP_SOME: // oversized stack - can not take all when clicking + // server behaviour: leave a full stack in the slot, take everything else + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + int taken = event.getCurrentItem().getAmount() - event.getCurrentItem().getMaxStackSize(); + modifications.addModification(event.getCursor(), -taken); + } + break; + case PICKUP_ALL: + case DROP_ALL_SLOT: + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount()); + } + break; + case PLACE_ONE: + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + modifications.addModification(event.getCursor(), 1); + } + break; + case PLACE_SOME: // not enough free place in target slot + // server behaviour: place as much as possible + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + int placeable = event.getCurrentItem().getMaxStackSize() - event.getCurrentItem().getAmount(); + modifications.addModification(event.getCursor(), placeable); + } + break; + case PLACE_ALL: + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + modifications.addModification(event.getCursor(), event.getCursor().getAmount()); + } + break; + case SWAP_WITH_CURSOR: + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + modifications.addModification(event.getCursor(), event.getCursor().getAmount()); + modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount()); + } + break; + case MOVE_TO_OTHER_INVENTORY: // shift + click + boolean removed = event.getRawSlot() < event.getView().getTopInventory().getSize(); + modifications.addModification(event.getCurrentItem(), event.getCurrentItem().getAmount() * (removed ? -1 : 1)); + break; + case COLLECT_TO_CURSOR: // double click + // server behaviour: first collect all with an amount != maxstacksize, then others, starting from slot 0 (container) + ItemStack cursor = event.getCursor(); + if (cursor == null) { + return; + } + int toPickUp = cursor.getMaxStackSize() - cursor.getAmount(); + int takenFromContainer = 0; + boolean takeFromFullStacks = false; + Inventory top = event.getView().getTopInventory(); + Inventory bottom = event.getView().getBottomInventory(); + while (toPickUp > 0) { + for (ItemStack stack : top.getStorageContents()) { + if (cursor.isSimilar(stack)) { + if (takeFromFullStacks == (stack.getAmount() == stack.getMaxStackSize())) { + int take = Math.min(toPickUp, stack.getAmount()); + toPickUp -= take; + takenFromContainer += take; + if (toPickUp <= 0) { + break; + } + } + } + } + if (toPickUp <= 0) { + break; + } + for (ItemStack stack : bottom.getStorageContents()) { + if (cursor.isSimilar(stack)) { + if (takeFromFullStacks == (stack.getAmount() == stack.getMaxStackSize())) { + int take = Math.min(toPickUp, stack.getAmount()); + toPickUp -= take; + if (toPickUp <= 0) { + break; + } + } + } + } + if (takeFromFullStacks) { + break; + } else { + takeFromFullStacks = true; + } + } + if (takenFromContainer > 0) { + modifications.addModification(event.getCursor(), -takenFromContainer); + } + break; + case HOTBAR_SWAP: // number key or offhand key + case HOTBAR_MOVE_AND_READD: // something was in the other slot + if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { + ItemStack otherSlot = (event.getClick() == ClickType.SWAP_OFFHAND) ? event.getWhoClicked().getInventory().getItemInOffHand() : event.getWhoClicked().getInventory().getItem(event.getHotbarButton()); + if (event.getCurrentItem() != null && event.getCurrentItem().getType() != Material.AIR) { + modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount()); + } + if (otherSlot != null && otherSlot.getType() != Material.AIR) { + modifications.addModification(otherSlot, otherSlot.getAmount()); + } + } + break; + case DROP_ALL_CURSOR: + case DROP_ONE_CURSOR: + case CLONE_STACK: + case NOTHING: + // only the cursor or nothing (but not the inventory) was modified + break; + case UNKNOWN: + default: + // unable to log something we don't know + consumer.getLogblock().getLogger().warning("Unknown inventory action by " + event.getWhoClicked().getName() + ": " + event.getAction() + " Slot: " + event.getSlot() + " Slot type: " + event.getSlotType()); + break; + } + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onInventoryDrag(InventoryDragEvent event) { + final HumanEntity player = event.getWhoClicked(); + if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) { + return; + } + InventoryHolder holder = event.getInventory().getHolder(); + if (holder instanceof BlockState || holder instanceof DoubleChest) { + final PlayerActiveInventoryModifications modifications = containersByOwner.get(player); + if (modifications != null) { + Inventory container = event.getView().getTopInventory(); + int containerSize = container.getSize(); + for (Entry e : event.getNewItems().entrySet()) { + int slot = e.getKey(); + if (slot < containerSize) { + ItemStack old = container.getItem(slot); + int oldAmount = (old == null || old.getType() == Material.AIR) ? 0 : old.getAmount(); + modifications.addModification(e.getValue(), e.getValue().getAmount() - oldAmount); + } + } + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java index 5b89ad44..b7fe92a3 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java @@ -1,24 +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; - } - } -} +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; + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index 20fd01dd..62801a69 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -1,229 +1,229 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.Actor; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -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.Location; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.data.type.RespawnAnchor; -import org.bukkit.entity.*; -import org.bukkit.entity.minecart.ExplosiveMinecart; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.Action; -import org.bukkit.event.block.BlockExplodeEvent; -import org.bukkit.event.entity.EntityExplodeEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.inventory.ItemStack; -import org.bukkit.projectiles.ProjectileSource; -import org.bukkit.scheduler.BukkitRunnable; - -import static de.diddiz.LogBlock.config.Config.getWorldConfig; -import static de.diddiz.LogBlock.config.Config.logCreeperExplosionsAsPlayerWhoTriggeredThese; -import static de.diddiz.LogBlock.util.BukkitUtils.getContainerBlocks; - -import java.util.UUID; - -public class ExplosionLogging extends LoggingListener { - - private UUID lastBedInteractionPlayer; - private Location lastBedInteractionLocation; - private UUID lastRespawnAnchorInteractionPlayer; - private Location lastRespawnAnchorInteractionLocation; - - public ExplosionLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onEntityExplode(EntityExplodeEvent event) { - final WorldConfig wcfg = getWorldConfig(event.getLocation().getWorld()); - if (wcfg != null) { - Actor actor = new Actor("Explosion"); - Entity source = event.getEntity(); - if (source == null) { - if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { - return; - } - } else if (source instanceof TNTPrimed) { - if (!wcfg.isLogging(Logging.TNTEXPLOSION)) { - return; - } - actor = new Actor("TNT"); - } else if (source instanceof ExplosiveMinecart) { - if (!wcfg.isLogging(Logging.TNTMINECARTEXPLOSION)) { - return; - } - actor = new Actor("TNTMinecart"); - } else if (source instanceof Creeper) { - if (!wcfg.isLogging(Logging.CREEPEREXPLOSION)) { - return; - } - if (logCreeperExplosionsAsPlayerWhoTriggeredThese) { - final Entity target = ((Creeper) source).getTarget(); - actor = target instanceof Player ? Actor.actorFromEntity(target) : new Actor("Creeper"); - } else { - actor = new Actor("Creeper"); - } - } else if (source instanceof Wither) { - if (!wcfg.isLogging(Logging.WITHER)) { - return; - } - actor = Actor.actorFromEntity(source); - } else if (source instanceof WitherSkull) { - if (!wcfg.isLogging(Logging.WITHER_SKULL)) { - return; - } - actor = Actor.actorFromEntity(source); - } else if (source instanceof Fireball) { - Fireball fireball = (Fireball) source; - ProjectileSource shooter = fireball.getShooter(); - if (shooter == null) { - if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { - return; - } - actor = Actor.actorFromEntity(source); - } else if (shooter instanceof Ghast) { - if (!wcfg.isLogging(Logging.GHASTFIREBALLEXPLOSION)) { - return; - } - actor = Actor.actorFromProjectileSource(shooter); - } else if (shooter instanceof Wither) { - if (!wcfg.isLogging(Logging.WITHER)) { - return; - } - actor = Actor.actorFromProjectileSource(shooter); - } - } else if (source instanceof EnderDragon) { - if (!wcfg.isLogging(Logging.ENDERDRAGON)) { - return; - } - actor = Actor.actorFromEntity(source); - } else if (source instanceof EnderCrystal) { - if (!wcfg.isLogging(Logging.ENDERCRYSTALEXPLOSION)) { - return; - } - actor = Actor.actorFromEntity(source); - - } else { - if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { - return; - } - } - for (final Block block : event.blockList()) { - final Material type = block.getType(); - if (wcfg.isLogging(Logging.CHESTACCESS) && getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) { - consumer.queueContainerBreak(actor, block.getState()); - } else { - consumer.queueBlockBreak(actor, block.getState()); - } - } - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onPlayerInteract(PlayerInteractEvent event) { - if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.hasBlock()) { - Block block = event.getClickedBlock(); - if (BukkitUtils.isBed(block.getType()) && !block.getWorld().isBedWorks()) { - if (!Config.isLogging(block.getWorld(), Logging.BEDEXPLOSION)) { - return; - } - lastBedInteractionPlayer = event.getPlayer().getUniqueId(); - lastBedInteractionLocation = block.getLocation(); - new BukkitRunnable() { - @Override - public void run() { - lastBedInteractionPlayer = null; - lastBedInteractionLocation = null; - } - }.runTask(LogBlock.getInstance()); - } else if (block.getType() == Material.RESPAWN_ANCHOR && block.getBlockData() instanceof RespawnAnchor data) { - if (!Config.isLogging(block.getWorld(), Logging.RESPAWNANCHOREXPLOSION)) { - return; - } - ItemStack inHand = event.getItem(); - int charges = data.getCharges(); - if (charges < data.getMaximumCharges() && inHand != null && inHand.getType() == Material.GLOWSTONE) { - // charge - Actor actor = Actor.actorFromEntity(event.getPlayer()); - RespawnAnchor blockNew = (RespawnAnchor) data.clone(); - blockNew.setCharges(charges + 1); - consumer.queueBlockReplace(actor, block.getState(), blockNew); - } else if (charges > 0 && !block.getWorld().isRespawnAnchorWorks()) { - // explode - Actor actor = Actor.actorFromEntity(event.getPlayer()); - consumer.queueBlockBreak(actor, block.getState()); - lastRespawnAnchorInteractionPlayer = event.getPlayer().getUniqueId(); - lastRespawnAnchorInteractionLocation = block.getLocation(); - new BukkitRunnable() { - @Override - public void run() { - lastRespawnAnchorInteractionPlayer = null; - lastRespawnAnchorInteractionLocation = null; - } - }.runTask(LogBlock.getInstance()); - } - } - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockExplode(BlockExplodeEvent event) { - Player bedCause = null; - if (lastBedInteractionPlayer != null && lastBedInteractionLocation != null) { - Location block = event.getBlock().getLocation(); - if (lastBedInteractionLocation.getWorld() == block.getWorld() && block.distanceSquared(lastBedInteractionLocation) <= 1) { - bedCause = Bukkit.getPlayer(lastBedInteractionPlayer); - } - } - Player respawnAnchorCause = null; - if (lastRespawnAnchorInteractionPlayer != null && lastRespawnAnchorInteractionLocation != null) { - Location block = event.getBlock().getLocation(); - if (lastRespawnAnchorInteractionLocation.equals(block)) { - respawnAnchorCause = Bukkit.getPlayer(lastRespawnAnchorInteractionPlayer); - } - } - - for (final Block block : event.blockList()) { - final WorldConfig wcfg = getWorldConfig(block.getLocation().getWorld()); - - if (wcfg != null) { - Actor actor = new Actor("Explosion"); - if (bedCause != null) { - if (!wcfg.isLogging(Logging.BEDEXPLOSION)) { - return; - } - if (Config.logBedExplosionsAsPlayerWhoTriggeredThese) { - actor = Actor.actorFromEntity(bedCause); - } else { - actor = new Actor("BedExplosion"); - } - } else if (respawnAnchorCause != null) { - if (!wcfg.isLogging(Logging.RESPAWNANCHOREXPLOSION)) { - return; - } - if (Config.logBedExplosionsAsPlayerWhoTriggeredThese) { - actor = Actor.actorFromEntity(respawnAnchorCause); - } else { - actor = new Actor("RespawnAnchorExplosion"); - } - } else if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { - return; - } - - final Material type = block.getType(); - if (wcfg.isLogging(Logging.CHESTACCESS) && getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) { - consumer.queueContainerBreak(actor, block.getState()); - } else { - consumer.queueBlockBreak(actor, block.getState()); - } - } - } - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +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.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.data.type.RespawnAnchor; +import org.bukkit.entity.*; +import org.bukkit.entity.minecart.ExplosiveMinecart; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockExplodeEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.projectiles.ProjectileSource; +import org.bukkit.scheduler.BukkitRunnable; + +import static de.diddiz.LogBlock.config.Config.getWorldConfig; +import static de.diddiz.LogBlock.config.Config.logCreeperExplosionsAsPlayerWhoTriggeredThese; +import static de.diddiz.LogBlock.util.BukkitUtils.getContainerBlocks; + +import java.util.UUID; + +public class ExplosionLogging extends LoggingListener { + + private UUID lastBedInteractionPlayer; + private Location lastBedInteractionLocation; + private UUID lastRespawnAnchorInteractionPlayer; + private Location lastRespawnAnchorInteractionLocation; + + public ExplosionLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onEntityExplode(EntityExplodeEvent event) { + final WorldConfig wcfg = getWorldConfig(event.getLocation().getWorld()); + if (wcfg != null) { + Actor actor = new Actor("Explosion"); + Entity source = event.getEntity(); + if (source == null) { + if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { + return; + } + } else if (source instanceof TNTPrimed) { + if (!wcfg.isLogging(Logging.TNTEXPLOSION)) { + return; + } + actor = new Actor("TNT"); + } else if (source instanceof ExplosiveMinecart) { + if (!wcfg.isLogging(Logging.TNTMINECARTEXPLOSION)) { + return; + } + actor = new Actor("TNTMinecart"); + } else if (source instanceof Creeper) { + if (!wcfg.isLogging(Logging.CREEPEREXPLOSION)) { + return; + } + if (logCreeperExplosionsAsPlayerWhoTriggeredThese) { + final Entity target = ((Creeper) source).getTarget(); + actor = target instanceof Player ? Actor.actorFromEntity(target) : new Actor("Creeper"); + } else { + actor = new Actor("Creeper"); + } + } else if (source instanceof Wither) { + if (!wcfg.isLogging(Logging.WITHER)) { + return; + } + actor = Actor.actorFromEntity(source); + } else if (source instanceof WitherSkull) { + if (!wcfg.isLogging(Logging.WITHER_SKULL)) { + return; + } + actor = Actor.actorFromEntity(source); + } else if (source instanceof Fireball) { + Fireball fireball = (Fireball) source; + ProjectileSource shooter = fireball.getShooter(); + if (shooter == null) { + if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { + return; + } + actor = Actor.actorFromEntity(source); + } else if (shooter instanceof Ghast) { + if (!wcfg.isLogging(Logging.GHASTFIREBALLEXPLOSION)) { + return; + } + actor = Actor.actorFromProjectileSource(shooter); + } else if (shooter instanceof Wither) { + if (!wcfg.isLogging(Logging.WITHER)) { + return; + } + actor = Actor.actorFromProjectileSource(shooter); + } + } else if (source instanceof EnderDragon) { + if (!wcfg.isLogging(Logging.ENDERDRAGON)) { + return; + } + actor = Actor.actorFromEntity(source); + } else if (source instanceof EnderCrystal) { + if (!wcfg.isLogging(Logging.ENDERCRYSTALEXPLOSION)) { + return; + } + actor = Actor.actorFromEntity(source); + + } else { + if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { + return; + } + } + for (final Block block : event.blockList()) { + final Material type = block.getType(); + if (wcfg.isLogging(Logging.CHESTACCESS) && getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) { + consumer.queueContainerBreak(actor, block.getState()); + } else { + consumer.queueBlockBreak(actor, block.getState()); + } + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerInteract(PlayerInteractEvent event) { + if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.hasBlock()) { + Block block = event.getClickedBlock(); + if (BukkitUtils.isBed(block.getType()) && !block.getWorld().isBedWorks()) { + if (!Config.isLogging(block.getWorld(), Logging.BEDEXPLOSION)) { + return; + } + lastBedInteractionPlayer = event.getPlayer().getUniqueId(); + lastBedInteractionLocation = block.getLocation(); + new BukkitRunnable() { + @Override + public void run() { + lastBedInteractionPlayer = null; + lastBedInteractionLocation = null; + } + }.runTask(LogBlock.getInstance()); + } else if (block.getType() == Material.RESPAWN_ANCHOR && block.getBlockData() instanceof RespawnAnchor data) { + if (!Config.isLogging(block.getWorld(), Logging.RESPAWNANCHOREXPLOSION)) { + return; + } + ItemStack inHand = event.getItem(); + int charges = data.getCharges(); + if (charges < data.getMaximumCharges() && inHand != null && inHand.getType() == Material.GLOWSTONE) { + // charge + Actor actor = Actor.actorFromEntity(event.getPlayer()); + RespawnAnchor blockNew = (RespawnAnchor) data.clone(); + blockNew.setCharges(charges + 1); + consumer.queueBlockReplace(actor, block.getState(), blockNew); + } else if (charges > 0 && !block.getWorld().isRespawnAnchorWorks()) { + // explode + Actor actor = Actor.actorFromEntity(event.getPlayer()); + consumer.queueBlockBreak(actor, block.getState()); + lastRespawnAnchorInteractionPlayer = event.getPlayer().getUniqueId(); + lastRespawnAnchorInteractionLocation = block.getLocation(); + new BukkitRunnable() { + @Override + public void run() { + lastRespawnAnchorInteractionPlayer = null; + lastRespawnAnchorInteractionLocation = null; + } + }.runTask(LogBlock.getInstance()); + } + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockExplode(BlockExplodeEvent event) { + Player bedCause = null; + if (lastBedInteractionPlayer != null && lastBedInteractionLocation != null) { + Location block = event.getBlock().getLocation(); + if (lastBedInteractionLocation.getWorld() == block.getWorld() && block.distanceSquared(lastBedInteractionLocation) <= 1) { + bedCause = Bukkit.getPlayer(lastBedInteractionPlayer); + } + } + Player respawnAnchorCause = null; + if (lastRespawnAnchorInteractionPlayer != null && lastRespawnAnchorInteractionLocation != null) { + Location block = event.getBlock().getLocation(); + if (lastRespawnAnchorInteractionLocation.equals(block)) { + respawnAnchorCause = Bukkit.getPlayer(lastRespawnAnchorInteractionPlayer); + } + } + + for (final Block block : event.blockList()) { + final WorldConfig wcfg = getWorldConfig(block.getLocation().getWorld()); + + if (wcfg != null) { + Actor actor = new Actor("Explosion"); + if (bedCause != null) { + if (!wcfg.isLogging(Logging.BEDEXPLOSION)) { + return; + } + if (Config.logBedExplosionsAsPlayerWhoTriggeredThese) { + actor = Actor.actorFromEntity(bedCause); + } else { + actor = new Actor("BedExplosion"); + } + } else if (respawnAnchorCause != null) { + if (!wcfg.isLogging(Logging.RESPAWNANCHOREXPLOSION)) { + return; + } + if (Config.logBedExplosionsAsPlayerWhoTriggeredThese) { + actor = Actor.actorFromEntity(respawnAnchorCause); + } else { + actor = new Actor("RespawnAnchorExplosion"); + } + } else if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { + return; + } + + final Material type = block.getType(); + if (wcfg.isLogging(Logging.CHESTACCESS) && getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) { + consumer.queueContainerBreak(actor, block.getState()); + } else { + consumer.queueBlockBreak(actor, block.getState()); + } + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index 9e85a5b5..9c9e1b3a 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -1,127 +1,127 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.Actor; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import de.diddiz.LogBlock.config.Config; -import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.LogBlock.util.BukkitUtils; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Levelled; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.BlockFormEvent; -import org.bukkit.event.block.BlockFromToEvent; - -import static de.diddiz.LogBlock.config.Config.getWorldConfig; - -public class FluidFlowLogging extends LoggingListener { - - public FluidFlowLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockFromTo(BlockFromToEvent event) { - final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld()); - if (wcfg != null && (wcfg.isLogging(Logging.WATERFLOW) || wcfg.isLogging(Logging.LAVAFLOW))) { - final BlockData blockDataFrom = event.getBlock().getBlockData(); - Material typeFrom = blockDataFrom.getMaterial(); - boolean fromWaterlogged = false; - if (blockDataFrom instanceof Waterlogged) { - typeFrom = Material.WATER; - fromWaterlogged = true; - } - if (typeFrom == Material.SEAGRASS || typeFrom == Material.KELP_PLANT || typeFrom == Material.KELP) { - typeFrom = Material.WATER; - fromWaterlogged = true; - } - - Block source = Config.logFluidFlowAsPlayerWhoTriggeredIt ? event.getBlock() : null; - final Block to = event.getToBlock(); - final Material typeTo = to.getType(); - boolean down = event.getFace() == BlockFace.DOWN; - final boolean canFlow = BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo); - if (typeFrom == Material.LAVA && wcfg.isLogging(Logging.LAVAFLOW)) { - Levelled levelledFrom = (Levelled) blockDataFrom; - if (canFlow) { - if (isSurroundedByWater(to) && levelledFrom.getLevel() <= 2) { - consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData()); - } else { - Levelled newBlock = (Levelled) blockDataFrom.clone(); - newBlock.setLevel(down ? 1 : Math.min(levelledFrom.getLevel() + 1, levelledFrom.getMaximumLevel())); - if (BukkitUtils.isEmpty(typeTo)) { - consumer.queueBlockPlace(new Actor("LavaFlow", source), to.getLocation(), newBlock); - } else { - consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), newBlock); - } - } - } else if (typeTo == Material.WATER) { - if (down) { - consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.STONE.createBlockData()); - } else { - consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData()); - } - } - } else if ((typeFrom == Material.WATER) && wcfg.isLogging(Logging.WATERFLOW)) { - Levelled levelledFrom = fromWaterlogged ? null : (Levelled) blockDataFrom; - Levelled newBlock = (Levelled) Material.WATER.createBlockData(); - newBlock.setLevel(fromWaterlogged || down ? 1 : Math.min(levelledFrom.getLevel() + 1, levelledFrom.getMaximumLevel())); - if (BukkitUtils.isEmpty(typeTo)) { - consumer.queueBlockPlace(new Actor("WaterFlow", source), to.getLocation(), newBlock); - } else if (BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { - consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), newBlock); - } else if (typeTo == Material.LAVA) { - int toLevel = ((Levelled) to.getBlockData()).getLevel(); - if (toLevel == 0) { - consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), Material.OBSIDIAN.createBlockData()); - } else if (event.getFace() == BlockFace.DOWN) { - consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), Material.STONE.createBlockData()); - } - } - if (BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { - for (final BlockFace face : new BlockFace[] { BlockFace.DOWN, BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH }) { - final Block lower = to.getRelative(face); - if (lower.getType() == Material.LAVA) { - int toLevel = ((Levelled) lower.getBlockData()).getLevel(); - if (toLevel == 0) { - consumer.queueBlockReplace(new Actor("WaterFlow", source), lower.getState(), Material.OBSIDIAN.createBlockData()); - } else if (event.getFace() == BlockFace.DOWN) { - consumer.queueBlockReplace(new Actor("WaterFlow", source), lower.getState(), Material.STONE.createBlockData()); - } - } - } - } - } - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockForm(BlockFormEvent event) { - final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld()); - if (wcfg != null && (wcfg.isLogging(Logging.WATERFLOW) || wcfg.isLogging(Logging.LAVAFLOW))) { - if (wcfg.isLogging(Logging.LAVAFLOW) && event.getBlock().getType() == Material.WATER && event.getNewState().getType() == Material.COBBLESTONE) { - consumer.queueBlockReplace(new Actor("LavaFlow"), event.getBlock().getBlockData(), event.getNewState()); - } - if (wcfg.isLogging(Logging.WATERFLOW) && event.getBlock().getType() == Material.LAVA) { - consumer.queueBlockReplace(new Actor("WaterFlow"), event.getBlock().getBlockData(), event.getNewState()); - } - if (wcfg.isLogging(Logging.WATERFLOW) && BukkitUtils.isConcreteBlock(event.getNewState().getType())) { - consumer.queueBlockReplace(new Actor("WaterFlow"), event.getBlock().getBlockData(), event.getNewState()); - } - } - } - - private static boolean isSurroundedByWater(Block block) { - for (final BlockFace face : new BlockFace[] { BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH }) { - if (block.getRelative(face).getType() == Material.WATER) { - return true; - } - } - return false; - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.Config; +import de.diddiz.LogBlock.config.WorldConfig; +import de.diddiz.LogBlock.util.BukkitUtils; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Levelled; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockFormEvent; +import org.bukkit.event.block.BlockFromToEvent; + +import static de.diddiz.LogBlock.config.Config.getWorldConfig; + +public class FluidFlowLogging extends LoggingListener { + + public FluidFlowLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockFromTo(BlockFromToEvent event) { + final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld()); + if (wcfg != null && (wcfg.isLogging(Logging.WATERFLOW) || wcfg.isLogging(Logging.LAVAFLOW))) { + final BlockData blockDataFrom = event.getBlock().getBlockData(); + Material typeFrom = blockDataFrom.getMaterial(); + boolean fromWaterlogged = false; + if (blockDataFrom instanceof Waterlogged) { + typeFrom = Material.WATER; + fromWaterlogged = true; + } + if (typeFrom == Material.SEAGRASS || typeFrom == Material.KELP_PLANT || typeFrom == Material.KELP) { + typeFrom = Material.WATER; + fromWaterlogged = true; + } + + Block source = Config.logFluidFlowAsPlayerWhoTriggeredIt ? event.getBlock() : null; + final Block to = event.getToBlock(); + final Material typeTo = to.getType(); + boolean down = event.getFace() == BlockFace.DOWN; + final boolean canFlow = BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo); + if (typeFrom == Material.LAVA && wcfg.isLogging(Logging.LAVAFLOW)) { + Levelled levelledFrom = (Levelled) blockDataFrom; + if (canFlow) { + if (isSurroundedByWater(to) && levelledFrom.getLevel() <= 2) { + consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData()); + } else { + Levelled newBlock = (Levelled) blockDataFrom.clone(); + newBlock.setLevel(down ? 1 : Math.min(levelledFrom.getLevel() + 1, levelledFrom.getMaximumLevel())); + if (BukkitUtils.isEmpty(typeTo)) { + consumer.queueBlockPlace(new Actor("LavaFlow", source), to.getLocation(), newBlock); + } else { + consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), newBlock); + } + } + } else if (typeTo == Material.WATER) { + if (down) { + consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.STONE.createBlockData()); + } else { + consumer.queueBlockReplace(new Actor("LavaFlow", source), to.getState(), Material.COBBLESTONE.createBlockData()); + } + } + } else if ((typeFrom == Material.WATER) && wcfg.isLogging(Logging.WATERFLOW)) { + Levelled levelledFrom = fromWaterlogged ? null : (Levelled) blockDataFrom; + Levelled newBlock = (Levelled) Material.WATER.createBlockData(); + newBlock.setLevel(fromWaterlogged || down ? 1 : Math.min(levelledFrom.getLevel() + 1, levelledFrom.getMaximumLevel())); + if (BukkitUtils.isEmpty(typeTo)) { + consumer.queueBlockPlace(new Actor("WaterFlow", source), to.getLocation(), newBlock); + } else if (BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { + consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), newBlock); + } else if (typeTo == Material.LAVA) { + int toLevel = ((Levelled) to.getBlockData()).getLevel(); + if (toLevel == 0) { + consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), Material.OBSIDIAN.createBlockData()); + } else if (event.getFace() == BlockFace.DOWN) { + consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), Material.STONE.createBlockData()); + } + } + if (BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { + for (final BlockFace face : new BlockFace[] { BlockFace.DOWN, BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH }) { + final Block lower = to.getRelative(face); + if (lower.getType() == Material.LAVA) { + int toLevel = ((Levelled) lower.getBlockData()).getLevel(); + if (toLevel == 0) { + consumer.queueBlockReplace(new Actor("WaterFlow", source), lower.getState(), Material.OBSIDIAN.createBlockData()); + } else if (event.getFace() == BlockFace.DOWN) { + consumer.queueBlockReplace(new Actor("WaterFlow", source), lower.getState(), Material.STONE.createBlockData()); + } + } + } + } + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockForm(BlockFormEvent event) { + final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld()); + if (wcfg != null && (wcfg.isLogging(Logging.WATERFLOW) || wcfg.isLogging(Logging.LAVAFLOW))) { + if (wcfg.isLogging(Logging.LAVAFLOW) && event.getBlock().getType() == Material.WATER && event.getNewState().getType() == Material.COBBLESTONE) { + consumer.queueBlockReplace(new Actor("LavaFlow"), event.getBlock().getBlockData(), event.getNewState()); + } + if (wcfg.isLogging(Logging.WATERFLOW) && event.getBlock().getType() == Material.LAVA) { + consumer.queueBlockReplace(new Actor("WaterFlow"), event.getBlock().getBlockData(), event.getNewState()); + } + if (wcfg.isLogging(Logging.WATERFLOW) && BukkitUtils.isConcreteBlock(event.getNewState().getType())) { + consumer.queueBlockReplace(new Actor("WaterFlow"), event.getBlock().getBlockData(), event.getNewState()); + } + } + } + + private static boolean isSurroundedByWater(Block block) { + for (final BlockFace face : new BlockFace[] { BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH }) { + if (block.getRelative(face).getType() == Material.WATER) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index 88e68fff..55dd7136 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -1,276 +1,276 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.Actor; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import de.diddiz.LogBlock.config.WorldConfig; -import de.diddiz.LogBlock.util.BukkitUtils; -import de.diddiz.LogBlock.util.Reflections; -import java.util.UUID; -import org.bukkit.DyeColor; -import org.bukkit.GameEvent; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Note; -import org.bukkit.Note.Tone; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockState; -import org.bukkit.block.Sign; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Directional; -import org.bukkit.block.data.Lightable; -import org.bukkit.block.data.Openable; -import org.bukkit.block.data.type.Cake; -import org.bukkit.block.data.type.Candle; -import org.bukkit.block.data.type.Comparator; -import org.bukkit.block.data.type.Comparator.Mode; -import org.bukkit.block.data.type.DaylightDetector; -import org.bukkit.block.data.type.Door; -import org.bukkit.block.data.type.NoteBlock; -import org.bukkit.block.data.type.Repeater; -import org.bukkit.block.data.type.Switch; -import org.bukkit.block.data.type.TurtleEgg; -import org.bukkit.block.sign.Side; -import org.bukkit.block.sign.SignSide; -import org.bukkit.entity.Player; -import org.bukkit.event.Event.Result; -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.world.GenericGameEvent; -import org.bukkit.inventory.ItemStack; - -import static de.diddiz.LogBlock.config.Config.getWorldConfig; - -public class InteractLogging extends LoggingListener { - public InteractLogging(LogBlock lb) { - super(lb); - } - - private UUID lastInteractionPlayer; - private BlockData lastInteractionBlockData; - private Location lastInteractionLocation; - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onPlayerInteract(PlayerInteractEvent event) { - final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld()); - if (wcfg != null) { - final Block clicked = event.getClickedBlock(); - if (clicked == null) { - return; - } - final BlockData blockData = clicked.getBlockData(); - final Material type = blockData.getMaterial(); - final Player player = event.getPlayer(); - final Location loc = clicked.getLocation(); - lastInteractionPlayer = player.getUniqueId(); - lastInteractionBlockData = blockData; - lastInteractionLocation = loc; - - if (BukkitUtils.isFenceGate(type) || BukkitUtils.isWoodenTrapdoor(type)) { - if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Openable newBlockData = (Openable) blockData.clone(); - newBlockData.setOpen(!newBlockData.isOpen()); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - } else if (BukkitUtils.isPressurePlate(type)) { - if (wcfg.isLogging(Logging.PRESUREPLATEINTERACT) && event.getAction() == Action.PHYSICAL) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); - } - } else if (BukkitUtils.isWoodenDoor(type)) { - if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Door newBlockData = (Door) blockData.clone(); - newBlockData.setOpen(!newBlockData.isOpen()); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - } else if (BukkitUtils.isButton(type) || type == Material.LEVER) { - if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Switch newBlockData = (Switch) blockData.clone(); - if (!newBlockData.isPowered() || type == Material.LEVER) { - newBlockData.setPowered(!newBlockData.isPowered()); - } - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - } else if (BukkitUtils.isSign(type)) { - if (wcfg.isLogging(Logging.SIGNTEXT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getItem() != null) { - Material itemType = event.getItem().getType(); - if (BukkitUtils.isDye(itemType) || itemType == Material.GLOW_INK_SAC || itemType == Material.INK_SAC || itemType == Material.HONEYCOMB) { - final BlockState before = event.getClickedBlock().getState(); - if (before instanceof Sign signBefore) { - boolean waxed = Reflections.isSignWaxed(signBefore); - if (!waxed) { - final Sign signAfter = (Sign) event.getClickedBlock().getState(); - Side side = BukkitUtils.getFacingSignSide(player, clicked); - SignSide signSideBefore = signBefore.getSide(side); - SignSide signSideAfter = signAfter.getSide(side); - if (itemType == Material.GLOW_INK_SAC) { - if (!signSideBefore.isGlowingText() && hasText(signSideBefore)) { - signSideAfter.setGlowingText(true); - consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); - } - } else if (itemType == Material.INK_SAC) { - if (signSideBefore.isGlowingText() && hasText(signSideBefore)) { - signSideAfter.setGlowingText(false); - consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); - } - } else if (itemType == Material.HONEYCOMB) { - signAfter.setEditable(false); - consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); - } else if (BukkitUtils.isDye(itemType) && hasText(signSideBefore)) { - DyeColor newColor = BukkitUtils.dyeToDyeColor(itemType); - if (newColor != null && signSideBefore.getColor() != newColor) { - signSideAfter.setColor(newColor); - consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); - } - } - } - } - } - } - } else if (type == Material.CAKE) { - if (event.hasItem() && BukkitUtils.isCandle(event.getItem().getType()) && event.useItemInHand() != Result.DENY) { - BlockData newBlockData = Material.valueOf(event.getItem().getType().name() + "_CAKE").createBlockData(); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } else if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20) { - Cake newBlockData = (Cake) blockData.clone(); - if (newBlockData.getBites() < 6) { - newBlockData.setBites(newBlockData.getBites() + 1); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } else { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.AIR.createBlockData()); - } - } - } else if (type == Material.NOTE_BLOCK) { - if (wcfg.isLogging(Logging.NOTEBLOCKINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - NoteBlock newBlockData = (NoteBlock) blockData.clone(); - if (newBlockData.getNote().getOctave() == 2) { - newBlockData.setNote(new Note(0, Tone.F, true)); - } else { - newBlockData.setNote(newBlockData.getNote().sharped()); - } - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - } else if (type == Material.REPEATER) { - if (wcfg.isLogging(Logging.DIODEINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Repeater newBlockData = (Repeater) blockData.clone(); - newBlockData.setDelay((newBlockData.getDelay() % 4) + 1); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - } else if (type == Material.COMPARATOR) { - if (wcfg.isLogging(Logging.COMPARATORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Comparator newBlockData = (Comparator) blockData.clone(); - newBlockData.setMode(newBlockData.getMode() == Mode.COMPARE ? Mode.SUBTRACT : Mode.COMPARE); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - } else if (type == Material.DAYLIGHT_DETECTOR) { - if (wcfg.isLogging(Logging.DAYLIGHTDETECTORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - DaylightDetector newBlockData = (DaylightDetector) blockData.clone(); - newBlockData.setInverted(!newBlockData.isInverted()); - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - } else if (type == Material.TRIPWIRE) { - if (wcfg.isLogging(Logging.TRIPWIREINTERACT) && event.getAction() == Action.PHYSICAL) { - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); - } - } else if (type == Material.FARMLAND) { - if (wcfg.isLogging(Logging.CROPTRAMPLE) && event.getAction() == Action.PHYSICAL) { - // 3 = Dirt ID - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.DIRT.createBlockData()); - // Log the crop on top as being broken - Block trampledCrop = clicked.getRelative(BlockFace.UP); - if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) { - consumer.queueBlockBreak(Actor.actorFromEntity(player), trampledCrop.getState()); - } - } - } else if (type == Material.TURTLE_EGG) { - if (wcfg.isLogging(Logging.BLOCKBREAK) && event.getAction() == Action.PHYSICAL) { - TurtleEgg turtleEggData = (TurtleEgg) blockData; - int eggs = turtleEggData.getEggs(); - if (eggs > 1) { - TurtleEgg turtleEggData2 = (TurtleEgg) turtleEggData.clone(); - turtleEggData2.setEggs(eggs - 1); - consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, turtleEggData2); - } else { - consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, Material.AIR.createBlockData()); - } - } - } else if (type == Material.PUMPKIN) { - if ((wcfg.isLogging(Logging.BLOCKBREAK) || wcfg.isLogging(Logging.BLOCKPLACE)) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - ItemStack inHand = event.getItem(); - if (inHand != null && inHand.getType() == Material.SHEARS) { - BlockFace clickedFace = event.getBlockFace(); - Directional newBlockData = (Directional) Material.CARVED_PUMPKIN.createBlockData(); - if (clickedFace == BlockFace.NORTH || clickedFace == BlockFace.SOUTH || clickedFace == BlockFace.EAST || clickedFace == BlockFace.WEST) { - newBlockData.setFacing(clickedFace); - } else { - // use player distance to calculate the facing - Location playerLoc = player.getLocation(); - playerLoc.subtract(0.5, 0, 0.5); - double dx = playerLoc.getX() - loc.getX(); - double dz = playerLoc.getZ() - loc.getZ(); - if (Math.abs(dx) > Math.abs(dz)) { - newBlockData.setFacing(dx > 0 ? BlockFace.EAST : BlockFace.WEST); - } else { - newBlockData.setFacing(dz > 0 ? BlockFace.SOUTH : BlockFace.NORTH); - } - } - consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); - } - } - } - } - } - - private boolean hasText(SignSide signSide) { - for (int i = 0; i < 4; i++) { - if (!signSide.getLine(i).isEmpty()) { - return true; - } - } - return false; - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onGenericGameEvent(GenericGameEvent event) { - if (lastInteractionPlayer != null && event.getEntity() != null && event.getEntity().getUniqueId().equals(lastInteractionPlayer) && lastInteractionLocation != null && event.getLocation().equals(lastInteractionLocation)) { - if (lastInteractionBlockData instanceof Candle) { - Candle previousCandle = (Candle) lastInteractionBlockData; - if (previousCandle.isLit()) { - BlockData newData = lastInteractionLocation.getBlock().getBlockData(); - if (newData instanceof Candle) { - Candle newCandle = (Candle) newData; - if (!newCandle.isLit() && !newCandle.isWaterlogged()) { - // log candle extinguish - consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), lastInteractionLocation, lastInteractionBlockData, newData); - } - } - } - } else if (lastInteractionBlockData instanceof Lightable && BukkitUtils.isCandleCake(lastInteractionBlockData.getMaterial())) { - Lightable previousLightable = (Lightable) lastInteractionBlockData; - BlockData newData = lastInteractionLocation.getBlock().getBlockData(); - if (event.getEvent().equals(GameEvent.EAT)) { - final WorldConfig wcfg = getWorldConfig(event.getLocation().getWorld()); - if (wcfg.isLogging(Logging.CAKEEAT)) { - // nom nom (don't know why newData is incorrect here) - newData = Material.CAKE.createBlockData(); - ((Cake) newData).setBites(1); - consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), lastInteractionLocation, lastInteractionBlockData, newData); - } - } else if (previousLightable.isLit()) { - if (newData instanceof Lightable) { - Lightable newLightable = (Lightable) newData; - if (!newLightable.isLit()) { - // log cake extinguish - consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), lastInteractionLocation, lastInteractionBlockData, newData); - } - } - } - } - } - lastInteractionPlayer = null; - lastInteractionBlockData = null; - lastInteractionLocation = null; - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.WorldConfig; +import de.diddiz.LogBlock.util.BukkitUtils; +import de.diddiz.LogBlock.util.Reflections; +import java.util.UUID; +import org.bukkit.DyeColor; +import org.bukkit.GameEvent; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Note; +import org.bukkit.Note.Tone; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.block.Sign; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Directional; +import org.bukkit.block.data.Lightable; +import org.bukkit.block.data.Openable; +import org.bukkit.block.data.type.Cake; +import org.bukkit.block.data.type.Candle; +import org.bukkit.block.data.type.Comparator; +import org.bukkit.block.data.type.Comparator.Mode; +import org.bukkit.block.data.type.DaylightDetector; +import org.bukkit.block.data.type.Door; +import org.bukkit.block.data.type.NoteBlock; +import org.bukkit.block.data.type.Repeater; +import org.bukkit.block.data.type.Switch; +import org.bukkit.block.data.type.TurtleEgg; +import org.bukkit.block.sign.Side; +import org.bukkit.block.sign.SignSide; +import org.bukkit.entity.Player; +import org.bukkit.event.Event.Result; +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.world.GenericGameEvent; +import org.bukkit.inventory.ItemStack; + +import static de.diddiz.LogBlock.config.Config.getWorldConfig; + +public class InteractLogging extends LoggingListener { + public InteractLogging(LogBlock lb) { + super(lb); + } + + private UUID lastInteractionPlayer; + private BlockData lastInteractionBlockData; + private Location lastInteractionLocation; + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerInteract(PlayerInteractEvent event) { + final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld()); + if (wcfg != null) { + final Block clicked = event.getClickedBlock(); + if (clicked == null) { + return; + } + final BlockData blockData = clicked.getBlockData(); + final Material type = blockData.getMaterial(); + final Player player = event.getPlayer(); + final Location loc = clicked.getLocation(); + lastInteractionPlayer = player.getUniqueId(); + lastInteractionBlockData = blockData; + lastInteractionLocation = loc; + + if (BukkitUtils.isFenceGate(type) || BukkitUtils.isWoodenTrapdoor(type)) { + if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Openable newBlockData = (Openable) blockData.clone(); + newBlockData.setOpen(!newBlockData.isOpen()); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } else if (BukkitUtils.isPressurePlate(type)) { + if (wcfg.isLogging(Logging.PRESUREPLATEINTERACT) && event.getAction() == Action.PHYSICAL) { + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + } + } else if (BukkitUtils.isWoodenDoor(type)) { + if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Door newBlockData = (Door) blockData.clone(); + newBlockData.setOpen(!newBlockData.isOpen()); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } else if (BukkitUtils.isButton(type) || type == Material.LEVER) { + if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Switch newBlockData = (Switch) blockData.clone(); + if (!newBlockData.isPowered() || type == Material.LEVER) { + newBlockData.setPowered(!newBlockData.isPowered()); + } + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } else if (BukkitUtils.isSign(type)) { + if (wcfg.isLogging(Logging.SIGNTEXT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getItem() != null) { + Material itemType = event.getItem().getType(); + if (BukkitUtils.isDye(itemType) || itemType == Material.GLOW_INK_SAC || itemType == Material.INK_SAC || itemType == Material.HONEYCOMB) { + final BlockState before = event.getClickedBlock().getState(); + if (before instanceof Sign signBefore) { + boolean waxed = Reflections.isSignWaxed(signBefore); + if (!waxed) { + final Sign signAfter = (Sign) event.getClickedBlock().getState(); + Side side = BukkitUtils.getFacingSignSide(player, clicked); + SignSide signSideBefore = signBefore.getSide(side); + SignSide signSideAfter = signAfter.getSide(side); + if (itemType == Material.GLOW_INK_SAC) { + if (!signSideBefore.isGlowingText() && hasText(signSideBefore)) { + signSideAfter.setGlowingText(true); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } + } else if (itemType == Material.INK_SAC) { + if (signSideBefore.isGlowingText() && hasText(signSideBefore)) { + signSideAfter.setGlowingText(false); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } + } else if (itemType == Material.HONEYCOMB) { + signAfter.setEditable(false); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } else if (BukkitUtils.isDye(itemType) && hasText(signSideBefore)) { + DyeColor newColor = BukkitUtils.dyeToDyeColor(itemType); + if (newColor != null && signSideBefore.getColor() != newColor) { + signSideAfter.setColor(newColor); + consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); + } + } + } + } + } + } + } else if (type == Material.CAKE) { + if (event.hasItem() && BukkitUtils.isCandle(event.getItem().getType()) && event.useItemInHand() != Result.DENY) { + BlockData newBlockData = Material.valueOf(event.getItem().getType().name() + "_CAKE").createBlockData(); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } else if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20) { + Cake newBlockData = (Cake) blockData.clone(); + if (newBlockData.getBites() < 6) { + newBlockData.setBites(newBlockData.getBites() + 1); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } else { + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.AIR.createBlockData()); + } + } + } else if (type == Material.NOTE_BLOCK) { + if (wcfg.isLogging(Logging.NOTEBLOCKINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + NoteBlock newBlockData = (NoteBlock) blockData.clone(); + if (newBlockData.getNote().getOctave() == 2) { + newBlockData.setNote(new Note(0, Tone.F, true)); + } else { + newBlockData.setNote(newBlockData.getNote().sharped()); + } + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } else if (type == Material.REPEATER) { + if (wcfg.isLogging(Logging.DIODEINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Repeater newBlockData = (Repeater) blockData.clone(); + newBlockData.setDelay((newBlockData.getDelay() % 4) + 1); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } else if (type == Material.COMPARATOR) { + if (wcfg.isLogging(Logging.COMPARATORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Comparator newBlockData = (Comparator) blockData.clone(); + newBlockData.setMode(newBlockData.getMode() == Mode.COMPARE ? Mode.SUBTRACT : Mode.COMPARE); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } else if (type == Material.DAYLIGHT_DETECTOR) { + if (wcfg.isLogging(Logging.DAYLIGHTDETECTORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + DaylightDetector newBlockData = (DaylightDetector) blockData.clone(); + newBlockData.setInverted(!newBlockData.isInverted()); + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } else if (type == Material.TRIPWIRE) { + if (wcfg.isLogging(Logging.TRIPWIREINTERACT) && event.getAction() == Action.PHYSICAL) { + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, blockData); + } + } else if (type == Material.FARMLAND) { + if (wcfg.isLogging(Logging.CROPTRAMPLE) && event.getAction() == Action.PHYSICAL) { + // 3 = Dirt ID + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.DIRT.createBlockData()); + // Log the crop on top as being broken + Block trampledCrop = clicked.getRelative(BlockFace.UP); + if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) { + consumer.queueBlockBreak(Actor.actorFromEntity(player), trampledCrop.getState()); + } + } + } else if (type == Material.TURTLE_EGG) { + if (wcfg.isLogging(Logging.BLOCKBREAK) && event.getAction() == Action.PHYSICAL) { + TurtleEgg turtleEggData = (TurtleEgg) blockData; + int eggs = turtleEggData.getEggs(); + if (eggs > 1) { + TurtleEgg turtleEggData2 = (TurtleEgg) turtleEggData.clone(); + turtleEggData2.setEggs(eggs - 1); + consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, turtleEggData2); + } else { + consumer.queueBlock(Actor.actorFromEntity(player), loc, turtleEggData, Material.AIR.createBlockData()); + } + } + } else if (type == Material.PUMPKIN) { + if ((wcfg.isLogging(Logging.BLOCKBREAK) || wcfg.isLogging(Logging.BLOCKPLACE)) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { + ItemStack inHand = event.getItem(); + if (inHand != null && inHand.getType() == Material.SHEARS) { + BlockFace clickedFace = event.getBlockFace(); + Directional newBlockData = (Directional) Material.CARVED_PUMPKIN.createBlockData(); + if (clickedFace == BlockFace.NORTH || clickedFace == BlockFace.SOUTH || clickedFace == BlockFace.EAST || clickedFace == BlockFace.WEST) { + newBlockData.setFacing(clickedFace); + } else { + // use player distance to calculate the facing + Location playerLoc = player.getLocation(); + playerLoc.subtract(0.5, 0, 0.5); + double dx = playerLoc.getX() - loc.getX(); + double dz = playerLoc.getZ() - loc.getZ(); + if (Math.abs(dx) > Math.abs(dz)) { + newBlockData.setFacing(dx > 0 ? BlockFace.EAST : BlockFace.WEST); + } else { + newBlockData.setFacing(dz > 0 ? BlockFace.SOUTH : BlockFace.NORTH); + } + } + consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, newBlockData); + } + } + } + } + } + + private boolean hasText(SignSide signSide) { + for (int i = 0; i < 4; i++) { + if (!signSide.getLine(i).isEmpty()) { + return true; + } + } + return false; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onGenericGameEvent(GenericGameEvent event) { + if (lastInteractionPlayer != null && event.getEntity() != null && event.getEntity().getUniqueId().equals(lastInteractionPlayer) && lastInteractionLocation != null && event.getLocation().equals(lastInteractionLocation)) { + if (lastInteractionBlockData instanceof Candle) { + Candle previousCandle = (Candle) lastInteractionBlockData; + if (previousCandle.isLit()) { + BlockData newData = lastInteractionLocation.getBlock().getBlockData(); + if (newData instanceof Candle) { + Candle newCandle = (Candle) newData; + if (!newCandle.isLit() && !newCandle.isWaterlogged()) { + // log candle extinguish + consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), lastInteractionLocation, lastInteractionBlockData, newData); + } + } + } + } else if (lastInteractionBlockData instanceof Lightable && BukkitUtils.isCandleCake(lastInteractionBlockData.getMaterial())) { + Lightable previousLightable = (Lightable) lastInteractionBlockData; + BlockData newData = lastInteractionLocation.getBlock().getBlockData(); + if (event.getEvent().equals(GameEvent.EAT)) { + final WorldConfig wcfg = getWorldConfig(event.getLocation().getWorld()); + if (wcfg.isLogging(Logging.CAKEEAT)) { + // nom nom (don't know why newData is incorrect here) + newData = Material.CAKE.createBlockData(); + ((Cake) newData).setBites(1); + consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), lastInteractionLocation, lastInteractionBlockData, newData); + } + } else if (previousLightable.isLit()) { + if (newData instanceof Lightable) { + Lightable newLightable = (Lightable) newData; + if (!newLightable.isLit()) { + // log cake extinguish + consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), lastInteractionLocation, lastInteractionBlockData, newData); + } + } + } + } + } + lastInteractionPlayer = null; + lastInteractionBlockData = null; + lastInteractionLocation = null; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java index 3011fc21..ac6d3dd0 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java @@ -1,51 +1,51 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.Actor; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import de.diddiz.LogBlock.config.Config.*; -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.*; - -public class KillLogging extends LoggingListener { - - public KillLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onEntityDeath(EntityDeathEvent deathEvent) { - 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; - } - consumer.queueKill(new Actor(event.getCause().toString()), victim); - } - } - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.Config.*; +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.*; + +public class KillLogging extends LoggingListener { + + public KillLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onEntityDeath(EntityDeathEvent deathEvent) { + 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; + } + consumer.queueKill(new Actor(event.getCause().toString()), victim); + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/LeavesDecayLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/LeavesDecayLogging.java index 5b1a9d8d..c75ea06f 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/LeavesDecayLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/LeavesDecayLogging.java @@ -1,26 +1,26 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.Actor; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.LeavesDecayEvent; - -import static de.diddiz.LogBlock.config.Config.isLogging; -import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockBreak; -import static de.diddiz.LogBlock.util.LoggingUtil.smartLogFallables; - -public class LeavesDecayLogging extends LoggingListener { - public LeavesDecayLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onLeavesDecay(LeavesDecayEvent event) { - if (isLogging(event.getBlock().getWorld(), Logging.LEAVESDECAY)) { - smartLogBlockBreak(consumer, new Actor("LeavesDecay"), event.getBlock()); - smartLogFallables(consumer, new Actor("LeavesDecay"), event.getBlock()); - } - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.LeavesDecayEvent; + +import static de.diddiz.LogBlock.config.Config.isLogging; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogBlockBreak; +import static de.diddiz.LogBlock.util.LoggingUtil.smartLogFallables; + +public class LeavesDecayLogging extends LoggingListener { + public LeavesDecayLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onLeavesDecay(LeavesDecayEvent event) { + if (isLogging(event.getBlock().getWorld(), Logging.LEAVESDECAY)) { + smartLogBlockBreak(consumer, new Actor("LeavesDecay"), event.getBlock()); + smartLogFallables(consumer, new Actor("LeavesDecay"), event.getBlock()); + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/LoggingListener.java b/src/main/java/de/diddiz/LogBlock/listeners/LoggingListener.java index 4f910892..ca5db00a 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/LoggingListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/LoggingListener.java @@ -1,13 +1,13 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.Consumer; -import de.diddiz.LogBlock.LogBlock; -import org.bukkit.event.Listener; - -public class LoggingListener implements Listener { - protected final Consumer consumer; - - public LoggingListener(LogBlock lb) { - consumer = lb.getConsumer(); - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Consumer; +import de.diddiz.LogBlock.LogBlock; +import org.bukkit.event.Listener; + +public class LoggingListener implements Listener { + protected final Consumer consumer; + + public LoggingListener(LogBlock lb) { + consumer = lb.getConsumer(); + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/PlayerInfoLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/PlayerInfoLogging.java index fbdf9c4a..f10d65d6 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/PlayerInfoLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/PlayerInfoLogging.java @@ -1,43 +1,43 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.config.Config; - -import java.util.HashMap; -import java.util.UUID; - -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -public class PlayerInfoLogging extends LoggingListener { - - private final HashMap playerLogins = new HashMap<>(); - - public PlayerInfoLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerJoin(PlayerJoinEvent event) { - playerLogins.put(event.getPlayer().getUniqueId(), System.currentTimeMillis()); - consumer.queueJoin(event.getPlayer()); - } - - @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerQuit(PlayerQuitEvent event) { - onPlayerQuit(event.getPlayer()); - } - - public void onPlayerQuit(Player player) { - Long joinTime = playerLogins.remove(player.getUniqueId()); - if (Config.logPlayerInfo && joinTime != null) { - long onlineTime = (System.currentTimeMillis() - joinTime) / 1000; - if (onlineTime > 0) { - consumer.queueLeave(player, onlineTime); - } - } - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.config.Config; + +import java.util.HashMap; +import java.util.UUID; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +public class PlayerInfoLogging extends LoggingListener { + + private final HashMap playerLogins = new HashMap<>(); + + public PlayerInfoLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerJoin(PlayerJoinEvent event) { + playerLogins.put(event.getPlayer().getUniqueId(), System.currentTimeMillis()); + consumer.queueJoin(event.getPlayer()); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerQuit(PlayerQuitEvent event) { + onPlayerQuit(event.getPlayer()); + } + + public void onPlayerQuit(Player player) { + Long joinTime = playerLogins.remove(player.getUniqueId()); + if (Config.logPlayerInfo && joinTime != null) { + long onlineTime = (System.currentTimeMillis() - joinTime) / 1000; + if (onlineTime > 0) { + consumer.queueLeave(player, onlineTime); + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java index ce846761..d74e753e 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java @@ -1,33 +1,33 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.Actor; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import org.bukkit.block.BlockState; -import org.bukkit.block.Sign; -import org.bukkit.block.sign.SignSide; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.SignChangeEvent; - -import static de.diddiz.LogBlock.config.Config.isLogging; - -public class SignChangeLogging extends LoggingListener { - public SignChangeLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onSignChange(SignChangeEvent event) { - if (isLogging(event.getBlock().getWorld(), Logging.SIGNTEXT)) { - BlockState newState = event.getBlock().getState(); - if (newState instanceof Sign sign) { - SignSide signSide = sign.getSide(event.getSide()); - for (int i = 0; i < 4; i++) { - signSide.setLine(i, event.getLine(i)); - } - consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getState(), newState); - } - } - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import org.bukkit.block.BlockState; +import org.bukkit.block.Sign; +import org.bukkit.block.sign.SignSide; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.SignChangeEvent; + +import static de.diddiz.LogBlock.config.Config.isLogging; + +public class SignChangeLogging extends LoggingListener { + public SignChangeLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onSignChange(SignChangeEvent event) { + if (isLogging(event.getBlock().getWorld(), Logging.SIGNTEXT)) { + BlockState newState = event.getBlock().getState(); + if (newState instanceof Sign sign) { + SignSide signSide = sign.getSide(event.getSide()); + for (int i = 0; i < 4; i++) { + signSide.setLine(i, event.getLine(i)); + } + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getState(), newState); + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/SnowFadeLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/SnowFadeLogging.java index 1223893f..9c411ba9 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/SnowFadeLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/SnowFadeLogging.java @@ -1,28 +1,28 @@ -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.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.BlockFadeEvent; - -import static de.diddiz.LogBlock.config.Config.isLogging; - -public class SnowFadeLogging extends LoggingListener { - public SnowFadeLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockFade(BlockFadeEvent event) { - if (isLogging(event.getBlock().getWorld(), Logging.SNOWFADE)) { - final Material type = event.getBlock().getType(); - if (type == Material.SNOW || type == Material.ICE) { - consumer.queueBlockReplace(new Actor("SnowFade"), event.getBlock().getState(), event.getNewState()); - } - } - } -} +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.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockFadeEvent; + +import static de.diddiz.LogBlock.config.Config.isLogging; + +public class SnowFadeLogging extends LoggingListener { + public SnowFadeLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockFade(BlockFadeEvent event) { + if (isLogging(event.getBlock().getWorld(), Logging.SNOWFADE)) { + final Material type = event.getBlock().getType(); + if (type == Material.SNOW || type == Material.ICE) { + consumer.queueBlockReplace(new Actor("SnowFade"), event.getBlock().getState(), event.getNewState()); + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java index b269f029..6d4a2479 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java @@ -1,28 +1,28 @@ -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.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.BlockFormEvent; - -import static de.diddiz.LogBlock.config.Config.isLogging; - -public class SnowFormLogging extends LoggingListener { - public SnowFormLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockForm(BlockFormEvent event) { - if (isLogging(event.getBlock().getWorld(), Logging.SNOWFORM)) { - final Material type = event.getNewState().getType(); - if (type == Material.SNOW || type == Material.ICE) { - consumer.queueBlockReplace(new Actor("SnowForm"), event.getBlock().getState(), event.getNewState()); - } - } - } -} +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.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockFormEvent; + +import static de.diddiz.LogBlock.config.Config.isLogging; + +public class SnowFormLogging extends LoggingListener { + public SnowFormLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockForm(BlockFormEvent event) { + if (isLogging(event.getBlock().getWorld(), Logging.SNOWFORM)) { + final Material type = event.getNewState().getType(); + if (type == Material.SNOW || type == Material.ICE) { + consumer.queueBlockReplace(new Actor("SnowForm"), event.getBlock().getState(), event.getNewState()); + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/StructureGrowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/StructureGrowLogging.java index 62f43573..93b395f8 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/StructureGrowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/StructureGrowLogging.java @@ -1,34 +1,34 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.Actor; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import de.diddiz.LogBlock.config.WorldConfig; -import org.bukkit.block.BlockState; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.world.StructureGrowEvent; - -import static de.diddiz.LogBlock.config.Config.getWorldConfig; - -public class StructureGrowLogging extends LoggingListener { - public StructureGrowLogging(LogBlock lb) { - super(lb); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onStructureGrow(StructureGrowEvent event) { - final WorldConfig wcfg = getWorldConfig(event.getWorld()); - if (wcfg != null) { - if (!wcfg.isLogging(Logging.NATURALSTRUCTUREGROW)) { - return; - } - if (!event.isFromBonemeal()) { - final Actor actor = new Actor("NaturalGrow"); - for (final BlockState state : event.getBlocks()) { - consumer.queueBlockReplace(actor, state.getBlock().getState(), state); - } - } - } - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.WorldConfig; +import org.bukkit.block.BlockState; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.world.StructureGrowEvent; + +import static de.diddiz.LogBlock.config.Config.getWorldConfig; + +public class StructureGrowLogging extends LoggingListener { + public StructureGrowLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onStructureGrow(StructureGrowEvent event) { + final WorldConfig wcfg = getWorldConfig(event.getWorld()); + if (wcfg != null) { + if (!wcfg.isLogging(Logging.NATURALSTRUCTUREGROW)) { + return; + } + if (!event.isFromBonemeal()) { + final Actor actor = new Actor("NaturalGrow"); + for (final BlockState state : event.getBlocks()) { + consumer.queueBlockReplace(actor, state.getBlock().getState(), state); + } + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java index 7a192c59..9e468676 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java @@ -1,151 +1,151 @@ -package de.diddiz.LogBlock.listeners; - -import de.diddiz.LogBlock.*; -import de.diddiz.LogBlock.events.ToolUseEvent; -import de.diddiz.LogBlock.util.BukkitUtils; -import de.diddiz.LogBlock.util.CuboidRegion; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerChangedWorldEvent; -import org.bukkit.event.player.PlayerDropItemEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.inventory.ItemStack; - -import java.util.Map.Entry; - -import static de.diddiz.LogBlock.Session.getSession; -import static de.diddiz.LogBlock.Session.hasSession; -import static de.diddiz.LogBlock.config.Config.isLogged; -import static de.diddiz.LogBlock.config.Config.toolsByType; - -public class ToolListener implements Listener { - private final CommandsHandler handler; - private final LogBlock logblock; - - public ToolListener(LogBlock logblock) { - this.logblock = logblock; - handler = logblock.getCommandsHandler(); - } - - @EventHandler - public void onPlayerInteract(PlayerInteractEvent event) { - if (event.getMaterial() != null) { - final Action action = event.getAction(); - final Material type = event.getMaterial(); - final Tool tool = toolsByType.get(type); - final Player player = event.getPlayer(); - if (tool != null && (action == Action.RIGHT_CLICK_BLOCK || action == Action.LEFT_CLICK_BLOCK) && logblock.hasPermission(player, "logblock.tools." + tool.name)) { - final ToolBehavior behavior = action == Action.RIGHT_CLICK_BLOCK ? tool.rightClickBehavior : tool.leftClickBehavior; - final ToolData toolData = getSession(player).toolData.get(tool); - if (behavior != ToolBehavior.NONE && toolData.enabled) { - if (!isLogged(player.getWorld())) { - player.sendMessage(ChatColor.RED + "This world is not currently logged."); - event.setCancelled(true); - return; - } - final Block block = event.getClickedBlock(); - final QueryParams params = toolData.params.clone(); - params.loc = null; - params.sel = null; - if (behavior == ToolBehavior.BLOCK) { - params.setLocation(block.getRelative(event.getBlockFace()).getLocation()); - } else if (tool.params.radius != 0) { - params.setLocation(block.getLocation()); - } else { - Block otherHalfChest = BukkitUtils.getConnectedChest(block); - if (otherHalfChest == null) { - params.setLocation(block.getLocation()); - } else { - params.setSelection(CuboidRegion.fromCorners(block.getLocation().getWorld(), block.getLocation(), otherHalfChest.getLocation())); - } - } - try { - params.validate(); - if (this.callToolUseEvent(new ToolUseEvent(player, tool, behavior, params))) { - return; - } - if (toolData.mode == ToolMode.ROLLBACK) { - handler.new CommandRollback(player, params, true); - } else if (toolData.mode == ToolMode.REDO) { - handler.new CommandRedo(player, params, true); - } else if (toolData.mode == ToolMode.CLEARLOG) { - handler.new CommandClearLog(player, params, true); - } else if (toolData.mode == ToolMode.WRITELOGFILE) { - handler.new CommandWriteLogFile(player, params, true); - } else { - handler.new CommandLookup(player, params, true); - } - } catch (final Exception ex) { - player.sendMessage(ChatColor.RED + ex.getMessage()); - } - event.setCancelled(true); - } - } - } - } - - private boolean callToolUseEvent(ToolUseEvent event) { - this.logblock.getServer().getPluginManager().callEvent(event); - return event.isCancelled(); - } - - @EventHandler - public void onPlayerChangedWorld(PlayerChangedWorldEvent event) { - final Player player = event.getPlayer(); - if (hasSession(player)) { - final Session session = getSession(player); - for (final Entry entry : session.toolData.entrySet()) { - final Tool tool = entry.getKey(); - final ToolData toolData = entry.getValue(); - if (toolData.enabled && !logblock.hasPermission(player, "logblock.tools." + tool.name)) { - toolData.enabled = false; - if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) { - player.getInventory().removeItem(new ItemStack(tool.item, 1)); - } - player.sendMessage(ChatColor.GREEN + "Tool disabled."); - } - } - } - } - - @EventHandler - public void onPlayerDropItem(PlayerDropItemEvent event) { - final Player player = event.getPlayer(); - if (hasSession(player)) { - final Session session = getSession(player); - for (final Entry entry : session.toolData.entrySet()) { - final Tool tool = entry.getKey(); - final ToolData toolData = entry.getValue(); - final Material item = event.getItemDrop().getItemStack().getType(); - if (item == tool.item && toolData.enabled) { - if (tool.dropToDisable) { - toolData.enabled = false; - ItemStack stack = event.getItemDrop().getItemStack(); - if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) { - if (stack.isSimilar(new ItemStack(item))) { - if (stack.getAmount() > 1) { - stack.setAmount(stack.getAmount() - 1); - event.getItemDrop().setItemStack(stack); - } else { - event.getItemDrop().remove(); - } - } - } - if (BukkitUtils.hasInventoryStorageSpaceFor(player.getInventory(), stack)) { - event.setCancelled(true); - } - player.sendMessage(ChatColor.GREEN + "Tool disabled."); - } else if (!tool.canDrop) { - player.sendMessage(ChatColor.RED + "You cannot drop this tool."); - event.setCancelled(true); - } - } - } - } - } -} +package de.diddiz.LogBlock.listeners; + +import de.diddiz.LogBlock.*; +import de.diddiz.LogBlock.events.ToolUseEvent; +import de.diddiz.LogBlock.util.BukkitUtils; +import de.diddiz.LogBlock.util.CuboidRegion; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.Map.Entry; + +import static de.diddiz.LogBlock.Session.getSession; +import static de.diddiz.LogBlock.Session.hasSession; +import static de.diddiz.LogBlock.config.Config.isLogged; +import static de.diddiz.LogBlock.config.Config.toolsByType; + +public class ToolListener implements Listener { + private final CommandsHandler handler; + private final LogBlock logblock; + + public ToolListener(LogBlock logblock) { + this.logblock = logblock; + handler = logblock.getCommandsHandler(); + } + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + if (event.getMaterial() != null) { + final Action action = event.getAction(); + final Material type = event.getMaterial(); + final Tool tool = toolsByType.get(type); + final Player player = event.getPlayer(); + if (tool != null && (action == Action.RIGHT_CLICK_BLOCK || action == Action.LEFT_CLICK_BLOCK) && logblock.hasPermission(player, "logblock.tools." + tool.name)) { + final ToolBehavior behavior = action == Action.RIGHT_CLICK_BLOCK ? tool.rightClickBehavior : tool.leftClickBehavior; + final ToolData toolData = getSession(player).toolData.get(tool); + if (behavior != ToolBehavior.NONE && toolData.enabled) { + if (!isLogged(player.getWorld())) { + player.sendMessage(ChatColor.RED + "This world is not currently logged."); + event.setCancelled(true); + return; + } + final Block block = event.getClickedBlock(); + final QueryParams params = toolData.params.clone(); + params.loc = null; + params.sel = null; + if (behavior == ToolBehavior.BLOCK) { + params.setLocation(block.getRelative(event.getBlockFace()).getLocation()); + } else if (tool.params.radius != 0) { + params.setLocation(block.getLocation()); + } else { + Block otherHalfChest = BukkitUtils.getConnectedChest(block); + if (otherHalfChest == null) { + params.setLocation(block.getLocation()); + } else { + params.setSelection(CuboidRegion.fromCorners(block.getLocation().getWorld(), block.getLocation(), otherHalfChest.getLocation())); + } + } + try { + params.validate(); + if (this.callToolUseEvent(new ToolUseEvent(player, tool, behavior, params))) { + return; + } + if (toolData.mode == ToolMode.ROLLBACK) { + handler.new CommandRollback(player, params, true); + } else if (toolData.mode == ToolMode.REDO) { + handler.new CommandRedo(player, params, true); + } else if (toolData.mode == ToolMode.CLEARLOG) { + handler.new CommandClearLog(player, params, true); + } else if (toolData.mode == ToolMode.WRITELOGFILE) { + handler.new CommandWriteLogFile(player, params, true); + } else { + handler.new CommandLookup(player, params, true); + } + } catch (final Exception ex) { + player.sendMessage(ChatColor.RED + ex.getMessage()); + } + event.setCancelled(true); + } + } + } + } + + private boolean callToolUseEvent(ToolUseEvent event) { + this.logblock.getServer().getPluginManager().callEvent(event); + return event.isCancelled(); + } + + @EventHandler + public void onPlayerChangedWorld(PlayerChangedWorldEvent event) { + final Player player = event.getPlayer(); + if (hasSession(player)) { + final Session session = getSession(player); + for (final Entry entry : session.toolData.entrySet()) { + final Tool tool = entry.getKey(); + final ToolData toolData = entry.getValue(); + if (toolData.enabled && !logblock.hasPermission(player, "logblock.tools." + tool.name)) { + toolData.enabled = false; + if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) { + player.getInventory().removeItem(new ItemStack(tool.item, 1)); + } + player.sendMessage(ChatColor.GREEN + "Tool disabled."); + } + } + } + } + + @EventHandler + public void onPlayerDropItem(PlayerDropItemEvent event) { + final Player player = event.getPlayer(); + if (hasSession(player)) { + final Session session = getSession(player); + for (final Entry entry : session.toolData.entrySet()) { + final Tool tool = entry.getKey(); + final ToolData toolData = entry.getValue(); + final Material item = event.getItemDrop().getItemStack().getType(); + if (item == tool.item && toolData.enabled) { + if (tool.dropToDisable) { + toolData.enabled = false; + ItemStack stack = event.getItemDrop().getItemStack(); + if (tool.removeOnDisable && logblock.hasPermission(player, "logblock.spawnTools")) { + if (stack.isSimilar(new ItemStack(item))) { + if (stack.getAmount() > 1) { + stack.setAmount(stack.getAmount() - 1); + event.getItemDrop().setItemStack(stack); + } else { + event.getItemDrop().remove(); + } + } + } + if (BukkitUtils.hasInventoryStorageSpaceFor(player.getInventory(), stack)) { + event.setCancelled(true); + } + player.sendMessage(ChatColor.GREEN + "Tool disabled."); + } else if (!tool.canDrop) { + player.sendMessage(ChatColor.RED + "You cannot drop this tool."); + event.setCancelled(true); + } + } + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java index 3f8c9a8e..04c452ce 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java @@ -1,24 +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. - } - } -} +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. + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 91d19c0c..96fb0854 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -1,1312 +1,1312 @@ -package de.diddiz.LogBlock.util; - -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.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.Set; -import java.util.UUID; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.HoverEvent; -import net.md_5.bungee.api.chat.HoverEvent.Action; -import net.md_5.bungee.api.chat.ItemTag; -import net.md_5.bungee.api.chat.TextComponent; -import net.md_5.bungee.api.chat.hover.content.Item; -import net.md_5.bungee.api.chat.hover.content.Text; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Chunk; -import org.bukkit.DyeColor; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockState; -import org.bukkit.block.DoubleChest; -import org.bukkit.block.data.Bisected; -import org.bukkit.block.data.Bisected.Half; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Directional; -import org.bukkit.block.data.Rotatable; -import org.bukkit.block.data.type.HangingSign; -import org.bukkit.block.data.type.Sign; -import org.bukkit.block.data.type.Slab; -import org.bukkit.block.data.type.Slab.Type; -import org.bukkit.block.data.type.Stairs; -import org.bukkit.block.data.type.WallHangingSign; -import org.bukkit.block.data.type.WallSign; -import org.bukkit.block.sign.Side; -import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.entity.TNTPrimed; -import org.bukkit.inventory.EquipmentSlot; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryHolder; -import org.bukkit.inventory.ItemStack; - -public class BukkitUtils { - private static final Set> blockEquivalents; - private static final Set relativeBreakable; - private static final Set relativeTopBreakable; - private static final Set fallingEntityKillers; - - private static final Set cropBlocks; - private static final Set containerBlocks; - private static final Set shulkerBoxBlocks; - - private static final Set singleBlockPlants; - private static final Set doublePlants; - - private static final Set nonFluidProofBlocks; - - private static final Set bedBlocks; - - private static final Map projectileItems; - private static final HashSet signs; - private static final HashSet wallSigns; - private static final HashSet hangingSigns; - private static final HashSet hangingWallSigns; - private static final HashSet allSigns; - private static final Set unmodifiableSigns; - private static final HashSet buttons; - private static final HashSet pressurePlates; - private static final HashSet woodenDoors; - private static final HashSet slabs; - private static final HashSet concreteBlocks; - private static final HashMap dyes; - private static final HashSet alwaysWaterlogged; - private static final HashSet candles; - private static final HashSet candleCakes; - private static final HashSet fenceGates; - private static final HashSet woodenTrapdoors; - - static { - fenceGates = new HashSet<>(); - fenceGates.add(Material.OAK_FENCE_GATE); - fenceGates.add(Material.SPRUCE_FENCE_GATE); - fenceGates.add(Material.BIRCH_FENCE_GATE); - fenceGates.add(Material.JUNGLE_FENCE_GATE); - fenceGates.add(Material.ACACIA_FENCE_GATE); - fenceGates.add(Material.DARK_OAK_FENCE_GATE); - fenceGates.add(Material.WARPED_FENCE_GATE); - fenceGates.add(Material.CRIMSON_FENCE_GATE); - fenceGates.add(Material.MANGROVE_FENCE_GATE); - fenceGates.add(Material.BAMBOO_FENCE_GATE); - fenceGates.add(Material.CHERRY_FENCE_GATE); - - woodenTrapdoors = new HashSet<>(); - woodenTrapdoors.add(Material.OAK_TRAPDOOR); - woodenTrapdoors.add(Material.SPRUCE_TRAPDOOR); - woodenTrapdoors.add(Material.BIRCH_TRAPDOOR); - woodenTrapdoors.add(Material.JUNGLE_TRAPDOOR); - woodenTrapdoors.add(Material.ACACIA_TRAPDOOR); - woodenTrapdoors.add(Material.DARK_OAK_TRAPDOOR); - woodenTrapdoors.add(Material.WARPED_TRAPDOOR); - woodenTrapdoors.add(Material.CRIMSON_TRAPDOOR); - woodenTrapdoors.add(Material.MANGROVE_TRAPDOOR); - woodenTrapdoors.add(Material.BAMBOO_TRAPDOOR); - woodenTrapdoors.add(Material.CHERRY_TRAPDOOR); - - pressurePlates = new HashSet<>(); - pressurePlates.add(Material.OAK_PRESSURE_PLATE); - pressurePlates.add(Material.SPRUCE_PRESSURE_PLATE); - pressurePlates.add(Material.BIRCH_PRESSURE_PLATE); - pressurePlates.add(Material.JUNGLE_PRESSURE_PLATE); - pressurePlates.add(Material.ACACIA_PRESSURE_PLATE); - pressurePlates.add(Material.DARK_OAK_PRESSURE_PLATE); - pressurePlates.add(Material.WARPED_PRESSURE_PLATE); - pressurePlates.add(Material.CRIMSON_PRESSURE_PLATE); - pressurePlates.add(Material.MANGROVE_PRESSURE_PLATE); - pressurePlates.add(Material.BAMBOO_PRESSURE_PLATE); - pressurePlates.add(Material.CHERRY_PRESSURE_PLATE); - pressurePlates.add(Material.STONE_PRESSURE_PLATE); - pressurePlates.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); - pressurePlates.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); - - woodenDoors = new HashSet<>(); - woodenDoors.add(Material.OAK_DOOR); - woodenDoors.add(Material.SPRUCE_DOOR); - woodenDoors.add(Material.BIRCH_DOOR); - woodenDoors.add(Material.JUNGLE_DOOR); - woodenDoors.add(Material.ACACIA_DOOR); - woodenDoors.add(Material.DARK_OAK_DOOR); - woodenDoors.add(Material.WARPED_DOOR); - woodenDoors.add(Material.CRIMSON_DOOR); - woodenDoors.add(Material.MANGROVE_DOOR); - woodenDoors.add(Material.BAMBOO_DOOR); - woodenDoors.add(Material.CHERRY_DOOR); - - HashSet saplings = new HashSet<>(); - saplings.add(Material.OAK_SAPLING); - saplings.add(Material.SPRUCE_SAPLING); - saplings.add(Material.BIRCH_SAPLING); - saplings.add(Material.JUNGLE_SAPLING); - saplings.add(Material.ACACIA_SAPLING); - saplings.add(Material.DARK_OAK_SAPLING); - saplings.add(Material.CHERRY_SAPLING); - saplings.add(Material.WARPED_FUNGUS); - saplings.add(Material.CRIMSON_FUNGUS); - saplings.add(Material.MANGROVE_PROPAGULE); - - HashSet carpets = new HashSet<>(); - carpets.add(Material.BLACK_CARPET); - carpets.add(Material.BLUE_CARPET); - carpets.add(Material.LIGHT_GRAY_CARPET); - carpets.add(Material.BROWN_CARPET); - carpets.add(Material.CYAN_CARPET); - carpets.add(Material.GRAY_CARPET); - carpets.add(Material.GREEN_CARPET); - carpets.add(Material.LIGHT_BLUE_CARPET); - carpets.add(Material.MAGENTA_CARPET); - carpets.add(Material.LIME_CARPET); - carpets.add(Material.ORANGE_CARPET); - carpets.add(Material.PINK_CARPET); - carpets.add(Material.PURPLE_CARPET); - carpets.add(Material.RED_CARPET); - carpets.add(Material.WHITE_CARPET); - carpets.add(Material.YELLOW_CARPET); - - slabs = new HashSet<>(); - slabs.add(Material.OAK_SLAB); - slabs.add(Material.SPRUCE_SLAB); - slabs.add(Material.BIRCH_SLAB); - slabs.add(Material.JUNGLE_SLAB); - slabs.add(Material.ACACIA_SLAB); - slabs.add(Material.DARK_OAK_SLAB); - slabs.add(Material.WARPED_SLAB); - slabs.add(Material.CRIMSON_SLAB); - slabs.add(Material.STONE_SLAB); - slabs.add(Material.STONE_BRICK_SLAB); - slabs.add(Material.COBBLESTONE_SLAB); - slabs.add(Material.PETRIFIED_OAK_SLAB); - slabs.add(Material.SANDSTONE_SLAB); - slabs.add(Material.RED_SANDSTONE_SLAB); - slabs.add(Material.NETHER_BRICK_SLAB); - slabs.add(Material.PURPUR_SLAB); - slabs.add(Material.QUARTZ_SLAB); - slabs.add(Material.BRICK_SLAB); - slabs.add(Material.PRISMARINE_SLAB); - slabs.add(Material.DARK_PRISMARINE_SLAB); - slabs.add(Material.PRISMARINE_BRICK_SLAB); - slabs.add(Material.BLACKSTONE_SLAB); - slabs.add(Material.POLISHED_BLACKSTONE_SLAB); - slabs.add(Material.DEEPSLATE_BRICK_SLAB); - slabs.add(Material.DEEPSLATE_TILE_SLAB); - slabs.add(Material.COBBLED_DEEPSLATE_SLAB); - slabs.add(Material.POLISHED_DEEPSLATE_SLAB); - slabs.add(Material.MANGROVE_SLAB); - slabs.add(Material.BAMBOO_SLAB); - slabs.add(Material.CHERRY_SLAB); - - buttons = new HashSet<>(); - buttons.add(Material.STONE_BUTTON); - buttons.add(Material.OAK_BUTTON); - buttons.add(Material.SPRUCE_BUTTON); - buttons.add(Material.BIRCH_BUTTON); - buttons.add(Material.JUNGLE_BUTTON); - buttons.add(Material.ACACIA_BUTTON); - buttons.add(Material.DARK_OAK_BUTTON); - buttons.add(Material.WARPED_BUTTON); - buttons.add(Material.CRIMSON_BUTTON); - buttons.add(Material.MANGROVE_BUTTON); - buttons.add(Material.BAMBOO_BUTTON); - buttons.add(Material.CHERRY_BUTTON); - buttons.add(Material.POLISHED_BLACKSTONE_BUTTON); - - signs = new HashSet<>(); - signs.add(Material.OAK_SIGN); - signs.add(Material.SPRUCE_SIGN); - signs.add(Material.BIRCH_SIGN); - signs.add(Material.JUNGLE_SIGN); - signs.add(Material.DARK_OAK_SIGN); - signs.add(Material.ACACIA_SIGN); - signs.add(Material.WARPED_SIGN); - signs.add(Material.CRIMSON_SIGN); - signs.add(Material.MANGROVE_SIGN); - signs.add(Material.BAMBOO_SIGN); - signs.add(Material.CHERRY_SIGN); - - wallSigns = new HashSet<>(); - wallSigns.add(Material.OAK_WALL_SIGN); - wallSigns.add(Material.SPRUCE_WALL_SIGN); - wallSigns.add(Material.BIRCH_WALL_SIGN); - wallSigns.add(Material.JUNGLE_WALL_SIGN); - wallSigns.add(Material.DARK_OAK_WALL_SIGN); - wallSigns.add(Material.ACACIA_WALL_SIGN); - wallSigns.add(Material.WARPED_WALL_SIGN); - wallSigns.add(Material.CRIMSON_WALL_SIGN); - wallSigns.add(Material.MANGROVE_WALL_SIGN); - wallSigns.add(Material.BAMBOO_WALL_SIGN); - wallSigns.add(Material.CHERRY_WALL_SIGN); - - hangingSigns = new HashSet<>(); - hangingSigns.add(Material.OAK_HANGING_SIGN); - hangingSigns.add(Material.SPRUCE_HANGING_SIGN); - hangingSigns.add(Material.BIRCH_HANGING_SIGN); - hangingSigns.add(Material.JUNGLE_HANGING_SIGN); - hangingSigns.add(Material.DARK_OAK_HANGING_SIGN); - hangingSigns.add(Material.ACACIA_HANGING_SIGN); - hangingSigns.add(Material.WARPED_HANGING_SIGN); - hangingSigns.add(Material.CRIMSON_HANGING_SIGN); - hangingSigns.add(Material.MANGROVE_HANGING_SIGN); - hangingSigns.add(Material.BAMBOO_HANGING_SIGN); - hangingSigns.add(Material.CHERRY_HANGING_SIGN); - - hangingWallSigns = new HashSet<>(); - hangingWallSigns.add(Material.OAK_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.SPRUCE_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.BIRCH_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.JUNGLE_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.DARK_OAK_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.ACACIA_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.WARPED_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.CRIMSON_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.MANGROVE_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.BAMBOO_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.CHERRY_WALL_HANGING_SIGN); - - allSigns = new HashSet<>(); - allSigns.addAll(signs); - allSigns.addAll(wallSigns); - allSigns.addAll(hangingSigns); - allSigns.addAll(hangingWallSigns); - unmodifiableSigns = Collections.unmodifiableSet(allSigns); - - singleBlockPlants = new HashSet<>(); - singleBlockPlants.add(Material.GRASS); - singleBlockPlants.add(Material.FERN); - singleBlockPlants.add(Material.DEAD_BUSH); - singleBlockPlants.add(Material.DANDELION); - singleBlockPlants.add(Material.POPPY); - singleBlockPlants.add(Material.BLUE_ORCHID); - singleBlockPlants.add(Material.ALLIUM); - singleBlockPlants.add(Material.AZURE_BLUET); - singleBlockPlants.add(Material.ORANGE_TULIP); - singleBlockPlants.add(Material.WHITE_TULIP); - singleBlockPlants.add(Material.PINK_TULIP); - singleBlockPlants.add(Material.RED_TULIP); - singleBlockPlants.add(Material.OXEYE_DAISY); - singleBlockPlants.add(Material.BROWN_MUSHROOM); - singleBlockPlants.add(Material.RED_MUSHROOM); - singleBlockPlants.add(Material.SWEET_BERRY_BUSH); - singleBlockPlants.add(Material.LILY_OF_THE_VALLEY); - singleBlockPlants.add(Material.CORNFLOWER); - singleBlockPlants.add(Material.WITHER_ROSE); - singleBlockPlants.add(Material.CRIMSON_FUNGUS); - singleBlockPlants.add(Material.WARPED_FUNGUS); - singleBlockPlants.add(Material.CRIMSON_ROOTS); - singleBlockPlants.add(Material.WARPED_ROOTS); - singleBlockPlants.add(Material.NETHER_SPROUTS); - singleBlockPlants.add(Material.AZALEA); - singleBlockPlants.add(Material.FLOWERING_AZALEA); - singleBlockPlants.add(Material.PINK_PETALS); - singleBlockPlants.add(Material.TORCHFLOWER); - singleBlockPlants.add(Material.PITCHER_CROP); - - doublePlants = new HashSet<>(); - doublePlants.add(Material.TALL_GRASS); - doublePlants.add(Material.LARGE_FERN); - doublePlants.add(Material.TALL_SEAGRASS); - doublePlants.add(Material.ROSE_BUSH); - doublePlants.add(Material.LILAC); - doublePlants.add(Material.SUNFLOWER); - doublePlants.add(Material.PEONY); - doublePlants.add(Material.SMALL_DRIPLEAF); - doublePlants.add(Material.PITCHER_PLANT); - - blockEquivalents = new HashSet<>(7); - blockEquivalents.add(new HashSet<>(Arrays.asList(2, 3, 60))); - blockEquivalents.add(new HashSet<>(Arrays.asList(8, 9, 79))); - blockEquivalents.add(new HashSet<>(Arrays.asList(10, 11))); - blockEquivalents.add(new HashSet<>(Arrays.asList(61, 62))); - blockEquivalents.add(new HashSet<>(Arrays.asList(73, 74))); - blockEquivalents.add(new HashSet<>(Arrays.asList(75, 76))); - blockEquivalents.add(new HashSet<>(Arrays.asList(93, 94))); - - // Blocks that break when they are attached to a block - relativeBreakable = new HashSet<>(); - relativeBreakable.addAll(wallSigns); - relativeBreakable.add(Material.LADDER); - relativeBreakable.addAll(buttons); - relativeBreakable.add(Material.REDSTONE_WALL_TORCH); - relativeBreakable.add(Material.LEVER); - relativeBreakable.add(Material.WALL_TORCH); - relativeBreakable.add(Material.TRIPWIRE_HOOK); - relativeBreakable.add(Material.COCOA); - relativeBreakable.add(Material.BELL); - relativeBreakable.add(Material.AMETHYST_CLUSTER); - relativeBreakable.add(Material.SMALL_AMETHYST_BUD); - relativeBreakable.add(Material.MEDIUM_AMETHYST_BUD); - relativeBreakable.add(Material.LARGE_AMETHYST_BUD); - - // Blocks that break when they are on top of a block - relativeTopBreakable = new HashSet<>(); - relativeTopBreakable.addAll(saplings); - relativeTopBreakable.addAll(singleBlockPlants); - relativeTopBreakable.add(Material.WHEAT); - relativeTopBreakable.add(Material.POTATO); - relativeTopBreakable.add(Material.CARROT); - relativeTopBreakable.add(Material.LILY_PAD); - relativeTopBreakable.add(Material.CACTUS); - relativeTopBreakable.add(Material.SUGAR_CANE); - relativeTopBreakable.add(Material.FLOWER_POT); - relativeTopBreakable.add(Material.POWERED_RAIL); - relativeTopBreakable.add(Material.DETECTOR_RAIL); - relativeTopBreakable.add(Material.ACTIVATOR_RAIL); - relativeTopBreakable.add(Material.RAIL); - relativeTopBreakable.add(Material.REDSTONE_WIRE); - relativeTopBreakable.addAll(signs); - relativeTopBreakable.addAll(pressurePlates); - relativeTopBreakable.add(Material.SNOW); - relativeTopBreakable.add(Material.REPEATER); - relativeTopBreakable.add(Material.COMPARATOR); - relativeTopBreakable.add(Material.TORCH); - relativeTopBreakable.add(Material.SOUL_TORCH); - relativeTopBreakable.add(Material.REDSTONE_TORCH); - relativeTopBreakable.addAll(woodenDoors); - relativeTopBreakable.add(Material.IRON_DOOR); - relativeTopBreakable.addAll(carpets); - relativeTopBreakable.addAll(doublePlants); - relativeTopBreakable.add(Material.BAMBOO); - relativeTopBreakable.add(Material.BAMBOO_SAPLING); - relativeTopBreakable.add(Material.TWISTING_VINES); - relativeTopBreakable.add(Material.TWISTING_VINES_PLANT); - relativeTopBreakable.add(Material.BIG_DRIPLEAF); - relativeTopBreakable.add(Material.BIG_DRIPLEAF_STEM); - for (Material m : Material.values()) { - if (m.name().startsWith("POTTED_")) { - relativeTopBreakable.add(m); - } - if (m.name().endsWith("CANDLE_CAKE")) { - relativeTopBreakable.add(m); - } - } - - // Blocks that break falling entities - fallingEntityKillers = new HashSet<>(); - fallingEntityKillers.addAll(signs); - fallingEntityKillers.addAll(wallSigns); - fallingEntityKillers.addAll(pressurePlates); - fallingEntityKillers.addAll(saplings); - fallingEntityKillers.addAll(singleBlockPlants); - fallingEntityKillers.remove(Material.GRASS); - fallingEntityKillers.remove(Material.NETHER_SPROUTS); - fallingEntityKillers.addAll(doublePlants); - fallingEntityKillers.add(Material.WHEAT); - fallingEntityKillers.add(Material.CARROT); - fallingEntityKillers.add(Material.POTATO); - fallingEntityKillers.add(Material.BEETROOT); - fallingEntityKillers.add(Material.NETHER_WART); - fallingEntityKillers.add(Material.COCOA); - fallingEntityKillers.addAll(slabs); - fallingEntityKillers.add(Material.TORCH); - fallingEntityKillers.add(Material.WALL_TORCH); - fallingEntityKillers.add(Material.SOUL_TORCH); - fallingEntityKillers.add(Material.SOUL_WALL_TORCH); - fallingEntityKillers.add(Material.FLOWER_POT); - fallingEntityKillers.add(Material.POWERED_RAIL); - fallingEntityKillers.add(Material.DETECTOR_RAIL); - fallingEntityKillers.add(Material.ACTIVATOR_RAIL); - fallingEntityKillers.add(Material.RAIL); - fallingEntityKillers.add(Material.LEVER); - fallingEntityKillers.add(Material.REDSTONE_WIRE); - fallingEntityKillers.add(Material.REDSTONE_TORCH); - fallingEntityKillers.add(Material.REDSTONE_WALL_TORCH); - fallingEntityKillers.add(Material.REPEATER); - fallingEntityKillers.add(Material.COMPARATOR); - fallingEntityKillers.add(Material.DAYLIGHT_DETECTOR); - fallingEntityKillers.addAll(carpets); - fallingEntityKillers.add(Material.PLAYER_HEAD); - fallingEntityKillers.add(Material.PLAYER_WALL_HEAD); - fallingEntityKillers.add(Material.CREEPER_HEAD); - fallingEntityKillers.add(Material.CREEPER_WALL_HEAD); - fallingEntityKillers.add(Material.DRAGON_HEAD); - fallingEntityKillers.add(Material.DRAGON_WALL_HEAD); - fallingEntityKillers.add(Material.ZOMBIE_HEAD); - fallingEntityKillers.add(Material.ZOMBIE_WALL_HEAD); - fallingEntityKillers.add(Material.SKELETON_SKULL); - fallingEntityKillers.add(Material.SKELETON_WALL_SKULL); - fallingEntityKillers.add(Material.WITHER_SKELETON_SKULL); - fallingEntityKillers.add(Material.WITHER_SKELETON_WALL_SKULL); - for (Material m : Material.values()) { - if (m.name().contains("CANDLE")) { - fallingEntityKillers.add(m); - } - } - - // Crop Blocks - cropBlocks = new HashSet<>(); - cropBlocks.add(Material.WHEAT); - cropBlocks.add(Material.MELON_STEM); - cropBlocks.add(Material.PUMPKIN_STEM); - cropBlocks.add(Material.CARROT); - cropBlocks.add(Material.POTATO); - cropBlocks.add(Material.BEETROOT); - cropBlocks.add(Material.TORCHFLOWER_CROP); - - // Shulker Boxes - shulkerBoxBlocks = new HashSet<>(); - shulkerBoxBlocks.add(Material.SHULKER_BOX); - shulkerBoxBlocks.add(Material.BLACK_SHULKER_BOX); - shulkerBoxBlocks.add(Material.BLUE_SHULKER_BOX); - shulkerBoxBlocks.add(Material.LIGHT_GRAY_SHULKER_BOX); - shulkerBoxBlocks.add(Material.BROWN_SHULKER_BOX); - shulkerBoxBlocks.add(Material.CYAN_SHULKER_BOX); - shulkerBoxBlocks.add(Material.GRAY_SHULKER_BOX); - shulkerBoxBlocks.add(Material.GREEN_SHULKER_BOX); - shulkerBoxBlocks.add(Material.LIGHT_BLUE_SHULKER_BOX); - shulkerBoxBlocks.add(Material.MAGENTA_SHULKER_BOX); - shulkerBoxBlocks.add(Material.LIME_SHULKER_BOX); - shulkerBoxBlocks.add(Material.ORANGE_SHULKER_BOX); - shulkerBoxBlocks.add(Material.PINK_SHULKER_BOX); - shulkerBoxBlocks.add(Material.PURPLE_SHULKER_BOX); - shulkerBoxBlocks.add(Material.RED_SHULKER_BOX); - shulkerBoxBlocks.add(Material.WHITE_SHULKER_BOX); - shulkerBoxBlocks.add(Material.YELLOW_SHULKER_BOX); - - // Container Blocks - containerBlocks = new HashSet<>(); - containerBlocks.add(Material.CHEST); - containerBlocks.add(Material.TRAPPED_CHEST); - containerBlocks.add(Material.DISPENSER); - containerBlocks.add(Material.DROPPER); - containerBlocks.add(Material.HOPPER); - containerBlocks.add(Material.BREWING_STAND); - containerBlocks.add(Material.FURNACE); - containerBlocks.addAll(shulkerBoxBlocks); - containerBlocks.add(Material.BARREL); - containerBlocks.add(Material.BLAST_FURNACE); - containerBlocks.add(Material.SMOKER); - containerBlocks.add(Material.CHISELED_BOOKSHELF); - // Doesn't actually have a block inventory - // containerBlocks.add(Material.ENDER_CHEST); - - // It doesn't seem like you could injure people with some of these, but they exist, so.... - projectileItems = new HashMap<>(); - projectileItems.put(EntityType.ARROW, Material.ARROW); - projectileItems.put(EntityType.EGG, Material.EGG); - 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_HOOK, Material.FISHING_ROD); - projectileItems.put(EntityType.SNOWBALL, Material.SNOWBALL); - projectileItems.put(EntityType.SPLASH_POTION, Material.SPLASH_POTION); - projectileItems.put(EntityType.THROWN_EXP_BOTTLE, Material.EXPERIENCE_BOTTLE); - projectileItems.put(EntityType.WITHER_SKULL, Material.WITHER_SKELETON_SKULL); - projectileItems.put(EntityType.FIREWORK, Material.FIREWORK_ROCKET); - - nonFluidProofBlocks = new HashSet<>(); - nonFluidProofBlocks.addAll(singleBlockPlants); - nonFluidProofBlocks.addAll(doublePlants); - nonFluidProofBlocks.add(Material.REDSTONE_WALL_TORCH); - nonFluidProofBlocks.add(Material.LEVER); - nonFluidProofBlocks.add(Material.WALL_TORCH); - nonFluidProofBlocks.add(Material.SOUL_WALL_TORCH); - nonFluidProofBlocks.add(Material.TRIPWIRE_HOOK); - nonFluidProofBlocks.add(Material.COCOA); - nonFluidProofBlocks.addAll(pressurePlates); - nonFluidProofBlocks.addAll(saplings); - nonFluidProofBlocks.add(Material.WHEAT); - nonFluidProofBlocks.add(Material.CARROT); - nonFluidProofBlocks.add(Material.POTATO); - nonFluidProofBlocks.add(Material.BEETROOT); - nonFluidProofBlocks.add(Material.NETHER_WART); - nonFluidProofBlocks.add(Material.TORCH); - nonFluidProofBlocks.add(Material.SOUL_TORCH); - nonFluidProofBlocks.add(Material.FLOWER_POT); - // nonFluidProofBlocks.add(Material.POWERED_RAIL); - // nonFluidProofBlocks.add(Material.DETECTOR_RAIL); - // nonFluidProofBlocks.add(Material.ACTIVATOR_RAIL); - // nonFluidProofBlocks.add(Material.RAIL); - nonFluidProofBlocks.add(Material.LEVER); - nonFluidProofBlocks.add(Material.REDSTONE_WIRE); - nonFluidProofBlocks.add(Material.REDSTONE_TORCH); - nonFluidProofBlocks.add(Material.REPEATER); - nonFluidProofBlocks.add(Material.COMPARATOR); - nonFluidProofBlocks.add(Material.DAYLIGHT_DETECTOR); - nonFluidProofBlocks.addAll(carpets); - - alwaysWaterlogged = new HashSet<>(); - alwaysWaterlogged.add(Material.SEAGRASS); - alwaysWaterlogged.add(Material.TALL_SEAGRASS); - alwaysWaterlogged.add(Material.KELP); - alwaysWaterlogged.add(Material.KELP_PLANT); - - bedBlocks = new HashSet<>(); - bedBlocks.add(Material.BLACK_BED); - bedBlocks.add(Material.BLUE_BED); - bedBlocks.add(Material.LIGHT_GRAY_BED); - bedBlocks.add(Material.BROWN_BED); - bedBlocks.add(Material.CYAN_BED); - bedBlocks.add(Material.GRAY_BED); - bedBlocks.add(Material.GREEN_BED); - bedBlocks.add(Material.LIGHT_BLUE_BED); - bedBlocks.add(Material.MAGENTA_BED); - bedBlocks.add(Material.LIME_BED); - bedBlocks.add(Material.ORANGE_BED); - bedBlocks.add(Material.PINK_BED); - bedBlocks.add(Material.PURPLE_BED); - bedBlocks.add(Material.RED_BED); - bedBlocks.add(Material.WHITE_BED); - bedBlocks.add(Material.YELLOW_BED); - - concreteBlocks = new HashSet<>(); - concreteBlocks.add(Material.BLACK_CONCRETE); - concreteBlocks.add(Material.BLUE_CONCRETE); - concreteBlocks.add(Material.LIGHT_GRAY_CONCRETE); - concreteBlocks.add(Material.BROWN_CONCRETE); - concreteBlocks.add(Material.CYAN_CONCRETE); - concreteBlocks.add(Material.GRAY_CONCRETE); - concreteBlocks.add(Material.GREEN_CONCRETE); - concreteBlocks.add(Material.LIGHT_BLUE_CONCRETE); - concreteBlocks.add(Material.MAGENTA_CONCRETE); - concreteBlocks.add(Material.LIME_CONCRETE); - concreteBlocks.add(Material.ORANGE_CONCRETE); - concreteBlocks.add(Material.PINK_CONCRETE); - concreteBlocks.add(Material.PURPLE_CONCRETE); - concreteBlocks.add(Material.RED_CONCRETE); - concreteBlocks.add(Material.WHITE_CONCRETE); - concreteBlocks.add(Material.YELLOW_CONCRETE); - - candles = new HashSet<>(); - candles.add(Material.CANDLE); - candles.add(Material.BLACK_CANDLE); - candles.add(Material.BLUE_CANDLE); - candles.add(Material.LIGHT_GRAY_CANDLE); - candles.add(Material.BROWN_CANDLE); - candles.add(Material.CYAN_CANDLE); - candles.add(Material.GRAY_CANDLE); - candles.add(Material.GREEN_CANDLE); - candles.add(Material.LIGHT_BLUE_CANDLE); - candles.add(Material.MAGENTA_CANDLE); - candles.add(Material.LIME_CANDLE); - candles.add(Material.ORANGE_CANDLE); - candles.add(Material.PINK_CANDLE); - candles.add(Material.PURPLE_CANDLE); - candles.add(Material.RED_CANDLE); - candles.add(Material.WHITE_CANDLE); - candles.add(Material.YELLOW_CANDLE); - - candleCakes = new HashSet<>(); - candleCakes.add(Material.CANDLE_CAKE); - candleCakes.add(Material.BLACK_CANDLE_CAKE); - candleCakes.add(Material.BLUE_CANDLE_CAKE); - candleCakes.add(Material.LIGHT_GRAY_CANDLE_CAKE); - candleCakes.add(Material.BROWN_CANDLE_CAKE); - candleCakes.add(Material.CYAN_CANDLE_CAKE); - candleCakes.add(Material.GRAY_CANDLE_CAKE); - candleCakes.add(Material.GREEN_CANDLE_CAKE); - candleCakes.add(Material.LIGHT_BLUE_CANDLE_CAKE); - candleCakes.add(Material.MAGENTA_CANDLE_CAKE); - candleCakes.add(Material.LIME_CANDLE_CAKE); - candleCakes.add(Material.ORANGE_CANDLE_CAKE); - candleCakes.add(Material.PINK_CANDLE_CAKE); - candleCakes.add(Material.PURPLE_CANDLE_CAKE); - candleCakes.add(Material.RED_CANDLE_CAKE); - candleCakes.add(Material.WHITE_CANDLE_CAKE); - candleCakes.add(Material.YELLOW_CANDLE_CAKE); - - dyes = new HashMap<>(); - dyes.put(Material.BLACK_DYE, DyeColor.BLACK); - dyes.put(Material.BLUE_DYE, DyeColor.BLUE); - dyes.put(Material.LIGHT_GRAY_DYE, DyeColor.LIGHT_GRAY); - dyes.put(Material.BROWN_DYE, DyeColor.BROWN); - dyes.put(Material.CYAN_DYE, DyeColor.CYAN); - dyes.put(Material.GRAY_DYE, DyeColor.GRAY); - dyes.put(Material.GREEN_DYE, DyeColor.GREEN); - dyes.put(Material.LIGHT_BLUE_DYE, DyeColor.LIGHT_BLUE); - dyes.put(Material.MAGENTA_DYE, DyeColor.MAGENTA); - dyes.put(Material.LIME_DYE, DyeColor.LIME); - dyes.put(Material.ORANGE_DYE, DyeColor.ORANGE); - dyes.put(Material.PINK_DYE, DyeColor.PINK); - dyes.put(Material.PURPLE_DYE, DyeColor.PURPLE); - dyes.put(Material.RED_DYE, DyeColor.RED); - dyes.put(Material.WHITE_DYE, DyeColor.WHITE); - dyes.put(Material.YELLOW_DYE, DyeColor.YELLOW); - } - - private static final BlockFace[] relativeBlockFaces = new BlockFace[] { - BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN - }; - - /** - * Returns a list of block locations around the block that are of the type specified by the integer list parameter - * - * @param block The central block to get the blocks around - * @param type The type of blocks around the center block to return - * @return List of block locations around the block that are of the type specified by the integer list parameter - */ - public static List getBlocksNearby(org.bukkit.block.Block block, Set type) { - ArrayList blocks = new ArrayList<>(); - for (BlockFace blockFace : relativeBlockFaces) { - if (type.contains(block.getRelative(blockFace).getType())) { - blocks.add(block.getRelative(blockFace).getLocation()); - } - } - return blocks; - } - - public static boolean isTop(BlockData data) { - if (data instanceof Bisected && !(data instanceof Stairs)) { - return ((Bisected) data).getHalf() == Half.TOP; - } - return false; - } - - public static Material getInventoryHolderType(InventoryHolder holder) { - if (holder instanceof DoubleChest) { - return getInventoryHolderType(((DoubleChest) holder).getLeftSide()); - } else if (holder instanceof BlockState) { - return ((BlockState) holder).getType(); - } else { - return null; - } - } - - public static Location getInventoryHolderLocation(InventoryHolder holder) { - if (holder instanceof DoubleChest) { - return getInventoryHolderLocation(((DoubleChest) holder).getLeftSide()); - } else if (holder instanceof BlockState) { - return ((BlockState) holder).getLocation(); - } else { - return null; - } - } - - public static ItemStack[] compareInventories(ItemStack[] items1, ItemStack[] items2) { - final ArrayList diff = new ArrayList<>(); - for (ItemStack current : items2) { - try { - diff.add(new ItemStack(current)); - } catch (NullPointerException e) { - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not clone ItemStack, probably Spigot bug SPIGOT-6025", e); // SPIGOT-6025 - } - } - for (ItemStack previous : items1) { - boolean found = false; - for (ItemStack current : diff) { - if (current.isSimilar(previous)) { - int newAmount = current.getAmount() - previous.getAmount(); - if (newAmount == 0) { - diff.remove(current); - } else { - current.setAmount(newAmount); - } - found = true; - break; - } - } - if (!found) { - try { - ItemStack subtracted = new ItemStack(previous); - subtracted.setAmount(-subtracted.getAmount()); - diff.add(subtracted); - } catch (NullPointerException e) { - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not clone ItemStack, probably Spigot bug SPIGOT-6025", e); // SPIGOT-6025 - } - } - } - return diff.toArray(new ItemStack[diff.size()]); - } - - public static ItemStack[] compressInventory(ItemStack[] items) { - final ArrayList compressed = new ArrayList<>(); - for (final ItemStack item : items) { - 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()); - } - } - } - return compressed.toArray(new ItemStack[compressed.size()]); - } - - public static boolean equalTypes(int type1, int type2) { - if (type1 == type2) { - return true; - } - for (final Set equivalent : blockEquivalents) { - if (equivalent.contains(type1) && equivalent.contains(type2)) { - return true; - } - } - return false; - } - - public static String friendlyWorldname(String worldName) { - return new File(worldName).getName(); - } - - public static Set> getBlockEquivalents() { - return blockEquivalents; - } - - public static Set getRelativeBreakables() { - return relativeBreakable; - } - - public static Set getRelativeTopBreakabls() { - return relativeTopBreakable; - } - - public static Set getFallingEntityKillers() { - return fallingEntityKillers; - } - - public static Set getNonFluidProofBlocks() { - return nonFluidProofBlocks; - } - - public static Set getCropBlocks() { - return cropBlocks; - } - - public static Set getContainerBlocks() { - return containerBlocks; - } - - public static Set getShulkerBoxBlocks() { - return shulkerBoxBlocks; - } - - public static boolean isConcreteBlock(Material m) { - return concreteBlocks.contains(m); - } - - public static String entityName(Entity entity) { - if (entity instanceof Player) { - return ((Player) entity).getName(); - } - if (entity instanceof TNTPrimed) { - return "TNT"; - } - return entity.getClass().getSimpleName().substring(5); - } - - public static void giveTool(Player player, Material type) { - final Inventory inv = player.getInventory(); - if (inv.contains(type)) { - player.sendMessage(ChatColor.RED + "You have already a " + type.name()); - } else { - final int free = inv.firstEmpty(); - if (free >= 0) { - if (player.getInventory().getItemInMainHand() != null && player.getInventory().getItemInMainHand().getType() != Material.AIR) { - inv.setItem(free, player.getInventory().getItemInMainHand()); - } - player.getInventory().setItemInMainHand(new ItemStack(type)); - player.sendMessage(ChatColor.GREEN + "Here's your " + type.name()); - } else { - player.sendMessage(ChatColor.RED + "You have no empty slot in your inventory"); - } - } - } - - public static int safeSpawnHeight(Location loc) { - final World world = loc.getWorld(); - world.getChunkAt(loc); - final int x = loc.getBlockX(), z = loc.getBlockZ(); - int y = loc.getBlockY(); - boolean lower = world.getBlockAt(x, y, z).isEmpty(), upper = world.getBlockAt(x, y + 1, z).isEmpty(); - while ((!lower || !upper) && y != world.getMaxHeight()) { - lower = upper; - upper = world.getBlockAt(x, ++y, z).isEmpty(); - } - while (world.getBlockAt(x, y - 1, z).isEmpty() && y != world.getMinHeight()) { - y--; - } - return y; - } - - public static int modifyContainer(BlockState b, ItemStack item, boolean remove) { - if (b instanceof InventoryHolder) { - final Inventory inv = ((InventoryHolder) b).getInventory(); - if (remove) { - 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; - } - - public static boolean canFallIn(World world, int x, int y, int z) { - Block block = world.getBlockAt(x, y, z); - Material mat = block.getType(); - if (canDirectlyFallIn(mat)) { - return true; - } else if (getFallingEntityKillers().contains(mat) || singleBlockPlants.contains(mat) || mat == Material.VINE) { - if (slabs.contains(mat)) { - if (((Slab) block.getBlockData()).getType() != Type.BOTTOM) { - return false; - } - } - return true; - } - return false; - } - - public static boolean canDirectlyFallIn(Material m) { - return isEmpty(m) || m == Material.WATER || m == Material.LAVA || m == Material.FIRE; - } - - public static Material itemIDfromProjectileEntity(Entity e) { - return projectileItems.get(e.getType()); - } - - public static boolean isDoublePlant(Material m) { - return doublePlants.contains(m); - } - - public static boolean isWoodenDoor(Material m) { - return woodenDoors.contains(m); - } - - public static boolean isButton(Material m) { - return buttons.contains(m); - } - - public static boolean isEmpty(Material m) { - return m == Material.AIR || m == Material.CAVE_AIR || m == Material.VOID_AIR; - } - - public static TextComponent toString(ItemStack stack) { - if (stack == null || stack.getAmount() == 0 || isEmpty(stack.getType())) { - return prettyMaterial("nothing"); - } - TextComponent msg = MessagingUtil.createTextComponentWithColor(stack.getAmount() + "x ", TypeColor.DEFAULT.getColor()); - msg.addExtra(prettyMaterial(stack.getType())); - - try { - 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()) }))); - } - - 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; - for (int i = 0; i < cap.length; i++) { - char c = cap[i]; - if (c == '_') { - c = ' '; - lastSpace = true; - } else if (c >= '0' && c <= '9' || c == '(' || c == ')') { - lastSpace = true; - } else { - if (lastSpace) { - c = Character.toUpperCase(c); - } else { - c = Character.toLowerCase(c); - } - lastSpace = false; - } - cap[i] = c; - } - return new String(cap); - } - - public static boolean isBed(Material type) { - return bedBlocks.contains(type); - } - - public static boolean isDye(Material type) { - return dyes.containsKey(type); - } - - public static DyeColor dyeToDyeColor(Material type) { - return dyes.get(type); - } - - public static Block getConnectedChest(Block chestBlock) { - // is this a chest? - BlockData blockData = chestBlock.getBlockData(); - if (!(blockData instanceof org.bukkit.block.data.type.Chest)) { - return null; - } - // so check if is should have a neighbour - org.bukkit.block.data.type.Chest chestData = (org.bukkit.block.data.type.Chest) blockData; - org.bukkit.block.data.type.Chest.Type chestType = chestData.getType(); - if (chestType != org.bukkit.block.data.type.Chest.Type.SINGLE) { - // check if the neighbour exists - BlockFace chestFace = chestData.getFacing(); - BlockFace faceToSecondChest; - if (chestFace == BlockFace.WEST) { - faceToSecondChest = BlockFace.NORTH; - } else if (chestFace == BlockFace.NORTH) { - faceToSecondChest = BlockFace.EAST; - } else if (chestFace == BlockFace.EAST) { - faceToSecondChest = BlockFace.SOUTH; - } else if (chestFace == BlockFace.SOUTH) { - faceToSecondChest = BlockFace.WEST; - } else { - return null; - } - org.bukkit.block.data.type.Chest.Type wantedChestType = org.bukkit.block.data.type.Chest.Type.RIGHT; - if (chestType == org.bukkit.block.data.type.Chest.Type.RIGHT) { - faceToSecondChest = faceToSecondChest.getOppositeFace(); - wantedChestType = org.bukkit.block.data.type.Chest.Type.LEFT; - } - Block face = chestBlock.getRelative(faceToSecondChest); - if (face.getType() == chestBlock.getType()) { - // check is the neighbour connects to this chest - org.bukkit.block.data.type.Chest otherChestData = (org.bukkit.block.data.type.Chest) face.getBlockData(); - if (otherChestData.getType() != wantedChestType || otherChestData.getFacing() != chestFace) { - return null; - } - return face; - } - } - return null; - } - - public static Entity loadEntityAround(Chunk chunk, UUID uuid) { - Entity e = Bukkit.getEntity(uuid); - if (e != null) { - return e; - } - if (!chunk.isLoaded()) { - chunk.getWorld().getChunkAt(chunk.getX(), chunk.getZ()); - e = Bukkit.getEntity(uuid); - if (e != null) { - return e; - } - } - int chunkx = chunk.getX(); - int chunkz = chunk.getZ(); - for (int i = 0; i < 8; i++) { - int x = i < 3 ? chunkx - 1 : (i < 5 ? chunkx : chunkx + 1); - int z = i == 0 || i == 3 || i == 5 ? chunkz - 1 : (i == 1 || i == 6 ? chunkz : chunkz + 1); - if (!chunk.getWorld().isChunkLoaded(x, z)) { - chunk.getWorld().getChunkAt(x, z); - e = Bukkit.getEntity(uuid); - if (e != null) { - return e; - } - } - } - return null; - } - - private static final HashMap types = new HashMap<>(); - static { - for (EntityType t : EntityType.values()) { - if (t != EntityType.UNKNOWN) { - types.put(t.name().toLowerCase(), t); - @SuppressWarnings("deprecation") - String typeName = t.getName(); - if (typeName != null) { - types.put(typeName.toLowerCase(), t); - } - Class ec = t.getEntityClass(); - if (ec != null) { - types.put(ec.getSimpleName().toLowerCase(), t); - } - types.put(t.getKey().getKey(), t); - types.put(t.getKey().toString(), t); - } - } - } - - public static EntityType matchEntityType(String typeName) { - return types.get(typeName.toLowerCase()); - } - - public static ItemStack getItemInSlot(ArmorStand stand, EquipmentSlot slot) { - if (slot == EquipmentSlot.HAND) { - return stand.getEquipment().getItemInMainHand(); - } else if (slot == EquipmentSlot.OFF_HAND) { - return stand.getEquipment().getItemInOffHand(); - } else if (slot == EquipmentSlot.FEET) { - return stand.getEquipment().getBoots(); - } else if (slot == EquipmentSlot.LEGS) { - return stand.getEquipment().getLeggings(); - } else if (slot == EquipmentSlot.CHEST) { - return stand.getEquipment().getChestplate(); - } else if (slot == EquipmentSlot.HEAD) { - return stand.getEquipment().getHelmet(); - } - return null; - } - - public static void setItemInSlot(ArmorStand stand, EquipmentSlot slot, ItemStack stack) { - if (slot == EquipmentSlot.HAND) { - stand.getEquipment().setItemInMainHand(stack); - } else if (slot == EquipmentSlot.OFF_HAND) { - stand.getEquipment().setItemInOffHand(stack); - } else if (slot == EquipmentSlot.FEET) { - stand.getEquipment().setBoots(stack); - } else if (slot == EquipmentSlot.LEGS) { - stand.getEquipment().setLeggings(stack); - } else if (slot == EquipmentSlot.CHEST) { - stand.getEquipment().setChestplate(stack); - } else if (slot == EquipmentSlot.HEAD) { - stand.getEquipment().setHelmet(stack); - } - } - - public static ItemStack[] deepCopy(ItemStack[] of) { - ItemStack[] result = new ItemStack[of.length]; - for (int i = 0; i < result.length; i++) { - result[i] = of[i] == null ? null : new ItemStack(of[i]); - } - return result; - } - - private static int getFirstPartialItemStack(ItemStack item, ItemStack[] contents, int start) { - for (int i = start; i < contents.length; i++) { - ItemStack content = contents[i]; - if (content != null && content.isSimilar(item) && content.getAmount() < content.getMaxStackSize()) { - return i; - } - } - return -1; - } - - private static int getFirstFreeItemStack(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; - } - - public static boolean hasInventoryStorageSpaceFor(Inventory inv, ItemStack... items) { - ItemStack[] contents = deepCopy(inv.getStorageContents()); - for (ItemStack item : items) { - if (item != null && item.getType() != Material.AIR) { - int remaining = item.getAmount(); - // fill partial stacks - int firstPartial = -1; - while (remaining > 0) { - firstPartial = getFirstPartialItemStack(item, contents, firstPartial + 1); - if (firstPartial < 0) { - break; - } - ItemStack content = contents[firstPartial]; - int add = Math.min(content.getMaxStackSize() - content.getAmount(), remaining); - content.setAmount(content.getAmount() + add); - remaining -= add; - } - // create new stacks - int firstFree = -1; - while (remaining > 0) { - firstFree = getFirstFreeItemStack(contents, firstFree + 1); - if (firstFree < 0) { - return false; // no free place found - } - ItemStack content = new ItemStack(item); - contents[firstFree] = content; - // max stack size might return -1, in this case assume 1 - int add = Math.min(Math.max(content.getMaxStackSize(), 1), remaining); - content.setAmount(add); - remaining -= add; - } - } - } - return true; - } - - public static boolean isSimilarForRollback(Material expected, Material found) { - if (expected == found) { - return true; - } - if (expected == Material.DIRT || expected == Material.MYCELIUM || expected == Material.FARMLAND || expected == Material.GRASS_BLOCK || expected == Material.PODZOL || expected == Material.DIRT_PATH) { - return found == Material.DIRT || found == Material.MYCELIUM || found == Material.FARMLAND || found == Material.GRASS_BLOCK || found == Material.PODZOL || found == Material.DIRT_PATH; - } - if (expected == Material.BAMBOO || expected == Material.BAMBOO_SAPLING) { - return found == Material.BAMBOO || found == Material.BAMBOO_SAPLING; - } - if (expected == Material.SPONGE || expected == Material.WET_SPONGE) { - return found == Material.SPONGE || found == Material.WET_SPONGE; - } - if (expected == Material.MELON_STEM || expected == Material.ATTACHED_MELON_STEM) { - return found == Material.MELON_STEM || found == Material.ATTACHED_MELON_STEM; - } - if (expected == Material.PUMPKIN_STEM || expected == Material.ATTACHED_PUMPKIN_STEM) { - return found == Material.PUMPKIN_STEM || found == Material.ATTACHED_PUMPKIN_STEM; - } - if (expected == Material.TWISTING_VINES || expected == Material.TWISTING_VINES_PLANT) { - return found == Material.TWISTING_VINES || found == Material.TWISTING_VINES_PLANT; - } - if (expected == Material.WEEPING_VINES || expected == Material.WEEPING_VINES_PLANT) { - return found == Material.WEEPING_VINES || found == Material.WEEPING_VINES_PLANT; - } - if (expected == Material.CAVE_VINES || expected == Material.CAVE_VINES_PLANT) { - return found == Material.CAVE_VINES || found == Material.CAVE_VINES_PLANT; - } - if (expected == Material.BIG_DRIPLEAF || expected == Material.BIG_DRIPLEAF_STEM) { - return found == Material.BIG_DRIPLEAF || found == Material.BIG_DRIPLEAF_STEM; - } - if (expected == Material.COPPER_BLOCK || expected == Material.EXPOSED_COPPER || expected == Material.WEATHERED_COPPER || expected == Material.OXIDIZED_COPPER) { - return found == Material.COPPER_BLOCK || found == Material.EXPOSED_COPPER || found == Material.WEATHERED_COPPER || found == Material.OXIDIZED_COPPER; - } - if (expected == Material.CUT_COPPER || expected == Material.EXPOSED_CUT_COPPER || expected == Material.WEATHERED_CUT_COPPER || expected == Material.OXIDIZED_CUT_COPPER) { - return found == Material.CUT_COPPER || found == Material.EXPOSED_CUT_COPPER || found == Material.WEATHERED_CUT_COPPER || found == Material.OXIDIZED_CUT_COPPER; - } - if (expected == Material.CUT_COPPER_STAIRS || expected == Material.EXPOSED_CUT_COPPER_STAIRS || expected == Material.WEATHERED_CUT_COPPER_STAIRS || expected == Material.OXIDIZED_CUT_COPPER_STAIRS) { - return found == Material.CUT_COPPER_STAIRS || found == Material.EXPOSED_CUT_COPPER_STAIRS || found == Material.WEATHERED_CUT_COPPER_STAIRS || found == Material.OXIDIZED_CUT_COPPER_STAIRS; - } - if (expected == Material.CUT_COPPER_SLAB || expected == Material.EXPOSED_CUT_COPPER_SLAB || expected == Material.WEATHERED_CUT_COPPER_SLAB || expected == Material.OXIDIZED_CUT_COPPER_SLAB) { - return found == Material.CUT_COPPER_SLAB || found == Material.EXPOSED_CUT_COPPER_SLAB || found == Material.WEATHERED_CUT_COPPER_SLAB || found == Material.OXIDIZED_CUT_COPPER_SLAB; - } - return false; - } - - public static Set getAllSignMaterials() { - return unmodifiableSigns; - } - - public static boolean isAlwaysWaterlogged(Material m) { - return alwaysWaterlogged.contains(m); - } - - public static boolean isCandle(Material m) { - return candles.contains(m); - } - - public static boolean isCandleCake(Material m) { - return candleCakes.contains(m); - } - - public static boolean isHangingSign(Material m) { - return hangingSigns.contains(m); - } - - public static boolean isFenceGate(Material m) { - return fenceGates.contains(m); - } - - public static boolean isWoodenTrapdoor(Material m) { - return woodenTrapdoors.contains(m); - } - - public static boolean isPressurePlate(Material m) { - return pressurePlates.contains(m); - } - - public static boolean isSign(Material m) { - return allSigns.contains(m); - } - - public static Side getFacingSignSide(Entity entity, Block sign) { - BlockData data = sign.getBlockData(); - Material type = data.getMaterial(); - BlockFace signFace = null; - double centerx = 0.5; - double centerz = 0.5; - double yRotationDegree = 0; - if (type.data == Sign.class || type.data == HangingSign.class) { - Rotatable rotatableData = (Rotatable) data; - signFace = rotatableData.getRotation(); - if (signFace == BlockFace.SOUTH) { - yRotationDegree = 360 * 0.0 / 16.0; - } else if (signFace == BlockFace.SOUTH_SOUTH_WEST) { - yRotationDegree = 360 * 1.0 / 16.0; - } else if (signFace == BlockFace.SOUTH_WEST) { - yRotationDegree = 360 * 2.0 / 16.0; - } else if (signFace == BlockFace.WEST_SOUTH_WEST) { - yRotationDegree = 360 * 3.0 / 16.0; - } else if (signFace == BlockFace.WEST) { - yRotationDegree = 360 * 4.0 / 16.0; - } else if (signFace == BlockFace.WEST_NORTH_WEST) { - yRotationDegree = 360 * 5.0 / 16.0; - } else if (signFace == BlockFace.NORTH_WEST) { - yRotationDegree = 360 * 6.0 / 16.0; - } else if (signFace == BlockFace.NORTH_NORTH_WEST) { - yRotationDegree = 360 * 7.0 / 16.0; - } else if (signFace == BlockFace.NORTH) { - yRotationDegree = 360 * 8.0 / 16.0; - } else if (signFace == BlockFace.NORTH_NORTH_EAST) { - yRotationDegree = 360 * 9.0 / 16.0; - } else if (signFace == BlockFace.NORTH_EAST) { - yRotationDegree = 360 * 10.0 / 16.0; - } else if (signFace == BlockFace.EAST_NORTH_EAST) { - yRotationDegree = 360 * 11.0 / 16.0; - } else if (signFace == BlockFace.EAST) { - yRotationDegree = 360 * 12.0 / 16.0; - } else if (signFace == BlockFace.EAST_SOUTH_EAST) { - yRotationDegree = 360 * 13.0 / 16.0; - } else if (signFace == BlockFace.SOUTH_EAST) { - yRotationDegree = 360 * 14.0 / 16.0; - } else if (signFace == BlockFace.SOUTH_SOUTH_EAST) { - yRotationDegree = 360 * 15.0 / 16.0; - } - } else if (type.data == WallSign.class || type.data == WallHangingSign.class) { - Directional directionalData = (Directional) data; - signFace = directionalData.getFacing(); - if (signFace == BlockFace.SOUTH) { - yRotationDegree = 0; - } else if (signFace == BlockFace.WEST) { - yRotationDegree = 90; - } else if (signFace == BlockFace.NORTH) { - yRotationDegree = 180; - } else if (signFace == BlockFace.EAST) { - yRotationDegree = 270; - } - // wall signs are not centered on the block (but hanging wall signs are) - if (type.data == WallSign.class) { - if (signFace == BlockFace.NORTH) { - centerz = 15.0 / 16.0; - } else if (signFace == BlockFace.SOUTH) { - centerz = 1.0 / 16.0; - } else if (signFace == BlockFace.WEST) { - centerx = 15.0 / 16.0; - } else if (signFace == BlockFace.EAST) { - centerx = 1.0 / 16.0; - } - } - } else { - throw new IllegalArgumentException("block is not a sign"); - } - - Location entityLoc = entity.getLocation(); - double relativeX = entityLoc.getX() - (sign.getX() + centerx); - double relativeZ = entityLoc.getZ() - (sign.getZ() + centerz); - double f = Math.atan2(relativeZ, relativeX) * 180.0 / Math.PI - 90.0; - - return Math.abs(Utils.warpDegrees(f - yRotationDegree)) <= 90.0 ? Side.FRONT : Side.BACK; - } -} +package de.diddiz.LogBlock.util; + +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.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.Set; +import java.util.UUID; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.HoverEvent.Action; +import net.md_5.bungee.api.chat.ItemTag; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.chat.hover.content.Item; +import net.md_5.bungee.api.chat.hover.content.Text; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Chunk; +import org.bukkit.DyeColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.block.DoubleChest; +import org.bukkit.block.data.Bisected; +import org.bukkit.block.data.Bisected.Half; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Directional; +import org.bukkit.block.data.Rotatable; +import org.bukkit.block.data.type.HangingSign; +import org.bukkit.block.data.type.Sign; +import org.bukkit.block.data.type.Slab; +import org.bukkit.block.data.type.Slab.Type; +import org.bukkit.block.data.type.Stairs; +import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.block.data.type.WallSign; +import org.bukkit.block.sign.Side; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; + +public class BukkitUtils { + private static final Set> blockEquivalents; + private static final Set relativeBreakable; + private static final Set relativeTopBreakable; + private static final Set fallingEntityKillers; + + private static final Set cropBlocks; + private static final Set containerBlocks; + private static final Set shulkerBoxBlocks; + + private static final Set singleBlockPlants; + private static final Set doublePlants; + + private static final Set nonFluidProofBlocks; + + private static final Set bedBlocks; + + private static final Map projectileItems; + private static final HashSet signs; + private static final HashSet wallSigns; + private static final HashSet hangingSigns; + private static final HashSet hangingWallSigns; + private static final HashSet allSigns; + private static final Set unmodifiableSigns; + private static final HashSet buttons; + private static final HashSet pressurePlates; + private static final HashSet woodenDoors; + private static final HashSet slabs; + private static final HashSet concreteBlocks; + private static final HashMap dyes; + private static final HashSet alwaysWaterlogged; + private static final HashSet candles; + private static final HashSet candleCakes; + private static final HashSet fenceGates; + private static final HashSet woodenTrapdoors; + + static { + fenceGates = new HashSet<>(); + fenceGates.add(Material.OAK_FENCE_GATE); + fenceGates.add(Material.SPRUCE_FENCE_GATE); + fenceGates.add(Material.BIRCH_FENCE_GATE); + fenceGates.add(Material.JUNGLE_FENCE_GATE); + fenceGates.add(Material.ACACIA_FENCE_GATE); + fenceGates.add(Material.DARK_OAK_FENCE_GATE); + fenceGates.add(Material.WARPED_FENCE_GATE); + fenceGates.add(Material.CRIMSON_FENCE_GATE); + fenceGates.add(Material.MANGROVE_FENCE_GATE); + fenceGates.add(Material.BAMBOO_FENCE_GATE); + fenceGates.add(Material.CHERRY_FENCE_GATE); + + woodenTrapdoors = new HashSet<>(); + woodenTrapdoors.add(Material.OAK_TRAPDOOR); + woodenTrapdoors.add(Material.SPRUCE_TRAPDOOR); + woodenTrapdoors.add(Material.BIRCH_TRAPDOOR); + woodenTrapdoors.add(Material.JUNGLE_TRAPDOOR); + woodenTrapdoors.add(Material.ACACIA_TRAPDOOR); + woodenTrapdoors.add(Material.DARK_OAK_TRAPDOOR); + woodenTrapdoors.add(Material.WARPED_TRAPDOOR); + woodenTrapdoors.add(Material.CRIMSON_TRAPDOOR); + woodenTrapdoors.add(Material.MANGROVE_TRAPDOOR); + woodenTrapdoors.add(Material.BAMBOO_TRAPDOOR); + woodenTrapdoors.add(Material.CHERRY_TRAPDOOR); + + pressurePlates = new HashSet<>(); + pressurePlates.add(Material.OAK_PRESSURE_PLATE); + pressurePlates.add(Material.SPRUCE_PRESSURE_PLATE); + pressurePlates.add(Material.BIRCH_PRESSURE_PLATE); + pressurePlates.add(Material.JUNGLE_PRESSURE_PLATE); + pressurePlates.add(Material.ACACIA_PRESSURE_PLATE); + pressurePlates.add(Material.DARK_OAK_PRESSURE_PLATE); + pressurePlates.add(Material.WARPED_PRESSURE_PLATE); + pressurePlates.add(Material.CRIMSON_PRESSURE_PLATE); + pressurePlates.add(Material.MANGROVE_PRESSURE_PLATE); + pressurePlates.add(Material.BAMBOO_PRESSURE_PLATE); + pressurePlates.add(Material.CHERRY_PRESSURE_PLATE); + pressurePlates.add(Material.STONE_PRESSURE_PLATE); + pressurePlates.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); + pressurePlates.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); + + woodenDoors = new HashSet<>(); + woodenDoors.add(Material.OAK_DOOR); + woodenDoors.add(Material.SPRUCE_DOOR); + woodenDoors.add(Material.BIRCH_DOOR); + woodenDoors.add(Material.JUNGLE_DOOR); + woodenDoors.add(Material.ACACIA_DOOR); + woodenDoors.add(Material.DARK_OAK_DOOR); + woodenDoors.add(Material.WARPED_DOOR); + woodenDoors.add(Material.CRIMSON_DOOR); + woodenDoors.add(Material.MANGROVE_DOOR); + woodenDoors.add(Material.BAMBOO_DOOR); + woodenDoors.add(Material.CHERRY_DOOR); + + HashSet saplings = new HashSet<>(); + saplings.add(Material.OAK_SAPLING); + saplings.add(Material.SPRUCE_SAPLING); + saplings.add(Material.BIRCH_SAPLING); + saplings.add(Material.JUNGLE_SAPLING); + saplings.add(Material.ACACIA_SAPLING); + saplings.add(Material.DARK_OAK_SAPLING); + saplings.add(Material.CHERRY_SAPLING); + saplings.add(Material.WARPED_FUNGUS); + saplings.add(Material.CRIMSON_FUNGUS); + saplings.add(Material.MANGROVE_PROPAGULE); + + HashSet carpets = new HashSet<>(); + carpets.add(Material.BLACK_CARPET); + carpets.add(Material.BLUE_CARPET); + carpets.add(Material.LIGHT_GRAY_CARPET); + carpets.add(Material.BROWN_CARPET); + carpets.add(Material.CYAN_CARPET); + carpets.add(Material.GRAY_CARPET); + carpets.add(Material.GREEN_CARPET); + carpets.add(Material.LIGHT_BLUE_CARPET); + carpets.add(Material.MAGENTA_CARPET); + carpets.add(Material.LIME_CARPET); + carpets.add(Material.ORANGE_CARPET); + carpets.add(Material.PINK_CARPET); + carpets.add(Material.PURPLE_CARPET); + carpets.add(Material.RED_CARPET); + carpets.add(Material.WHITE_CARPET); + carpets.add(Material.YELLOW_CARPET); + + slabs = new HashSet<>(); + slabs.add(Material.OAK_SLAB); + slabs.add(Material.SPRUCE_SLAB); + slabs.add(Material.BIRCH_SLAB); + slabs.add(Material.JUNGLE_SLAB); + slabs.add(Material.ACACIA_SLAB); + slabs.add(Material.DARK_OAK_SLAB); + slabs.add(Material.WARPED_SLAB); + slabs.add(Material.CRIMSON_SLAB); + slabs.add(Material.STONE_SLAB); + slabs.add(Material.STONE_BRICK_SLAB); + slabs.add(Material.COBBLESTONE_SLAB); + slabs.add(Material.PETRIFIED_OAK_SLAB); + slabs.add(Material.SANDSTONE_SLAB); + slabs.add(Material.RED_SANDSTONE_SLAB); + slabs.add(Material.NETHER_BRICK_SLAB); + slabs.add(Material.PURPUR_SLAB); + slabs.add(Material.QUARTZ_SLAB); + slabs.add(Material.BRICK_SLAB); + slabs.add(Material.PRISMARINE_SLAB); + slabs.add(Material.DARK_PRISMARINE_SLAB); + slabs.add(Material.PRISMARINE_BRICK_SLAB); + slabs.add(Material.BLACKSTONE_SLAB); + slabs.add(Material.POLISHED_BLACKSTONE_SLAB); + slabs.add(Material.DEEPSLATE_BRICK_SLAB); + slabs.add(Material.DEEPSLATE_TILE_SLAB); + slabs.add(Material.COBBLED_DEEPSLATE_SLAB); + slabs.add(Material.POLISHED_DEEPSLATE_SLAB); + slabs.add(Material.MANGROVE_SLAB); + slabs.add(Material.BAMBOO_SLAB); + slabs.add(Material.CHERRY_SLAB); + + buttons = new HashSet<>(); + buttons.add(Material.STONE_BUTTON); + buttons.add(Material.OAK_BUTTON); + buttons.add(Material.SPRUCE_BUTTON); + buttons.add(Material.BIRCH_BUTTON); + buttons.add(Material.JUNGLE_BUTTON); + buttons.add(Material.ACACIA_BUTTON); + buttons.add(Material.DARK_OAK_BUTTON); + buttons.add(Material.WARPED_BUTTON); + buttons.add(Material.CRIMSON_BUTTON); + buttons.add(Material.MANGROVE_BUTTON); + buttons.add(Material.BAMBOO_BUTTON); + buttons.add(Material.CHERRY_BUTTON); + buttons.add(Material.POLISHED_BLACKSTONE_BUTTON); + + signs = new HashSet<>(); + signs.add(Material.OAK_SIGN); + signs.add(Material.SPRUCE_SIGN); + signs.add(Material.BIRCH_SIGN); + signs.add(Material.JUNGLE_SIGN); + signs.add(Material.DARK_OAK_SIGN); + signs.add(Material.ACACIA_SIGN); + signs.add(Material.WARPED_SIGN); + signs.add(Material.CRIMSON_SIGN); + signs.add(Material.MANGROVE_SIGN); + signs.add(Material.BAMBOO_SIGN); + signs.add(Material.CHERRY_SIGN); + + wallSigns = new HashSet<>(); + wallSigns.add(Material.OAK_WALL_SIGN); + wallSigns.add(Material.SPRUCE_WALL_SIGN); + wallSigns.add(Material.BIRCH_WALL_SIGN); + wallSigns.add(Material.JUNGLE_WALL_SIGN); + wallSigns.add(Material.DARK_OAK_WALL_SIGN); + wallSigns.add(Material.ACACIA_WALL_SIGN); + wallSigns.add(Material.WARPED_WALL_SIGN); + wallSigns.add(Material.CRIMSON_WALL_SIGN); + wallSigns.add(Material.MANGROVE_WALL_SIGN); + wallSigns.add(Material.BAMBOO_WALL_SIGN); + wallSigns.add(Material.CHERRY_WALL_SIGN); + + hangingSigns = new HashSet<>(); + hangingSigns.add(Material.OAK_HANGING_SIGN); + hangingSigns.add(Material.SPRUCE_HANGING_SIGN); + hangingSigns.add(Material.BIRCH_HANGING_SIGN); + hangingSigns.add(Material.JUNGLE_HANGING_SIGN); + hangingSigns.add(Material.DARK_OAK_HANGING_SIGN); + hangingSigns.add(Material.ACACIA_HANGING_SIGN); + hangingSigns.add(Material.WARPED_HANGING_SIGN); + hangingSigns.add(Material.CRIMSON_HANGING_SIGN); + hangingSigns.add(Material.MANGROVE_HANGING_SIGN); + hangingSigns.add(Material.BAMBOO_HANGING_SIGN); + hangingSigns.add(Material.CHERRY_HANGING_SIGN); + + hangingWallSigns = new HashSet<>(); + hangingWallSigns.add(Material.OAK_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.SPRUCE_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.BIRCH_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.JUNGLE_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.DARK_OAK_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.ACACIA_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.WARPED_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.CRIMSON_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.MANGROVE_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.BAMBOO_WALL_HANGING_SIGN); + hangingWallSigns.add(Material.CHERRY_WALL_HANGING_SIGN); + + allSigns = new HashSet<>(); + allSigns.addAll(signs); + allSigns.addAll(wallSigns); + allSigns.addAll(hangingSigns); + allSigns.addAll(hangingWallSigns); + unmodifiableSigns = Collections.unmodifiableSet(allSigns); + + singleBlockPlants = new HashSet<>(); + singleBlockPlants.add(Material.GRASS); + singleBlockPlants.add(Material.FERN); + singleBlockPlants.add(Material.DEAD_BUSH); + singleBlockPlants.add(Material.DANDELION); + singleBlockPlants.add(Material.POPPY); + singleBlockPlants.add(Material.BLUE_ORCHID); + singleBlockPlants.add(Material.ALLIUM); + singleBlockPlants.add(Material.AZURE_BLUET); + singleBlockPlants.add(Material.ORANGE_TULIP); + singleBlockPlants.add(Material.WHITE_TULIP); + singleBlockPlants.add(Material.PINK_TULIP); + singleBlockPlants.add(Material.RED_TULIP); + singleBlockPlants.add(Material.OXEYE_DAISY); + singleBlockPlants.add(Material.BROWN_MUSHROOM); + singleBlockPlants.add(Material.RED_MUSHROOM); + singleBlockPlants.add(Material.SWEET_BERRY_BUSH); + singleBlockPlants.add(Material.LILY_OF_THE_VALLEY); + singleBlockPlants.add(Material.CORNFLOWER); + singleBlockPlants.add(Material.WITHER_ROSE); + singleBlockPlants.add(Material.CRIMSON_FUNGUS); + singleBlockPlants.add(Material.WARPED_FUNGUS); + singleBlockPlants.add(Material.CRIMSON_ROOTS); + singleBlockPlants.add(Material.WARPED_ROOTS); + singleBlockPlants.add(Material.NETHER_SPROUTS); + singleBlockPlants.add(Material.AZALEA); + singleBlockPlants.add(Material.FLOWERING_AZALEA); + singleBlockPlants.add(Material.PINK_PETALS); + singleBlockPlants.add(Material.TORCHFLOWER); + singleBlockPlants.add(Material.PITCHER_CROP); + + doublePlants = new HashSet<>(); + doublePlants.add(Material.TALL_GRASS); + doublePlants.add(Material.LARGE_FERN); + doublePlants.add(Material.TALL_SEAGRASS); + doublePlants.add(Material.ROSE_BUSH); + doublePlants.add(Material.LILAC); + doublePlants.add(Material.SUNFLOWER); + doublePlants.add(Material.PEONY); + doublePlants.add(Material.SMALL_DRIPLEAF); + doublePlants.add(Material.PITCHER_PLANT); + + blockEquivalents = new HashSet<>(7); + blockEquivalents.add(new HashSet<>(Arrays.asList(2, 3, 60))); + blockEquivalents.add(new HashSet<>(Arrays.asList(8, 9, 79))); + blockEquivalents.add(new HashSet<>(Arrays.asList(10, 11))); + blockEquivalents.add(new HashSet<>(Arrays.asList(61, 62))); + blockEquivalents.add(new HashSet<>(Arrays.asList(73, 74))); + blockEquivalents.add(new HashSet<>(Arrays.asList(75, 76))); + blockEquivalents.add(new HashSet<>(Arrays.asList(93, 94))); + + // Blocks that break when they are attached to a block + relativeBreakable = new HashSet<>(); + relativeBreakable.addAll(wallSigns); + relativeBreakable.add(Material.LADDER); + relativeBreakable.addAll(buttons); + relativeBreakable.add(Material.REDSTONE_WALL_TORCH); + relativeBreakable.add(Material.LEVER); + relativeBreakable.add(Material.WALL_TORCH); + relativeBreakable.add(Material.TRIPWIRE_HOOK); + relativeBreakable.add(Material.COCOA); + relativeBreakable.add(Material.BELL); + relativeBreakable.add(Material.AMETHYST_CLUSTER); + relativeBreakable.add(Material.SMALL_AMETHYST_BUD); + relativeBreakable.add(Material.MEDIUM_AMETHYST_BUD); + relativeBreakable.add(Material.LARGE_AMETHYST_BUD); + + // Blocks that break when they are on top of a block + relativeTopBreakable = new HashSet<>(); + relativeTopBreakable.addAll(saplings); + relativeTopBreakable.addAll(singleBlockPlants); + relativeTopBreakable.add(Material.WHEAT); + relativeTopBreakable.add(Material.POTATO); + relativeTopBreakable.add(Material.CARROT); + relativeTopBreakable.add(Material.LILY_PAD); + relativeTopBreakable.add(Material.CACTUS); + relativeTopBreakable.add(Material.SUGAR_CANE); + relativeTopBreakable.add(Material.FLOWER_POT); + relativeTopBreakable.add(Material.POWERED_RAIL); + relativeTopBreakable.add(Material.DETECTOR_RAIL); + relativeTopBreakable.add(Material.ACTIVATOR_RAIL); + relativeTopBreakable.add(Material.RAIL); + relativeTopBreakable.add(Material.REDSTONE_WIRE); + relativeTopBreakable.addAll(signs); + relativeTopBreakable.addAll(pressurePlates); + relativeTopBreakable.add(Material.SNOW); + relativeTopBreakable.add(Material.REPEATER); + relativeTopBreakable.add(Material.COMPARATOR); + relativeTopBreakable.add(Material.TORCH); + relativeTopBreakable.add(Material.SOUL_TORCH); + relativeTopBreakable.add(Material.REDSTONE_TORCH); + relativeTopBreakable.addAll(woodenDoors); + relativeTopBreakable.add(Material.IRON_DOOR); + relativeTopBreakable.addAll(carpets); + relativeTopBreakable.addAll(doublePlants); + relativeTopBreakable.add(Material.BAMBOO); + relativeTopBreakable.add(Material.BAMBOO_SAPLING); + relativeTopBreakable.add(Material.TWISTING_VINES); + relativeTopBreakable.add(Material.TWISTING_VINES_PLANT); + relativeTopBreakable.add(Material.BIG_DRIPLEAF); + relativeTopBreakable.add(Material.BIG_DRIPLEAF_STEM); + for (Material m : Material.values()) { + if (m.name().startsWith("POTTED_")) { + relativeTopBreakable.add(m); + } + if (m.name().endsWith("CANDLE_CAKE")) { + relativeTopBreakable.add(m); + } + } + + // Blocks that break falling entities + fallingEntityKillers = new HashSet<>(); + fallingEntityKillers.addAll(signs); + fallingEntityKillers.addAll(wallSigns); + fallingEntityKillers.addAll(pressurePlates); + fallingEntityKillers.addAll(saplings); + fallingEntityKillers.addAll(singleBlockPlants); + fallingEntityKillers.remove(Material.GRASS); + fallingEntityKillers.remove(Material.NETHER_SPROUTS); + fallingEntityKillers.addAll(doublePlants); + fallingEntityKillers.add(Material.WHEAT); + fallingEntityKillers.add(Material.CARROT); + fallingEntityKillers.add(Material.POTATO); + fallingEntityKillers.add(Material.BEETROOT); + fallingEntityKillers.add(Material.NETHER_WART); + fallingEntityKillers.add(Material.COCOA); + fallingEntityKillers.addAll(slabs); + fallingEntityKillers.add(Material.TORCH); + fallingEntityKillers.add(Material.WALL_TORCH); + fallingEntityKillers.add(Material.SOUL_TORCH); + fallingEntityKillers.add(Material.SOUL_WALL_TORCH); + fallingEntityKillers.add(Material.FLOWER_POT); + fallingEntityKillers.add(Material.POWERED_RAIL); + fallingEntityKillers.add(Material.DETECTOR_RAIL); + fallingEntityKillers.add(Material.ACTIVATOR_RAIL); + fallingEntityKillers.add(Material.RAIL); + fallingEntityKillers.add(Material.LEVER); + fallingEntityKillers.add(Material.REDSTONE_WIRE); + fallingEntityKillers.add(Material.REDSTONE_TORCH); + fallingEntityKillers.add(Material.REDSTONE_WALL_TORCH); + fallingEntityKillers.add(Material.REPEATER); + fallingEntityKillers.add(Material.COMPARATOR); + fallingEntityKillers.add(Material.DAYLIGHT_DETECTOR); + fallingEntityKillers.addAll(carpets); + fallingEntityKillers.add(Material.PLAYER_HEAD); + fallingEntityKillers.add(Material.PLAYER_WALL_HEAD); + fallingEntityKillers.add(Material.CREEPER_HEAD); + fallingEntityKillers.add(Material.CREEPER_WALL_HEAD); + fallingEntityKillers.add(Material.DRAGON_HEAD); + fallingEntityKillers.add(Material.DRAGON_WALL_HEAD); + fallingEntityKillers.add(Material.ZOMBIE_HEAD); + fallingEntityKillers.add(Material.ZOMBIE_WALL_HEAD); + fallingEntityKillers.add(Material.SKELETON_SKULL); + fallingEntityKillers.add(Material.SKELETON_WALL_SKULL); + fallingEntityKillers.add(Material.WITHER_SKELETON_SKULL); + fallingEntityKillers.add(Material.WITHER_SKELETON_WALL_SKULL); + for (Material m : Material.values()) { + if (m.name().contains("CANDLE")) { + fallingEntityKillers.add(m); + } + } + + // Crop Blocks + cropBlocks = new HashSet<>(); + cropBlocks.add(Material.WHEAT); + cropBlocks.add(Material.MELON_STEM); + cropBlocks.add(Material.PUMPKIN_STEM); + cropBlocks.add(Material.CARROT); + cropBlocks.add(Material.POTATO); + cropBlocks.add(Material.BEETROOT); + cropBlocks.add(Material.TORCHFLOWER_CROP); + + // Shulker Boxes + shulkerBoxBlocks = new HashSet<>(); + shulkerBoxBlocks.add(Material.SHULKER_BOX); + shulkerBoxBlocks.add(Material.BLACK_SHULKER_BOX); + shulkerBoxBlocks.add(Material.BLUE_SHULKER_BOX); + shulkerBoxBlocks.add(Material.LIGHT_GRAY_SHULKER_BOX); + shulkerBoxBlocks.add(Material.BROWN_SHULKER_BOX); + shulkerBoxBlocks.add(Material.CYAN_SHULKER_BOX); + shulkerBoxBlocks.add(Material.GRAY_SHULKER_BOX); + shulkerBoxBlocks.add(Material.GREEN_SHULKER_BOX); + shulkerBoxBlocks.add(Material.LIGHT_BLUE_SHULKER_BOX); + shulkerBoxBlocks.add(Material.MAGENTA_SHULKER_BOX); + shulkerBoxBlocks.add(Material.LIME_SHULKER_BOX); + shulkerBoxBlocks.add(Material.ORANGE_SHULKER_BOX); + shulkerBoxBlocks.add(Material.PINK_SHULKER_BOX); + shulkerBoxBlocks.add(Material.PURPLE_SHULKER_BOX); + shulkerBoxBlocks.add(Material.RED_SHULKER_BOX); + shulkerBoxBlocks.add(Material.WHITE_SHULKER_BOX); + shulkerBoxBlocks.add(Material.YELLOW_SHULKER_BOX); + + // Container Blocks + containerBlocks = new HashSet<>(); + containerBlocks.add(Material.CHEST); + containerBlocks.add(Material.TRAPPED_CHEST); + containerBlocks.add(Material.DISPENSER); + containerBlocks.add(Material.DROPPER); + containerBlocks.add(Material.HOPPER); + containerBlocks.add(Material.BREWING_STAND); + containerBlocks.add(Material.FURNACE); + containerBlocks.addAll(shulkerBoxBlocks); + containerBlocks.add(Material.BARREL); + containerBlocks.add(Material.BLAST_FURNACE); + containerBlocks.add(Material.SMOKER); + containerBlocks.add(Material.CHISELED_BOOKSHELF); + // Doesn't actually have a block inventory + // containerBlocks.add(Material.ENDER_CHEST); + + // It doesn't seem like you could injure people with some of these, but they exist, so.... + projectileItems = new HashMap<>(); + projectileItems.put(EntityType.ARROW, Material.ARROW); + projectileItems.put(EntityType.EGG, Material.EGG); + 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_HOOK, Material.FISHING_ROD); + projectileItems.put(EntityType.SNOWBALL, Material.SNOWBALL); + projectileItems.put(EntityType.SPLASH_POTION, Material.SPLASH_POTION); + projectileItems.put(EntityType.THROWN_EXP_BOTTLE, Material.EXPERIENCE_BOTTLE); + projectileItems.put(EntityType.WITHER_SKULL, Material.WITHER_SKELETON_SKULL); + projectileItems.put(EntityType.FIREWORK, Material.FIREWORK_ROCKET); + + nonFluidProofBlocks = new HashSet<>(); + nonFluidProofBlocks.addAll(singleBlockPlants); + nonFluidProofBlocks.addAll(doublePlants); + nonFluidProofBlocks.add(Material.REDSTONE_WALL_TORCH); + nonFluidProofBlocks.add(Material.LEVER); + nonFluidProofBlocks.add(Material.WALL_TORCH); + nonFluidProofBlocks.add(Material.SOUL_WALL_TORCH); + nonFluidProofBlocks.add(Material.TRIPWIRE_HOOK); + nonFluidProofBlocks.add(Material.COCOA); + nonFluidProofBlocks.addAll(pressurePlates); + nonFluidProofBlocks.addAll(saplings); + nonFluidProofBlocks.add(Material.WHEAT); + nonFluidProofBlocks.add(Material.CARROT); + nonFluidProofBlocks.add(Material.POTATO); + nonFluidProofBlocks.add(Material.BEETROOT); + nonFluidProofBlocks.add(Material.NETHER_WART); + nonFluidProofBlocks.add(Material.TORCH); + nonFluidProofBlocks.add(Material.SOUL_TORCH); + nonFluidProofBlocks.add(Material.FLOWER_POT); + // nonFluidProofBlocks.add(Material.POWERED_RAIL); + // nonFluidProofBlocks.add(Material.DETECTOR_RAIL); + // nonFluidProofBlocks.add(Material.ACTIVATOR_RAIL); + // nonFluidProofBlocks.add(Material.RAIL); + nonFluidProofBlocks.add(Material.LEVER); + nonFluidProofBlocks.add(Material.REDSTONE_WIRE); + nonFluidProofBlocks.add(Material.REDSTONE_TORCH); + nonFluidProofBlocks.add(Material.REPEATER); + nonFluidProofBlocks.add(Material.COMPARATOR); + nonFluidProofBlocks.add(Material.DAYLIGHT_DETECTOR); + nonFluidProofBlocks.addAll(carpets); + + alwaysWaterlogged = new HashSet<>(); + alwaysWaterlogged.add(Material.SEAGRASS); + alwaysWaterlogged.add(Material.TALL_SEAGRASS); + alwaysWaterlogged.add(Material.KELP); + alwaysWaterlogged.add(Material.KELP_PLANT); + + bedBlocks = new HashSet<>(); + bedBlocks.add(Material.BLACK_BED); + bedBlocks.add(Material.BLUE_BED); + bedBlocks.add(Material.LIGHT_GRAY_BED); + bedBlocks.add(Material.BROWN_BED); + bedBlocks.add(Material.CYAN_BED); + bedBlocks.add(Material.GRAY_BED); + bedBlocks.add(Material.GREEN_BED); + bedBlocks.add(Material.LIGHT_BLUE_BED); + bedBlocks.add(Material.MAGENTA_BED); + bedBlocks.add(Material.LIME_BED); + bedBlocks.add(Material.ORANGE_BED); + bedBlocks.add(Material.PINK_BED); + bedBlocks.add(Material.PURPLE_BED); + bedBlocks.add(Material.RED_BED); + bedBlocks.add(Material.WHITE_BED); + bedBlocks.add(Material.YELLOW_BED); + + concreteBlocks = new HashSet<>(); + concreteBlocks.add(Material.BLACK_CONCRETE); + concreteBlocks.add(Material.BLUE_CONCRETE); + concreteBlocks.add(Material.LIGHT_GRAY_CONCRETE); + concreteBlocks.add(Material.BROWN_CONCRETE); + concreteBlocks.add(Material.CYAN_CONCRETE); + concreteBlocks.add(Material.GRAY_CONCRETE); + concreteBlocks.add(Material.GREEN_CONCRETE); + concreteBlocks.add(Material.LIGHT_BLUE_CONCRETE); + concreteBlocks.add(Material.MAGENTA_CONCRETE); + concreteBlocks.add(Material.LIME_CONCRETE); + concreteBlocks.add(Material.ORANGE_CONCRETE); + concreteBlocks.add(Material.PINK_CONCRETE); + concreteBlocks.add(Material.PURPLE_CONCRETE); + concreteBlocks.add(Material.RED_CONCRETE); + concreteBlocks.add(Material.WHITE_CONCRETE); + concreteBlocks.add(Material.YELLOW_CONCRETE); + + candles = new HashSet<>(); + candles.add(Material.CANDLE); + candles.add(Material.BLACK_CANDLE); + candles.add(Material.BLUE_CANDLE); + candles.add(Material.LIGHT_GRAY_CANDLE); + candles.add(Material.BROWN_CANDLE); + candles.add(Material.CYAN_CANDLE); + candles.add(Material.GRAY_CANDLE); + candles.add(Material.GREEN_CANDLE); + candles.add(Material.LIGHT_BLUE_CANDLE); + candles.add(Material.MAGENTA_CANDLE); + candles.add(Material.LIME_CANDLE); + candles.add(Material.ORANGE_CANDLE); + candles.add(Material.PINK_CANDLE); + candles.add(Material.PURPLE_CANDLE); + candles.add(Material.RED_CANDLE); + candles.add(Material.WHITE_CANDLE); + candles.add(Material.YELLOW_CANDLE); + + candleCakes = new HashSet<>(); + candleCakes.add(Material.CANDLE_CAKE); + candleCakes.add(Material.BLACK_CANDLE_CAKE); + candleCakes.add(Material.BLUE_CANDLE_CAKE); + candleCakes.add(Material.LIGHT_GRAY_CANDLE_CAKE); + candleCakes.add(Material.BROWN_CANDLE_CAKE); + candleCakes.add(Material.CYAN_CANDLE_CAKE); + candleCakes.add(Material.GRAY_CANDLE_CAKE); + candleCakes.add(Material.GREEN_CANDLE_CAKE); + candleCakes.add(Material.LIGHT_BLUE_CANDLE_CAKE); + candleCakes.add(Material.MAGENTA_CANDLE_CAKE); + candleCakes.add(Material.LIME_CANDLE_CAKE); + candleCakes.add(Material.ORANGE_CANDLE_CAKE); + candleCakes.add(Material.PINK_CANDLE_CAKE); + candleCakes.add(Material.PURPLE_CANDLE_CAKE); + candleCakes.add(Material.RED_CANDLE_CAKE); + candleCakes.add(Material.WHITE_CANDLE_CAKE); + candleCakes.add(Material.YELLOW_CANDLE_CAKE); + + dyes = new HashMap<>(); + dyes.put(Material.BLACK_DYE, DyeColor.BLACK); + dyes.put(Material.BLUE_DYE, DyeColor.BLUE); + dyes.put(Material.LIGHT_GRAY_DYE, DyeColor.LIGHT_GRAY); + dyes.put(Material.BROWN_DYE, DyeColor.BROWN); + dyes.put(Material.CYAN_DYE, DyeColor.CYAN); + dyes.put(Material.GRAY_DYE, DyeColor.GRAY); + dyes.put(Material.GREEN_DYE, DyeColor.GREEN); + dyes.put(Material.LIGHT_BLUE_DYE, DyeColor.LIGHT_BLUE); + dyes.put(Material.MAGENTA_DYE, DyeColor.MAGENTA); + dyes.put(Material.LIME_DYE, DyeColor.LIME); + dyes.put(Material.ORANGE_DYE, DyeColor.ORANGE); + dyes.put(Material.PINK_DYE, DyeColor.PINK); + dyes.put(Material.PURPLE_DYE, DyeColor.PURPLE); + dyes.put(Material.RED_DYE, DyeColor.RED); + dyes.put(Material.WHITE_DYE, DyeColor.WHITE); + dyes.put(Material.YELLOW_DYE, DyeColor.YELLOW); + } + + private static final BlockFace[] relativeBlockFaces = new BlockFace[] { + BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN + }; + + /** + * Returns a list of block locations around the block that are of the type specified by the integer list parameter + * + * @param block The central block to get the blocks around + * @param type The type of blocks around the center block to return + * @return List of block locations around the block that are of the type specified by the integer list parameter + */ + public static List getBlocksNearby(org.bukkit.block.Block block, Set type) { + ArrayList blocks = new ArrayList<>(); + for (BlockFace blockFace : relativeBlockFaces) { + if (type.contains(block.getRelative(blockFace).getType())) { + blocks.add(block.getRelative(blockFace).getLocation()); + } + } + return blocks; + } + + public static boolean isTop(BlockData data) { + if (data instanceof Bisected && !(data instanceof Stairs)) { + return ((Bisected) data).getHalf() == Half.TOP; + } + return false; + } + + public static Material getInventoryHolderType(InventoryHolder holder) { + if (holder instanceof DoubleChest) { + return getInventoryHolderType(((DoubleChest) holder).getLeftSide()); + } else if (holder instanceof BlockState) { + return ((BlockState) holder).getType(); + } else { + return null; + } + } + + public static Location getInventoryHolderLocation(InventoryHolder holder) { + if (holder instanceof DoubleChest) { + return getInventoryHolderLocation(((DoubleChest) holder).getLeftSide()); + } else if (holder instanceof BlockState) { + return ((BlockState) holder).getLocation(); + } else { + return null; + } + } + + public static ItemStack[] compareInventories(ItemStack[] items1, ItemStack[] items2) { + final ArrayList diff = new ArrayList<>(); + for (ItemStack current : items2) { + try { + diff.add(new ItemStack(current)); + } catch (NullPointerException e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not clone ItemStack, probably Spigot bug SPIGOT-6025", e); // SPIGOT-6025 + } + } + for (ItemStack previous : items1) { + boolean found = false; + for (ItemStack current : diff) { + if (current.isSimilar(previous)) { + int newAmount = current.getAmount() - previous.getAmount(); + if (newAmount == 0) { + diff.remove(current); + } else { + current.setAmount(newAmount); + } + found = true; + break; + } + } + if (!found) { + try { + ItemStack subtracted = new ItemStack(previous); + subtracted.setAmount(-subtracted.getAmount()); + diff.add(subtracted); + } catch (NullPointerException e) { + LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not clone ItemStack, probably Spigot bug SPIGOT-6025", e); // SPIGOT-6025 + } + } + } + return diff.toArray(new ItemStack[diff.size()]); + } + + public static ItemStack[] compressInventory(ItemStack[] items) { + final ArrayList compressed = new ArrayList<>(); + for (final ItemStack item : items) { + 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()); + } + } + } + return compressed.toArray(new ItemStack[compressed.size()]); + } + + public static boolean equalTypes(int type1, int type2) { + if (type1 == type2) { + return true; + } + for (final Set equivalent : blockEquivalents) { + if (equivalent.contains(type1) && equivalent.contains(type2)) { + return true; + } + } + return false; + } + + public static String friendlyWorldname(String worldName) { + return new File(worldName).getName(); + } + + public static Set> getBlockEquivalents() { + return blockEquivalents; + } + + public static Set getRelativeBreakables() { + return relativeBreakable; + } + + public static Set getRelativeTopBreakabls() { + return relativeTopBreakable; + } + + public static Set getFallingEntityKillers() { + return fallingEntityKillers; + } + + public static Set getNonFluidProofBlocks() { + return nonFluidProofBlocks; + } + + public static Set getCropBlocks() { + return cropBlocks; + } + + public static Set getContainerBlocks() { + return containerBlocks; + } + + public static Set getShulkerBoxBlocks() { + return shulkerBoxBlocks; + } + + public static boolean isConcreteBlock(Material m) { + return concreteBlocks.contains(m); + } + + public static String entityName(Entity entity) { + if (entity instanceof Player) { + return ((Player) entity).getName(); + } + if (entity instanceof TNTPrimed) { + return "TNT"; + } + return entity.getClass().getSimpleName().substring(5); + } + + public static void giveTool(Player player, Material type) { + final Inventory inv = player.getInventory(); + if (inv.contains(type)) { + player.sendMessage(ChatColor.RED + "You have already a " + type.name()); + } else { + final int free = inv.firstEmpty(); + if (free >= 0) { + if (player.getInventory().getItemInMainHand() != null && player.getInventory().getItemInMainHand().getType() != Material.AIR) { + inv.setItem(free, player.getInventory().getItemInMainHand()); + } + player.getInventory().setItemInMainHand(new ItemStack(type)); + player.sendMessage(ChatColor.GREEN + "Here's your " + type.name()); + } else { + player.sendMessage(ChatColor.RED + "You have no empty slot in your inventory"); + } + } + } + + public static int safeSpawnHeight(Location loc) { + final World world = loc.getWorld(); + world.getChunkAt(loc); + final int x = loc.getBlockX(), z = loc.getBlockZ(); + int y = loc.getBlockY(); + boolean lower = world.getBlockAt(x, y, z).isEmpty(), upper = world.getBlockAt(x, y + 1, z).isEmpty(); + while ((!lower || !upper) && y != world.getMaxHeight()) { + lower = upper; + upper = world.getBlockAt(x, ++y, z).isEmpty(); + } + while (world.getBlockAt(x, y - 1, z).isEmpty() && y != world.getMinHeight()) { + y--; + } + return y; + } + + public static int modifyContainer(BlockState b, ItemStack item, boolean remove) { + if (b instanceof InventoryHolder) { + final Inventory inv = ((InventoryHolder) b).getInventory(); + if (remove) { + 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; + } + + public static boolean canFallIn(World world, int x, int y, int z) { + Block block = world.getBlockAt(x, y, z); + Material mat = block.getType(); + if (canDirectlyFallIn(mat)) { + return true; + } else if (getFallingEntityKillers().contains(mat) || singleBlockPlants.contains(mat) || mat == Material.VINE) { + if (slabs.contains(mat)) { + if (((Slab) block.getBlockData()).getType() != Type.BOTTOM) { + return false; + } + } + return true; + } + return false; + } + + public static boolean canDirectlyFallIn(Material m) { + return isEmpty(m) || m == Material.WATER || m == Material.LAVA || m == Material.FIRE; + } + + public static Material itemIDfromProjectileEntity(Entity e) { + return projectileItems.get(e.getType()); + } + + public static boolean isDoublePlant(Material m) { + return doublePlants.contains(m); + } + + public static boolean isWoodenDoor(Material m) { + return woodenDoors.contains(m); + } + + public static boolean isButton(Material m) { + return buttons.contains(m); + } + + public static boolean isEmpty(Material m) { + return m == Material.AIR || m == Material.CAVE_AIR || m == Material.VOID_AIR; + } + + public static TextComponent toString(ItemStack stack) { + if (stack == null || stack.getAmount() == 0 || isEmpty(stack.getType())) { + return prettyMaterial("nothing"); + } + TextComponent msg = MessagingUtil.createTextComponentWithColor(stack.getAmount() + "x ", TypeColor.DEFAULT.getColor()); + msg.addExtra(prettyMaterial(stack.getType())); + + try { + 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()) }))); + } + + 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; + for (int i = 0; i < cap.length; i++) { + char c = cap[i]; + if (c == '_') { + c = ' '; + lastSpace = true; + } else if (c >= '0' && c <= '9' || c == '(' || c == ')') { + lastSpace = true; + } else { + if (lastSpace) { + c = Character.toUpperCase(c); + } else { + c = Character.toLowerCase(c); + } + lastSpace = false; + } + cap[i] = c; + } + return new String(cap); + } + + public static boolean isBed(Material type) { + return bedBlocks.contains(type); + } + + public static boolean isDye(Material type) { + return dyes.containsKey(type); + } + + public static DyeColor dyeToDyeColor(Material type) { + return dyes.get(type); + } + + public static Block getConnectedChest(Block chestBlock) { + // is this a chest? + BlockData blockData = chestBlock.getBlockData(); + if (!(blockData instanceof org.bukkit.block.data.type.Chest)) { + return null; + } + // so check if is should have a neighbour + org.bukkit.block.data.type.Chest chestData = (org.bukkit.block.data.type.Chest) blockData; + org.bukkit.block.data.type.Chest.Type chestType = chestData.getType(); + if (chestType != org.bukkit.block.data.type.Chest.Type.SINGLE) { + // check if the neighbour exists + BlockFace chestFace = chestData.getFacing(); + BlockFace faceToSecondChest; + if (chestFace == BlockFace.WEST) { + faceToSecondChest = BlockFace.NORTH; + } else if (chestFace == BlockFace.NORTH) { + faceToSecondChest = BlockFace.EAST; + } else if (chestFace == BlockFace.EAST) { + faceToSecondChest = BlockFace.SOUTH; + } else if (chestFace == BlockFace.SOUTH) { + faceToSecondChest = BlockFace.WEST; + } else { + return null; + } + org.bukkit.block.data.type.Chest.Type wantedChestType = org.bukkit.block.data.type.Chest.Type.RIGHT; + if (chestType == org.bukkit.block.data.type.Chest.Type.RIGHT) { + faceToSecondChest = faceToSecondChest.getOppositeFace(); + wantedChestType = org.bukkit.block.data.type.Chest.Type.LEFT; + } + Block face = chestBlock.getRelative(faceToSecondChest); + if (face.getType() == chestBlock.getType()) { + // check is the neighbour connects to this chest + org.bukkit.block.data.type.Chest otherChestData = (org.bukkit.block.data.type.Chest) face.getBlockData(); + if (otherChestData.getType() != wantedChestType || otherChestData.getFacing() != chestFace) { + return null; + } + return face; + } + } + return null; + } + + public static Entity loadEntityAround(Chunk chunk, UUID uuid) { + Entity e = Bukkit.getEntity(uuid); + if (e != null) { + return e; + } + if (!chunk.isLoaded()) { + chunk.getWorld().getChunkAt(chunk.getX(), chunk.getZ()); + e = Bukkit.getEntity(uuid); + if (e != null) { + return e; + } + } + int chunkx = chunk.getX(); + int chunkz = chunk.getZ(); + for (int i = 0; i < 8; i++) { + int x = i < 3 ? chunkx - 1 : (i < 5 ? chunkx : chunkx + 1); + int z = i == 0 || i == 3 || i == 5 ? chunkz - 1 : (i == 1 || i == 6 ? chunkz : chunkz + 1); + if (!chunk.getWorld().isChunkLoaded(x, z)) { + chunk.getWorld().getChunkAt(x, z); + e = Bukkit.getEntity(uuid); + if (e != null) { + return e; + } + } + } + return null; + } + + private static final HashMap types = new HashMap<>(); + static { + for (EntityType t : EntityType.values()) { + if (t != EntityType.UNKNOWN) { + types.put(t.name().toLowerCase(), t); + @SuppressWarnings("deprecation") + String typeName = t.getName(); + if (typeName != null) { + types.put(typeName.toLowerCase(), t); + } + Class ec = t.getEntityClass(); + if (ec != null) { + types.put(ec.getSimpleName().toLowerCase(), t); + } + types.put(t.getKey().getKey(), t); + types.put(t.getKey().toString(), t); + } + } + } + + public static EntityType matchEntityType(String typeName) { + return types.get(typeName.toLowerCase()); + } + + public static ItemStack getItemInSlot(ArmorStand stand, EquipmentSlot slot) { + if (slot == EquipmentSlot.HAND) { + return stand.getEquipment().getItemInMainHand(); + } else if (slot == EquipmentSlot.OFF_HAND) { + return stand.getEquipment().getItemInOffHand(); + } else if (slot == EquipmentSlot.FEET) { + return stand.getEquipment().getBoots(); + } else if (slot == EquipmentSlot.LEGS) { + return stand.getEquipment().getLeggings(); + } else if (slot == EquipmentSlot.CHEST) { + return stand.getEquipment().getChestplate(); + } else if (slot == EquipmentSlot.HEAD) { + return stand.getEquipment().getHelmet(); + } + return null; + } + + public static void setItemInSlot(ArmorStand stand, EquipmentSlot slot, ItemStack stack) { + if (slot == EquipmentSlot.HAND) { + stand.getEquipment().setItemInMainHand(stack); + } else if (slot == EquipmentSlot.OFF_HAND) { + stand.getEquipment().setItemInOffHand(stack); + } else if (slot == EquipmentSlot.FEET) { + stand.getEquipment().setBoots(stack); + } else if (slot == EquipmentSlot.LEGS) { + stand.getEquipment().setLeggings(stack); + } else if (slot == EquipmentSlot.CHEST) { + stand.getEquipment().setChestplate(stack); + } else if (slot == EquipmentSlot.HEAD) { + stand.getEquipment().setHelmet(stack); + } + } + + public static ItemStack[] deepCopy(ItemStack[] of) { + ItemStack[] result = new ItemStack[of.length]; + for (int i = 0; i < result.length; i++) { + result[i] = of[i] == null ? null : new ItemStack(of[i]); + } + return result; + } + + private static int getFirstPartialItemStack(ItemStack item, ItemStack[] contents, int start) { + for (int i = start; i < contents.length; i++) { + ItemStack content = contents[i]; + if (content != null && content.isSimilar(item) && content.getAmount() < content.getMaxStackSize()) { + return i; + } + } + return -1; + } + + private static int getFirstFreeItemStack(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; + } + + public static boolean hasInventoryStorageSpaceFor(Inventory inv, ItemStack... items) { + ItemStack[] contents = deepCopy(inv.getStorageContents()); + for (ItemStack item : items) { + if (item != null && item.getType() != Material.AIR) { + int remaining = item.getAmount(); + // fill partial stacks + int firstPartial = -1; + while (remaining > 0) { + firstPartial = getFirstPartialItemStack(item, contents, firstPartial + 1); + if (firstPartial < 0) { + break; + } + ItemStack content = contents[firstPartial]; + int add = Math.min(content.getMaxStackSize() - content.getAmount(), remaining); + content.setAmount(content.getAmount() + add); + remaining -= add; + } + // create new stacks + int firstFree = -1; + while (remaining > 0) { + firstFree = getFirstFreeItemStack(contents, firstFree + 1); + if (firstFree < 0) { + return false; // no free place found + } + ItemStack content = new ItemStack(item); + contents[firstFree] = content; + // max stack size might return -1, in this case assume 1 + int add = Math.min(Math.max(content.getMaxStackSize(), 1), remaining); + content.setAmount(add); + remaining -= add; + } + } + } + return true; + } + + public static boolean isSimilarForRollback(Material expected, Material found) { + if (expected == found) { + return true; + } + if (expected == Material.DIRT || expected == Material.MYCELIUM || expected == Material.FARMLAND || expected == Material.GRASS_BLOCK || expected == Material.PODZOL || expected == Material.DIRT_PATH) { + return found == Material.DIRT || found == Material.MYCELIUM || found == Material.FARMLAND || found == Material.GRASS_BLOCK || found == Material.PODZOL || found == Material.DIRT_PATH; + } + if (expected == Material.BAMBOO || expected == Material.BAMBOO_SAPLING) { + return found == Material.BAMBOO || found == Material.BAMBOO_SAPLING; + } + if (expected == Material.SPONGE || expected == Material.WET_SPONGE) { + return found == Material.SPONGE || found == Material.WET_SPONGE; + } + if (expected == Material.MELON_STEM || expected == Material.ATTACHED_MELON_STEM) { + return found == Material.MELON_STEM || found == Material.ATTACHED_MELON_STEM; + } + if (expected == Material.PUMPKIN_STEM || expected == Material.ATTACHED_PUMPKIN_STEM) { + return found == Material.PUMPKIN_STEM || found == Material.ATTACHED_PUMPKIN_STEM; + } + if (expected == Material.TWISTING_VINES || expected == Material.TWISTING_VINES_PLANT) { + return found == Material.TWISTING_VINES || found == Material.TWISTING_VINES_PLANT; + } + if (expected == Material.WEEPING_VINES || expected == Material.WEEPING_VINES_PLANT) { + return found == Material.WEEPING_VINES || found == Material.WEEPING_VINES_PLANT; + } + if (expected == Material.CAVE_VINES || expected == Material.CAVE_VINES_PLANT) { + return found == Material.CAVE_VINES || found == Material.CAVE_VINES_PLANT; + } + if (expected == Material.BIG_DRIPLEAF || expected == Material.BIG_DRIPLEAF_STEM) { + return found == Material.BIG_DRIPLEAF || found == Material.BIG_DRIPLEAF_STEM; + } + if (expected == Material.COPPER_BLOCK || expected == Material.EXPOSED_COPPER || expected == Material.WEATHERED_COPPER || expected == Material.OXIDIZED_COPPER) { + return found == Material.COPPER_BLOCK || found == Material.EXPOSED_COPPER || found == Material.WEATHERED_COPPER || found == Material.OXIDIZED_COPPER; + } + if (expected == Material.CUT_COPPER || expected == Material.EXPOSED_CUT_COPPER || expected == Material.WEATHERED_CUT_COPPER || expected == Material.OXIDIZED_CUT_COPPER) { + return found == Material.CUT_COPPER || found == Material.EXPOSED_CUT_COPPER || found == Material.WEATHERED_CUT_COPPER || found == Material.OXIDIZED_CUT_COPPER; + } + if (expected == Material.CUT_COPPER_STAIRS || expected == Material.EXPOSED_CUT_COPPER_STAIRS || expected == Material.WEATHERED_CUT_COPPER_STAIRS || expected == Material.OXIDIZED_CUT_COPPER_STAIRS) { + return found == Material.CUT_COPPER_STAIRS || found == Material.EXPOSED_CUT_COPPER_STAIRS || found == Material.WEATHERED_CUT_COPPER_STAIRS || found == Material.OXIDIZED_CUT_COPPER_STAIRS; + } + if (expected == Material.CUT_COPPER_SLAB || expected == Material.EXPOSED_CUT_COPPER_SLAB || expected == Material.WEATHERED_CUT_COPPER_SLAB || expected == Material.OXIDIZED_CUT_COPPER_SLAB) { + return found == Material.CUT_COPPER_SLAB || found == Material.EXPOSED_CUT_COPPER_SLAB || found == Material.WEATHERED_CUT_COPPER_SLAB || found == Material.OXIDIZED_CUT_COPPER_SLAB; + } + return false; + } + + public static Set getAllSignMaterials() { + return unmodifiableSigns; + } + + public static boolean isAlwaysWaterlogged(Material m) { + return alwaysWaterlogged.contains(m); + } + + public static boolean isCandle(Material m) { + return candles.contains(m); + } + + public static boolean isCandleCake(Material m) { + return candleCakes.contains(m); + } + + public static boolean isHangingSign(Material m) { + return hangingSigns.contains(m); + } + + public static boolean isFenceGate(Material m) { + return fenceGates.contains(m); + } + + public static boolean isWoodenTrapdoor(Material m) { + return woodenTrapdoors.contains(m); + } + + public static boolean isPressurePlate(Material m) { + return pressurePlates.contains(m); + } + + public static boolean isSign(Material m) { + return allSigns.contains(m); + } + + public static Side getFacingSignSide(Entity entity, Block sign) { + BlockData data = sign.getBlockData(); + Material type = data.getMaterial(); + BlockFace signFace = null; + double centerx = 0.5; + double centerz = 0.5; + double yRotationDegree = 0; + if (type.data == Sign.class || type.data == HangingSign.class) { + Rotatable rotatableData = (Rotatable) data; + signFace = rotatableData.getRotation(); + if (signFace == BlockFace.SOUTH) { + yRotationDegree = 360 * 0.0 / 16.0; + } else if (signFace == BlockFace.SOUTH_SOUTH_WEST) { + yRotationDegree = 360 * 1.0 / 16.0; + } else if (signFace == BlockFace.SOUTH_WEST) { + yRotationDegree = 360 * 2.0 / 16.0; + } else if (signFace == BlockFace.WEST_SOUTH_WEST) { + yRotationDegree = 360 * 3.0 / 16.0; + } else if (signFace == BlockFace.WEST) { + yRotationDegree = 360 * 4.0 / 16.0; + } else if (signFace == BlockFace.WEST_NORTH_WEST) { + yRotationDegree = 360 * 5.0 / 16.0; + } else if (signFace == BlockFace.NORTH_WEST) { + yRotationDegree = 360 * 6.0 / 16.0; + } else if (signFace == BlockFace.NORTH_NORTH_WEST) { + yRotationDegree = 360 * 7.0 / 16.0; + } else if (signFace == BlockFace.NORTH) { + yRotationDegree = 360 * 8.0 / 16.0; + } else if (signFace == BlockFace.NORTH_NORTH_EAST) { + yRotationDegree = 360 * 9.0 / 16.0; + } else if (signFace == BlockFace.NORTH_EAST) { + yRotationDegree = 360 * 10.0 / 16.0; + } else if (signFace == BlockFace.EAST_NORTH_EAST) { + yRotationDegree = 360 * 11.0 / 16.0; + } else if (signFace == BlockFace.EAST) { + yRotationDegree = 360 * 12.0 / 16.0; + } else if (signFace == BlockFace.EAST_SOUTH_EAST) { + yRotationDegree = 360 * 13.0 / 16.0; + } else if (signFace == BlockFace.SOUTH_EAST) { + yRotationDegree = 360 * 14.0 / 16.0; + } else if (signFace == BlockFace.SOUTH_SOUTH_EAST) { + yRotationDegree = 360 * 15.0 / 16.0; + } + } else if (type.data == WallSign.class || type.data == WallHangingSign.class) { + Directional directionalData = (Directional) data; + signFace = directionalData.getFacing(); + if (signFace == BlockFace.SOUTH) { + yRotationDegree = 0; + } else if (signFace == BlockFace.WEST) { + yRotationDegree = 90; + } else if (signFace == BlockFace.NORTH) { + yRotationDegree = 180; + } else if (signFace == BlockFace.EAST) { + yRotationDegree = 270; + } + // wall signs are not centered on the block (but hanging wall signs are) + if (type.data == WallSign.class) { + if (signFace == BlockFace.NORTH) { + centerz = 15.0 / 16.0; + } else if (signFace == BlockFace.SOUTH) { + centerz = 1.0 / 16.0; + } else if (signFace == BlockFace.WEST) { + centerx = 15.0 / 16.0; + } else if (signFace == BlockFace.EAST) { + centerx = 1.0 / 16.0; + } + } + } else { + throw new IllegalArgumentException("block is not a sign"); + } + + Location entityLoc = entity.getLocation(); + double relativeX = entityLoc.getX() - (sign.getX() + centerx); + double relativeZ = entityLoc.getZ() - (sign.getZ() + centerz); + double f = Math.atan2(relativeZ, relativeX) * 180.0 / Math.PI - 90.0; + + return Math.abs(Utils.warpDegrees(f - yRotationDegree)) <= 90.0 ? Side.FRONT : Side.BACK; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/util/ComparableVersion.java b/src/main/java/de/diddiz/LogBlock/util/ComparableVersion.java index 17e88246..5bdec9a1 100644 --- a/src/main/java/de/diddiz/LogBlock/util/ComparableVersion.java +++ b/src/main/java/de/diddiz/LogBlock/util/ComparableVersion.java @@ -1,424 +1,424 @@ -package de.diddiz.LogBlock.util; - -// Taken from maven-artifact at -// http://grepcode.com/file_/repo1.maven.org/maven2/org.apache.maven/maven-artifact/3.2.3/org/apache/maven/artifact/versioning/ComparableVersion.java/?v=source - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Locale; -import java.util.Properties; -import java.util.Stack; - -/** - * Generic implementation of version comparison. - * - *

    Features: - *

      - *
    • mixing of '-' (dash) and '.' (dot) separators,
    • - *
    • transition between characters and digits also constitutes a separator: - * 1.0alpha1 => [1, 0, alpha, 1]
    • - *
    • unlimited number of version components,
    • - *
    • version components in the text can be digits or strings,
    • - *
    • strings are checked for well-known qualifiers and the qualifier ordering is used for version ordering. - * Well-known qualifiers (case insensitive) are:
        - *
      • alpha or a
      • - *
      • beta or b
      • - *
      • milestone or m
      • - *
      • rc or cr
      • - *
      • snapshot
      • - *
      • (the empty string) or ga or final
      • - *
      • sp
      • - *
      - * Unknown qualifiers are considered after known qualifiers, with lexical order (always case insensitive), - *
    • - *
    • a dash usually precedes a qualifier, and is always less important than something preceded with a dot.
    • - *

    - * - * @see "Versioning" on Maven Wiki - * @author Kenney Westerhof - * @author Hervé Boutemy - */ -public class ComparableVersion implements Comparable { - private String value; - - private String canonical; - - private ListItem items; - - private interface Item { - int INTEGER_ITEM = 0; - int STRING_ITEM = 1; - int LIST_ITEM = 2; - - int compareTo(Item item); - - int getType(); - - boolean isNull(); - } - - /** - * Represents a numeric item in the version item list. - */ - private static class IntegerItem implements Item { - private static final BigInteger BIG_INTEGER_ZERO = new BigInteger("0"); - - private final BigInteger value; - - public static final IntegerItem ZERO = new IntegerItem(); - - private IntegerItem() { - this.value = BIG_INTEGER_ZERO; - } - - public IntegerItem(String str) { - this.value = new BigInteger(str); - } - - @Override - public int getType() { - return INTEGER_ITEM; - } - - @Override - public boolean isNull() { - return BIG_INTEGER_ZERO.equals(value); - } - - @Override - public int compareTo(Item item) { - if (item == null) { - return BIG_INTEGER_ZERO.equals(value) ? 0 : 1; // 1.0 == 1, 1.1 > 1 - } - - switch (item.getType()) { - case INTEGER_ITEM: - return value.compareTo(((IntegerItem) item).value); - - case STRING_ITEM: - return 1; // 1.1 > 1-sp - - case LIST_ITEM: - return 1; // 1.1 > 1-1 - - default: - throw new RuntimeException("invalid item: " + item.getClass()); - } - } - - @Override - public String toString() { - return value.toString(); - } - } - - /** - * Represents a string in the version item list, usually a qualifier. - */ - private static class StringItem implements Item { - private static final String[] QUALIFIERS = { "alpha", "beta", "milestone", "rc", "snapshot", "", "sp" }; - - private static final List _QUALIFIERS = Arrays.asList(QUALIFIERS); - - private static final Properties ALIASES = new Properties(); - static { - ALIASES.put("ga", ""); - ALIASES.put("final", ""); - ALIASES.put("cr", "rc"); - } - - /** - * A comparable value for the empty-string qualifier. This one is used to determine if a given qualifier makes - * the version older than one without a qualifier, or more recent. - */ - private static final String RELEASE_VERSION_INDEX = String.valueOf(_QUALIFIERS.indexOf("")); - - private String value; - - public StringItem(String value, boolean followedByDigit) { - if (followedByDigit && value.length() == 1) { - // a1 = alpha-1, b1 = beta-1, m1 = milestone-1 - switch (value.charAt(0)) { - case 'a': - value = "alpha"; - break; - case 'b': - value = "beta"; - break; - case 'm': - value = "milestone"; - break; - } - } - this.value = ALIASES.getProperty(value, value); - } - - @Override - public int getType() { - return STRING_ITEM; - } - - @Override - public boolean isNull() { - return (comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX) == 0); - } - - /** - * Returns a comparable value for a qualifier. - * - * This method takes into account the ordering of known qualifiers then unknown qualifiers with lexical ordering. - * - * just returning an Integer with the index here is faster, but requires a lot of if/then/else to check for -1 - * or QUALIFIERS.size and then resort to lexical ordering. Most comparisons are decided by the first character, - * so this is still fast. If more characters are needed then it requires a lexical sort anyway. - * - * @param qualifier - * @return an equivalent value that can be used with lexical comparison - */ - public static String comparableQualifier(String qualifier) { - int i = _QUALIFIERS.indexOf(qualifier); - - return i == -1 ? (_QUALIFIERS.size() + "-" + qualifier) : String.valueOf(i); - } - - @Override - public int compareTo(Item item) { - if (item == null) { - // 1-rc < 1, 1-ga > 1 - return comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX); - } - switch (item.getType()) { - case INTEGER_ITEM: - return -1; // 1.any < 1.1 ? - - case STRING_ITEM: - return comparableQualifier(value).compareTo(comparableQualifier(((StringItem) item).value)); - - case LIST_ITEM: - return -1; // 1.any < 1-1 - - default: - throw new RuntimeException("invalid item: " + item.getClass()); - } - } - - @Override - public String toString() { - return value; - } - } - - /** - * Represents a version list item. This class is used both for the global item list and for sub-lists (which start - * with '-(number)' in the version specification). - */ - private static class ListItem extends ArrayList implements Item { - private static final long serialVersionUID = 5914575811857700009L; - - @Override - public int getType() { - return LIST_ITEM; - } - - @Override - public boolean isNull() { - return (size() == 0); - } - - void normalize() { - for (ListIterator iterator = listIterator(size()); iterator.hasPrevious();) { - Item item = iterator.previous(); - if (item.isNull()) { - iterator.remove(); // remove null trailing items: 0, "", empty list - } else { - break; - } - } - } - - @Override - public int compareTo(Item item) { - if (item == null) { - if (size() == 0) { - return 0; // 1-0 = 1- (normalize) = 1 - } - Item first = get(0); - return first.compareTo(null); - } - switch (item.getType()) { - case INTEGER_ITEM: - return -1; // 1-1 < 1.0.x - - case STRING_ITEM: - return 1; // 1-1 > 1-sp - - case LIST_ITEM: - Iterator left = iterator(); - Iterator right = ((ListItem) item).iterator(); - - while (left.hasNext() || right.hasNext()) { - Item l = left.hasNext() ? left.next() : null; - Item r = right.hasNext() ? right.next() : null; - - // if this is shorter, then invert the compare and mul with -1 - int result = l == null ? (r == null ? 0 : -1 * r.compareTo(l)) : l.compareTo(r); - - if (result != 0) { - return result; - } - } - - return 0; - - default: - throw new RuntimeException("invalid item: " + item.getClass()); - } - } - - @Override - public String toString() { - StringBuilder buffer = new StringBuilder("("); - for (Iterator iter = iterator(); iter.hasNext();) { - buffer.append(iter.next()); - if (iter.hasNext()) { - buffer.append(','); - } - } - buffer.append(')'); - return buffer.toString(); - } - } - - public ComparableVersion(String version) { - parseVersion(version); - } - - public final void parseVersion(String version) { - this.value = version; - - items = new ListItem(); - - version = version.toLowerCase(Locale.ENGLISH); - - ListItem list = items; - - Stack stack = new Stack<>(); - stack.push(list); - - boolean isDigit = false; - - int startIndex = 0; - - for (int i = 0; i < version.length(); i++) { - char c = version.charAt(i); - - if (c == '.') { - if (i == startIndex) { - list.add(IntegerItem.ZERO); - } else { - list.add(parseItem(isDigit, version.substring(startIndex, i))); - } - startIndex = i + 1; - } else if (c == '-') { - if (i == startIndex) { - list.add(IntegerItem.ZERO); - } else { - list.add(parseItem(isDigit, version.substring(startIndex, i))); - } - startIndex = i + 1; - - if (isDigit) { - list.normalize(); // 1.0-* = 1-* - - if ((i + 1 < version.length()) && Character.isDigit(version.charAt(i + 1))) { - // new ListItem only if previous were digits and new char is a digit, - // ie need to differentiate only 1.1 from 1-1 - list.add(list = new ListItem()); - - stack.push(list); - } - } - } else if (Character.isDigit(c)) { - if (!isDigit && i > startIndex) { - list.add(new StringItem(version.substring(startIndex, i), true)); - startIndex = i; - } - - isDigit = true; - } else { - if (isDigit && i > startIndex) { - list.add(parseItem(true, version.substring(startIndex, i))); - startIndex = i; - } - - isDigit = false; - } - } - - if (version.length() > startIndex) { - list.add(parseItem(isDigit, version.substring(startIndex))); - } - - while (!stack.isEmpty()) { - list = (ListItem) stack.pop(); - list.normalize(); - } - - canonical = items.toString(); - } - - private static Item parseItem(boolean isDigit, String buf) { - return isDigit ? new IntegerItem(buf) : new StringItem(buf, false); - } - - @Override - public int compareTo(ComparableVersion o) { - return items.compareTo(o.items); - } - - public int compareTo(String version) { - return compareTo(new ComparableVersion(version)); - } - - @Override - public String toString() { - return value; - } - - public String toCanonicalString() { - return canonical; - } - - @Override - public boolean equals(Object o) { - return (o instanceof ComparableVersion) && canonical.equals(((ComparableVersion) o).canonical); - } - - @Override - public int hashCode() { - return canonical.hashCode(); - } -} +package de.diddiz.LogBlock.util; + +// Taken from maven-artifact at +// http://grepcode.com/file_/repo1.maven.org/maven2/org.apache.maven/maven-artifact/3.2.3/org/apache/maven/artifact/versioning/ComparableVersion.java/?v=source + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Locale; +import java.util.Properties; +import java.util.Stack; + +/** + * Generic implementation of version comparison. + * + *

    Features: + *

      + *
    • mixing of '-' (dash) and '.' (dot) separators,
    • + *
    • transition between characters and digits also constitutes a separator: + * 1.0alpha1 => [1, 0, alpha, 1]
    • + *
    • unlimited number of version components,
    • + *
    • version components in the text can be digits or strings,
    • + *
    • strings are checked for well-known qualifiers and the qualifier ordering is used for version ordering. + * Well-known qualifiers (case insensitive) are:
        + *
      • alpha or a
      • + *
      • beta or b
      • + *
      • milestone or m
      • + *
      • rc or cr
      • + *
      • snapshot
      • + *
      • (the empty string) or ga or final
      • + *
      • sp
      • + *
      + * Unknown qualifiers are considered after known qualifiers, with lexical order (always case insensitive), + *
    • + *
    • a dash usually precedes a qualifier, and is always less important than something preceded with a dot.
    • + *

    + * + * @see "Versioning" on Maven Wiki + * @author Kenney Westerhof + * @author Hervé Boutemy + */ +public class ComparableVersion implements Comparable { + private String value; + + private String canonical; + + private ListItem items; + + private interface Item { + int INTEGER_ITEM = 0; + int STRING_ITEM = 1; + int LIST_ITEM = 2; + + int compareTo(Item item); + + int getType(); + + boolean isNull(); + } + + /** + * Represents a numeric item in the version item list. + */ + private static class IntegerItem implements Item { + private static final BigInteger BIG_INTEGER_ZERO = new BigInteger("0"); + + private final BigInteger value; + + public static final IntegerItem ZERO = new IntegerItem(); + + private IntegerItem() { + this.value = BIG_INTEGER_ZERO; + } + + public IntegerItem(String str) { + this.value = new BigInteger(str); + } + + @Override + public int getType() { + return INTEGER_ITEM; + } + + @Override + public boolean isNull() { + return BIG_INTEGER_ZERO.equals(value); + } + + @Override + public int compareTo(Item item) { + if (item == null) { + return BIG_INTEGER_ZERO.equals(value) ? 0 : 1; // 1.0 == 1, 1.1 > 1 + } + + switch (item.getType()) { + case INTEGER_ITEM: + return value.compareTo(((IntegerItem) item).value); + + case STRING_ITEM: + return 1; // 1.1 > 1-sp + + case LIST_ITEM: + return 1; // 1.1 > 1-1 + + default: + throw new RuntimeException("invalid item: " + item.getClass()); + } + } + + @Override + public String toString() { + return value.toString(); + } + } + + /** + * Represents a string in the version item list, usually a qualifier. + */ + private static class StringItem implements Item { + private static final String[] QUALIFIERS = { "alpha", "beta", "milestone", "rc", "snapshot", "", "sp" }; + + private static final List _QUALIFIERS = Arrays.asList(QUALIFIERS); + + private static final Properties ALIASES = new Properties(); + static { + ALIASES.put("ga", ""); + ALIASES.put("final", ""); + ALIASES.put("cr", "rc"); + } + + /** + * A comparable value for the empty-string qualifier. This one is used to determine if a given qualifier makes + * the version older than one without a qualifier, or more recent. + */ + private static final String RELEASE_VERSION_INDEX = String.valueOf(_QUALIFIERS.indexOf("")); + + private String value; + + public StringItem(String value, boolean followedByDigit) { + if (followedByDigit && value.length() == 1) { + // a1 = alpha-1, b1 = beta-1, m1 = milestone-1 + switch (value.charAt(0)) { + case 'a': + value = "alpha"; + break; + case 'b': + value = "beta"; + break; + case 'm': + value = "milestone"; + break; + } + } + this.value = ALIASES.getProperty(value, value); + } + + @Override + public int getType() { + return STRING_ITEM; + } + + @Override + public boolean isNull() { + return (comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX) == 0); + } + + /** + * Returns a comparable value for a qualifier. + * + * This method takes into account the ordering of known qualifiers then unknown qualifiers with lexical ordering. + * + * just returning an Integer with the index here is faster, but requires a lot of if/then/else to check for -1 + * or QUALIFIERS.size and then resort to lexical ordering. Most comparisons are decided by the first character, + * so this is still fast. If more characters are needed then it requires a lexical sort anyway. + * + * @param qualifier + * @return an equivalent value that can be used with lexical comparison + */ + public static String comparableQualifier(String qualifier) { + int i = _QUALIFIERS.indexOf(qualifier); + + return i == -1 ? (_QUALIFIERS.size() + "-" + qualifier) : String.valueOf(i); + } + + @Override + public int compareTo(Item item) { + if (item == null) { + // 1-rc < 1, 1-ga > 1 + return comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX); + } + switch (item.getType()) { + case INTEGER_ITEM: + return -1; // 1.any < 1.1 ? + + case STRING_ITEM: + return comparableQualifier(value).compareTo(comparableQualifier(((StringItem) item).value)); + + case LIST_ITEM: + return -1; // 1.any < 1-1 + + default: + throw new RuntimeException("invalid item: " + item.getClass()); + } + } + + @Override + public String toString() { + return value; + } + } + + /** + * Represents a version list item. This class is used both for the global item list and for sub-lists (which start + * with '-(number)' in the version specification). + */ + private static class ListItem extends ArrayList implements Item { + private static final long serialVersionUID = 5914575811857700009L; + + @Override + public int getType() { + return LIST_ITEM; + } + + @Override + public boolean isNull() { + return (size() == 0); + } + + void normalize() { + for (ListIterator iterator = listIterator(size()); iterator.hasPrevious();) { + Item item = iterator.previous(); + if (item.isNull()) { + iterator.remove(); // remove null trailing items: 0, "", empty list + } else { + break; + } + } + } + + @Override + public int compareTo(Item item) { + if (item == null) { + if (size() == 0) { + return 0; // 1-0 = 1- (normalize) = 1 + } + Item first = get(0); + return first.compareTo(null); + } + switch (item.getType()) { + case INTEGER_ITEM: + return -1; // 1-1 < 1.0.x + + case STRING_ITEM: + return 1; // 1-1 > 1-sp + + case LIST_ITEM: + Iterator left = iterator(); + Iterator right = ((ListItem) item).iterator(); + + while (left.hasNext() || right.hasNext()) { + Item l = left.hasNext() ? left.next() : null; + Item r = right.hasNext() ? right.next() : null; + + // if this is shorter, then invert the compare and mul with -1 + int result = l == null ? (r == null ? 0 : -1 * r.compareTo(l)) : l.compareTo(r); + + if (result != 0) { + return result; + } + } + + return 0; + + default: + throw new RuntimeException("invalid item: " + item.getClass()); + } + } + + @Override + public String toString() { + StringBuilder buffer = new StringBuilder("("); + for (Iterator iter = iterator(); iter.hasNext();) { + buffer.append(iter.next()); + if (iter.hasNext()) { + buffer.append(','); + } + } + buffer.append(')'); + return buffer.toString(); + } + } + + public ComparableVersion(String version) { + parseVersion(version); + } + + public final void parseVersion(String version) { + this.value = version; + + items = new ListItem(); + + version = version.toLowerCase(Locale.ENGLISH); + + ListItem list = items; + + Stack stack = new Stack<>(); + stack.push(list); + + boolean isDigit = false; + + int startIndex = 0; + + for (int i = 0; i < version.length(); i++) { + char c = version.charAt(i); + + if (c == '.') { + if (i == startIndex) { + list.add(IntegerItem.ZERO); + } else { + list.add(parseItem(isDigit, version.substring(startIndex, i))); + } + startIndex = i + 1; + } else if (c == '-') { + if (i == startIndex) { + list.add(IntegerItem.ZERO); + } else { + list.add(parseItem(isDigit, version.substring(startIndex, i))); + } + startIndex = i + 1; + + if (isDigit) { + list.normalize(); // 1.0-* = 1-* + + if ((i + 1 < version.length()) && Character.isDigit(version.charAt(i + 1))) { + // new ListItem only if previous were digits and new char is a digit, + // ie need to differentiate only 1.1 from 1-1 + list.add(list = new ListItem()); + + stack.push(list); + } + } + } else if (Character.isDigit(c)) { + if (!isDigit && i > startIndex) { + list.add(new StringItem(version.substring(startIndex, i), true)); + startIndex = i; + } + + isDigit = true; + } else { + if (isDigit && i > startIndex) { + list.add(parseItem(true, version.substring(startIndex, i))); + startIndex = i; + } + + isDigit = false; + } + } + + if (version.length() > startIndex) { + list.add(parseItem(isDigit, version.substring(startIndex))); + } + + while (!stack.isEmpty()) { + list = (ListItem) stack.pop(); + list.normalize(); + } + + canonical = items.toString(); + } + + private static Item parseItem(boolean isDigit, String buf) { + return isDigit ? new IntegerItem(buf) : new StringItem(buf, false); + } + + @Override + public int compareTo(ComparableVersion o) { + return items.compareTo(o.items); + } + + public int compareTo(String version) { + return compareTo(new ComparableVersion(version)); + } + + @Override + public String toString() { + return value; + } + + public String toCanonicalString() { + return canonical; + } + + @Override + public boolean equals(Object o) { + return (o instanceof ComparableVersion) && canonical.equals(((ComparableVersion) o).canonical); + } + + @Override + public int hashCode() { + return canonical.hashCode(); + } +} diff --git a/src/main/java/de/diddiz/LogBlock/util/MySQLConnectionPool.java b/src/main/java/de/diddiz/LogBlock/util/MySQLConnectionPool.java index 3a0f854a..d2b8337a 100644 --- a/src/main/java/de/diddiz/LogBlock/util/MySQLConnectionPool.java +++ b/src/main/java/de/diddiz/LogBlock/util/MySQLConnectionPool.java @@ -1,51 +1,51 @@ -package de.diddiz.LogBlock.util; - -import com.zaxxer.hikari.HikariDataSource; -import de.diddiz.LogBlock.config.Config; - -import java.io.Closeable; -import java.sql.Connection; -import java.sql.SQLException; - -public class MySQLConnectionPool implements Closeable { - - private final HikariDataSource ds; - - public MySQLConnectionPool(String url, String user, String password, boolean useSSL, boolean requireSSL) { - this.ds = new HikariDataSource(); - ds.setJdbcUrl(url); - ds.setUsername(user); - ds.setPassword(password); - - ds.setMinimumIdle(2); - ds.setMaximumPoolSize(15); - ds.setPoolName("LogBlock-Connection-Pool"); - - ds.addDataSourceProperty("useUnicode", "true"); - ds.addDataSourceProperty("characterEncoding", "utf-8"); - ds.addDataSourceProperty("rewriteBatchedStatements", "true"); - - ds.addDataSourceProperty("cachePrepStmts", "true"); - ds.addDataSourceProperty("prepStmtCacheSize", "250"); - ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); - ds.addDataSourceProperty("useServerPrepStmts", "true"); - - ds.addDataSourceProperty("useSSL", Boolean.toString(useSSL)); - ds.addDataSourceProperty("requireSSL", Boolean.toString(requireSSL)); - ds.addDataSourceProperty("verifyServerCertificate", "false"); - } - - @Override - public void close() { - ds.close(); - } - - public Connection getConnection() throws SQLException { - Connection connection = ds.getConnection(); - if (Config.mb4) { - connection.createStatement().executeUpdate("SET NAMES utf8mb4"); - } - return connection; - } - -} +package de.diddiz.LogBlock.util; + +import com.zaxxer.hikari.HikariDataSource; +import de.diddiz.LogBlock.config.Config; + +import java.io.Closeable; +import java.sql.Connection; +import java.sql.SQLException; + +public class MySQLConnectionPool implements Closeable { + + private final HikariDataSource ds; + + public MySQLConnectionPool(String url, String user, String password, boolean useSSL, boolean requireSSL) { + this.ds = new HikariDataSource(); + ds.setJdbcUrl(url); + ds.setUsername(user); + ds.setPassword(password); + + ds.setMinimumIdle(2); + ds.setMaximumPoolSize(15); + ds.setPoolName("LogBlock-Connection-Pool"); + + ds.addDataSourceProperty("useUnicode", "true"); + ds.addDataSourceProperty("characterEncoding", "utf-8"); + ds.addDataSourceProperty("rewriteBatchedStatements", "true"); + + ds.addDataSourceProperty("cachePrepStmts", "true"); + ds.addDataSourceProperty("prepStmtCacheSize", "250"); + ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); + ds.addDataSourceProperty("useServerPrepStmts", "true"); + + ds.addDataSourceProperty("useSSL", Boolean.toString(useSSL)); + ds.addDataSourceProperty("requireSSL", Boolean.toString(requireSSL)); + ds.addDataSourceProperty("verifyServerCertificate", "false"); + } + + @Override + public void close() { + ds.close(); + } + + public Connection getConnection() throws SQLException { + Connection connection = ds.getConnection(); + if (Config.mb4) { + connection.createStatement().executeUpdate("SET NAMES utf8mb4"); + } + return connection; + } + +} diff --git a/src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java b/src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java index d6bca85b..baeaac69 100644 --- a/src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java +++ b/src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java @@ -1,61 +1,61 @@ -package de.diddiz.LogBlock.util; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -// Adapted from https://gist.github.com/evilmidget38/26d70114b834f71fb3b4 - -public class UUIDFetcher { - - private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft"; - private static final Gson gson = new GsonBuilder().setLenient().create(); - - public static Map getUUIDs(List names) throws Exception { - Map uuidMap = new HashMap<>(); - HttpURLConnection connection = createConnection(); - String body = gson.toJson(names); - writeBody(connection, body); - JsonArray array = gson.fromJson(new InputStreamReader(connection.getInputStream()), JsonArray.class); - for (JsonElement profile : array) { - JsonObject jsonProfile = (JsonObject) profile; - String id = jsonProfile.get("id").getAsString(); - String name = jsonProfile.get("name").getAsString(); - UUID uuid = getUUID(id); - uuidMap.put(name, uuid); - } - return uuidMap; - } - - private static void writeBody(HttpURLConnection connection, String body) throws Exception { - OutputStream stream = connection.getOutputStream(); - stream.write(body.getBytes()); - stream.flush(); - stream.close(); - } - - private static HttpURLConnection createConnection() throws Exception { - URL url = new URL(PROFILE_URL); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("POST"); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setUseCaches(false); - connection.setDoInput(true); - connection.setDoOutput(true); - return connection; - } - - private static UUID getUUID(String id) { - return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" + id.substring(20, 32)); - } -} +package de.diddiz.LogBlock.util; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +// Adapted from https://gist.github.com/evilmidget38/26d70114b834f71fb3b4 + +public class UUIDFetcher { + + private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft"; + private static final Gson gson = new GsonBuilder().setLenient().create(); + + public static Map getUUIDs(List names) throws Exception { + Map uuidMap = new HashMap<>(); + HttpURLConnection connection = createConnection(); + String body = gson.toJson(names); + writeBody(connection, body); + JsonArray array = gson.fromJson(new InputStreamReader(connection.getInputStream()), JsonArray.class); + for (JsonElement profile : array) { + JsonObject jsonProfile = (JsonObject) profile; + String id = jsonProfile.get("id").getAsString(); + String name = jsonProfile.get("name").getAsString(); + UUID uuid = getUUID(id); + uuidMap.put(name, uuid); + } + return uuidMap; + } + + private static void writeBody(HttpURLConnection connection, String body) throws Exception { + OutputStream stream = connection.getOutputStream(); + stream.write(body.getBytes()); + stream.flush(); + stream.close(); + } + + private static HttpURLConnection createConnection() throws Exception { + URL url = new URL(PROFILE_URL); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setUseCaches(false); + connection.setDoInput(true); + connection.setDoOutput(true); + return connection; + } + + private static UUID getUUID(String id) { + return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" + id.substring(20, 32)); + } +} diff --git a/src/main/java/de/diddiz/LogBlock/util/Utils.java b/src/main/java/de/diddiz/LogBlock/util/Utils.java index 2c62a90f..353c4af5 100644 --- a/src/main/java/de/diddiz/LogBlock/util/Utils.java +++ b/src/main/java/de/diddiz/LogBlock/util/Utils.java @@ -1,298 +1,298 @@ -package de.diddiz.LogBlock.util; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; -import java.util.zip.ZipException; - -import org.bukkit.configuration.InvalidConfigurationException; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.inventory.ItemStack; - -import de.diddiz.LogBlock.LogBlock; - -public class Utils { - public static String newline = System.getProperty("line.separator"); - - public static boolean isInt(String str) { - try { - Integer.parseInt(str); - return true; - } catch (final NumberFormatException ex) { - } - return false; - } - - public static boolean isShort(String str) { - try { - Short.parseShort(str); - return true; - } catch (final NumberFormatException ex) { - } - return false; - } - - public static boolean isByte(String str) { - try { - Byte.parseByte(str); - return true; - } catch (final NumberFormatException ex) { - } - return false; - } - - public static String listing(String[] entries, String delimiter, String finalDelimiter) { - final int len = entries.length; - if (len == 0) { - return ""; - } - if (len == 1) { - return entries[0]; - } - final StringBuilder builder = new StringBuilder(entries[0]); - for (int i = 1; i < len - 1; i++) { - builder.append(delimiter).append(entries[i]); - } - builder.append(finalDelimiter).append(entries[len - 1]); - return builder.toString(); - } - - public static String listing(List entries, String delimiter, String finalDelimiter) { - final int len = entries.size(); - if (len == 0) { - return ""; - } - if (len == 1) { - return entries.get(0).toString(); - } - final StringBuilder builder = new StringBuilder(entries.get(0).toString()); - for (int i = 1; i < len - 1; i++) { - builder.append(delimiter).append(entries.get(i).toString()); - } - builder.append(finalDelimiter).append(entries.get(len - 1).toString()); - return builder.toString(); - } - - public static int parseTimeSpec(String[] spec) { - if (spec == null || spec.length < 1 || spec.length > 2) { - return -1; - } - if (spec.length == 1 && isInt(spec[0])) { - return Integer.valueOf(spec[0]); - } - if (!spec[0].contains(":") && !spec[0].contains(".")) { - if (spec.length == 2) { - if (!isInt(spec[0])) { - return -1; - } - int min = Integer.parseInt(spec[0]); - if (spec[1].startsWith("h")) { - min *= 60; - } else if (spec[1].startsWith("d")) { - min *= 1440; - } - return min; - } else if (spec.length == 1) { - int days = 0, hours = 0, minutes = 0; - int lastIndex = 0, currIndex = 1; - while (currIndex <= spec[0].length()) { - while (currIndex <= spec[0].length() && isInt(spec[0].substring(lastIndex, currIndex))) { - currIndex++; - } - if (currIndex - 1 != lastIndex) { - if (currIndex > spec[0].length()) { - return -1; - } - final String param = spec[0].substring(currIndex - 1, currIndex).toLowerCase(); - if (param.equals("d")) { - days = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1)); - } else if (param.equals("h")) { - hours = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1)); - } else if (param.equals("m")) { - minutes = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1)); - } - } - lastIndex = currIndex; - currIndex++; - } - if (days == 0 && hours == 0 && minutes == 0) { - return -1; - } - return minutes + hours * 60 + days * 1440; - } else { - return -1; - } - } - final String timestamp; - if (spec.length == 1) { - if (spec[0].contains(":")) { - timestamp = new SimpleDateFormat("dd.MM.yyyy").format(System.currentTimeMillis()) + " " + spec[0]; - } else { - timestamp = spec[0] + " 00:00:00"; - } - } else { - timestamp = spec[0] + " " + spec[1]; - } - try { - return (int) ((System.currentTimeMillis() - new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").parse(timestamp).getTime()) / 60000); - } catch (final ParseException ex) { - return -1; - } - } - - public static String spaces(int count) { - final StringBuilder filled = new StringBuilder(count); - for (int i = 0; i < count; i++) { - filled.append(' '); - } - return filled.toString(); - } - - public static String join(String[] s, String delimiter) { - if (s == null || s.length == 0) { - return ""; - } - final int len = s.length; - final StringBuilder builder = new StringBuilder(s[0]); - for (int i = 1; i < len; i++) { - builder.append(delimiter).append(s[i]); - } - return builder.toString(); - } - - /** - * Converts a list of arguments e.g ['lb', 'clearlog', 'world', '"my', 'world', 'of', 'swag"'] - * into a list of arguments with any text encapsulated by quotes treated as one word - * For this particular example: ['lb', 'clearlog', 'world', '"my world of swag"'] - * - * @param args The list of arguments - * @return A new list with the quoted arguments parsed to single values - */ - public static List parseQuotes(List args) { - List newArguments = new ArrayList<>(); - String subjectString = join(args.toArray(new String[args.size()]), " "); - - Pattern regex = Pattern.compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'"); - Matcher regexMatcher = regex.matcher(subjectString); - while (regexMatcher.find()) { - newArguments.add(regexMatcher.group()); - } - - return newArguments; - } - - public static class ExtensionFilenameFilter implements FilenameFilter { - private final String ext; - - public ExtensionFilenameFilter(String ext) { - this.ext = "." + ext; - } - - @Override - public boolean accept(File dir, String name) { - return name.toLowerCase().endsWith(ext); - } - } - - private final static char[] hexArray = "0123456789ABCDEF".toCharArray(); - - public static String mysqlEscapeBytes(byte[] bytes) { - char[] hexChars = new char[bytes.length * 2 + 2]; - hexChars[0] = '0'; - hexChars[1] = 'x'; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2 + 2] = hexArray[v >>> 4]; - hexChars[j * 2 + 3] = hexArray[v & 0x0F]; - } - return new String(hexChars); - } - - public static String mysqlPrepareBytesForInsertAllowNull(byte[] bytes) { - if (bytes == null) { - return "null"; - } - return "'" + mysqlEscapeBytes(bytes) + "'"; - } - - public static String mysqlTextEscape(String untrusted) { - return untrusted.replace("\\", "\\\\").replace("'", "\\'"); - } - - public static ItemStack loadItemStack(byte[] data) { - if (data == null || data.length == 0) { - return null; - } - YamlConfiguration conf = deserializeYamlConfiguration(data); - return conf == null ? null : conf.getItemStack("stack"); - } - - public static byte[] saveItemStack(ItemStack stack) { - if (stack == null || BukkitUtils.isEmpty(stack.getType())) { - return null; - } - YamlConfiguration conf = new YamlConfiguration(); - conf.set("stack", stack); - return serializeYamlConfiguration(conf); - } - - public static YamlConfiguration deserializeYamlConfiguration(byte[] data) { - if (data == null || data.length == 0) { - return null; - } - YamlConfiguration conf = new YamlConfiguration(); - try { - InputStreamReader reader = new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(data)), "UTF-8"); - conf.load(reader); - reader.close(); - return conf; - } catch (ZipException | InvalidConfigurationException e) { - LogBlock.getInstance().getLogger().warning("Could not deserialize YamlConfiguration: " + e.getMessage()); - return conf; - } catch (IOException e) { - throw new RuntimeException("IOException should be impossible for ByteArrayInputStream", e); - } - } - - public static byte[] serializeYamlConfiguration(YamlConfiguration conf) { - if (conf == null || conf.getKeys(false).isEmpty()) { - return null; - } - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStreamWriter writer = new OutputStreamWriter(new GZIPOutputStream(baos), "UTF-8"); - writer.write(conf.saveToString()); - writer.close(); - return baos.toByteArray(); - } catch (IOException e) { - throw new RuntimeException("IOException should be impossible for ByteArrayOutputStream", e); - } - } - - public static String serializeForSQL(YamlConfiguration conf) { - return mysqlPrepareBytesForInsertAllowNull(serializeYamlConfiguration(conf)); - } - - public static double warpDegrees(double degrees) { - double d = degrees % 360.0; - if (d >= 180.0) { - d -= 360.0; - } - if (d < -180.0) { - d += 360.0; - } - return d; - } -} +package de.diddiz.LogBlock.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; +import java.util.zip.ZipException; + +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemStack; + +import de.diddiz.LogBlock.LogBlock; + +public class Utils { + public static String newline = System.getProperty("line.separator"); + + public static boolean isInt(String str) { + try { + Integer.parseInt(str); + return true; + } catch (final NumberFormatException ex) { + } + return false; + } + + public static boolean isShort(String str) { + try { + Short.parseShort(str); + return true; + } catch (final NumberFormatException ex) { + } + return false; + } + + public static boolean isByte(String str) { + try { + Byte.parseByte(str); + return true; + } catch (final NumberFormatException ex) { + } + return false; + } + + public static String listing(String[] entries, String delimiter, String finalDelimiter) { + final int len = entries.length; + if (len == 0) { + return ""; + } + if (len == 1) { + return entries[0]; + } + final StringBuilder builder = new StringBuilder(entries[0]); + for (int i = 1; i < len - 1; i++) { + builder.append(delimiter).append(entries[i]); + } + builder.append(finalDelimiter).append(entries[len - 1]); + return builder.toString(); + } + + public static String listing(List entries, String delimiter, String finalDelimiter) { + final int len = entries.size(); + if (len == 0) { + return ""; + } + if (len == 1) { + return entries.get(0).toString(); + } + final StringBuilder builder = new StringBuilder(entries.get(0).toString()); + for (int i = 1; i < len - 1; i++) { + builder.append(delimiter).append(entries.get(i).toString()); + } + builder.append(finalDelimiter).append(entries.get(len - 1).toString()); + return builder.toString(); + } + + public static int parseTimeSpec(String[] spec) { + if (spec == null || spec.length < 1 || spec.length > 2) { + return -1; + } + if (spec.length == 1 && isInt(spec[0])) { + return Integer.valueOf(spec[0]); + } + if (!spec[0].contains(":") && !spec[0].contains(".")) { + if (spec.length == 2) { + if (!isInt(spec[0])) { + return -1; + } + int min = Integer.parseInt(spec[0]); + if (spec[1].startsWith("h")) { + min *= 60; + } else if (spec[1].startsWith("d")) { + min *= 1440; + } + return min; + } else if (spec.length == 1) { + int days = 0, hours = 0, minutes = 0; + int lastIndex = 0, currIndex = 1; + while (currIndex <= spec[0].length()) { + while (currIndex <= spec[0].length() && isInt(spec[0].substring(lastIndex, currIndex))) { + currIndex++; + } + if (currIndex - 1 != lastIndex) { + if (currIndex > spec[0].length()) { + return -1; + } + final String param = spec[0].substring(currIndex - 1, currIndex).toLowerCase(); + if (param.equals("d")) { + days = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1)); + } else if (param.equals("h")) { + hours = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1)); + } else if (param.equals("m")) { + minutes = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1)); + } + } + lastIndex = currIndex; + currIndex++; + } + if (days == 0 && hours == 0 && minutes == 0) { + return -1; + } + return minutes + hours * 60 + days * 1440; + } else { + return -1; + } + } + final String timestamp; + if (spec.length == 1) { + if (spec[0].contains(":")) { + timestamp = new SimpleDateFormat("dd.MM.yyyy").format(System.currentTimeMillis()) + " " + spec[0]; + } else { + timestamp = spec[0] + " 00:00:00"; + } + } else { + timestamp = spec[0] + " " + spec[1]; + } + try { + return (int) ((System.currentTimeMillis() - new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").parse(timestamp).getTime()) / 60000); + } catch (final ParseException ex) { + return -1; + } + } + + public static String spaces(int count) { + final StringBuilder filled = new StringBuilder(count); + for (int i = 0; i < count; i++) { + filled.append(' '); + } + return filled.toString(); + } + + public static String join(String[] s, String delimiter) { + if (s == null || s.length == 0) { + return ""; + } + final int len = s.length; + final StringBuilder builder = new StringBuilder(s[0]); + for (int i = 1; i < len; i++) { + builder.append(delimiter).append(s[i]); + } + return builder.toString(); + } + + /** + * Converts a list of arguments e.g ['lb', 'clearlog', 'world', '"my', 'world', 'of', 'swag"'] + * into a list of arguments with any text encapsulated by quotes treated as one word + * For this particular example: ['lb', 'clearlog', 'world', '"my world of swag"'] + * + * @param args The list of arguments + * @return A new list with the quoted arguments parsed to single values + */ + public static List parseQuotes(List args) { + List newArguments = new ArrayList<>(); + String subjectString = join(args.toArray(new String[args.size()]), " "); + + Pattern regex = Pattern.compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'"); + Matcher regexMatcher = regex.matcher(subjectString); + while (regexMatcher.find()) { + newArguments.add(regexMatcher.group()); + } + + return newArguments; + } + + public static class ExtensionFilenameFilter implements FilenameFilter { + private final String ext; + + public ExtensionFilenameFilter(String ext) { + this.ext = "." + ext; + } + + @Override + public boolean accept(File dir, String name) { + return name.toLowerCase().endsWith(ext); + } + } + + private final static char[] hexArray = "0123456789ABCDEF".toCharArray(); + + public static String mysqlEscapeBytes(byte[] bytes) { + char[] hexChars = new char[bytes.length * 2 + 2]; + hexChars[0] = '0'; + hexChars[1] = 'x'; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2 + 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 3] = hexArray[v & 0x0F]; + } + return new String(hexChars); + } + + public static String mysqlPrepareBytesForInsertAllowNull(byte[] bytes) { + if (bytes == null) { + return "null"; + } + return "'" + mysqlEscapeBytes(bytes) + "'"; + } + + public static String mysqlTextEscape(String untrusted) { + return untrusted.replace("\\", "\\\\").replace("'", "\\'"); + } + + public static ItemStack loadItemStack(byte[] data) { + if (data == null || data.length == 0) { + return null; + } + YamlConfiguration conf = deserializeYamlConfiguration(data); + return conf == null ? null : conf.getItemStack("stack"); + } + + public static byte[] saveItemStack(ItemStack stack) { + if (stack == null || BukkitUtils.isEmpty(stack.getType())) { + return null; + } + YamlConfiguration conf = new YamlConfiguration(); + conf.set("stack", stack); + return serializeYamlConfiguration(conf); + } + + public static YamlConfiguration deserializeYamlConfiguration(byte[] data) { + if (data == null || data.length == 0) { + return null; + } + YamlConfiguration conf = new YamlConfiguration(); + try { + InputStreamReader reader = new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(data)), "UTF-8"); + conf.load(reader); + reader.close(); + return conf; + } catch (ZipException | InvalidConfigurationException e) { + LogBlock.getInstance().getLogger().warning("Could not deserialize YamlConfiguration: " + e.getMessage()); + return conf; + } catch (IOException e) { + throw new RuntimeException("IOException should be impossible for ByteArrayInputStream", e); + } + } + + public static byte[] serializeYamlConfiguration(YamlConfiguration conf) { + if (conf == null || conf.getKeys(false).isEmpty()) { + return null; + } + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStreamWriter writer = new OutputStreamWriter(new GZIPOutputStream(baos), "UTF-8"); + writer.write(conf.saveToString()); + writer.close(); + return baos.toByteArray(); + } catch (IOException e) { + throw new RuntimeException("IOException should be impossible for ByteArrayOutputStream", e); + } + } + + public static String serializeForSQL(YamlConfiguration conf) { + return mysqlPrepareBytesForInsertAllowNull(serializeYamlConfiguration(conf)); + } + + public static double warpDegrees(double degrees) { + double d = degrees % 360.0; + if (d >= 180.0) { + d -= 360.0; + } + if (d < -180.0) { + d += 360.0; + } + return d; + } +} From 95a8d6043d262d4f11fcf30af7d43cc33d6c9975 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 9 Oct 2023 08:54:12 +0200 Subject: [PATCH 354/399] add .gitattributes --- .gitattributes | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..1adafa6e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. +*.java text +*.txt text +*.yml text +*.xml text +*.md text +LICENSE text \ No newline at end of file From fc92ad230745aa0e43b5bff525a34557500508bd Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 9 Oct 2023 09:00:31 +0200 Subject: [PATCH 355/399] remove eol setting from .editorconfig --- .editorconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 03601399..085fb981 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,7 +2,6 @@ root = true [*] charset = utf-8 -end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true From f2e76a50cb3a3c267255bdc1fc3e243a4964c367 Mon Sep 17 00:00:00 2001 From: KleinCrafter Date: Tue, 17 Oct 2023 08:33:06 +0200 Subject: [PATCH 356/399] MC Version 1.20.1, use waxed sign api (#884) * bump api version to 1.20.1 * Sign.isWaxed is now API --- pom.xml | 2 +- .../blockstate/BlockStateCodecSign.java | 7 +-- .../LogBlock/listeners/InteractLogging.java | 6 +- .../de/diddiz/LogBlock/util/Reflections.java | 61 ------------------- 4 files changed, 6 insertions(+), 70 deletions(-) delete mode 100644 src/main/java/de/diddiz/LogBlock/util/Reflections.java diff --git a/pom.xml b/pom.xml index 471fba0f..a402c556 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ org.spigotmc spigot-api - 1.20-R0.1-SNAPSHOT + 1.20.1-R0.1-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index 64c2570c..8196baae 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -1,7 +1,6 @@ package de.diddiz.LogBlock.blockstate; import de.diddiz.LogBlock.util.BukkitUtils; -import de.diddiz.LogBlock.util.Reflections; import java.awt.Color; import java.util.Arrays; import java.util.Collections; @@ -28,7 +27,7 @@ public Material[] getApplicableMaterials() { public YamlConfiguration serialize(BlockState state) { YamlConfiguration conf = null; if (state instanceof Sign sign) { - boolean waxed = Reflections.isSignWaxed(sign); + boolean waxed = sign.isWaxed(); if (waxed) { conf = new YamlConfiguration(); conf.set("waxed", waxed); @@ -92,7 +91,7 @@ public void deserialize(BlockState state, YamlConfiguration conf) { if (state instanceof Sign) { Sign sign = (Sign) state; if (conf != null) { - sign.setEditable(!conf.getBoolean("waxed")); + sign.setWaxed(conf.getBoolean("waxed")); for (Side side : Side.values()) { ConfigurationSection sideSection = side == Side.FRONT ? conf : conf.getConfigurationSection(side.name().toLowerCase()); DyeColor signColor = DyeColor.BLACK; @@ -120,7 +119,7 @@ public void deserialize(BlockState state, YamlConfiguration conf) { signSide.setGlowingText(glowing); } } else { - sign.setEditable(true); + sign.setWaxed(false); for (Side side : Side.values()) { SignSide signSide = sign.getSide(side); for (int i = 0; i < 4; i++) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index 55dd7136..13d1b98a 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -5,7 +5,6 @@ import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.LogBlock.util.BukkitUtils; -import de.diddiz.LogBlock.util.Reflections; import java.util.UUID; import org.bukkit.DyeColor; import org.bukkit.GameEvent; @@ -99,8 +98,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { if (BukkitUtils.isDye(itemType) || itemType == Material.GLOW_INK_SAC || itemType == Material.INK_SAC || itemType == Material.HONEYCOMB) { final BlockState before = event.getClickedBlock().getState(); if (before instanceof Sign signBefore) { - boolean waxed = Reflections.isSignWaxed(signBefore); - if (!waxed) { + if (!signBefore.isWaxed()) { final Sign signAfter = (Sign) event.getClickedBlock().getState(); Side side = BukkitUtils.getFacingSignSide(player, clicked); SignSide signSideBefore = signBefore.getSide(side); @@ -116,7 +114,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); } } else if (itemType == Material.HONEYCOMB) { - signAfter.setEditable(false); + signAfter.setWaxed(true); consumer.queueBlockReplace(Actor.actorFromEntity(player), signBefore, signAfter); } else if (BukkitUtils.isDye(itemType) && hasText(signSideBefore)) { DyeColor newColor = BukkitUtils.dyeToDyeColor(itemType); diff --git a/src/main/java/de/diddiz/LogBlock/util/Reflections.java b/src/main/java/de/diddiz/LogBlock/util/Reflections.java deleted file mode 100644 index 83f820d3..00000000 --- a/src/main/java/de/diddiz/LogBlock/util/Reflections.java +++ /dev/null @@ -1,61 +0,0 @@ -package de.diddiz.LogBlock.util; - -import de.diddiz.LogBlock.LogBlock; -import java.lang.reflect.Field; -import java.util.logging.Level; -import org.bukkit.block.Sign; - -public class Reflections { - private static Field FIELD_CraftBlockEntityState_snapshot; - private static Field FIELD_SignBlockEntity_isWaxed; - - public static boolean isSignWaxed(Sign sign) { - try { - if (FIELD_CraftBlockEntityState_snapshot == null) { - Class superClass = sign.getClass().getSuperclass(); - while (superClass != null) { - try { - FIELD_CraftBlockEntityState_snapshot = superClass.getDeclaredField("snapshot"); - FIELD_CraftBlockEntityState_snapshot.setAccessible(true); - break; - } catch (NoSuchFieldException ignored) { - } - superClass = superClass.getSuperclass(); - } - } - if (FIELD_CraftBlockEntityState_snapshot == null) { - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Reflections: Sign field 'snapshot' not found"); - return false; - } - Object snapshot = FIELD_CraftBlockEntityState_snapshot.get(sign); - if (snapshot == null) { - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Reflections: Sign snapshot is null?"); - return false; - } - if (FIELD_SignBlockEntity_isWaxed == null) { - Class snapshotClass = snapshot.getClass(); - while (snapshotClass != null) { - for (Field f : snapshotClass.getDeclaredFields()) { - if (f.getType() == boolean.class) { - FIELD_SignBlockEntity_isWaxed = f; - FIELD_SignBlockEntity_isWaxed.setAccessible(true); - break; - } - } - if (FIELD_SignBlockEntity_isWaxed != null) { - break; - } - snapshotClass = snapshotClass.getSuperclass(); - } - } - if (FIELD_SignBlockEntity_isWaxed == null) { - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Reflections: Sign field 'isWaxed' not found"); - return false; - } - return FIELD_SignBlockEntity_isWaxed.getBoolean(snapshot); - } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) { - LogBlock.getInstance().getLogger().log(Level.SEVERE, "Reflections: Sign.isWaxed reflection failed", e); - } - return false; - } -} From d7e458ad68925cc429a4388dd1ab7b312c4fcfe6 Mon Sep 17 00:00:00 2001 From: KleinCrafter Date: Tue, 17 Oct 2023 08:38:46 +0200 Subject: [PATCH 357/399] Use Tags for Materials in BukkitUtils (#883) --- .../java/de/diddiz/LogBlock/BlockChange.java | 2 +- .../blockstate/BlockStateCodecShulkerBox.java | 2 +- .../blockstate/BlockStateCodecSign.java | 2 +- .../LogBlock/listeners/BlockBreakLogging.java | 2 +- .../listeners/CreatureInteractLogging.java | 2 +- .../LogBlock/listeners/ExplosionLogging.java | 5 +- .../LogBlock/listeners/FluidFlowLogging.java | 6 +- .../LogBlock/listeners/InteractLogging.java | 2 +- .../de/diddiz/LogBlock/util/BukkitUtils.java | 726 ++++++------------ .../de/diddiz/LogBlock/util/LoggingUtil.java | 10 +- 10 files changed, 261 insertions(+), 498 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 79dcf54a..6b769b24 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -160,7 +160,7 @@ public BaseComponent[] getLogMessage(int entry) { msg.addExtra(createTextComponentWithColor("dried ", DESTROY.getColor())); msg.addExtra(prettyMaterial(type)); } - } else if (BukkitUtils.getContainerBlocks().contains(type.getMaterial())) { + } else if (BukkitUtils.isContainerBlock(type.getMaterial())) { msg.addExtra(createTextComponentWithColor("opened ", INTERACT.getColor())); msg.addExtra(prettyMaterial(type)); } else if (type instanceof Openable && ((Openable) type).isOpen() != ((Openable) replaced).isOpen()) { diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java index 9e632384..1325a862 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java @@ -16,7 +16,7 @@ public class BlockStateCodecShulkerBox implements BlockStateCodec { @Override public Material[] getApplicableMaterials() { - return BukkitUtils.getShulkerBoxBlocks().toArray(new Material[BukkitUtils.getShulkerBoxBlocks().size()]); + return BukkitUtils.getShulkerBoxBlocks().toArray(Material[]::new); } @Override diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index 8196baae..e230dae6 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -20,7 +20,7 @@ public class BlockStateCodecSign implements BlockStateCodec { @Override public Material[] getApplicableMaterials() { - return BukkitUtils.getAllSignMaterials().toArray(new Material[BukkitUtils.getAllSignMaterials().size()]); + return BukkitUtils.getAllSignMaterials().toArray(Material[]::new); } @Override diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java index 12c0b2b6..ffa6aca9 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java @@ -39,7 +39,7 @@ public void onBlockBreak(BlockBreakEvent event) { final Block origin = event.getBlock(); final Material type = origin.getType(); - if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) { + if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.isContainerBlock(type) && !BukkitUtils.isShulkerBoxBlock(type)) { consumer.queueContainerBreak(actor, origin.getState()); } else if (type == Material.ICE) { // When in creative mode ice doesn't form water diff --git a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java index 395fe353..7066b357 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java @@ -42,7 +42,7 @@ public void onEntityInteract(EntityInteractEvent event) { consumer.queueBlock(new Actor("CreatureTrample"), loc, type.createBlockData(), Material.DIRT.createBlockData()); // Log the crop on top as being broken Block trampledCrop = clicked.getRelative(BlockFace.UP); - if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) { + if (BukkitUtils.isCropBlock(trampledCrop.getType())) { consumer.queueBlockBreak(new Actor("CreatureTrample"), trampledCrop.getState()); } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index 62801a69..cd97d04d 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -25,7 +25,6 @@ import static de.diddiz.LogBlock.config.Config.getWorldConfig; import static de.diddiz.LogBlock.config.Config.logCreeperExplosionsAsPlayerWhoTriggeredThese; -import static de.diddiz.LogBlock.util.BukkitUtils.getContainerBlocks; import java.util.UUID; @@ -117,7 +116,7 @@ public void onEntityExplode(EntityExplodeEvent event) { } for (final Block block : event.blockList()) { final Material type = block.getType(); - if (wcfg.isLogging(Logging.CHESTACCESS) && getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) { + if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.isContainerBlock(type) && !BukkitUtils.isShulkerBoxBlock(type)) { consumer.queueContainerBreak(actor, block.getState()); } else { consumer.queueBlockBreak(actor, block.getState()); @@ -218,7 +217,7 @@ public void onBlockExplode(BlockExplodeEvent event) { } final Material type = block.getType(); - if (wcfg.isLogging(Logging.CHESTACCESS) && getContainerBlocks().contains(type) && !BukkitUtils.getShulkerBoxBlocks().contains(type)) { + if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.isContainerBlock(type) && !BukkitUtils.isShulkerBoxBlock(type)) { consumer.queueContainerBreak(actor, block.getState()); } else { consumer.queueBlockBreak(actor, block.getState()); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index 9c9e1b3a..ca607c63 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -45,7 +45,7 @@ public void onBlockFromTo(BlockFromToEvent event) { final Block to = event.getToBlock(); final Material typeTo = to.getType(); boolean down = event.getFace() == BlockFace.DOWN; - final boolean canFlow = BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo); + final boolean canFlow = BukkitUtils.isEmpty(typeTo) || BukkitUtils.isNonFluidProofBlock(typeTo); if (typeFrom == Material.LAVA && wcfg.isLogging(Logging.LAVAFLOW)) { Levelled levelledFrom = (Levelled) blockDataFrom; if (canFlow) { @@ -73,7 +73,7 @@ public void onBlockFromTo(BlockFromToEvent event) { newBlock.setLevel(fromWaterlogged || down ? 1 : Math.min(levelledFrom.getLevel() + 1, levelledFrom.getMaximumLevel())); if (BukkitUtils.isEmpty(typeTo)) { consumer.queueBlockPlace(new Actor("WaterFlow", source), to.getLocation(), newBlock); - } else if (BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { + } else if (BukkitUtils.isNonFluidProofBlock(typeTo)) { consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), newBlock); } else if (typeTo == Material.LAVA) { int toLevel = ((Levelled) to.getBlockData()).getLevel(); @@ -83,7 +83,7 @@ public void onBlockFromTo(BlockFromToEvent event) { consumer.queueBlockReplace(new Actor("WaterFlow", source), to.getState(), Material.STONE.createBlockData()); } } - if (BukkitUtils.isEmpty(typeTo) || BukkitUtils.getNonFluidProofBlocks().contains(typeTo)) { + if (BukkitUtils.isEmpty(typeTo) || BukkitUtils.isNonFluidProofBlock(typeTo)) { for (final BlockFace face : new BlockFace[] { BlockFace.DOWN, BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH }) { final Block lower = to.getRelative(face); if (lower.getType() == Material.LAVA) { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index 13d1b98a..4942d707 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -178,7 +178,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { consumer.queueBlock(Actor.actorFromEntity(player), loc, blockData, Material.DIRT.createBlockData()); // Log the crop on top as being broken Block trampledCrop = clicked.getRelative(BlockFace.UP); - if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) { + if (BukkitUtils.isCropBlock(trampledCrop.getType())) { consumer.queueBlockBreak(Actor.actorFromEntity(player), trampledCrop.getState()); } } diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 96fb0854..56fd50f0 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -6,7 +6,6 @@ import java.io.File; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -28,6 +27,7 @@ import org.bukkit.DyeColor; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.Tag; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -57,253 +57,165 @@ import org.bukkit.inventory.ItemStack; public class BukkitUtils { - private static final Set> blockEquivalents; - private static final Set relativeBreakable; - private static final Set relativeTopBreakable; - private static final Set fallingEntityKillers; - private static final Set cropBlocks; - private static final Set containerBlocks; - private static final Set shulkerBoxBlocks; + private static final Map dyes; + private static final Map projectileItems; - private static final Set singleBlockPlants; + private static final Set alwaysWaterlogged; + private static final Set concreteBlocks; + private static final Set containerBlocks; private static final Set doublePlants; - + private static final Set fallingEntityKillers; private static final Set nonFluidProofBlocks; + private static final Set relativeBreakable; + private static final Set relativeTopBreakable; + private static final Set singleBlockPlants; - private static final Set bedBlocks; - - private static final Map projectileItems; - private static final HashSet signs; - private static final HashSet wallSigns; - private static final HashSet hangingSigns; - private static final HashSet hangingWallSigns; - private static final HashSet allSigns; - private static final Set unmodifiableSigns; - private static final HashSet buttons; - private static final HashSet pressurePlates; - private static final HashSet woodenDoors; - private static final HashSet slabs; - private static final HashSet concreteBlocks; - private static final HashMap dyes; - private static final HashSet alwaysWaterlogged; - private static final HashSet candles; - private static final HashSet candleCakes; - private static final HashSet fenceGates; - private static final HashSet woodenTrapdoors; + private static final Tag allSigns; + private static final Tag bedBlocks; + private static final Tag buttons; + private static final Tag candleCakes; + private static final Tag candles; + private static final Tag cropBlocks; + private static final Tag fenceGates; + private static final Tag hangingSigns; + private static final Tag pressurePlates; + private static final Tag shulkerBoxBlocks; + private static final Tag slabs; + private static final Tag woodenDoors; + private static final Tag woodenTrapdoors; static { - fenceGates = new HashSet<>(); - fenceGates.add(Material.OAK_FENCE_GATE); - fenceGates.add(Material.SPRUCE_FENCE_GATE); - fenceGates.add(Material.BIRCH_FENCE_GATE); - fenceGates.add(Material.JUNGLE_FENCE_GATE); - fenceGates.add(Material.ACACIA_FENCE_GATE); - fenceGates.add(Material.DARK_OAK_FENCE_GATE); - fenceGates.add(Material.WARPED_FENCE_GATE); - fenceGates.add(Material.CRIMSON_FENCE_GATE); - fenceGates.add(Material.MANGROVE_FENCE_GATE); - fenceGates.add(Material.BAMBOO_FENCE_GATE); - fenceGates.add(Material.CHERRY_FENCE_GATE); - - woodenTrapdoors = new HashSet<>(); - woodenTrapdoors.add(Material.OAK_TRAPDOOR); - woodenTrapdoors.add(Material.SPRUCE_TRAPDOOR); - woodenTrapdoors.add(Material.BIRCH_TRAPDOOR); - woodenTrapdoors.add(Material.JUNGLE_TRAPDOOR); - woodenTrapdoors.add(Material.ACACIA_TRAPDOOR); - woodenTrapdoors.add(Material.DARK_OAK_TRAPDOOR); - woodenTrapdoors.add(Material.WARPED_TRAPDOOR); - woodenTrapdoors.add(Material.CRIMSON_TRAPDOOR); - woodenTrapdoors.add(Material.MANGROVE_TRAPDOOR); - woodenTrapdoors.add(Material.BAMBOO_TRAPDOOR); - woodenTrapdoors.add(Material.CHERRY_TRAPDOOR); - - pressurePlates = new HashSet<>(); - pressurePlates.add(Material.OAK_PRESSURE_PLATE); - pressurePlates.add(Material.SPRUCE_PRESSURE_PLATE); - pressurePlates.add(Material.BIRCH_PRESSURE_PLATE); - pressurePlates.add(Material.JUNGLE_PRESSURE_PLATE); - pressurePlates.add(Material.ACACIA_PRESSURE_PLATE); - pressurePlates.add(Material.DARK_OAK_PRESSURE_PLATE); - pressurePlates.add(Material.WARPED_PRESSURE_PLATE); - pressurePlates.add(Material.CRIMSON_PRESSURE_PLATE); - pressurePlates.add(Material.MANGROVE_PRESSURE_PLATE); - pressurePlates.add(Material.BAMBOO_PRESSURE_PLATE); - pressurePlates.add(Material.CHERRY_PRESSURE_PLATE); - pressurePlates.add(Material.STONE_PRESSURE_PLATE); - pressurePlates.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE); - pressurePlates.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE); - - woodenDoors = new HashSet<>(); - woodenDoors.add(Material.OAK_DOOR); - woodenDoors.add(Material.SPRUCE_DOOR); - woodenDoors.add(Material.BIRCH_DOOR); - woodenDoors.add(Material.JUNGLE_DOOR); - woodenDoors.add(Material.ACACIA_DOOR); - woodenDoors.add(Material.DARK_OAK_DOOR); - woodenDoors.add(Material.WARPED_DOOR); - woodenDoors.add(Material.CRIMSON_DOOR); - woodenDoors.add(Material.MANGROVE_DOOR); - woodenDoors.add(Material.BAMBOO_DOOR); - woodenDoors.add(Material.CHERRY_DOOR); - - HashSet saplings = new HashSet<>(); - saplings.add(Material.OAK_SAPLING); - saplings.add(Material.SPRUCE_SAPLING); - saplings.add(Material.BIRCH_SAPLING); - saplings.add(Material.JUNGLE_SAPLING); - saplings.add(Material.ACACIA_SAPLING); - saplings.add(Material.DARK_OAK_SAPLING); - saplings.add(Material.CHERRY_SAPLING); - saplings.add(Material.WARPED_FUNGUS); - saplings.add(Material.CRIMSON_FUNGUS); - saplings.add(Material.MANGROVE_PROPAGULE); - - HashSet carpets = new HashSet<>(); - carpets.add(Material.BLACK_CARPET); - carpets.add(Material.BLUE_CARPET); - carpets.add(Material.LIGHT_GRAY_CARPET); - carpets.add(Material.BROWN_CARPET); - carpets.add(Material.CYAN_CARPET); - carpets.add(Material.GRAY_CARPET); - carpets.add(Material.GREEN_CARPET); - carpets.add(Material.LIGHT_BLUE_CARPET); - carpets.add(Material.MAGENTA_CARPET); - carpets.add(Material.LIME_CARPET); - carpets.add(Material.ORANGE_CARPET); - carpets.add(Material.PINK_CARPET); - carpets.add(Material.PURPLE_CARPET); - carpets.add(Material.RED_CARPET); - carpets.add(Material.WHITE_CARPET); - carpets.add(Material.YELLOW_CARPET); - - slabs = new HashSet<>(); - slabs.add(Material.OAK_SLAB); - slabs.add(Material.SPRUCE_SLAB); - slabs.add(Material.BIRCH_SLAB); - slabs.add(Material.JUNGLE_SLAB); - slabs.add(Material.ACACIA_SLAB); - slabs.add(Material.DARK_OAK_SLAB); - slabs.add(Material.WARPED_SLAB); - slabs.add(Material.CRIMSON_SLAB); - slabs.add(Material.STONE_SLAB); - slabs.add(Material.STONE_BRICK_SLAB); - slabs.add(Material.COBBLESTONE_SLAB); - slabs.add(Material.PETRIFIED_OAK_SLAB); - slabs.add(Material.SANDSTONE_SLAB); - slabs.add(Material.RED_SANDSTONE_SLAB); - slabs.add(Material.NETHER_BRICK_SLAB); - slabs.add(Material.PURPUR_SLAB); - slabs.add(Material.QUARTZ_SLAB); - slabs.add(Material.BRICK_SLAB); - slabs.add(Material.PRISMARINE_SLAB); - slabs.add(Material.DARK_PRISMARINE_SLAB); - slabs.add(Material.PRISMARINE_BRICK_SLAB); - slabs.add(Material.BLACKSTONE_SLAB); - slabs.add(Material.POLISHED_BLACKSTONE_SLAB); - slabs.add(Material.DEEPSLATE_BRICK_SLAB); - slabs.add(Material.DEEPSLATE_TILE_SLAB); - slabs.add(Material.COBBLED_DEEPSLATE_SLAB); - slabs.add(Material.POLISHED_DEEPSLATE_SLAB); - slabs.add(Material.MANGROVE_SLAB); - slabs.add(Material.BAMBOO_SLAB); - slabs.add(Material.CHERRY_SLAB); - - buttons = new HashSet<>(); - buttons.add(Material.STONE_BUTTON); - buttons.add(Material.OAK_BUTTON); - buttons.add(Material.SPRUCE_BUTTON); - buttons.add(Material.BIRCH_BUTTON); - buttons.add(Material.JUNGLE_BUTTON); - buttons.add(Material.ACACIA_BUTTON); - buttons.add(Material.DARK_OAK_BUTTON); - buttons.add(Material.WARPED_BUTTON); - buttons.add(Material.CRIMSON_BUTTON); - buttons.add(Material.MANGROVE_BUTTON); - buttons.add(Material.BAMBOO_BUTTON); - buttons.add(Material.CHERRY_BUTTON); - buttons.add(Material.POLISHED_BLACKSTONE_BUTTON); - - signs = new HashSet<>(); - signs.add(Material.OAK_SIGN); - signs.add(Material.SPRUCE_SIGN); - signs.add(Material.BIRCH_SIGN); - signs.add(Material.JUNGLE_SIGN); - signs.add(Material.DARK_OAK_SIGN); - signs.add(Material.ACACIA_SIGN); - signs.add(Material.WARPED_SIGN); - signs.add(Material.CRIMSON_SIGN); - signs.add(Material.MANGROVE_SIGN); - signs.add(Material.BAMBOO_SIGN); - signs.add(Material.CHERRY_SIGN); - - wallSigns = new HashSet<>(); - wallSigns.add(Material.OAK_WALL_SIGN); - wallSigns.add(Material.SPRUCE_WALL_SIGN); - wallSigns.add(Material.BIRCH_WALL_SIGN); - wallSigns.add(Material.JUNGLE_WALL_SIGN); - wallSigns.add(Material.DARK_OAK_WALL_SIGN); - wallSigns.add(Material.ACACIA_WALL_SIGN); - wallSigns.add(Material.WARPED_WALL_SIGN); - wallSigns.add(Material.CRIMSON_WALL_SIGN); - wallSigns.add(Material.MANGROVE_WALL_SIGN); - wallSigns.add(Material.BAMBOO_WALL_SIGN); - wallSigns.add(Material.CHERRY_WALL_SIGN); - - hangingSigns = new HashSet<>(); - hangingSigns.add(Material.OAK_HANGING_SIGN); - hangingSigns.add(Material.SPRUCE_HANGING_SIGN); - hangingSigns.add(Material.BIRCH_HANGING_SIGN); - hangingSigns.add(Material.JUNGLE_HANGING_SIGN); - hangingSigns.add(Material.DARK_OAK_HANGING_SIGN); - hangingSigns.add(Material.ACACIA_HANGING_SIGN); - hangingSigns.add(Material.WARPED_HANGING_SIGN); - hangingSigns.add(Material.CRIMSON_HANGING_SIGN); - hangingSigns.add(Material.MANGROVE_HANGING_SIGN); - hangingSigns.add(Material.BAMBOO_HANGING_SIGN); - hangingSigns.add(Material.CHERRY_HANGING_SIGN); - - hangingWallSigns = new HashSet<>(); - hangingWallSigns.add(Material.OAK_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.SPRUCE_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.BIRCH_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.JUNGLE_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.DARK_OAK_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.ACACIA_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.WARPED_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.CRIMSON_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.MANGROVE_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.BAMBOO_WALL_HANGING_SIGN); - hangingWallSigns.add(Material.CHERRY_WALL_HANGING_SIGN); - - allSigns = new HashSet<>(); - allSigns.addAll(signs); - allSigns.addAll(wallSigns); - allSigns.addAll(hangingSigns); - allSigns.addAll(hangingWallSigns); - unmodifiableSigns = Collections.unmodifiableSet(allSigns); - - singleBlockPlants = new HashSet<>(); + // Global Tags + + // https://minecraft.fandom.com/wiki/Tag#blocks_fence_gates + fenceGates = Tag.FENCE_GATES; + + // https://minecraft.fandom.com/wiki/Tag#blocks_wooden_trapdoors + woodenTrapdoors = Tag.WOODEN_TRAPDOORS; + + // https://minecraft.fandom.com/wiki/Tag#blocks_pressure_plates + pressurePlates = Tag.PRESSURE_PLATES; + + // https://minecraft.fandom.com/wiki/Tag#blocks_wooden_doors + woodenDoors = Tag.WOODEN_DOORS; + + // https://minecraft.fandom.com/wiki/Tag#blocks_slabs + slabs = Tag.SLABS; + + // https://minecraft.fandom.com/wiki/Tag#blocks_buttons + buttons = Tag.BUTTONS; + + // https://minecraft.fandom.com/wiki/Tag#blocks_ceiling_hanging_signs + hangingSigns = Tag.CEILING_HANGING_SIGNS; + + // https://minecraft.fandom.com/wiki/Tag#blocks_all_signs + allSigns = Tag.ALL_SIGNS; + + // https://minecraft.fandom.com/wiki/Tag#blocks_candles + candles = Tag.CANDLES; + + // https://minecraft.fandom.com/wiki/Tag#blocks_candle_cakes + candleCakes = Tag.CANDLE_CAKES; + + // https://minecraft.fandom.com/wiki/Tag#blocks_crops + cropBlocks = Tag.CROPS; + + // https://minecraft.fandom.com/wiki/Tag#blocks_shulker_boxes + shulkerBoxBlocks = Tag.SHULKER_BOXES; + + // https://minecraft.fandom.com/wiki/Tag#blocks_beds + bedBlocks = Tag.BEDS; + + // Local Tags + + // https://minecraft.fandom.com/wiki/Tag#blocks_standing_signs + Set signs = Tag.STANDING_SIGNS.getValues(); + + // https://minecraft.fandom.com/wiki/Tag#blocks_wall_signs + Set wallSigns = Tag.WALL_SIGNS.getValues(); + + // https://minecraft.fandom.com/wiki/Tag#blocks_wool_carpets + Set carpets = Tag.WOOL_CARPETS.getValues(); + + // https://minecraft.fandom.com/wiki/Tag#blocks_flower_pots + Set flowserPots = Tag.FLOWER_POTS.getValues(); + + // https://minecraft.fandom.com/wiki/Tag#blocks_saplings + Set saplings = Tag.SAPLINGS.getValues(); + + // https://minecraft.fandom.com/wiki/Tag#blocks_small_flowers + Set smallFlowers = Tag.SMALL_FLOWERS.getValues(); + + // https://minecraft.fandom.com/wiki/Tag#blocks_tall_flowers + Set tallFlowers = Tag.TALL_FLOWERS.getValues(); + + Set bannerStanding = Set.of(Material.WHITE_BANNER, + Material.ORANGE_BANNER, + Material.MAGENTA_BANNER, + Material.LIGHT_BLUE_BANNER, + Material.YELLOW_BANNER, + Material.LIME_BANNER, + Material.PINK_BANNER, + Material.GRAY_BANNER, + Material.LIGHT_GRAY_BANNER, + Material.CYAN_BANNER, + Material.PURPLE_BANNER, + Material.BLUE_BANNER, + Material.BROWN_BANNER, + Material.GREEN_BANNER, + Material.RED_BANNER, + Material.BLACK_BANNER); + + Set bannerWall = Set.of(Material.WHITE_WALL_BANNER, + Material.ORANGE_WALL_BANNER, + Material.MAGENTA_WALL_BANNER, + Material.LIGHT_BLUE_WALL_BANNER, + Material.YELLOW_WALL_BANNER, + Material.LIME_WALL_BANNER, + Material.PINK_WALL_BANNER, + Material.GRAY_WALL_BANNER, + Material.LIGHT_GRAY_WALL_BANNER, + Material.CYAN_WALL_BANNER, + Material.PURPLE_WALL_BANNER, + Material.BLUE_WALL_BANNER, + Material.BROWN_WALL_BANNER, + Material.GREEN_WALL_BANNER, + Material.RED_WALL_BANNER, + Material.BLACK_WALL_BANNER); + + Set bannerAll = Tag.BANNERS.getValues(); + + Set headAndSkulls = Set.of(Material.SKELETON_WALL_SKULL, + Material.PLAYER_HEAD, + Material.PLAYER_WALL_HEAD, + Material.CREEPER_HEAD, + Material.CREEPER_WALL_HEAD, + Material.DRAGON_HEAD, + Material.DRAGON_WALL_HEAD, + Material.ZOMBIE_HEAD, + Material.ZOMBIE_WALL_HEAD, + Material.SKELETON_SKULL, + Material.SKELETON_WALL_SKULL, + Material.WITHER_SKELETON_SKULL, + Material.WITHER_SKELETON_WALL_SKULL); + + Set standingTorch = Set.of(Material.TORCH, + Material.SOUL_TORCH, + Material.REDSTONE_TORCH); + + Set wallTorch = Set.of(Material.WALL_TORCH, + Material.SOUL_WALL_TORCH, + Material.REDSTONE_WALL_TORCH); + + singleBlockPlants = new HashSet(); + singleBlockPlants.addAll(smallFlowers); singleBlockPlants.add(Material.GRASS); singleBlockPlants.add(Material.FERN); singleBlockPlants.add(Material.DEAD_BUSH); - singleBlockPlants.add(Material.DANDELION); - singleBlockPlants.add(Material.POPPY); - singleBlockPlants.add(Material.BLUE_ORCHID); - singleBlockPlants.add(Material.ALLIUM); - singleBlockPlants.add(Material.AZURE_BLUET); - singleBlockPlants.add(Material.ORANGE_TULIP); - singleBlockPlants.add(Material.WHITE_TULIP); - singleBlockPlants.add(Material.PINK_TULIP); - singleBlockPlants.add(Material.RED_TULIP); - singleBlockPlants.add(Material.OXEYE_DAISY); singleBlockPlants.add(Material.BROWN_MUSHROOM); singleBlockPlants.add(Material.RED_MUSHROOM); singleBlockPlants.add(Material.SWEET_BERRY_BUSH); - singleBlockPlants.add(Material.LILY_OF_THE_VALLEY); - singleBlockPlants.add(Material.CORNFLOWER); - singleBlockPlants.add(Material.WITHER_ROSE); singleBlockPlants.add(Material.CRIMSON_FUNGUS); singleBlockPlants.add(Material.WARPED_FUNGUS); singleBlockPlants.add(Material.CRIMSON_ROOTS); @@ -312,37 +224,23 @@ public class BukkitUtils { singleBlockPlants.add(Material.AZALEA); singleBlockPlants.add(Material.FLOWERING_AZALEA); singleBlockPlants.add(Material.PINK_PETALS); - singleBlockPlants.add(Material.TORCHFLOWER); singleBlockPlants.add(Material.PITCHER_CROP); - doublePlants = new HashSet<>(); + doublePlants = new HashSet(); + doublePlants.addAll(tallFlowers); doublePlants.add(Material.TALL_GRASS); doublePlants.add(Material.LARGE_FERN); doublePlants.add(Material.TALL_SEAGRASS); - doublePlants.add(Material.ROSE_BUSH); - doublePlants.add(Material.LILAC); - doublePlants.add(Material.SUNFLOWER); - doublePlants.add(Material.PEONY); doublePlants.add(Material.SMALL_DRIPLEAF); - doublePlants.add(Material.PITCHER_PLANT); - - blockEquivalents = new HashSet<>(7); - blockEquivalents.add(new HashSet<>(Arrays.asList(2, 3, 60))); - blockEquivalents.add(new HashSet<>(Arrays.asList(8, 9, 79))); - blockEquivalents.add(new HashSet<>(Arrays.asList(10, 11))); - blockEquivalents.add(new HashSet<>(Arrays.asList(61, 62))); - blockEquivalents.add(new HashSet<>(Arrays.asList(73, 74))); - blockEquivalents.add(new HashSet<>(Arrays.asList(75, 76))); - blockEquivalents.add(new HashSet<>(Arrays.asList(93, 94))); // Blocks that break when they are attached to a block - relativeBreakable = new HashSet<>(); + relativeBreakable = new HashSet(); + relativeBreakable.addAll(bannerWall); + relativeBreakable.addAll(buttons.getValues()); relativeBreakable.addAll(wallSigns); + relativeBreakable.addAll(wallTorch); relativeBreakable.add(Material.LADDER); - relativeBreakable.addAll(buttons); - relativeBreakable.add(Material.REDSTONE_WALL_TORCH); relativeBreakable.add(Material.LEVER); - relativeBreakable.add(Material.WALL_TORCH); relativeBreakable.add(Material.TRIPWIRE_HOOK); relativeBreakable.add(Material.COCOA); relativeBreakable.add(Material.BELL); @@ -352,12 +250,20 @@ public class BukkitUtils { relativeBreakable.add(Material.LARGE_AMETHYST_BUD); // Blocks that break when they are on top of a block - relativeTopBreakable = new HashSet<>(); + relativeTopBreakable = new HashSet(); + relativeTopBreakable.addAll(bannerStanding); + relativeTopBreakable.addAll(candleCakes.getValues()); + relativeTopBreakable.addAll(candles.getValues()); + relativeTopBreakable.addAll(carpets); + relativeTopBreakable.addAll(cropBlocks.getValues()); + relativeTopBreakable.addAll(doublePlants); + relativeTopBreakable.addAll(flowserPots); + relativeTopBreakable.addAll(pressurePlates.getValues()); relativeTopBreakable.addAll(saplings); + relativeTopBreakable.addAll(signs); relativeTopBreakable.addAll(singleBlockPlants); - relativeTopBreakable.add(Material.WHEAT); - relativeTopBreakable.add(Material.POTATO); - relativeTopBreakable.add(Material.CARROT); + relativeTopBreakable.addAll(standingTorch); + relativeTopBreakable.addAll(woodenDoors.getValues()); relativeTopBreakable.add(Material.LILY_PAD); relativeTopBreakable.add(Material.CACTUS); relativeTopBreakable.add(Material.SUGAR_CANE); @@ -367,54 +273,36 @@ public class BukkitUtils { relativeTopBreakable.add(Material.ACTIVATOR_RAIL); relativeTopBreakable.add(Material.RAIL); relativeTopBreakable.add(Material.REDSTONE_WIRE); - relativeTopBreakable.addAll(signs); - relativeTopBreakable.addAll(pressurePlates); relativeTopBreakable.add(Material.SNOW); relativeTopBreakable.add(Material.REPEATER); relativeTopBreakable.add(Material.COMPARATOR); - relativeTopBreakable.add(Material.TORCH); - relativeTopBreakable.add(Material.SOUL_TORCH); - relativeTopBreakable.add(Material.REDSTONE_TORCH); - relativeTopBreakable.addAll(woodenDoors); relativeTopBreakable.add(Material.IRON_DOOR); - relativeTopBreakable.addAll(carpets); - relativeTopBreakable.addAll(doublePlants); relativeTopBreakable.add(Material.BAMBOO); relativeTopBreakable.add(Material.BAMBOO_SAPLING); relativeTopBreakable.add(Material.TWISTING_VINES); relativeTopBreakable.add(Material.TWISTING_VINES_PLANT); relativeTopBreakable.add(Material.BIG_DRIPLEAF); relativeTopBreakable.add(Material.BIG_DRIPLEAF_STEM); - for (Material m : Material.values()) { - if (m.name().startsWith("POTTED_")) { - relativeTopBreakable.add(m); - } - if (m.name().endsWith("CANDLE_CAKE")) { - relativeTopBreakable.add(m); - } - } // Blocks that break falling entities - fallingEntityKillers = new HashSet<>(); - fallingEntityKillers.addAll(signs); - fallingEntityKillers.addAll(wallSigns); - fallingEntityKillers.addAll(pressurePlates); + fallingEntityKillers = new HashSet(); + fallingEntityKillers.addAll(bannerAll); + fallingEntityKillers.addAll(candleCakes.getValues()); + fallingEntityKillers.addAll(candles.getValues()); + fallingEntityKillers.addAll(carpets); + fallingEntityKillers.addAll(cropBlocks.getValues()); + fallingEntityKillers.addAll(doublePlants); + fallingEntityKillers.addAll(pressurePlates.getValues()); fallingEntityKillers.addAll(saplings); + fallingEntityKillers.addAll(signs); fallingEntityKillers.addAll(singleBlockPlants); - fallingEntityKillers.remove(Material.GRASS); - fallingEntityKillers.remove(Material.NETHER_SPROUTS); - fallingEntityKillers.addAll(doublePlants); - fallingEntityKillers.add(Material.WHEAT); - fallingEntityKillers.add(Material.CARROT); - fallingEntityKillers.add(Material.POTATO); - fallingEntityKillers.add(Material.BEETROOT); + fallingEntityKillers.addAll(headAndSkulls); + fallingEntityKillers.addAll(slabs.getValues()); + fallingEntityKillers.addAll(standingTorch); + fallingEntityKillers.addAll(wallSigns); + fallingEntityKillers.addAll(wallTorch); fallingEntityKillers.add(Material.NETHER_WART); fallingEntityKillers.add(Material.COCOA); - fallingEntityKillers.addAll(slabs); - fallingEntityKillers.add(Material.TORCH); - fallingEntityKillers.add(Material.WALL_TORCH); - fallingEntityKillers.add(Material.SOUL_TORCH); - fallingEntityKillers.add(Material.SOUL_WALL_TORCH); fallingEntityKillers.add(Material.FLOWER_POT); fallingEntityKillers.add(Material.POWERED_RAIL); fallingEntityKillers.add(Material.DETECTOR_RAIL); @@ -422,62 +310,15 @@ public class BukkitUtils { fallingEntityKillers.add(Material.RAIL); fallingEntityKillers.add(Material.LEVER); fallingEntityKillers.add(Material.REDSTONE_WIRE); - fallingEntityKillers.add(Material.REDSTONE_TORCH); - fallingEntityKillers.add(Material.REDSTONE_WALL_TORCH); fallingEntityKillers.add(Material.REPEATER); fallingEntityKillers.add(Material.COMPARATOR); fallingEntityKillers.add(Material.DAYLIGHT_DETECTOR); - fallingEntityKillers.addAll(carpets); - fallingEntityKillers.add(Material.PLAYER_HEAD); - fallingEntityKillers.add(Material.PLAYER_WALL_HEAD); - fallingEntityKillers.add(Material.CREEPER_HEAD); - fallingEntityKillers.add(Material.CREEPER_WALL_HEAD); - fallingEntityKillers.add(Material.DRAGON_HEAD); - fallingEntityKillers.add(Material.DRAGON_WALL_HEAD); - fallingEntityKillers.add(Material.ZOMBIE_HEAD); - fallingEntityKillers.add(Material.ZOMBIE_WALL_HEAD); - fallingEntityKillers.add(Material.SKELETON_SKULL); - fallingEntityKillers.add(Material.SKELETON_WALL_SKULL); - fallingEntityKillers.add(Material.WITHER_SKELETON_SKULL); - fallingEntityKillers.add(Material.WITHER_SKELETON_WALL_SKULL); - for (Material m : Material.values()) { - if (m.name().contains("CANDLE")) { - fallingEntityKillers.add(m); - } - } - - // Crop Blocks - cropBlocks = new HashSet<>(); - cropBlocks.add(Material.WHEAT); - cropBlocks.add(Material.MELON_STEM); - cropBlocks.add(Material.PUMPKIN_STEM); - cropBlocks.add(Material.CARROT); - cropBlocks.add(Material.POTATO); - cropBlocks.add(Material.BEETROOT); - cropBlocks.add(Material.TORCHFLOWER_CROP); - - // Shulker Boxes - shulkerBoxBlocks = new HashSet<>(); - shulkerBoxBlocks.add(Material.SHULKER_BOX); - shulkerBoxBlocks.add(Material.BLACK_SHULKER_BOX); - shulkerBoxBlocks.add(Material.BLUE_SHULKER_BOX); - shulkerBoxBlocks.add(Material.LIGHT_GRAY_SHULKER_BOX); - shulkerBoxBlocks.add(Material.BROWN_SHULKER_BOX); - shulkerBoxBlocks.add(Material.CYAN_SHULKER_BOX); - shulkerBoxBlocks.add(Material.GRAY_SHULKER_BOX); - shulkerBoxBlocks.add(Material.GREEN_SHULKER_BOX); - shulkerBoxBlocks.add(Material.LIGHT_BLUE_SHULKER_BOX); - shulkerBoxBlocks.add(Material.MAGENTA_SHULKER_BOX); - shulkerBoxBlocks.add(Material.LIME_SHULKER_BOX); - shulkerBoxBlocks.add(Material.ORANGE_SHULKER_BOX); - shulkerBoxBlocks.add(Material.PINK_SHULKER_BOX); - shulkerBoxBlocks.add(Material.PURPLE_SHULKER_BOX); - shulkerBoxBlocks.add(Material.RED_SHULKER_BOX); - shulkerBoxBlocks.add(Material.WHITE_SHULKER_BOX); - shulkerBoxBlocks.add(Material.YELLOW_SHULKER_BOX); + fallingEntityKillers.remove(Material.GRASS); + fallingEntityKillers.remove(Material.NETHER_SPROUTS); // Container Blocks - containerBlocks = new HashSet<>(); + containerBlocks = new HashSet(); + containerBlocks.addAll(shulkerBoxBlocks.getValues()); containerBlocks.add(Material.CHEST); containerBlocks.add(Material.TRAPPED_CHEST); containerBlocks.add(Material.DISPENSER); @@ -485,7 +326,6 @@ public class BukkitUtils { containerBlocks.add(Material.HOPPER); containerBlocks.add(Material.BREWING_STAND); containerBlocks.add(Material.FURNACE); - containerBlocks.addAll(shulkerBoxBlocks); containerBlocks.add(Material.BARREL); containerBlocks.add(Material.BLAST_FURNACE); containerBlocks.add(Material.SMOKER); @@ -507,24 +347,20 @@ public class BukkitUtils { projectileItems.put(EntityType.WITHER_SKULL, Material.WITHER_SKELETON_SKULL); projectileItems.put(EntityType.FIREWORK, Material.FIREWORK_ROCKET); - nonFluidProofBlocks = new HashSet<>(); - nonFluidProofBlocks.addAll(singleBlockPlants); + nonFluidProofBlocks = new HashSet(); + nonFluidProofBlocks.addAll(carpets); + nonFluidProofBlocks.addAll(cropBlocks.getValues()); nonFluidProofBlocks.addAll(doublePlants); - nonFluidProofBlocks.add(Material.REDSTONE_WALL_TORCH); + nonFluidProofBlocks.addAll(headAndSkulls); + nonFluidProofBlocks.addAll(pressurePlates.getValues()); + nonFluidProofBlocks.addAll(saplings); + nonFluidProofBlocks.addAll(singleBlockPlants); + nonFluidProofBlocks.addAll(standingTorch); + nonFluidProofBlocks.addAll(wallTorch); nonFluidProofBlocks.add(Material.LEVER); - nonFluidProofBlocks.add(Material.WALL_TORCH); - nonFluidProofBlocks.add(Material.SOUL_WALL_TORCH); nonFluidProofBlocks.add(Material.TRIPWIRE_HOOK); nonFluidProofBlocks.add(Material.COCOA); - nonFluidProofBlocks.addAll(pressurePlates); - nonFluidProofBlocks.addAll(saplings); - nonFluidProofBlocks.add(Material.WHEAT); - nonFluidProofBlocks.add(Material.CARROT); - nonFluidProofBlocks.add(Material.POTATO); - nonFluidProofBlocks.add(Material.BEETROOT); nonFluidProofBlocks.add(Material.NETHER_WART); - nonFluidProofBlocks.add(Material.TORCH); - nonFluidProofBlocks.add(Material.SOUL_TORCH); nonFluidProofBlocks.add(Material.FLOWER_POT); // nonFluidProofBlocks.add(Material.POWERED_RAIL); // nonFluidProofBlocks.add(Material.DETECTOR_RAIL); @@ -532,91 +368,31 @@ public class BukkitUtils { // nonFluidProofBlocks.add(Material.RAIL); nonFluidProofBlocks.add(Material.LEVER); nonFluidProofBlocks.add(Material.REDSTONE_WIRE); - nonFluidProofBlocks.add(Material.REDSTONE_TORCH); nonFluidProofBlocks.add(Material.REPEATER); nonFluidProofBlocks.add(Material.COMPARATOR); nonFluidProofBlocks.add(Material.DAYLIGHT_DETECTOR); - nonFluidProofBlocks.addAll(carpets); - alwaysWaterlogged = new HashSet<>(); - alwaysWaterlogged.add(Material.SEAGRASS); - alwaysWaterlogged.add(Material.TALL_SEAGRASS); - alwaysWaterlogged.add(Material.KELP); - alwaysWaterlogged.add(Material.KELP_PLANT); - - bedBlocks = new HashSet<>(); - bedBlocks.add(Material.BLACK_BED); - bedBlocks.add(Material.BLUE_BED); - bedBlocks.add(Material.LIGHT_GRAY_BED); - bedBlocks.add(Material.BROWN_BED); - bedBlocks.add(Material.CYAN_BED); - bedBlocks.add(Material.GRAY_BED); - bedBlocks.add(Material.GREEN_BED); - bedBlocks.add(Material.LIGHT_BLUE_BED); - bedBlocks.add(Material.MAGENTA_BED); - bedBlocks.add(Material.LIME_BED); - bedBlocks.add(Material.ORANGE_BED); - bedBlocks.add(Material.PINK_BED); - bedBlocks.add(Material.PURPLE_BED); - bedBlocks.add(Material.RED_BED); - bedBlocks.add(Material.WHITE_BED); - bedBlocks.add(Material.YELLOW_BED); - - concreteBlocks = new HashSet<>(); - concreteBlocks.add(Material.BLACK_CONCRETE); - concreteBlocks.add(Material.BLUE_CONCRETE); - concreteBlocks.add(Material.LIGHT_GRAY_CONCRETE); - concreteBlocks.add(Material.BROWN_CONCRETE); - concreteBlocks.add(Material.CYAN_CONCRETE); - concreteBlocks.add(Material.GRAY_CONCRETE); - concreteBlocks.add(Material.GREEN_CONCRETE); - concreteBlocks.add(Material.LIGHT_BLUE_CONCRETE); - concreteBlocks.add(Material.MAGENTA_CONCRETE); - concreteBlocks.add(Material.LIME_CONCRETE); - concreteBlocks.add(Material.ORANGE_CONCRETE); - concreteBlocks.add(Material.PINK_CONCRETE); - concreteBlocks.add(Material.PURPLE_CONCRETE); - concreteBlocks.add(Material.RED_CONCRETE); - concreteBlocks.add(Material.WHITE_CONCRETE); - concreteBlocks.add(Material.YELLOW_CONCRETE); - - candles = new HashSet<>(); - candles.add(Material.CANDLE); - candles.add(Material.BLACK_CANDLE); - candles.add(Material.BLUE_CANDLE); - candles.add(Material.LIGHT_GRAY_CANDLE); - candles.add(Material.BROWN_CANDLE); - candles.add(Material.CYAN_CANDLE); - candles.add(Material.GRAY_CANDLE); - candles.add(Material.GREEN_CANDLE); - candles.add(Material.LIGHT_BLUE_CANDLE); - candles.add(Material.MAGENTA_CANDLE); - candles.add(Material.LIME_CANDLE); - candles.add(Material.ORANGE_CANDLE); - candles.add(Material.PINK_CANDLE); - candles.add(Material.PURPLE_CANDLE); - candles.add(Material.RED_CANDLE); - candles.add(Material.WHITE_CANDLE); - candles.add(Material.YELLOW_CANDLE); - - candleCakes = new HashSet<>(); - candleCakes.add(Material.CANDLE_CAKE); - candleCakes.add(Material.BLACK_CANDLE_CAKE); - candleCakes.add(Material.BLUE_CANDLE_CAKE); - candleCakes.add(Material.LIGHT_GRAY_CANDLE_CAKE); - candleCakes.add(Material.BROWN_CANDLE_CAKE); - candleCakes.add(Material.CYAN_CANDLE_CAKE); - candleCakes.add(Material.GRAY_CANDLE_CAKE); - candleCakes.add(Material.GREEN_CANDLE_CAKE); - candleCakes.add(Material.LIGHT_BLUE_CANDLE_CAKE); - candleCakes.add(Material.MAGENTA_CANDLE_CAKE); - candleCakes.add(Material.LIME_CANDLE_CAKE); - candleCakes.add(Material.ORANGE_CANDLE_CAKE); - candleCakes.add(Material.PINK_CANDLE_CAKE); - candleCakes.add(Material.PURPLE_CANDLE_CAKE); - candleCakes.add(Material.RED_CANDLE_CAKE); - candleCakes.add(Material.WHITE_CANDLE_CAKE); - candleCakes.add(Material.YELLOW_CANDLE_CAKE); + alwaysWaterlogged = Set.of(Material.SEAGRASS, + Material.TALL_SEAGRASS, + Material.KELP, + Material.KELP_PLANT); + + concreteBlocks = Set.of(Material.BLACK_CONCRETE, + Material.BLUE_CONCRETE, + Material.LIGHT_GRAY_CONCRETE, + Material.BROWN_CONCRETE, + Material.CYAN_CONCRETE, + Material.GRAY_CONCRETE, + Material.GREEN_CONCRETE, + Material.LIGHT_BLUE_CONCRETE, + Material.MAGENTA_CONCRETE, + Material.LIME_CONCRETE, + Material.ORANGE_CONCRETE, + Material.PINK_CONCRETE, + Material.PURPLE_CONCRETE, + Material.RED_CONCRETE, + Material.WHITE_CONCRETE, + Material.YELLOW_CONCRETE); dyes = new HashMap<>(); dyes.put(Material.BLACK_DYE, DyeColor.BLACK); @@ -638,7 +414,7 @@ public class BukkitUtils { } private static final BlockFace[] relativeBlockFaces = new BlockFace[] { - BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN + BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN }; /** @@ -741,52 +517,40 @@ public static ItemStack[] compressInventory(ItemStack[] items) { return compressed.toArray(new ItemStack[compressed.size()]); } - public static boolean equalTypes(int type1, int type2) { - if (type1 == type2) { - return true; - } - for (final Set equivalent : blockEquivalents) { - if (equivalent.contains(type1) && equivalent.contains(type2)) { - return true; - } - } - return false; - } - public static String friendlyWorldname(String worldName) { return new File(worldName).getName(); } - public static Set> getBlockEquivalents() { - return blockEquivalents; - } - public static Set getRelativeBreakables() { - return relativeBreakable; + return Collections.unmodifiableSet(relativeBreakable); } - public static Set getRelativeTopBreakabls() { - return relativeTopBreakable; + public static boolean isRelativeTopBreakable(Material type) { + return relativeTopBreakable.contains(type); } - public static Set getFallingEntityKillers() { - return fallingEntityKillers; + public static boolean isFallingEntityKiller(Material type) { + return fallingEntityKillers.contains(type); } - public static Set getNonFluidProofBlocks() { - return nonFluidProofBlocks; + public static boolean isNonFluidProofBlock(Material type) { + return nonFluidProofBlocks.contains(type); } - public static Set getCropBlocks() { - return cropBlocks; + public static boolean isCropBlock(Material type) { + return cropBlocks.isTagged(type); } - public static Set getContainerBlocks() { - return containerBlocks; + public static boolean isContainerBlock(Material type) { + return containerBlocks.contains(type); } public static Set getShulkerBoxBlocks() { - return shulkerBoxBlocks; + return shulkerBoxBlocks.getValues(); // Already an unmodifiable Set + } + + public static boolean isShulkerBoxBlock(Material type) { + return shulkerBoxBlocks.isTagged(type); } public static boolean isConcreteBlock(Material m) { @@ -794,8 +558,8 @@ public static boolean isConcreteBlock(Material m) { } public static String entityName(Entity entity) { - if (entity instanceof Player) { - return ((Player) entity).getName(); + if (entity instanceof Player player) { + return player.getName(); } if (entity instanceof TNTPrimed) { return "TNT"; @@ -856,8 +620,8 @@ public static boolean canFallIn(World world, int x, int y, int z) { Material mat = block.getType(); if (canDirectlyFallIn(mat)) { return true; - } else if (getFallingEntityKillers().contains(mat) || singleBlockPlants.contains(mat) || mat == Material.VINE) { - if (slabs.contains(mat)) { + } else if (isFallingEntityKiller(mat) || singleBlockPlants.contains(mat) || mat == Material.VINE) { + if (slabs.isTagged(mat)) { if (((Slab) block.getBlockData()).getType() != Type.BOTTOM) { return false; } @@ -880,11 +644,11 @@ public static boolean isDoublePlant(Material m) { } public static boolean isWoodenDoor(Material m) { - return woodenDoors.contains(m); + return woodenDoors.isTagged(m); } public static boolean isButton(Material m) { - return buttons.contains(m); + return buttons.isTagged(m); } public static boolean isEmpty(Material m) { @@ -947,7 +711,7 @@ public static String formatMinecraftKey(String s) { } public static boolean isBed(Material type) { - return bedBlocks.contains(type); + return bedBlocks.isTagged(type); } public static boolean isDye(Material type) { @@ -1196,7 +960,7 @@ public static boolean isSimilarForRollback(Material expected, Material found) { } public static Set getAllSignMaterials() { - return unmodifiableSigns; + return allSigns.getValues(); } public static boolean isAlwaysWaterlogged(Material m) { @@ -1204,31 +968,31 @@ public static boolean isAlwaysWaterlogged(Material m) { } public static boolean isCandle(Material m) { - return candles.contains(m); + return candles.isTagged(m); } public static boolean isCandleCake(Material m) { - return candleCakes.contains(m); + return candleCakes.isTagged(m); } public static boolean isHangingSign(Material m) { - return hangingSigns.contains(m); + return hangingSigns.isTagged(m); } public static boolean isFenceGate(Material m) { - return fenceGates.contains(m); + return fenceGates.isTagged(m); } public static boolean isWoodenTrapdoor(Material m) { - return woodenTrapdoors.contains(m); + return woodenTrapdoors.isTagged(m); } public static boolean isPressurePlate(Material m) { - return pressurePlates.contains(m); + return pressurePlates.isTagged(m); } public static boolean isSign(Material m) { - return allSigns.contains(m); + return allSigns.isTagged(m); } public static Side getFacingSignSide(Entity entity, Block sign) { diff --git a/src/main/java/de/diddiz/LogBlock/util/LoggingUtil.java b/src/main/java/de/diddiz/LogBlock/util/LoggingUtil.java index 5235d944..8322f765 100644 --- a/src/main/java/de/diddiz/LogBlock/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/LogBlock/util/LoggingUtil.java @@ -65,7 +65,7 @@ public static void smartLogBlockPlace(Consumer consumer, Actor actor, BlockState if (y > loc.getWorld().getMinHeight()) { // Run this check to avoid false positives Location finalLoc = new Location(loc.getWorld(), x, y, z); - if (y == initialy || !BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) { + if (y == initialy || !BukkitUtils.isFallingEntityKiller(finalLoc.getBlock().getType())) { if (BukkitUtils.isEmpty(finalLoc.getBlock().getType())) { consumer.queueBlockPlace(actor, finalLoc, placed.getBlockData()); } else { @@ -103,7 +103,7 @@ public static void smartLogFallables(Consumer consumer, Actor actor, Block origi if (y > loc.getWorld().getMinHeight()) { Location finalLoc = new Location(loc.getWorld(), x, y, z); // Run this check to avoid false positives - if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) { + if (!BukkitUtils.isFallingEntityKiller(finalLoc.getBlock().getType())) { finalLoc.add(0, up, 0); // Add this here after checking for block breakers if (BukkitUtils.isEmpty(finalLoc.getBlock().getType())) { consumer.queueBlockPlace(actor, finalLoc, checkBlock.getBlockData()); @@ -155,7 +155,7 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or Block checkBlock = origin.getRelative(BlockFace.UP); Material typeAbove = checkBlock.getType(); - if (BukkitUtils.getRelativeTopBreakabls().contains(typeAbove)) { + if (BukkitUtils.isRelativeTopBreakable(typeAbove)) { if (typeAbove == Material.IRON_DOOR || BukkitUtils.isWoodenDoor(typeAbove)) { Block doorBlock = checkBlock; // If the doorBlock is the top half a door the player simply punched a door @@ -185,7 +185,7 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or // check next blocks above checkBlock = checkBlock.getRelative(BlockFace.UP); typeAbove = checkBlock.getType(); - while (BukkitUtils.getRelativeTopBreakabls().contains(typeAbove)) { + while (BukkitUtils.isRelativeTopBreakable(typeAbove)) { consumer.queueBlockBreak(actor, checkBlock.getState()); checkBlock = checkBlock.getRelative(BlockFace.UP); typeAbove = checkBlock.getType(); @@ -276,7 +276,7 @@ public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block or } List relativeBreakables = BukkitUtils.getBlocksNearby(origin, BukkitUtils.getRelativeBreakables()); - if (relativeBreakables.size() != 0) { + if (!relativeBreakables.isEmpty()) { for (Location location : relativeBreakables) { Block block = location.getBlock(); BlockData blockData = block.getBlockData(); From f972bae6ba57dbc01c170d870beb1b5aaaaf7800 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 17 Oct 2023 08:40:56 +0200 Subject: [PATCH 358/399] typo --- src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 56fd50f0..bea7e54c 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -139,7 +139,7 @@ public class BukkitUtils { Set carpets = Tag.WOOL_CARPETS.getValues(); // https://minecraft.fandom.com/wiki/Tag#blocks_flower_pots - Set flowserPots = Tag.FLOWER_POTS.getValues(); + Set flowerPots = Tag.FLOWER_POTS.getValues(); // https://minecraft.fandom.com/wiki/Tag#blocks_saplings Set saplings = Tag.SAPLINGS.getValues(); @@ -257,7 +257,7 @@ public class BukkitUtils { relativeTopBreakable.addAll(carpets); relativeTopBreakable.addAll(cropBlocks.getValues()); relativeTopBreakable.addAll(doublePlants); - relativeTopBreakable.addAll(flowserPots); + relativeTopBreakable.addAll(flowerPots); relativeTopBreakable.addAll(pressurePlates.getValues()); relativeTopBreakable.addAll(saplings); relativeTopBreakable.addAll(signs); From 499573fa661c7f384bb0cc1da304fbba326c5b2d Mon Sep 17 00:00:00 2001 From: aerulion Date: Tue, 17 Oct 2023 23:52:13 +0200 Subject: [PATCH 359/399] Fix duplicate set entry & add missing piglin head (#888) --- src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index bea7e54c..acfea096 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -186,8 +186,7 @@ public class BukkitUtils { Set bannerAll = Tag.BANNERS.getValues(); - Set headAndSkulls = Set.of(Material.SKELETON_WALL_SKULL, - Material.PLAYER_HEAD, + Set headAndSkulls = Set.of(Material.PLAYER_HEAD, Material.PLAYER_WALL_HEAD, Material.CREEPER_HEAD, Material.CREEPER_WALL_HEAD, @@ -198,7 +197,9 @@ public class BukkitUtils { Material.SKELETON_SKULL, Material.SKELETON_WALL_SKULL, Material.WITHER_SKELETON_SKULL, - Material.WITHER_SKELETON_WALL_SKULL); + Material.WITHER_SKELETON_WALL_SKULL, + Material.PIGLIN_HEAD, + Material.PIGLIN_WALL_HEAD); Set standingTorch = Set.of(Material.TORCH, Material.SOUL_TORCH, From 267108066563e70248cb86f2e98a8611b721ea5f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 18 Oct 2023 04:05:45 +0200 Subject: [PATCH 360/399] formating... --- .../de/diddiz/LogBlock/util/BukkitUtils.java | 146 +++++++++--------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index acfea096..86d6ed50 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -151,65 +151,65 @@ public class BukkitUtils { Set tallFlowers = Tag.TALL_FLOWERS.getValues(); Set bannerStanding = Set.of(Material.WHITE_BANNER, - Material.ORANGE_BANNER, - Material.MAGENTA_BANNER, - Material.LIGHT_BLUE_BANNER, - Material.YELLOW_BANNER, - Material.LIME_BANNER, - Material.PINK_BANNER, - Material.GRAY_BANNER, - Material.LIGHT_GRAY_BANNER, - Material.CYAN_BANNER, - Material.PURPLE_BANNER, - Material.BLUE_BANNER, - Material.BROWN_BANNER, - Material.GREEN_BANNER, - Material.RED_BANNER, - Material.BLACK_BANNER); + Material.ORANGE_BANNER, + Material.MAGENTA_BANNER, + Material.LIGHT_BLUE_BANNER, + Material.YELLOW_BANNER, + Material.LIME_BANNER, + Material.PINK_BANNER, + Material.GRAY_BANNER, + Material.LIGHT_GRAY_BANNER, + Material.CYAN_BANNER, + Material.PURPLE_BANNER, + Material.BLUE_BANNER, + Material.BROWN_BANNER, + Material.GREEN_BANNER, + Material.RED_BANNER, + Material.BLACK_BANNER); Set bannerWall = Set.of(Material.WHITE_WALL_BANNER, - Material.ORANGE_WALL_BANNER, - Material.MAGENTA_WALL_BANNER, - Material.LIGHT_BLUE_WALL_BANNER, - Material.YELLOW_WALL_BANNER, - Material.LIME_WALL_BANNER, - Material.PINK_WALL_BANNER, - Material.GRAY_WALL_BANNER, - Material.LIGHT_GRAY_WALL_BANNER, - Material.CYAN_WALL_BANNER, - Material.PURPLE_WALL_BANNER, - Material.BLUE_WALL_BANNER, - Material.BROWN_WALL_BANNER, - Material.GREEN_WALL_BANNER, - Material.RED_WALL_BANNER, - Material.BLACK_WALL_BANNER); + Material.ORANGE_WALL_BANNER, + Material.MAGENTA_WALL_BANNER, + Material.LIGHT_BLUE_WALL_BANNER, + Material.YELLOW_WALL_BANNER, + Material.LIME_WALL_BANNER, + Material.PINK_WALL_BANNER, + Material.GRAY_WALL_BANNER, + Material.LIGHT_GRAY_WALL_BANNER, + Material.CYAN_WALL_BANNER, + Material.PURPLE_WALL_BANNER, + Material.BLUE_WALL_BANNER, + Material.BROWN_WALL_BANNER, + Material.GREEN_WALL_BANNER, + Material.RED_WALL_BANNER, + Material.BLACK_WALL_BANNER); Set bannerAll = Tag.BANNERS.getValues(); Set headAndSkulls = Set.of(Material.PLAYER_HEAD, - Material.PLAYER_WALL_HEAD, - Material.CREEPER_HEAD, - Material.CREEPER_WALL_HEAD, - Material.DRAGON_HEAD, - Material.DRAGON_WALL_HEAD, - Material.ZOMBIE_HEAD, - Material.ZOMBIE_WALL_HEAD, - Material.SKELETON_SKULL, - Material.SKELETON_WALL_SKULL, - Material.WITHER_SKELETON_SKULL, - Material.WITHER_SKELETON_WALL_SKULL, - Material.PIGLIN_HEAD, - Material.PIGLIN_WALL_HEAD); + Material.PLAYER_WALL_HEAD, + Material.CREEPER_HEAD, + Material.CREEPER_WALL_HEAD, + Material.DRAGON_HEAD, + Material.DRAGON_WALL_HEAD, + Material.ZOMBIE_HEAD, + Material.ZOMBIE_WALL_HEAD, + Material.SKELETON_SKULL, + Material.SKELETON_WALL_SKULL, + Material.WITHER_SKELETON_SKULL, + Material.WITHER_SKELETON_WALL_SKULL, + Material.PIGLIN_HEAD, + Material.PIGLIN_WALL_HEAD); Set standingTorch = Set.of(Material.TORCH, - Material.SOUL_TORCH, - Material.REDSTONE_TORCH); + Material.SOUL_TORCH, + Material.REDSTONE_TORCH); Set wallTorch = Set.of(Material.WALL_TORCH, - Material.SOUL_WALL_TORCH, - Material.REDSTONE_WALL_TORCH); + Material.SOUL_WALL_TORCH, + Material.REDSTONE_WALL_TORCH); - singleBlockPlants = new HashSet(); + singleBlockPlants = new HashSet<>(); singleBlockPlants.addAll(smallFlowers); singleBlockPlants.add(Material.GRASS); singleBlockPlants.add(Material.FERN); @@ -227,7 +227,7 @@ public class BukkitUtils { singleBlockPlants.add(Material.PINK_PETALS); singleBlockPlants.add(Material.PITCHER_CROP); - doublePlants = new HashSet(); + doublePlants = new HashSet<>(); doublePlants.addAll(tallFlowers); doublePlants.add(Material.TALL_GRASS); doublePlants.add(Material.LARGE_FERN); @@ -235,7 +235,7 @@ public class BukkitUtils { doublePlants.add(Material.SMALL_DRIPLEAF); // Blocks that break when they are attached to a block - relativeBreakable = new HashSet(); + relativeBreakable = new HashSet<>(); relativeBreakable.addAll(bannerWall); relativeBreakable.addAll(buttons.getValues()); relativeBreakable.addAll(wallSigns); @@ -251,7 +251,7 @@ public class BukkitUtils { relativeBreakable.add(Material.LARGE_AMETHYST_BUD); // Blocks that break when they are on top of a block - relativeTopBreakable = new HashSet(); + relativeTopBreakable = new HashSet<>(); relativeTopBreakable.addAll(bannerStanding); relativeTopBreakable.addAll(candleCakes.getValues()); relativeTopBreakable.addAll(candles.getValues()); @@ -286,7 +286,7 @@ public class BukkitUtils { relativeTopBreakable.add(Material.BIG_DRIPLEAF_STEM); // Blocks that break falling entities - fallingEntityKillers = new HashSet(); + fallingEntityKillers = new HashSet<>(); fallingEntityKillers.addAll(bannerAll); fallingEntityKillers.addAll(candleCakes.getValues()); fallingEntityKillers.addAll(candles.getValues()); @@ -318,7 +318,7 @@ public class BukkitUtils { fallingEntityKillers.remove(Material.NETHER_SPROUTS); // Container Blocks - containerBlocks = new HashSet(); + containerBlocks = new HashSet<>(); containerBlocks.addAll(shulkerBoxBlocks.getValues()); containerBlocks.add(Material.CHEST); containerBlocks.add(Material.TRAPPED_CHEST); @@ -348,7 +348,7 @@ public class BukkitUtils { projectileItems.put(EntityType.WITHER_SKULL, Material.WITHER_SKELETON_SKULL); projectileItems.put(EntityType.FIREWORK, Material.FIREWORK_ROCKET); - nonFluidProofBlocks = new HashSet(); + nonFluidProofBlocks = new HashSet<>(); nonFluidProofBlocks.addAll(carpets); nonFluidProofBlocks.addAll(cropBlocks.getValues()); nonFluidProofBlocks.addAll(doublePlants); @@ -374,26 +374,26 @@ public class BukkitUtils { nonFluidProofBlocks.add(Material.DAYLIGHT_DETECTOR); alwaysWaterlogged = Set.of(Material.SEAGRASS, - Material.TALL_SEAGRASS, - Material.KELP, - Material.KELP_PLANT); + Material.TALL_SEAGRASS, + Material.KELP, + Material.KELP_PLANT); concreteBlocks = Set.of(Material.BLACK_CONCRETE, - Material.BLUE_CONCRETE, - Material.LIGHT_GRAY_CONCRETE, - Material.BROWN_CONCRETE, - Material.CYAN_CONCRETE, - Material.GRAY_CONCRETE, - Material.GREEN_CONCRETE, - Material.LIGHT_BLUE_CONCRETE, - Material.MAGENTA_CONCRETE, - Material.LIME_CONCRETE, - Material.ORANGE_CONCRETE, - Material.PINK_CONCRETE, - Material.PURPLE_CONCRETE, - Material.RED_CONCRETE, - Material.WHITE_CONCRETE, - Material.YELLOW_CONCRETE); + Material.BLUE_CONCRETE, + Material.LIGHT_GRAY_CONCRETE, + Material.BROWN_CONCRETE, + Material.CYAN_CONCRETE, + Material.GRAY_CONCRETE, + Material.GREEN_CONCRETE, + Material.LIGHT_BLUE_CONCRETE, + Material.MAGENTA_CONCRETE, + Material.LIME_CONCRETE, + Material.ORANGE_CONCRETE, + Material.PINK_CONCRETE, + Material.PURPLE_CONCRETE, + Material.RED_CONCRETE, + Material.WHITE_CONCRETE, + Material.YELLOW_CONCRETE); dyes = new HashMap<>(); dyes.put(Material.BLACK_DYE, DyeColor.BLACK); @@ -415,7 +415,7 @@ public class BukkitUtils { } private static final BlockFace[] relativeBlockFaces = new BlockFace[] { - BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN + BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN }; /** From e30e331cce373d38f9a638428074999e5bec764d Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 20 Oct 2023 06:48:05 +0200 Subject: [PATCH 361/399] allow mobspawners without spawned type --- .../blockstate/BlockStateCodecSpawner.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java index 8220b5d8..db6d42e5 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock.blockstate; +import de.diddiz.LogBlock.LogBlock; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Material; @@ -25,7 +26,9 @@ public YamlConfiguration serialize(BlockState state) { conf.set("minSpawnDelay", spawner.getMinSpawnDelay()); conf.set("requiredPlayerRange", spawner.getRequiredPlayerRange()); conf.set("spawnCount", spawner.getSpawnCount()); - conf.set("spawnedType", spawner.getSpawnedType().name()); + if (spawner.getSpawnedType() != null) { + conf.set("spawnedType", spawner.getSpawnedType().name()); + } conf.set("spawnRange", spawner.getSpawnRange()); return conf; } @@ -43,7 +46,16 @@ public void deserialize(BlockState state, YamlConfiguration conf) { spawner.setMinSpawnDelay(conf.getInt("minSpawnDelay")); spawner.setRequiredPlayerRange(conf.getInt("requiredPlayerRange")); spawner.setSpawnCount(conf.getInt("spawnCount")); - spawner.setSpawnedType(EntityType.valueOf(conf.getString("spawnedType"))); + EntityType spawnedType = null; + String spawnedTypeString = conf.getString("spawnedType"); + if (spawnedTypeString != null) { + try { + spawnedType = EntityType.valueOf(spawnedTypeString); + } catch (IllegalArgumentException ignored) { + LogBlock.getInstance().getLogger().warning("Could not find spawner spawned type: " + spawnedTypeString); + } + } + spawner.setSpawnedType(spawnedType); spawner.setSpawnRange(conf.getInt("spawnRange")); } } From 9c9f923536940e62d15a549aac337a30d19f08d5 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 13 Nov 2023 07:19:54 +0100 Subject: [PATCH 362/399] Log brushing suspicious sand/gravel --- .../LogBlock/listeners/BlockBreakLogging.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java index ffa6aca9..018cffa8 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java @@ -14,6 +14,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockDropItemEvent; import org.bukkit.event.player.PlayerBucketFillEvent; import static de.diddiz.LogBlock.config.Config.getWorldConfig; @@ -71,4 +72,17 @@ public void onPlayerBucketFill(PlayerBucketFillEvent event) { } } } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockDropItem(BlockDropItemEvent event) { + if (isLogging(event.getBlock().getWorld(), Logging.BLOCKBREAK)) { + Material type = event.getBlock().getType(); + if (type == Material.SUSPICIOUS_GRAVEL || type == Material.SUSPICIOUS_SAND) { + Material simplyBroken = type == Material.SUSPICIOUS_SAND ? Material.SAND : Material.GRAVEL; + if (event.getItems().size() != 1 || event.getItems().get(0).getItemStack().getType() != simplyBroken) { + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlockState(), simplyBroken.createBlockData()); + } + } + } + } } From 224bc1bae74b5544f9cf9f40c7a05c317d968fc4 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 9 Dec 2023 02:39:46 +0100 Subject: [PATCH 363/399] only log sign changes whan anything was changed --- .../diddiz/LogBlock/listeners/SignChangeLogging.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java index d74e753e..466883ac 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java @@ -3,6 +3,7 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; +import java.util.Objects; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.block.sign.SignSide; @@ -23,10 +24,16 @@ public void onSignChange(SignChangeEvent event) { BlockState newState = event.getBlock().getState(); if (newState instanceof Sign sign) { SignSide signSide = sign.getSide(event.getSide()); + boolean changed = false; for (int i = 0; i < 4; i++) { - signSide.setLine(i, event.getLine(i)); + if (!Objects.equals(signSide.getLine(i), event.getLine(i))) { + signSide.setLine(i, event.getLine(i)); + changed = true; + } + } + if (changed) { + consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getState(), newState); } - consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getState(), newState); } } } From e3dda845e2d246d5c28d445c6bdc250a777de9ae Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 9 Dec 2023 02:39:59 +0100 Subject: [PATCH 364/399] improve sign change log display --- .../blockstate/BlockStateCodecSign.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index e230dae6..7295709d 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -143,11 +143,8 @@ public BaseComponent getChangesAsComponent(YamlConfiguration state, YamlConfigur tc.addExtra(isWaxed ? "(waxed)" : "(not waxed)"); } for (Side side : Side.values()) { + boolean sideHeaderAdded = false; ConfigurationSection sideSection = side == Side.FRONT ? state : state.getConfigurationSection(side.name().toLowerCase()); - if (tc.getExtra() != null && !tc.getExtra().isEmpty()) { - tc.addExtra(" "); - } - tc.addExtra(side.name() + ":"); List lines = sideSection == null ? Collections.emptyList() : sideSection.getStringList("lines"); List oldLines = Collections.emptyList(); @@ -178,6 +175,7 @@ public BaseComponent getChangesAsComponent(YamlConfiguration state, YamlConfigur } if (!lines.equals(oldLines)) { + sideHeaderAdded = addSideHeaderText(tc, side, sideHeaderAdded); for (String line : lines) { if (tc.getExtra() != null && !tc.getExtra().isEmpty()) { tc.addExtra(" "); @@ -190,6 +188,7 @@ public BaseComponent getChangesAsComponent(YamlConfiguration state, YamlConfigur } } if (signColor != oldSignColor) { + sideHeaderAdded = addSideHeaderText(tc, side, sideHeaderAdded); if (tc.getExtra() != null && !tc.getExtra().isEmpty()) { tc.addExtra(" "); } @@ -200,6 +199,7 @@ public BaseComponent getChangesAsComponent(YamlConfiguration state, YamlConfigur tc.addExtra(")"); } if (glowing != oldGlowing) { + sideHeaderAdded = addSideHeaderText(tc, side, sideHeaderAdded); if (tc.getExtra() != null && !tc.getExtra().isEmpty()) { tc.addExtra(" "); } @@ -214,4 +214,14 @@ public BaseComponent getChangesAsComponent(YamlConfiguration state, YamlConfigur } return null; } + + private static boolean addSideHeaderText(TextComponent tc, Side side, boolean wasAdded) { + if (!wasAdded) { + if (tc.getExtra() != null && !tc.getExtra().isEmpty()) { + tc.addExtra(" "); + } + tc.addExtra(side.name() + ":"); + } + return true; + } } From da2264481c16ce0b419816f7a2b1e96b8289a9a6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 13 Dec 2023 09:33:08 +0100 Subject: [PATCH 365/399] Update for 1.20.4 (requires 1.20.4 to run) --- pom.xml | 2 +- src/main/java/de/diddiz/LogBlock/Updater.java | 5 +++++ .../de/diddiz/LogBlock/listeners/BlockSpreadLogging.java | 2 +- src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java | 4 ++-- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index a402c556..89ef2bad 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ org.spigotmc spigot-api - 1.20.1-R0.1-SNAPSHOT + 1.20.4-R0.1-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 34653c0f..b1a83f86 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -950,6 +950,11 @@ private void updateMaterialsPost1_13() { renameMaterial("minecraft:grass_path", Material.DIRT_PATH); } + if (comparablePreviousMinecraftVersion.compareTo("1.20.4") < 0 && comparableCurrentMinecraftVersion.compareTo("1.20.4") >= 0) { + logblock.getLogger().info("[Updater] Upgrading Materials to 1.20.4"); + renameMaterial("minecraft:grass", Material.SHORT_GRASS); + } + config.set("previousMinecraftVersion", currentMinecraftVersion); logblock.saveConfig(); } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java index ebcafa60..c2a12552 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java @@ -29,7 +29,7 @@ public void onBlockSpread(BlockSpreadEvent event) { World world = event.getNewState().getWorld(); Material type = event.getNewState().getType(); - if (type == Material.GRASS) { + if (type == Material.SHORT_GRASS) { if (!isLogging(world, Logging.GRASSGROWTH)) { return; } diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 86d6ed50..c44e0215 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -211,7 +211,7 @@ public class BukkitUtils { singleBlockPlants = new HashSet<>(); singleBlockPlants.addAll(smallFlowers); - singleBlockPlants.add(Material.GRASS); + singleBlockPlants.add(Material.SHORT_GRASS); singleBlockPlants.add(Material.FERN); singleBlockPlants.add(Material.DEAD_BUSH); singleBlockPlants.add(Material.BROWN_MUSHROOM); @@ -314,7 +314,7 @@ public class BukkitUtils { fallingEntityKillers.add(Material.REPEATER); fallingEntityKillers.add(Material.COMPARATOR); fallingEntityKillers.add(Material.DAYLIGHT_DETECTOR); - fallingEntityKillers.remove(Material.GRASS); + fallingEntityKillers.remove(Material.SHORT_GRASS); fallingEntityKillers.remove(Material.NETHER_SPROUTS); // Container Blocks From 7adf7a1cb4ff4ac3a96593c66bdf8c68b6e7141a Mon Sep 17 00:00:00 2001 From: Dieu Date: Wed, 7 Feb 2024 11:38:13 +0100 Subject: [PATCH 366/399] Fix NPE: [LogBlock] Could not parse BlockState for PLAYER_HEAD java.lang.NullPointerException: Cannot invoke "java.util.UUID.toString()" because the return value of "org.bukkit.profile.PlayerProfile.getUniqueId()" is null at de.diddiz.LogBlock.blockstate.BlockStateCodecSkull.getChangesAsComponent(BlockStateCodecSkull.java:77) ~[LogBlock.jar:?] at de.diddiz.LogBlock.blockstate.BlockStateCodecs.getChangesAsComponent(BlockStateCodecs.java:57) ~[LogBlock.jar:?] at de.diddiz.LogBlock.BlockChange.getTypeDetails(BlockChange.java:95) ~[LogBlock.jar:?] at de.diddiz.LogBlock.BlockChange.getTypeDetails(BlockChange.java:87) ~[LogBlock.jar:?] at de.diddiz.LogBlock.BlockChange.getLogMessage(BlockChange.java:135) ~[LogBlock.jar:?] at de.diddiz.LogBlock.CommandsHandler.showPage(CommandsHandler.java:446) ~[LogBlock.jar:?] at de.diddiz.LogBlock.CommandsHandler.showPage(CommandsHandler.java:428) ~[LogBlock.jar:?] at de.diddiz.LogBlock.CommandsHandler$CommandLookup.run(CommandsHandler.java:578) ~[LogBlock.jar:?] at org.bukkit.craftbukkit.v1_20_R3.scheduler.CraftTask.run(CraftTask.java:101) ~[paper-1.20.4.jar:git-Paper-"9e171ef"] at org.bukkit.craftbukkit.v1_20_R3.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:57) ~[paper-1.20.4.jar:git-Paper-"9e171ef"] at com.destroystokyo.paper.ServerSchedulerReportingWrapper.run(ServerSchedulerReportingWrapper.java:22) ~[paper-1.20.4.jar:?] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[?:?] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?] at java.lang.Thread.run(Thread.java:840) ~[?:?] --- .../de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java index 0f21426d..310a72e6 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java @@ -73,7 +73,7 @@ public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfigura PlayerProfile profile = (PlayerProfile) conf.get("profile"); if (profile != null) { TextComponent tc = new TextComponent("[" + (profile.getName() != null ? profile.getName() : (profile.getUniqueId() != null ? profile.getUniqueId().toString() : "~unknown~")) + "]"); - if (profile.getName() != null) { + if (profile.getName() != null && profile.getUniqueId() != null) { tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("UUID: " + profile.getUniqueId().toString()))); } return tc; From 626ba83b185201531e2b94c31f4443599613fb3f Mon Sep 17 00:00:00 2001 From: Dieu Date: Wed, 7 Feb 2024 11:44:31 +0100 Subject: [PATCH 367/399] Update dependencies --- pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 89ef2bad..d9ca6306 100644 --- a/pom.xml +++ b/pom.xml @@ -62,13 +62,13 @@ junit junit - 4.11 + 4.13.2 test com.zaxxer HikariCP - 5.0.1 + 5.1.0 compile @@ -125,7 +125,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.10.1 + 3.12.1 17 @@ -133,7 +133,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.3.0 + 3.5.0 regex-property @@ -153,7 +153,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.3.0 + 3.5.1 From 43c9fd01a8dea18a460945589b9d115da1b1fd7e Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 10 Mar 2024 06:16:25 +0100 Subject: [PATCH 368/399] Compile against WorldEdit 7.3.0; fix compile --- pom.xml | 2 +- src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d9ca6306..460b3840 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ com.sk89q.worldedit worldedit-bukkit - 7.2.9-SNAPSHOT + 7.3.0 provided diff --git a/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java b/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java index f59aa8a1..3dacc1ee 100644 --- a/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java +++ b/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java @@ -139,7 +139,7 @@ public static byte[] serializeEntity(Entity entity) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); NBTOutputStream nbtos = new NBTOutputStream(baos); CompoundTag nbt = state.getNbtData(); - LinkedHashMap value = new LinkedHashMap<>(nbt.getValue()); + LinkedHashMap> 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)); From d2ec428381c6011858f502591b04f8cc8e31fc1f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 10 May 2024 01:48:50 +0200 Subject: [PATCH 369/399] 1.20.6 --- pom.xml | 8 ++++---- .../java/de/diddiz/LogBlock/config/EntityLogging.java | 4 ++-- src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index 460b3840..7bf8ef9a 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ org.spigotmc spigot-api - 1.20.4-R0.1-SNAPSHOT + 1.20.6-R0.1-SNAPSHOT provided @@ -125,9 +125,9 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.13.0 - 17 + 21 @@ -153,7 +153,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.5.1 + 3.5.3 diff --git a/src/main/java/de/diddiz/LogBlock/config/EntityLogging.java b/src/main/java/de/diddiz/LogBlock/config/EntityLogging.java index 6332250a..f2569a4c 100644 --- a/src/main/java/de/diddiz/LogBlock/config/EntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/config/EntityLogging.java @@ -7,8 +7,8 @@ import org.bukkit.entity.EntityType; public enum EntityLogging { - 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" }), + 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" }), MODIFY(new String[] { "ALL" }); public static final int length = EntityLogging.values().length; diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index c44e0215..fe59df3a 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -341,12 +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_HOOK, Material.FISHING_ROD); + projectileItems.put(EntityType.FISHING_BOBBER, Material.FISHING_ROD); projectileItems.put(EntityType.SNOWBALL, Material.SNOWBALL); - projectileItems.put(EntityType.SPLASH_POTION, Material.SPLASH_POTION); - projectileItems.put(EntityType.THROWN_EXP_BOTTLE, Material.EXPERIENCE_BOTTLE); + projectileItems.put(EntityType.POTION, Material.SPLASH_POTION); + projectileItems.put(EntityType.EXPERIENCE_BOTTLE, Material.EXPERIENCE_BOTTLE); projectileItems.put(EntityType.WITHER_SKULL, Material.WITHER_SKELETON_SKULL); - projectileItems.put(EntityType.FIREWORK, Material.FIREWORK_ROCKET); + projectileItems.put(EntityType.FIREWORK_ROCKET, Material.FIREWORK_ROCKET); nonFluidProofBlocks = new HashSet<>(); nonFluidProofBlocks.addAll(carpets); From 82e6d5bf3894b6c1e13459feef26ea36e554cd2f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 14 May 2024 03:28:10 +0200 Subject: [PATCH 370/399] better entity damage cause detection (uses new api) --- .../LogBlock/listeners/AdvancedEntityLogging.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index 6f71f938..84fffc14 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -192,18 +192,16 @@ public void onEntityDeath(EntityDeathEvent event) { LivingEntity entity = event.getEntity(); if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) { Actor actor = null; - EntityDamageEvent lastDamage = entity.getLastDamageCause(); - if (lastDamage instanceof EntityDamageByEntityEvent) { - Entity damager = LoggingUtil.getRealDamager(((EntityDamageByEntityEvent) lastDamage).getDamager()); - if (damager != null) { - actor = Actor.actorFromEntity(damager); - } + Entity cause = event.getDamageSource().getCausingEntity(); + Entity damager = LoggingUtil.getRealDamager(cause); + if (damager != null) { + actor = Actor.actorFromEntity(damager); } if (actor == null && entity.getKiller() != null) { actor = Actor.actorFromEntity(entity.getKiller()); } if (actor == null) { - actor = new Actor(lastDamage == null ? "UNKNOWN" : lastDamage.getCause().toString()); + actor = new Actor(event.getDamageSource().getDamageType().toString()); } queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); } From 20e70f91cdd26e7f56a78715ecf0387a0d335490 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 14 May 2024 03:39:54 +0200 Subject: [PATCH 371/399] improve kill logging --- .../diddiz/LogBlock/listeners/KillLogging.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java index ac6d3dd0..914c4eeb 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java @@ -10,8 +10,6 @@ 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.*; @@ -24,27 +22,23 @@ public KillLogging(LogBlock lb) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityDeath(EntityDeathEvent deathEvent) { - 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 (isLogging(deathEvent.getEntity().getWorld(), Logging.KILL)) { + LivingEntity victim = deathEvent.getEntity(); + Entity killer = deathEvent.getDamageSource().getCausingEntity(); + if (killer != null) { 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; } - consumer.queueKill(new Actor(event.getCause().toString()), victim); + consumer.queueKill(new Actor(deathEvent.getDamageSource().getDamageType().toString()), victim); } } } From 5f56f1677fda4f1b3a4be2112d17face36b32fa4 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 31 May 2024 07:32:26 +0200 Subject: [PATCH 372/399] no item tag logging at the moment (the method is no longer working) --- .../de/diddiz/LogBlock/util/BukkitUtils.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index fe59df3a..bac96688 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -4,7 +4,6 @@ import de.diddiz.LogBlock.LogBlock; import java.io.File; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -675,17 +674,18 @@ public static TextComponent toString(ItemStack stack) { } 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; + return null; // FIXME + // 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) { From 1965d5f985034177c81a0118ea547bf89aa9c8ed Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 31 May 2024 07:33:15 +0200 Subject: [PATCH 373/399] new logging options: GRASS_EAT and MISCENTITYCHANGEBLOCK --- .../java/de/diddiz/LogBlock/LogBlock.java | 7 +--- src/main/java/de/diddiz/LogBlock/Logging.java | 2 + .../LogBlock/listeners/EndermenLogging.java | 24 ----------- .../listeners/EntityChangeBlockLogging.java | 41 +++++++++++++++++++ .../LogBlock/listeners/WitherLogging.java | 24 ----------- 5 files changed, 45 insertions(+), 53 deletions(-) delete mode 100644 src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java create mode 100644 src/main/java/de/diddiz/LogBlock/listeners/EntityChangeBlockLogging.java delete mode 100644 src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 212129fc..504ad8c4 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -205,11 +205,8 @@ private void registerEvents() { 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.ENDERMEN)) { - pm.registerEvents(new EndermenLogging(this), this); - } - if (isLogging(Logging.WITHER)) { - pm.registerEvents(new WitherLogging(this), this); + if (isLogging(Logging.WITHER) || isLogging(Logging.ENDERMEN)) { + pm.registerEvents(new EntityChangeBlockLogging(this), this); } if (isLogging(Logging.NATURALSTRUCTUREGROW)) { pm.registerEvents(new StructureGrowLogging(this), this); diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index 2e8e0331..5be67a48 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -39,6 +39,8 @@ public enum Logging { BAMBOOGROWTH, WITHER(true), WITHER_SKULL(true), + GRASS_EAT, + MISCENTITYCHANGEBLOCK(true), BONEMEALSTRUCTUREGROW, WORLDEDIT, TNTMINECARTEXPLOSION(true), diff --git a/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java deleted file mode 100644 index b7fe92a3..00000000 --- a/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java +++ /dev/null @@ -1,24 +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.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; - } - } -} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/EntityChangeBlockLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/EntityChangeBlockLogging.java new file mode 100644 index 00000000..5e503b9b --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/listeners/EntityChangeBlockLogging.java @@ -0,0 +1,41 @@ +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.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) { + 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()); + } + } + } +} diff --git a/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java deleted file mode 100644 index 04c452ce..00000000 --- a/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java +++ /dev/null @@ -1,24 +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.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. - } - } -} From aa206f0c7be861d989a1899b758848be115e6f66 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 1 Jun 2024 08:43:15 +0200 Subject: [PATCH 374/399] use api, still won't work --- .../de/diddiz/LogBlock/util/BukkitUtils.java | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index bac96688..b6cc81a9 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -663,7 +663,7 @@ public static TextComponent toString(ItemStack stack) { msg.addExtra(prettyMaterial(stack.getType())); try { - String itemTag = getItemTag(stack); + String itemTag = stack.getItemMeta().getAsString(); 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); @@ -673,21 +673,6 @@ public static TextComponent toString(ItemStack stack) { return msg; } - public static String getItemTag(ItemStack itemStack) throws ReflectiveOperationException { - return null; // FIXME - // 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; From 659095a214b7c65d08e11aaeda1b6198411a7f0a Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 3 Jun 2024 03:30:32 +0200 Subject: [PATCH 375/399] wind charges do not break blocks --- .../java/de/diddiz/LogBlock/listeners/ExplosionLogging.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index cd97d04d..a9fdb968 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -49,6 +49,8 @@ public void onEntityExplode(EntityExplodeEvent event) { if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { return; } + } else if (source instanceof WindCharge) { + return; } else if (source instanceof TNTPrimed) { if (!wcfg.isLogging(Logging.TNTEXPLOSION)) { return; From 00bcb6ba990d160b2eef24b0b033b05616513fa4 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 3 Jun 2024 03:36:13 +0200 Subject: [PATCH 376/399] replace deprecated api usage --- .../java/de/diddiz/LogBlock/BlockChange.java | 6 +- .../java/de/diddiz/LogBlock/ChatMessage.java | 8 +-- .../de/diddiz/LogBlock/CommandsHandler.java | 4 +- .../java/de/diddiz/LogBlock/EntityChange.java | 4 +- src/main/java/de/diddiz/LogBlock/Kill.java | 4 +- .../diddiz/LogBlock/LookupCacheElement.java | 4 +- .../diddiz/LogBlock/SummedBlockChanges.java | 2 +- .../diddiz/LogBlock/SummedEntityChanges.java | 2 +- .../java/de/diddiz/LogBlock/SummedKills.java | 2 +- .../java/de/diddiz/LogBlock/WorldEditor.java | 4 +- .../blockstate/BlockStateCodecSign.java | 2 +- .../diddiz/LogBlock/util/MessagingUtil.java | 8 ++- .../de/diddiz/LogBlock/util/UUIDFetcher.java | 3 +- .../LogBlock/worldedit/WorldEditHelper.java | 60 +++++++++---------- 14 files changed, 57 insertions(+), 56 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 6b769b24..11c99890 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -113,7 +113,7 @@ public String toString() { } @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 BaseComponent[] getLogMessage(int entry) { BlockData replaced = getBlockReplaced(); if (type == null || replaced == null) { msg.addExtra("did an unknown block modification"); - return new BaseComponent[] { msg }; + return msg; } // Process type details once for later use. @@ -254,7 +254,7 @@ public BaseComponent[] getLogMessage(int entry) { msg.addExtra(" at "); msg.addExtra(prettyLocation(loc, entry)); } - return new BaseComponent[] { msg }; + return msg; } public BlockData getBlockReplaced() { diff --git a/src/main/java/de/diddiz/LogBlock/ChatMessage.java b/src/main/java/de/diddiz/LogBlock/ChatMessage.java index 43d93586..e7ccc1c7 100644 --- a/src/main/java/de/diddiz/LogBlock/ChatMessage.java +++ b/src/main/java/de/diddiz/LogBlock/ChatMessage.java @@ -39,7 +39,7 @@ public Location getLocation() { } @Override - public BaseComponent[] getLogMessage(int entry) { + public BaseComponent getLogMessage(int entry) { TextComponent msg = new TextComponent(); if (date > 0) { msg.addExtra(prettyDate(date)); @@ -50,10 +50,8 @@ public BaseComponent[] getLogMessage(int entry) { msg.addExtra(" "); } if (message != null) { - for (BaseComponent messageComponent : TextComponent.fromLegacyText(message)) { - msg.addExtra(messageComponent); - } + msg.addExtra(TextComponent.fromLegacy(message)); } - return new BaseComponent[] { msg }; + return msg; } } diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 26ae2693..2a57c5ae 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -443,9 +443,7 @@ private static void showPage(CommandSender sender, int page, LookupCacheElement[ if (lookupElements[i].getLocation() != null) { message.addExtra(new TextComponent("(" + (i + 1) + ") ")); } - for (BaseComponent component : lookupElements[i].getLogMessage(i + 1)) { - message.addExtra(component); - } + message.addExtra(lookupElements[i].getLogMessage(i + 1)); sender.spigot().sendMessage(message); } if (setSessionPage) { diff --git a/src/main/java/de/diddiz/LogBlock/EntityChange.java b/src/main/java/de/diddiz/LogBlock/EntityChange.java index a252e79d..385b9ba2 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityChange.java +++ b/src/main/java/de/diddiz/LogBlock/EntityChange.java @@ -77,7 +77,7 @@ public String toString() { } @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 BaseComponent[] getLogMessage(int entry) { msg.addExtra(" at "); msg.addExtra(prettyLocation(loc, entry)); } - return new BaseComponent[] { msg }; + return msg; } @Override diff --git a/src/main/java/de/diddiz/LogBlock/Kill.java b/src/main/java/de/diddiz/LogBlock/Kill.java index ac9634e4..ff6287eb 100755 --- a/src/main/java/de/diddiz/LogBlock/Kill.java +++ b/src/main/java/de/diddiz/LogBlock/Kill.java @@ -49,7 +49,7 @@ public Location getLocation() { } @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 BaseComponent[] getLogMessage(int entry) { msg.addExtra(" with "); msg.addExtra(prettyItemName(MaterialConverter.getMaterial(weapon))); } - return new BaseComponent[] { msg }; + return msg; } public TextComponent prettyItemName(Material t) { diff --git a/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java b/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java index ba3c55c4..88fc1c25 100644 --- a/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java +++ b/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java @@ -6,11 +6,11 @@ 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; diff --git a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java index 871666d5..08dfe8dc 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java @@ -32,7 +32,7 @@ public Location getLocation() { } @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); } diff --git a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java index d9a1499f..015978ca 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java @@ -33,7 +33,7 @@ public Location getLocation() { } @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); } diff --git a/src/main/java/de/diddiz/LogBlock/SummedKills.java b/src/main/java/de/diddiz/LogBlock/SummedKills.java index a185e9d2..2e366e04 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedKills.java +++ b/src/main/java/de/diddiz/LogBlock/SummedKills.java @@ -25,7 +25,7 @@ public Location getLocation() { } @Override - public BaseComponent[] getLogMessage(int entry) { + public BaseComponent getLogMessage(int entry) { return MessagingUtil.formatSummarizedChanges(kills, killed, new TextComponent(player.getName()), 6, 7, spaceFactor); } diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index c77eeaf1..702a7182 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -486,8 +486,8 @@ public Location getLocation() { } @Override - public BaseComponent[] getLogMessage(int entry) { - return TextComponent.fromLegacyText(getMessage()); + public BaseComponent getLogMessage(int entry) { + return TextComponent.fromLegacy(getMessage()); } } } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index 7295709d..442ffcb5 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -182,7 +182,7 @@ public BaseComponent getChangesAsComponent(YamlConfiguration state, YamlConfigur } tc.addExtra("["); if (line != null && !line.isEmpty()) { - tc.addExtra(new TextComponent(TextComponent.fromLegacyText(line))); + tc.addExtra(TextComponent.fromLegacy(line)); } tc.addExtra("]"); } diff --git a/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java b/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java index 343f2542..cbef43bb 100644 --- a/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java +++ b/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java @@ -18,10 +18,14 @@ 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()); - return new BaseComponent[] { textCreated, textDestroyed, actor }; + TextComponent result = new TextComponent(); + result.addExtra(textCreated); + result.addExtra(textDestroyed); + result.addExtra(actor); + return result; } public static TextComponent createTextComponentWithColor(String text, ChatColor color) { diff --git a/src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java b/src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java index baeaac69..6decf6c3 100644 --- a/src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java +++ b/src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java @@ -8,6 +8,7 @@ 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; @@ -45,7 +46,7 @@ private static void writeBody(HttpURLConnection connection, String body) throws } private static HttpURLConnection createConnection() throws Exception { - URL url = new URL(PROFILE_URL); + URL url = new URI(PROFILE_URL).toURL(); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/json"); diff --git a/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java b/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java index 3dacc1ee..a8e46a2a 100644 --- a/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java +++ b/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java @@ -2,10 +2,10 @@ 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,13 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.util.BlockVector; -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 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.LinListTag; +import org.enginehub.linbus.tree.LinRootEntry; +import org.enginehub.linbus.tree.LinTagType; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -33,6 +31,7 @@ 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; @@ -107,21 +106,20 @@ public static Entity restoreEntity(Location location, EntityType type, byte[] se com.sk89q.worldedit.world.entity.EntityType weType = BukkitAdapter.adapt(type); com.sk89q.worldedit.util.Location weLocation = BukkitAdapter.adapt(location); try { - NBTInputStream nbtis = new NBTInputStream(new ByteArrayInputStream(serialized)); - NamedTag namedTag = nbtis.readNamedTag(); - nbtis.close(); + LinStream stream = LinBinaryIO.read(new DataInputStream(new ByteArrayInputStream(serialized))); + LinRootEntry namedTag = LinRootEntry.readFrom(stream); UUID newUUID = null; - if (namedTag.getName().equals("entity") && namedTag.getTag() instanceof CompoundTag) { - CompoundTag serializedState = (CompoundTag) namedTag.getTag(); - BaseEntity state = new BaseEntity(weType, serializedState); + if (namedTag.name().equals("entity")) { + LinCompoundTag serializedState = namedTag.value(); + BaseEntity state = new BaseEntity(weType, LazyReference.computed(serializedState)); com.sk89q.worldedit.entity.Entity weEntity = weLocation.getExtent().createEntity(weLocation, state); if (weEntity != null) { - CompoundTag newNbt = weEntity.getState().getNbtData(); - int[] uuidInts = newNbt.getIntArray("UUID"); + LinCompoundTag newNbt = weEntity.getState().getNbt(); + int[] uuidInts = newNbt.findTag("UUID", LinTagType.intArrayTag()).value(); if (uuidInts != null && uuidInts.length >= 4) { newUUID = new UUID(((long) uuidInts[0] << 32) | (uuidInts[1] & 0xFFFFFFFFL), ((long) uuidInts[2] << 32) | (uuidInts[3] & 0xFFFFFFFFL)); } else { - newUUID = new UUID(newNbt.getLong("UUIDMost"), newNbt.getLong("UUIDLeast")); // pre 1.16 + newUUID = new UUID(newNbt.findTag("UUIDMost", LinTagType.longTag()).valueAsLong(), newNbt.findTag("UUIDLeast", LinTagType.longTag()).valueAsLong()); // pre 1.16 } } } @@ -136,16 +134,18 @@ public static byte[] serializeEntity(Entity entity) { 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(); - NBTOutputStream nbtos = new NBTOutputStream(baos); - CompoundTag nbt = state.getNbtData(); - LinkedHashMap> 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(); + try (DataOutputStream dos = new DataOutputStream(baos)) { + LinBinaryIO.write(dos, root); + } return baos.toByteArray(); } catch (IOException e) { throw new RuntimeException("This IOException should be impossible", e); @@ -175,7 +175,7 @@ public static CuboidRegion getSelectedRegion(Player player) throws IllegalArgume } BlockVector3 min = selection.getMinimumPoint(); BlockVector3 max = selection.getMaximumPoint(); - return new CuboidRegion(world, new BlockVector(min.getBlockX(), min.getBlockY(), min.getBlockZ()), new BlockVector(max.getBlockX(), max.getBlockY(), max.getBlockZ())); + return new CuboidRegion(world, new BlockVector(min.x(), min.y(), min.z()), new BlockVector(max.x(), max.y(), max.z())); } } } From dd70021979cafb406b731445ccda372ec1a153d3 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 25 Jul 2024 06:13:40 +0200 Subject: [PATCH 377/399] Minecraft 1.21 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7bf8ef9a..c7a398a4 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ org.spigotmc spigot-api - 1.20.6-R0.1-SNAPSHOT + 1.21-R0.1-SNAPSHOT provided From d9a4d31509a197a30b71b4a97f47098b2f16ddd0 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 10 Aug 2024 05:15:49 +0200 Subject: [PATCH 378/399] ignore stepping on redstone ore --- .../diddiz/LogBlock/listeners/EntityChangeBlockLogging.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/EntityChangeBlockLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/EntityChangeBlockLogging.java index 5e503b9b..e546c934 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/EntityChangeBlockLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/EntityChangeBlockLogging.java @@ -3,6 +3,7 @@ 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; @@ -20,6 +21,10 @@ public EntityChangeBlockLogging(LogBlock 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()); From 10b5bc8913c21d479a7847f37810e38a492d5130 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Mon, 19 Aug 2024 05:58:47 +0200 Subject: [PATCH 379/399] do not log explosions that do not remove blocks --- .../de/diddiz/LogBlock/listeners/ExplosionLogging.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index a9fdb968..0caedf97 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -7,6 +7,7 @@ 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; @@ -41,6 +42,9 @@ public ExplosionLogging(LogBlock lb) { @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"); @@ -49,8 +53,6 @@ public void onEntityExplode(EntityExplodeEvent event) { if (!wcfg.isLogging(Logging.MISCEXPLOSION)) { return; } - } else if (source instanceof WindCharge) { - return; } else if (source instanceof TNTPrimed) { if (!wcfg.isLogging(Logging.TNTEXPLOSION)) { return; @@ -176,6 +178,9 @@ public void run() { @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(); From 0d04823ae1226e9cb668b801413c48f5b54028e5 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 19 Sep 2024 23:04:07 +0200 Subject: [PATCH 380/399] improve rollbacks - allow rollbacking up to 10k row/tick if the max editing time is not exceeded - better show percentages of long rollbacks --- .../java/de/diddiz/LogBlock/WorldEditor.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 702a7182..e36bb86c 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -35,6 +35,7 @@ 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; @@ -53,6 +54,8 @@ public class WorldEditor implements Runnable { private final LogBlock logblock; private final ArrayList edits = new ArrayList<>(); + private int rowsCompleted; + private int totalRows; private final World world; /** @@ -135,6 +138,7 @@ synchronized public void start() throws Exception { } 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"); @@ -151,8 +155,9 @@ synchronized public void start() throws Exception { public synchronized void run() { final List errorList = new ArrayList<>(); int counter = 0; - float size = edits.size(); - while (!edits.isEmpty() && counter < 100) { + 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)) { try { switch (edits.remove(edits.size() - 1).perform()) { case SUCCESS: @@ -169,11 +174,12 @@ public synchronized void run() { } catch (final Exception ex) { logblock.getLogger().log(Level.WARNING, "[WorldEditor] Exeption: ", ex); } + rowsCompleted++; counter++; if (sender != null) { - float percentage = ((size - edits.size()) / size) * 100.0F; - if (percentage % 20 == 0) { - sender.sendMessage(ChatColor.GOLD + "[LogBlock]" + ChatColor.YELLOW + " Rollback progress: " + percentage + "%" + + float percentage = rowsCompleted * 100.0f / totalRows; + if (rowsCompleted % 10000 == 0) { + sender.sendMessage(ChatColor.GOLD + "[LogBlock]" + ChatColor.YELLOW + " Rollback progress: " + NumberFormat.getNumberInstance().format(percentage) + "%" + " Blocks edited: " + counter); } } From 73c221e8d0b3dd5c73bc46a6fdd6605b934f6eb8 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Thu, 19 Sep 2024 23:04:30 +0200 Subject: [PATCH 381/399] use modern api for banner codec --- .../blockstate/BlockStateCodecBanner.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java index e62652c6..890c34d1 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java @@ -1,9 +1,12 @@ 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; @@ -30,10 +33,13 @@ public YamlConfiguration serialize(BlockState state) { YamlConfiguration conf = new YamlConfiguration(); ConfigurationSection patternsSection = conf.createSection("patterns"); for (Pattern pattern : patterns) { - ConfigurationSection section = patternsSection.createSection(Integer.toString(nr)); - section.set("color", pattern.getColor().name()); - section.set("pattern", pattern.getPattern().name()); - nr++; + 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++; + } } return conf; } @@ -55,8 +61,13 @@ public void deserialize(BlockState state, YamlConfiguration conf) { ConfigurationSection section = patternsSection.getConfigurationSection(key); if (section != null) { DyeColor color = DyeColor.valueOf(section.getString("color")); - PatternType type = PatternType.valueOf(section.getString("pattern")); - banner.addPattern(new Pattern(color, type)); + 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)); + } + } } } } From d1ecbe0efcb6d3edcdd6898e3ef48e600803b89d Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 21 Sep 2024 07:35:28 +0200 Subject: [PATCH 382/399] log decorated pot and chiseled bookshelf inventory changes --- .../java/de/diddiz/LogBlock/WorldEditor.java | 3 +- .../listeners/ChestAccessLogging.java | 64 +++++++++++++++++++ .../de/diddiz/LogBlock/util/BukkitUtils.java | 5 +- 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index e36bb86c..bac7c33b 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -24,6 +24,7 @@ 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; @@ -374,7 +375,7 @@ public PerformResult perform() throws WorldEditorException { BlockState state = block.getState(); if (setBlock.equals(replacedBlock)) { if (ca != null) { - if (state instanceof Container && state.getType() == replacedBlock.getMaterial()) { + if (state instanceof InventoryHolder && state.getType() == replacedBlock.getMaterial()) { int leftover; try { leftover = modifyContainer(state, new ItemStack(ca.itemStack), !ca.remove); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index 319b66ba..bb12a1fa 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -5,19 +5,28 @@ import de.diddiz.LogBlock.Logging; 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; @@ -300,4 +309,59 @@ public void onInventoryDrag(InventoryDragEvent event) { } } } + + @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(), 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(); + 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(), 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(), stack, false); + } + } + } + } + } } diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index b6cc81a9..f13a07ff 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -330,6 +330,7 @@ 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); @@ -602,8 +603,8 @@ public static int safeSpawnHeight(Location loc) { } public static int modifyContainer(BlockState b, ItemStack item, boolean remove) { - if (b instanceof InventoryHolder) { - final Inventory inv = ((InventoryHolder) b).getInventory(); + if (b instanceof InventoryHolder c) { + final Inventory inv = c.getInventory(); if (remove) { final ItemStack tmp = inv.removeItem(item).get(0); return tmp != null ? tmp.getAmount() : 0; From dc9774b7c69639b4f3c76ac51ddcb0ba22a1f42f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 21 Sep 2024 07:41:32 +0200 Subject: [PATCH 383/399] fix lectern logging --- .../LogBlock/listeners/LecternLogging.java | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java index 16e7627b..df26b2b7 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/LecternLogging.java @@ -1,18 +1,24 @@ 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.block.BlockState; +import org.bukkit.Tag; +import org.bukkit.block.Block; 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.BlockPlaceEvent; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerTakeLecternBookEvent; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; public class LecternLogging extends LoggingListener { @@ -21,25 +27,31 @@ public LecternLogging(LogBlock lb) { } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - 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 + 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); } } } From ecb281ccaa359135518187800365c2436caef2fa Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 22 Sep 2024 07:38:02 +0200 Subject: [PATCH 384/399] fix rare npe --- .../de/diddiz/LogBlock/worldedit/WorldEditHelper.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java b/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java index a8e46a2a..446c635a 100644 --- a/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java +++ b/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java @@ -21,7 +21,9 @@ 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.worldedit.IncompleteRegionException; @@ -115,11 +117,16 @@ public static Entity restoreEntity(Location location, EntityType type, byte[] se com.sk89q.worldedit.entity.Entity weEntity = weLocation.getExtent().createEntity(weLocation, state); if (weEntity != null) { LinCompoundTag newNbt = weEntity.getState().getNbt(); - int[] uuidInts = newNbt.findTag("UUID", LinTagType.intArrayTag()).value(); + LinIntArrayTag uuidTag = newNbt.findTag("UUID", LinTagType.intArrayTag()); + int[] uuidInts = uuidTag == null ? null : uuidTag.value(); if (uuidInts != null && uuidInts.length >= 4) { newUUID = new UUID(((long) uuidInts[0] << 32) | (uuidInts[1] & 0xFFFFFFFFL), ((long) uuidInts[2] << 32) | (uuidInts[3] & 0xFFFFFFFFL)); } else { - newUUID = new UUID(newNbt.findTag("UUIDMost", LinTagType.longTag()).valueAsLong(), newNbt.findTag("UUIDLeast", LinTagType.longTag()).valueAsLong()); // pre 1.16 + 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 + } } } } From 8c024532b2436b7e34c32f824f92c138286b011b Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 4 Oct 2024 10:40:24 +0200 Subject: [PATCH 385/399] fix npe in combination with some plugins --- .../java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index bb12a1fa..ca864179 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -335,6 +335,9 @@ public void onPlayerInteract(PlayerInteractEvent event) { 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(); From 0a685bca27dcb9bc843423081bfca644baf7e1fb Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 6 Dec 2024 04:42:13 +0100 Subject: [PATCH 386/399] store amount in a seperate field for item updates + 1.21.4 --- pom.xml | 2 +- .../java/de/diddiz/LogBlock/BlockChange.java | 4 +- .../java/de/diddiz/LogBlock/ChestAccess.java | 6 +- .../java/de/diddiz/LogBlock/Consumer.java | 12 +- src/main/java/de/diddiz/LogBlock/Updater.java | 3 +- .../java/de/diddiz/LogBlock/WorldEditor.java | 2 +- .../LogBlock/WorldEditorEditFactory.java | 5 +- .../listeners/ChestAccessLogging.java | 14 ++- .../de/diddiz/LogBlock/util/BukkitUtils.java | 61 +++++----- .../diddiz/LogBlock/util/InventoryUtils.java | 113 ++++++++++++++++++ .../LogBlock/util/ItemStackAndAmount.java | 15 +++ .../java/de/diddiz/LogBlock/util/Utils.java | 25 +++- 12 files changed, 205 insertions(+), 57 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/util/InventoryUtils.java create mode 100644 src/main/java/de/diddiz/LogBlock/util/ItemStackAndAmount.java diff --git a/pom.xml b/pom.xml index c7a398a4..b7d690a8 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ org.spigotmc spigot-api - 1.21-R0.1-SNAPSHOT + 1.21.4-R0.1-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 11c99890..8cc33285 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -12,6 +12,7 @@ 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; @@ -35,7 +36,6 @@ 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 BlockChange(ResultSet rs, QueryParams p) throws SQLException { typeState = p.needType ? rs.getBytes("typeState") : null; ChestAccess catemp = null; if (p.needChestAccess) { - ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); + ItemStackAndAmount stack = Utils.loadItemStack(rs.getBytes("item")); if (stack != null) { catemp = new ChestAccess(stack, rs.getBoolean("itemremove"), rs.getInt("itemtype")); } diff --git a/src/main/java/de/diddiz/LogBlock/ChestAccess.java b/src/main/java/de/diddiz/LogBlock/ChestAccess.java index 71575161..92480b16 100644 --- a/src/main/java/de/diddiz/LogBlock/ChestAccess.java +++ b/src/main/java/de/diddiz/LogBlock/ChestAccess.java @@ -1,13 +1,13 @@ package de.diddiz.LogBlock; -import org.bukkit.inventory.ItemStack; +import de.diddiz.LogBlock.util.ItemStackAndAmount; public class ChestAccess { - public final ItemStack itemStack; + public final ItemStackAndAmount itemStack; public final boolean remove; public final int itemType; - public ChestAccess(ItemStack itemStack, boolean remove, int itemType) { + public ChestAccess(ItemStackAndAmount itemStack, boolean remove, int itemType) { this.itemStack = itemStack; this.remove = remove; this.itemType = itemType; diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index c07db642..b9b00049 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -19,6 +19,7 @@ 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; @@ -52,6 +53,7 @@ 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 { @@ -208,7 +210,7 @@ public void queueBlockReplace(Actor actor, Location loc, BlockData typeBefore, B * @param remove * true if the item was removed */ - public void queueChestAccess(Actor actor, BlockState container, ItemStack itemStack, boolean remove) { + public void queueChestAccess(Actor actor, BlockState container, ItemStackAndAmount itemStack, boolean remove) { if (!(container instanceof InventoryHolder)) { throw new IllegalArgumentException("Container must be instanceof InventoryHolder"); } @@ -229,8 +231,8 @@ public void queueChestAccess(Actor actor, BlockState container, ItemStack itemSt * @param remove * true if the item was removed */ - 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()))); + 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()))); } /** @@ -261,8 +263,8 @@ public void queueContainerBreak(Actor actor, BlockState container) { * The inventory of the container block */ public void queueContainerBreak(Actor actor, Location loc, BlockData type, Inventory inv) { - final ItemStack[] items = compressInventory(inv.getContents()); - for (final ItemStack item : items) { + final Collection items = compressInventory(inv.getContents()); + for (final ItemStackAndAmount item : items) { queueChestAccess(actor, loc, type, item, true); } queueBlockBreak(actor, loc, type); diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index b1a83f86..51e5a920 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -4,6 +4,7 @@ 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; @@ -534,7 +535,7 @@ boolean update() { @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(stack)); + insertChestData.setBytes(2, Utils.saveItemStack(ItemStackAndAmount.fromStack(stack))); insertChestData.setInt(3, amount >= 0 ? 0 : 1); insertChestData.setInt(4, MaterialConverter.getOrAddMaterialId(weaponMaterial)); insertChestData.addBatch(); diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index bac7c33b..8bb41a2c 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -378,7 +378,7 @@ public PerformResult perform() throws WorldEditorException { if (state instanceof InventoryHolder && state.getType() == replacedBlock.getMaterial()) { int leftover; try { - leftover = modifyContainer(state, new ItemStack(ca.itemStack), !ca.remove); + leftover = modifyContainer(state, ca.itemStack, !ca.remove); } catch (final Exception ex) { throw new WorldEditorException(ex.getMessage(), block.getLocation()); } diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java b/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java index d167d235..cc2b6d1d 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditorEditFactory.java @@ -3,9 +3,8 @@ 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 { @@ -25,7 +24,7 @@ public void processRow(ResultSet rs) throws SQLException { return; } ChestAccess chestaccess = null; - ItemStack stack = Utils.loadItemStack(rs.getBytes("item")); + ItemStackAndAmount stack = Utils.loadItemStack(rs.getBytes("item")); if (stack != null) { chestaccess = new ChestAccess(stack, rs.getBoolean("itemremove") == rollback, rs.getInt("itemtype")); } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index ca864179..cb986000 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -3,6 +3,7 @@ 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; @@ -78,9 +79,10 @@ public void flush() { for (Entry e : modifications.entrySet()) { ItemStack stack = e.getKey(); int amount = e.getValue(); - 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); + 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); + } } modifications.clear(); } @@ -328,7 +330,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { 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(), stack, false); + consumer.queueChestAccess(Actor.actorFromEntity(player), clicked.getLocation(), clicked.getBlockData(), ItemStackAndAmount.fromStack(stack), false); } } } else if (type == Material.CHISELED_BOOKSHELF) { @@ -353,7 +355,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { if (blockData.isSlotOccupied(slot)) { // not empty: always take if (currentInSlot != null && currentInSlot.getType() != Material.AIR) { - consumer.queueChestAccess(Actor.actorFromEntity(player), clicked.getLocation(), clicked.getBlockData(), currentInSlot, true); + consumer.queueChestAccess(Actor.actorFromEntity(player), clicked.getLocation(), clicked.getBlockData(), ItemStackAndAmount.fromStack(currentInSlot), true); } } else { // empty: put if has tag BOOKSHELF_BOOKS @@ -361,7 +363,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { 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(), stack, false); + consumer.queueChestAccess(Actor.actorFromEntity(player), clicked.getLocation(), clicked.getBlockData(), ItemStackAndAmount.fromStack(stack), false); } } } diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index f13a07ff..71bd4480 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -5,11 +5,13 @@ import de.diddiz.LogBlock.LogBlock; import java.io.File; 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; @@ -146,8 +148,11 @@ public class BukkitUtils { // https://minecraft.fandom.com/wiki/Tag#blocks_small_flowers Set smallFlowers = Tag.SMALL_FLOWERS.getValues(); - // https://minecraft.fandom.com/wiki/Tag#blocks_tall_flowers - Set tallFlowers = Tag.TALL_FLOWERS.getValues(); + Set tallFlowers = Set.of(Material.SUNFLOWER, + Material.LILAC, + Material.PEONY, + Material.ROSE_BUSH, + Material.PITCHER_PLANT); Set bannerStanding = Set.of(Material.WHITE_BANNER, Material.ORANGE_BANNER, @@ -498,24 +503,22 @@ public static ItemStack[] compareInventories(ItemStack[] items1, ItemStack[] ite return diff.toArray(new ItemStack[diff.size()]); } - public static ItemStack[] compressInventory(ItemStack[] items) { - final ArrayList compressed = new ArrayList<>(); + public static Collection compressInventory(ItemStack[] items) { + final HashMap compressed = new HashMap<>(); for (final ItemStack item : items) { - 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()); - } + 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); } } - return compressed.toArray(new ItemStack[compressed.size()]); + ArrayList result = new ArrayList<>(); + for (Entry e : compressed.entrySet()) { + result.add(new ItemStackAndAmount(e.getKey(), e.getValue())); + } + return result; } public static String friendlyWorldname(String worldName) { @@ -602,15 +605,13 @@ public static int safeSpawnHeight(Location loc) { return y; } - public static int modifyContainer(BlockState b, ItemStack item, boolean remove) { - if (b instanceof InventoryHolder c) { + public static int modifyContainer(BlockState b, ItemStackAndAmount item, boolean remove) { + if (item.amount() > 0 && b instanceof InventoryHolder c) { final Inventory inv = c.getInventory(); if (remove) { - 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 InventoryUtils.removeFromInventory(inv, item); + } else { + return InventoryUtils.addToInventory(inv, item); } } return 0; @@ -656,16 +657,16 @@ public static boolean isEmpty(Material m) { return m == Material.AIR || m == Material.CAVE_AIR || m == Material.VOID_AIR; } - public static TextComponent toString(ItemStack stack) { - if (stack == null || stack.getAmount() == 0 || isEmpty(stack.getType())) { + public static TextComponent toString(ItemStackAndAmount stack) { + if (stack == null || stack.stack() == null || stack.amount() == 0 || isEmpty(stack.stack().getType())) { return prettyMaterial("nothing"); } - TextComponent msg = MessagingUtil.createTextComponentWithColor(stack.getAmount() + "x ", TypeColor.DEFAULT.getColor()); - msg.addExtra(prettyMaterial(stack.getType())); + TextComponent msg = MessagingUtil.createTextComponentWithColor(stack.amount() + "x ", TypeColor.DEFAULT.getColor()); + msg.addExtra(prettyMaterial(stack.stack().getType())); try { - String itemTag = stack.getItemMeta().getAsString(); - msg.setHoverEvent(new HoverEvent(Action.SHOW_ITEM, new Item(stack.getType().getKey().toString(), 1, itemTag != null ? ItemTag.ofNbt(itemTag) : null))); + 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))); } 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()) }))); diff --git a/src/main/java/de/diddiz/LogBlock/util/InventoryUtils.java b/src/main/java/de/diddiz/LogBlock/util/InventoryUtils.java new file mode 100644 index 00000000..269be74b --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/util/InventoryUtils.java @@ -0,0 +1,113 @@ +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; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/util/ItemStackAndAmount.java b/src/main/java/de/diddiz/LogBlock/util/ItemStackAndAmount.java new file mode 100644 index 00000000..1737a4f0 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/util/ItemStackAndAmount.java @@ -0,0 +1,15 @@ +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); + } +} diff --git a/src/main/java/de/diddiz/LogBlock/util/Utils.java b/src/main/java/de/diddiz/LogBlock/util/Utils.java index 353c4af5..dd4296d2 100644 --- a/src/main/java/de/diddiz/LogBlock/util/Utils.java +++ b/src/main/java/de/diddiz/LogBlock/util/Utils.java @@ -231,20 +231,35 @@ public static String mysqlTextEscape(String untrusted) { return untrusted.replace("\\", "\\\\").replace("'", "\\'"); } - public static ItemStack loadItemStack(byte[] data) { + public static ItemStackAndAmount loadItemStack(byte[] data) { if (data == null || data.length == 0) { return null; } YamlConfiguration conf = deserializeYamlConfiguration(data); - return conf == null ? null : conf.getItemStack("stack"); + 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); } - public static byte[] saveItemStack(ItemStack stack) { - if (stack == null || BukkitUtils.isEmpty(stack.getType())) { + public static byte[] saveItemStack(ItemStackAndAmount stack) { + if (stack == null || stack.stack() == null || BukkitUtils.isEmpty(stack.stack().getType())) { return null; } YamlConfiguration conf = new YamlConfiguration(); - conf.set("stack", stack); + ItemStack itemStack = stack.stack(); + if (itemStack.getAmount() > 1) { + itemStack = itemStack.clone(); + itemStack.setAmount(1); + } + conf.set("stack", itemStack); + conf.set("amount", stack.amount()); return serializeYamlConfiguration(conf); } From c14b17a522d8727a1a2395206636a63516a571b9 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Wed, 26 Feb 2025 05:43:29 +0100 Subject: [PATCH 387/399] fix damage type actors --- .../de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java | 4 +++- src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index 84fffc14..0b85194f 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -2,6 +2,7 @@ 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; @@ -201,7 +202,8 @@ public void onEntityDeath(EntityDeathEvent event) { actor = Actor.actorFromEntity(entity.getKiller()); } if (actor == null) { - actor = new Actor(event.getDamageSource().getDamageType().toString()); + NamespacedKey key = event.getDamageSource().getDamageType().getKey(); + actor = new Actor(key == null ? "unknown" : key.getKey().toUpperCase()); } queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java index 914c4eeb..c6aff64e 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java @@ -4,6 +4,7 @@ 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; @@ -38,7 +39,10 @@ public void onEntityDeath(EntityDeathEvent deathEvent) { } else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster))) { return; } - consumer.queueKill(new Actor(deathEvent.getDamageSource().getDamageType().toString()), victim); + NamespacedKey key = deathEvent.getDamageSource().getDamageType().getKey(); + Actor actor = new Actor(key == null ? "unknown" : key.getKey().toUpperCase()); + + consumer.queueKill(actor, victim); } } } From 63f9d16891559d86206e82f0fb640e256835b569 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 16 May 2025 06:41:23 +0200 Subject: [PATCH 388/399] 1.21.5 --- pom.xml | 2 +- src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b7d690a8..5c5d8265 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ org.spigotmc spigot-api - 1.21.4-R0.1-SNAPSHOT + 1.21.5-R0.1-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 71bd4480..2e25bbbb 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -348,7 +348,8 @@ public class BukkitUtils { projectileItems.put(EntityType.FIREBALL, Material.FIRE_CHARGE); // Fire charge projectileItems.put(EntityType.FISHING_BOBBER, Material.FISHING_ROD); projectileItems.put(EntityType.SNOWBALL, Material.SNOWBALL); - projectileItems.put(EntityType.POTION, Material.SPLASH_POTION); + 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.WITHER_SKULL, Material.WITHER_SKELETON_SKULL); projectileItems.put(EntityType.FIREWORK_ROCKET, Material.FIREWORK_ROCKET); From 363d19e852a45946d68320f1c77116a015890349 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 8 Jul 2025 00:30:01 +0200 Subject: [PATCH 389/399] Fix npe in BlockStateCodecSpawner Fixes #908 --- .../LogBlock/blockstate/BlockStateCodecSpawner.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java index db6d42e5..1146e639 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java @@ -64,9 +64,12 @@ public void deserialize(BlockState state, YamlConfiguration conf) { @Override public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { if (conf != null) { - EntityType entity = EntityType.valueOf(conf.getString("spawnedType")); - if (entity != null) { - return new TextComponent("[" + entity.getKey().getKey() + "]"); + String spawnedTypeString = conf.getString("spawnedType"); + if (spawnedTypeString != null) { + EntityType entity = EntityType.valueOf(spawnedTypeString); + if (entity != null) { + return new TextComponent("[" + entity.getKey().getKey() + "]"); + } } } return null; From 524f408a3f122f48310cdebeaf144f14032020b4 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 8 Jul 2025 00:33:32 +0200 Subject: [PATCH 390/399] fix npe in WorldEditHelper Fixes #907 --- .../LogBlock/worldedit/WorldEditHelper.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java b/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java index 446c635a..1ca2a89c 100644 --- a/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java +++ b/src/main/java/de/diddiz/LogBlock/worldedit/WorldEditHelper.java @@ -140,22 +140,25 @@ public static byte[] serializeEntity(Entity entity) { com.sk89q.worldedit.entity.Entity weEntity = BukkitAdapter.adapt(entity); 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); + LinCompoundTag originalNbt = state.getNbt(); + if (originalNbt != null) { + try { + LinCompoundTag.Builder nbt = originalNbt.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); + } + return baos.toByteArray(); + } catch (IOException e) { + throw new RuntimeException("This IOException should be impossible", e); } - return baos.toByteArray(); - } catch (IOException e) { - throw new RuntimeException("This IOException should be impossible", e); } } return null; From 5e2c2550518c6b1b0e5d0337606211fdf242a642 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 8 Jul 2025 05:20:22 +0200 Subject: [PATCH 391/399] never log more moving than available target space on shift click Fixes #896 --- .../listeners/ChestAccessLogging.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index cb986000..4d98a485 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -210,7 +210,10 @@ public void onInventoryClick(InventoryClickEvent event) { break; case MOVE_TO_OTHER_INVENTORY: // shift + click boolean removed = event.getRawSlot() < event.getView().getTopInventory().getSize(); - modifications.addModification(event.getCurrentItem(), event.getCurrentItem().getAmount() * (removed ? -1 : 1)); + int maxMove = getFreeSpace(event.getCurrentItem(), removed ? event.getView().getBottomInventory() : event.getView().getTopInventory()); + if (maxMove > 0) { + modifications.addModification(event.getCurrentItem(), Math.min(event.getCurrentItem().getAmount(), maxMove) * (removed ? -1 : 1)); + } break; case COLLECT_TO_CURSOR: // double click // server behaviour: first collect all with an amount != maxstacksize, then others, starting from slot 0 (container) @@ -369,4 +372,25 @@ public void onPlayerInteract(PlayerInteractEvent event) { } } } + + private static int getFreeSpace(ItemStack item, Inventory inventory) { + int freeSpace = 0; + int maxStack = Math.max(item.getMaxStackSize(), 1); + + ItemStack[] contents = inventory.getStorageContents(); + for (int i = 0; i < contents.length; i++) { + ItemStack content = contents[i]; + + if (item.isSimilar(content)) { + freeSpace += Math.max(maxStack - content.getAmount(), 0); + } else if (content == null || content.getType() == Material.AIR) { + freeSpace += maxStack; + } + if (freeSpace >= item.getAmount()) { + return item.getAmount(); + } + } + + return freeSpace; + } } From 1136802117a5d8e2b899bc717e23f61af9a2c07c Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 8 Jul 2025 08:48:37 +0200 Subject: [PATCH 392/399] Bundle logging Fixes #903 --- .../listeners/ChestAccessLogging.java | 155 ++- .../de/diddiz/LogBlock/util/Fraction.java | 930 ++++++++++++++++++ 2 files changed, 1080 insertions(+), 5 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/util/Fraction.java diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index 4d98a485..a8b11ab7 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -3,10 +3,12 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.util.Fraction; import de.diddiz.LogBlock.util.ItemStackAndAmount; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Tag; +import org.bukkit.block.Beehive; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.DecoratedPot; @@ -18,6 +20,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.block.Action; import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryAction; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryDragEvent; @@ -27,9 +30,14 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BlockStateMeta; +import org.bukkit.inventory.meta.BundleMeta; +import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.util.Vector; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -37,15 +45,46 @@ import static de.diddiz.LogBlock.util.BukkitUtils.*; public class ChestAccessLogging extends LoggingListener { + private static final InventoryAction PICKUP_ALL_INTO_BUNDLE; + private static final InventoryAction PICKUP_FROM_BUNDLE; + private static final InventoryAction PICKUP_SOME_INTO_BUNDLE; + private static final InventoryAction PLACE_ALL_INTO_BUNDLE; + private static final InventoryAction PLACE_FROM_BUNDLE; + private static final InventoryAction PLACE_SOME_INTO_BUNDLE; + static { + InventoryAction pickupAllIntoBundle = null; + InventoryAction pickupFromBundle = null; + InventoryAction pickupSomeIntoBundle = null; + InventoryAction placeAllIntoBundle = null; + InventoryAction placeFromBundle = null; + InventoryAction placeSomeIntoBundle = null; + try { + pickupAllIntoBundle = InventoryAction.valueOf("PICKUP_ALL_INTO_BUNDLE"); + pickupFromBundle = InventoryAction.valueOf("PICKUP_FROM_BUNDLE"); + pickupSomeIntoBundle = InventoryAction.valueOf("PICKUP_SOME_INTO_BUNDLE"); + placeAllIntoBundle = InventoryAction.valueOf("PLACE_ALL_INTO_BUNDLE"); + placeFromBundle = InventoryAction.valueOf("PLACE_FROM_BUNDLE"); + placeSomeIntoBundle = InventoryAction.valueOf("PLACE_SOME_INTO_BUNDLE"); + } catch (IllegalArgumentException e) { + // ignore + } + PICKUP_ALL_INTO_BUNDLE = pickupAllIntoBundle; + PICKUP_FROM_BUNDLE = pickupFromBundle; + PICKUP_SOME_INTO_BUNDLE = pickupSomeIntoBundle; + PLACE_ALL_INTO_BUNDLE = placeAllIntoBundle; + PLACE_FROM_BUNDLE = placeFromBundle; + PLACE_SOME_INTO_BUNDLE = placeSomeIntoBundle; + } + private class PlayerActiveInventoryModifications { private final HumanEntity actor; private final Location location; - private final HashMap modifications; + private final LinkedHashMap modifications; public PlayerActiveInventoryModifications(HumanEntity actor, Location location) { this.actor = actor; this.location = location; - this.modifications = new HashMap<>(); + this.modifications = new LinkedHashMap<>(); } public void addModification(ItemStack stack, int amount) { @@ -159,7 +198,8 @@ public void onInventoryClick(InventoryClickEvent event) { if (holder instanceof BlockState || holder instanceof DoubleChest) { final PlayerActiveInventoryModifications modifications = containersByOwner.get(player); if (modifications != null) { - switch (event.getAction()) { + InventoryAction action = event.getAction(); + switch (action) { case PICKUP_ONE: case DROP_ONE_SLOT: if (event.getRawSlot() < event.getView().getTopInventory().getSize()) { @@ -283,8 +323,77 @@ public void onInventoryClick(InventoryClickEvent event) { break; case UNKNOWN: default: - // unable to log something we don't know - consumer.getLogblock().getLogger().warning("Unknown inventory action by " + event.getWhoClicked().getName() + ": " + event.getAction() + " Slot: " + event.getSlot() + " Slot type: " + event.getSlotType()); + if (action == PICKUP_ALL_INTO_BUNDLE || action == PICKUP_SOME_INTO_BUNDLE) { + // slot -> free space on cursor bundle + if (event.getRawSlot() < event.getView().getTopInventory().getSize() && event.getCursor() != null && event.getCurrentItem() != null) { + int amount = getMaxAmountToAdd(event.getCurrentItem(), event.getCursor()); + if (amount > 0) { + modifications.addModification(event.getCurrentItem(), -amount); + } + } + } else if (action == PICKUP_FROM_BUNDLE) { + // last stack from bundle in slot -> cursor (remove old bundle, add new bundle with lesser items) + if (event.getRawSlot() < event.getView().getTopInventory().getSize() && event.getCurrentItem() != null) { + ItemMeta meta = event.getCurrentItem().getItemMeta(); + if (meta != null && meta instanceof BundleMeta bundleMeta) { + ItemStack newBundleStack = event.getCurrentItem().clone(); + ArrayList bundleContent = new ArrayList<>(bundleMeta.getItems()); + if (!bundleContent.isEmpty()) { + bundleContent.removeFirst(); + bundleMeta = (BundleMeta) bundleMeta.clone(); + bundleMeta.setItems(bundleContent); + newBundleStack.setItemMeta(bundleMeta); + + modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount()); + modifications.addModification(newBundleStack, newBundleStack.getAmount()); + } + } + } + } else if (action == PLACE_ALL_INTO_BUNDLE || action == PLACE_SOME_INTO_BUNDLE) { + // cursor -> bundle in slot (remove old bundle, add new bundle with added items) + if (event.getRawSlot() < event.getView().getTopInventory().getSize() && event.getCursor() != null && event.getCurrentItem() != null) { + ItemMeta meta = event.getCurrentItem().getItemMeta(); + if (meta != null && meta instanceof BundleMeta bundleMeta) { + int addable = getMaxAmountToAdd(event.getCursor(), event.getCurrentItem()); + if (addable > 0) { + ItemStack addToBundle = event.getCursor().clone(); + addToBundle.setAmount(addable); + ItemStack newBundleStack = event.getCurrentItem().clone(); + ArrayList bundleContent = new ArrayList<>(bundleMeta.getItems()); + // if the bundle contains similar stack, remove that stack and add larger stack + for (int i = 0; i < bundleContent.size(); i++) { + if (bundleContent.get(i).isSimilar(addToBundle)) { + addToBundle.setAmount(addToBundle.getAmount() + bundleContent.get(i).getAmount()); + bundleContent.remove(i); + break; + } + } + bundleContent.addFirst(addToBundle); + bundleMeta = (BundleMeta) bundleMeta.clone(); + bundleMeta.setItems(bundleContent); + newBundleStack.setItemMeta(bundleMeta); + + modifications.addModification(event.getCurrentItem(), -event.getCurrentItem().getAmount()); + modifications.addModification(newBundleStack, newBundleStack.getAmount()); + } + } + } + } else if (action == PLACE_FROM_BUNDLE) { + // last stack from bundle on cursor -> slot + if (event.getRawSlot() < event.getView().getTopInventory().getSize() && event.getCursor() != null) { + ItemMeta meta = event.getCursor().getItemMeta(); + if (meta != null && meta instanceof BundleMeta bundleMeta) { + List items = bundleMeta.getItems(); + if (!items.isEmpty()) { + ItemStack item = items.getFirst(); + modifications.addModification(item, item.getAmount()); + } + } + } + } else { + // unable to log something we don't know + consumer.getLogblock().getLogger().warning("Unknown inventory action by " + event.getWhoClicked().getName() + ": " + event.getAction() + " Slot: " + event.getSlot() + " Slot type: " + event.getSlotType()); + } break; } } @@ -393,4 +502,40 @@ private static int getFreeSpace(ItemStack item, Inventory inventory) { return freeSpace; } + + private static final Fraction BUNDLE_IN_BUNDLE_WEIGHT = Fraction.getFraction(1, 16); + + private static Fraction computeContentWeight(List content) { + Fraction sum = Fraction.ZERO; + for (ItemStack itemStack : content) { + sum = sum.add(getWeightOfOne(itemStack).multiplyBy(Fraction.getFraction(itemStack.getAmount(), 1))); + } + return sum; + } + + private static Fraction getWeightOfOne(ItemStack stack) { + ItemMeta meta = stack.getItemMeta(); + if (meta != null && meta instanceof BundleMeta bundleMeta) { + return BUNDLE_IN_BUNDLE_WEIGHT.add(computeContentWeight(bundleMeta.getItems())); + } else if (meta instanceof BlockStateMeta blockStateMeta) { + if (blockStateMeta.getBlockState() instanceof Beehive hive) { + int entityCount = hive.getEntityCount(); + if (entityCount > 0) { + return Fraction.ONE; + } + } + } + return Fraction.getFraction(1, stack.getMaxStackSize()); + } + + private static int getMaxAmountToAdd(ItemStack stackToAdd, ItemStack bundle) { + ItemMeta meta = bundle.getItemMeta(); + if (meta == null || !(meta instanceof BundleMeta bundleMeta)) { + return 0; + } + Fraction weight = computeContentWeight(bundleMeta.getItems()); + + Fraction free = Fraction.ONE.subtract(weight); + return Math.min(stackToAdd.getAmount(), Math.max(free.divideBy(getWeightOfOne(stackToAdd)).intValue(), 0)); + } } diff --git a/src/main/java/de/diddiz/LogBlock/util/Fraction.java b/src/main/java/de/diddiz/LogBlock/util/Fraction.java new file mode 100644 index 00000000..f18b2b64 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/util/Fraction.java @@ -0,0 +1,930 @@ +package de.diddiz.LogBlock.util; +/* + * Copied from apache commons to avoid shading the whol library + */ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.Serializable; +import java.math.BigInteger; +import java.util.Objects; + +/** + * {@link Fraction} is a {@link Number} implementation that stores fractions accurately. + *

    + * This class is immutable, and interoperable with most methods that accept a {@link Number}. + *

    + *

    + * Note that this class is intended for common use cases, it is int based and thus suffers from various overflow issues. For a BigInteger based + * equivalent, please see the Commons Math BigFraction class. + *

    + * + * @since 2.0 + */ +public final class Fraction extends Number implements Comparable { + + /** + * Required for serialization support. Lang version 2.0. + * + * @see Serializable + */ + private static final long serialVersionUID = 65382027393090L; + + /** + * {@link Fraction} representation of 0. + */ + public static final Fraction ZERO = new Fraction(0, 1); + + /** + * {@link Fraction} representation of 1. + */ + public static final Fraction ONE = new Fraction(1, 1); + + /** + * {@link Fraction} representation of 1/2. + */ + public static final Fraction ONE_HALF = new Fraction(1, 2); + + /** + * {@link Fraction} representation of 1/3. + */ + public static final Fraction ONE_THIRD = new Fraction(1, 3); + + /** + * {@link Fraction} representation of 2/3. + */ + public static final Fraction TWO_THIRDS = new Fraction(2, 3); + + /** + * {@link Fraction} representation of 1/4. + */ + public static final Fraction ONE_QUARTER = new Fraction(1, 4); + + /** + * {@link Fraction} representation of 2/4. + */ + public static final Fraction TWO_QUARTERS = new Fraction(2, 4); + + /** + * {@link Fraction} representation of 3/4. + */ + public static final Fraction THREE_QUARTERS = new Fraction(3, 4); + + /** + * {@link Fraction} representation of 1/5. + */ + public static final Fraction ONE_FIFTH = new Fraction(1, 5); + + /** + * {@link Fraction} representation of 2/5. + */ + public static final Fraction TWO_FIFTHS = new Fraction(2, 5); + + /** + * {@link Fraction} representation of 3/5. + */ + public static final Fraction THREE_FIFTHS = new Fraction(3, 5); + + /** + * {@link Fraction} representation of 4/5. + */ + public static final Fraction FOUR_FIFTHS = new Fraction(4, 5); + + /** + * Adds two integers, checking for overflow. + * + * @param x an addend + * @param y an addend + * @return the sum {@code x+y} + * @throws ArithmeticException if the result cannot be represented as + * an int + */ + private static int addAndCheck(final int x, final int y) { + final long s = (long) x + (long) y; + if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) { + throw new ArithmeticException("overflow: add"); + } + return (int) s; + } + + /** + * Creates a {@link Fraction} instance from a {@code double} value. + *

    + * This method uses the continued fraction + * algorithm, computing a maximum of 25 convergents and bounding the denominator by 10,000. + *

    + * + * @param value the double value to convert + * @return a new fraction instance that is close to the value + * @throws ArithmeticException if {@code |value| > Integer.MAX_VALUE} or {@code value = NaN} + * @throws ArithmeticException if the calculated denominator is {@code zero} + * @throws ArithmeticException if the algorithm does not converge + */ + public static Fraction getFraction(double value) { + final int sign = value < 0 ? -1 : 1; + value = Math.abs(value); + if (value > Integer.MAX_VALUE || Double.isNaN(value)) { + throw new ArithmeticException("The value must not be greater than Integer.MAX_VALUE or NaN"); + } + final int wholeNumber = (int) value; + value -= wholeNumber; + int numer0 = 0; // the pre-previous + int denom0 = 1; // the pre-previous + int numer1 = 1; // the previous + int denom1 = 0; // the previous + int numer2; // the current, setup in calculation + int denom2; // the current, setup in calculation + int a1 = (int) value; + int a2; + double x1 = 1; + double x2; + double y1 = value - a1; + double y2; + double delta1; + double delta2 = Double.MAX_VALUE; + double fraction; + int i = 1; + do { + delta1 = delta2; + a2 = (int) (x1 / y1); + x2 = y1; + y2 = x1 - a2 * y1; + numer2 = a1 * numer1 + numer0; + denom2 = a1 * denom1 + denom0; + fraction = (double) numer2 / (double) denom2; + delta2 = Math.abs(value - fraction); + a1 = a2; + x1 = x2; + y1 = y2; + numer0 = numer1; + denom0 = denom1; + numer1 = numer2; + denom1 = denom2; + i++; + } while (delta1 > delta2 && denom2 <= 10000 && denom2 > 0 && i < 25); + if (i == 25) { + throw new ArithmeticException("Unable to convert double to fraction"); + } + return getReducedFraction((numer0 + wholeNumber * denom0) * sign, denom0); + } + + /** + * Creates a {@link Fraction} instance with the 2 parts of a fraction Y/Z. + *

    + * Any negative signs are resolved to be on the numerator. + *

    + * + * @param numerator the numerator, for example the three in 'three sevenths' + * @param denominator the denominator, for example the seven in 'three sevenths' + * @return a new fraction instance + * @throws ArithmeticException if the denominator is {@code zero} or the denominator is {@code negative} and the numerator is {@code Integer#MIN_VALUE} + */ + public static Fraction getFraction(int numerator, int denominator) { + if (denominator == 0) { + throw new ArithmeticException("The denominator must not be zero"); + } + if (denominator < 0) { + if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: can't negate"); + } + numerator = -numerator; + denominator = -denominator; + } + return new Fraction(numerator, denominator); + } + + /** + * Creates a {@link Fraction} instance with the 3 parts of a fraction X Y/Z. + *

    + * The negative sign must be passed in on the whole number part. + *

    + * + * @param whole the whole number, for example the one in 'one and three sevenths' + * @param numerator the numerator, for example the three in 'one and three sevenths' + * @param denominator the denominator, for example the seven in 'one and three sevenths' + * @return a new fraction instance + * @throws ArithmeticException if the denominator is {@code zero} + * @throws ArithmeticException if the denominator is negative + * @throws ArithmeticException if the numerator is negative + * @throws ArithmeticException if the resulting numerator exceeds {@code Integer.MAX_VALUE} + */ + public static Fraction getFraction(final int whole, final int numerator, final int denominator) { + if (denominator == 0) { + throw new ArithmeticException("The denominator must not be zero"); + } + if (denominator < 0) { + throw new ArithmeticException("The denominator must not be negative"); + } + if (numerator < 0) { + throw new ArithmeticException("The numerator must not be negative"); + } + final long numeratorValue; + if (whole < 0) { + numeratorValue = whole * (long) denominator - numerator; + } else { + numeratorValue = whole * (long) denominator + numerator; + } + if (numeratorValue < Integer.MIN_VALUE || numeratorValue > Integer.MAX_VALUE) { + throw new ArithmeticException("Numerator too large to represent as an Integer."); + } + return new Fraction((int) numeratorValue, denominator); + } + + /** + * Creates a Fraction from a {@link String}. + *

    + * The formats accepted are: + *

    + *
      + *
    1. {@code double} String containing a dot
    2. + *
    3. 'X Y/Z'
    4. + *
    5. 'Y/Z'
    6. + *
    7. 'X' (a simple whole number)
    8. + *
    + *

    + * and a . + *

    + * + * @param str the string to parse, must not be {@code null} + * @return the new {@link Fraction} instance + * @throws NullPointerException if the string is {@code null} + * @throws NumberFormatException if the number format is invalid + */ + public static Fraction getFraction(String str) { + Objects.requireNonNull(str, "str"); + // parse double format + int pos = str.indexOf('.'); + if (pos >= 0) { + return getFraction(Double.parseDouble(str)); + } + + // parse X Y/Z format + pos = str.indexOf(' '); + if (pos > 0) { + final int whole = Integer.parseInt(str.substring(0, pos)); + str = str.substring(pos + 1); + pos = str.indexOf('/'); + if (pos < 0) { + throw new NumberFormatException("The fraction could not be parsed as the format X Y/Z"); + } + final int numer = Integer.parseInt(str.substring(0, pos)); + final int denom = Integer.parseInt(str.substring(pos + 1)); + return getFraction(whole, numer, denom); + } + + // parse Y/Z format + pos = str.indexOf('/'); + if (pos < 0) { + // simple whole number + return getFraction(Integer.parseInt(str), 1); + } + final int numer = Integer.parseInt(str.substring(0, pos)); + final int denom = Integer.parseInt(str.substring(pos + 1)); + return getFraction(numer, denom); + } + + /** + * Creates a reduced {@link Fraction} instance with the 2 parts of a fraction Y/Z. + *

    + * For example, if the input parameters represent 2/4, then the created fraction will be 1/2. + *

    + * + *

    + * Any negative signs are resolved to be on the numerator. + *

    + * + * @param numerator the numerator, for example the three in 'three sevenths' + * @param denominator the denominator, for example the seven in 'three sevenths' + * @return a new fraction instance, with the numerator and denominator reduced + * @throws ArithmeticException if the denominator is {@code zero} + */ + public static Fraction getReducedFraction(int numerator, int denominator) { + if (denominator == 0) { + throw new ArithmeticException("The denominator must not be zero"); + } + if (numerator == 0) { + return ZERO; // normalize zero. + } + // allow 2^k/-2^31 as a valid fraction (where k>0) + if (denominator == Integer.MIN_VALUE && (numerator & 1) == 0) { + numerator /= 2; + denominator /= 2; + } + if (denominator < 0) { + if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: can't negate"); + } + numerator = -numerator; + denominator = -denominator; + } + // simplify fraction. + final int gcd = greatestCommonDivisor(numerator, denominator); + numerator /= gcd; + denominator /= gcd; + return new Fraction(numerator, denominator); + } + + /** + * Gets the greatest common divisor of the absolute value of + * two numbers, using the "binary gcd" method which avoids + * division and modulo operations. See Knuth 4.5.2 algorithm B. + * This algorithm is due to Josef Stein (1961). + * + * @param u a non-zero number + * @param v a non-zero number + * @return the greatest common divisor, never zero + */ + private static int greatestCommonDivisor(int u, int v) { + // From Commons Math: + if (u == 0 || v == 0) { + if (u == Integer.MIN_VALUE || v == Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: gcd is 2^31"); + } + return Math.abs(u) + Math.abs(v); + } + // if either operand is abs 1, return 1: + if (Math.abs(u) == 1 || Math.abs(v) == 1) { + return 1; + } + // keep u and v negative, as negative integers range down to + // -2^31, while positive numbers can only be as large as 2^31-1 + // (i.e. we can't necessarily negate a negative number without + // overflow) + if (u > 0) { + u = -u; + } // make u negative + if (v > 0) { + v = -v; + } // make v negative + // B1. [Find power of 2] + int k = 0; + while ((u & 1) == 0 && (v & 1) == 0 && k < 31) { // while u and v are both even... + u /= 2; + v /= 2; + k++; // cast out twos. + } + if (k == 31) { + throw new ArithmeticException("overflow: gcd is 2^31"); + } + // B2. Initialize: u and v have been divided by 2^k and at least + // one is odd. + int t = (u & 1) == 1 ? v : -(u / 2)/* B3 */; + // t negative: u was odd, v may be even (t replaces v) + // t positive: u was even, v is odd (t replaces u) + do { + /* assert u<0 && v<0; */ + // B4/B3: cast out twos from t. + while ((t & 1) == 0) { // while t is even. + t /= 2; // cast out twos + } + // B5 [reset max(u,v)] + if (t > 0) { + u = -t; + } else { + v = t; + } + // B6/B3. at this point both u and v should be odd. + t = (v - u) / 2; + // |u| larger: t positive (replace u) + // |v| larger: t negative (replace v) + } while (t != 0); + return -u * (1 << k); // gcd is u*2^k + } + + /** + * Multiplies two integers, checking for overflow. + * + * @param x a factor + * @param y a factor + * @return the product {@code x*y} + * @throws ArithmeticException if the result cannot be represented as + * an int + */ + private static int mulAndCheck(final int x, final int y) { + final long m = (long) x * (long) y; + if (m < Integer.MIN_VALUE || m > Integer.MAX_VALUE) { + throw new ArithmeticException("overflow: mul"); + } + return (int) m; + } + + /** + * Multiplies two non-negative integers, checking for overflow. + * + * @param x a non-negative factor + * @param y a non-negative factor + * @return the product {@code x*y} + * @throws ArithmeticException if the result cannot be represented as + * an int + */ + private static int mulPosAndCheck(final int x, final int y) { + /* assert x>=0 && y>=0; */ + final long m = (long) x * (long) y; + if (m > Integer.MAX_VALUE) { + throw new ArithmeticException("overflow: mulPos"); + } + return (int) m; + } + + /** + * Subtracts two integers, checking for overflow. + * + * @param x the minuend + * @param y the subtrahend + * @return the difference {@code x-y} + * @throws ArithmeticException if the result cannot be represented as + * an int + */ + private static int subAndCheck(final int x, final int y) { + final long s = (long) x - (long) y; + if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) { + throw new ArithmeticException("overflow: add"); + } + return (int) s; + } + + /** + * The numerator number part of the fraction (the three in three sevenths). + */ + private final int numerator; + + /** + * The denominator number part of the fraction (the seven in three sevenths). + */ + private final int denominator; + + /** + * Cached output hashCode (class is immutable). + */ + private transient int hashCode; + + /** + * Cached output toString (class is immutable). + */ + private transient String toString; + + /** + * Cached output toProperString (class is immutable). + */ + private transient String toProperString; + + /** + * Constructs a {@link Fraction} instance with the 2 parts + * of a fraction Y/Z. + * + * @param numerator the numerator, for example the three in 'three sevenths' + * @param denominator the denominator, for example the seven in 'three sevenths' + */ + private Fraction(final int numerator, final int denominator) { + this.numerator = numerator; + this.denominator = denominator; + } + + /** + * Gets a fraction that is the positive equivalent of this one. + *

    + * More precisely: {@code (fraction >= 0 ? this : -fraction)} + *

    + *

    + * The returned fraction is not reduced. + *

    + * + * @return {@code this} if it is positive, or a new positive fraction instance with the opposite signed numerator + */ + public Fraction abs() { + if (numerator >= 0) { + return this; + } + return negate(); + } + + /** + * Adds the value of this fraction to another, returning the result in reduced form. + * The algorithm follows Knuth, 4.5.1. + * + * @param fraction the fraction to add, must not be {@code null} + * @return a {@link Fraction} instance with the resulting values + * @throws NullPointerException if the fraction is {@code null} + * @throws ArithmeticException if the resulting numerator or denominator exceeds + * {@code Integer.MAX_VALUE} + */ + public Fraction add(final Fraction fraction) { + return addSub(fraction, true /* add */); + } + + /** + * Implements add and subtract using the algorithm described in + * The Art of Computer Programming (TAOCP) 4.5.1 by Donald Knuth. + * + * @param fraction the fraction to subtract, must not be {@code null} + * @param isAdd true to add, false to subtract + * @return a {@link Fraction} instance with the resulting values + * @throws IllegalArgumentException if the fraction is {@code null} + * @throws ArithmeticException if the resulting numerator or denominator + * cannot be represented in an {@code int}. + */ + private Fraction addSub(final Fraction fraction, final boolean isAdd) { + Objects.requireNonNull(fraction, "fraction"); + // zero is identity for addition. + if (numerator == 0) { + return isAdd ? fraction : fraction.negate(); + } + if (fraction.numerator == 0) { + return this; + } + // if denominators are randomly distributed, d1 will be 1 about 61% + // of the time. + final int d1 = greatestCommonDivisor(denominator, fraction.denominator); + if (d1 == 1) { + // result is ((u*v' +/- u'v) / u'v') + final int uvp = mulAndCheck(numerator, fraction.denominator); + final int upv = mulAndCheck(fraction.numerator, denominator); + return new Fraction(isAdd ? addAndCheck(uvp, upv) : subAndCheck(uvp, upv), mulPosAndCheck(denominator, + fraction.denominator)); + } + // the quantity 't' requires 65 bits of precision; see knuth 4.5.1 + // exercise 7. we're going to use a BigInteger. + // t = u(v'/d1) +/- v(u'/d1) + final BigInteger uvp = BigInteger.valueOf(numerator).multiply(BigInteger.valueOf(fraction.denominator / d1)); + final BigInteger upv = BigInteger.valueOf(fraction.numerator).multiply(BigInteger.valueOf(denominator / d1)); + final BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv); + // but d2 doesn't need extra precision because + // d2 = gcd(t,d1) = gcd(t mod d1, d1) + final int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue(); + final int d2 = tmodd1 == 0 ? d1 : greatestCommonDivisor(tmodd1, d1); + + // result is (t/d2) / (u'/d1)(v'/d2) + final BigInteger w = t.divide(BigInteger.valueOf(d2)); + if (w.bitLength() > 31) { + throw new ArithmeticException("overflow: numerator too large after multiply"); + } + return new Fraction(w.intValue(), mulPosAndCheck(denominator / d1, fraction.denominator / d2)); + } + + /** + * Compares this object to another based on size. + *

    + * Note: this class has a natural ordering that is inconsistent with equals, because, for example, equals treats 1/2 and 2/4 as different, whereas compareTo + * treats them as equal. + *

    + * + * @param other the object to compare to + * @return -1 if this is less, 0 if equal, +1 if greater + * @throws ClassCastException if the object is not a {@link Fraction} + * @throws NullPointerException if the object is {@code null} + */ + @Override + public int compareTo(final Fraction other) { + if (this == other) { + return 0; + } + if (numerator == other.numerator && denominator == other.denominator) { + return 0; + } + + // otherwise see which is less + final long first = (long) numerator * (long) other.denominator; + final long second = (long) other.numerator * (long) denominator; + return Long.compare(first, second); + } + + /** + * Divide the value of this fraction by another. + * + * @param fraction the fraction to divide by, must not be {@code null} + * @return a {@link Fraction} instance with the resulting values + * @throws NullPointerException if the fraction is {@code null} + * @throws ArithmeticException if the fraction to divide by is zero + * @throws ArithmeticException if the resulting numerator or denominator exceeds + * {@code Integer.MAX_VALUE} + */ + public Fraction divideBy(final Fraction fraction) { + Objects.requireNonNull(fraction, "fraction"); + if (fraction.numerator == 0) { + throw new ArithmeticException("The fraction to divide by must not be zero"); + } + return multiplyBy(fraction.invert()); + } + + /** + * Gets the fraction as a {@code double}. This calculates the fraction + * as the numerator divided by denominator. + * + * @return the fraction as a {@code double} + */ + @Override + public double doubleValue() { + return (double) numerator / (double) denominator; + } + + /** + * Compares this fraction to another object to test if they are equal. + *

    + * To be equal, both values must be equal. Thus 2/4 is not equal to 1/2. + *

    + * + * @param obj the reference object with which to compare + * @return {@code true} if this object is equal + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof Fraction)) { + return false; + } + final Fraction other = (Fraction) obj; + return getNumerator() == other.getNumerator() && getDenominator() == other.getDenominator(); + } + + /** + * Gets the fraction as a {@code float}. This calculates the fraction + * as the numerator divided by denominator. + * + * @return the fraction as a {@code float} + */ + @Override + public float floatValue() { + return (float) numerator / (float) denominator; + } + + /** + * Gets the denominator part of the fraction. + * + * @return the denominator fraction part + */ + public int getDenominator() { + return denominator; + } + + /** + * Gets the numerator part of the fraction. + *

    + * This method may return a value greater than the denominator, an improper fraction, such as the seven in 7/4. + *

    + * + * @return the numerator fraction part + */ + public int getNumerator() { + return numerator; + } + + /** + * Gets the proper numerator, always positive. + *

    + * An improper fraction 7/4 can be resolved into a proper one, 1 3/4. This method returns the 3 from the proper fraction. + *

    + * + *

    + * If the fraction is negative such as -7/4, it can be resolved into -1 3/4, so this method returns the positive proper numerator, 3. + *

    + * + * @return the numerator fraction part of a proper fraction, always positive + */ + public int getProperNumerator() { + return Math.abs(numerator % denominator); + } + + /** + * Gets the proper whole part of the fraction. + *

    + * An improper fraction 7/4 can be resolved into a proper one, 1 3/4. This method returns the 1 from the proper fraction. + *

    + * + *

    + * If the fraction is negative such as -7/4, it can be resolved into -1 3/4, so this method returns the positive whole part -1. + *

    + * + * @return the whole fraction part of a proper fraction, that includes the sign + */ + public int getProperWhole() { + return numerator / denominator; + } + + /** + * Gets a hashCode for the fraction. + * + * @return a hash code value for this object + */ + @Override + public int hashCode() { + if (hashCode == 0) { + // hash code update should be atomic. + hashCode = Objects.hash(denominator, numerator); + } + return hashCode; + } + + /** + * Gets the fraction as an {@code int}. This returns the whole number + * part of the fraction. + * + * @return the whole number fraction part + */ + @Override + public int intValue() { + return numerator / denominator; + } + + /** + * Gets a fraction that is the inverse (1/fraction) of this one. + *

    + * The returned fraction is not reduced. + *

    + * + * @return a new fraction instance with the numerator and denominator inverted. + * @throws ArithmeticException if the fraction represents zero. + */ + public Fraction invert() { + if (numerator == 0) { + throw new ArithmeticException("Unable to invert zero."); + } + if (numerator == Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: can't negate numerator"); + } + if (numerator < 0) { + return new Fraction(-denominator, -numerator); + } + return new Fraction(denominator, numerator); + } + + /** + * Gets the fraction as a {@code long}. This returns the whole number + * part of the fraction. + * + * @return the whole number fraction part + */ + @Override + public long longValue() { + return (long) numerator / denominator; + } + + /** + * Multiplies the value of this fraction by another, returning the + * result in reduced form. + * + * @param fraction the fraction to multiply by, must not be {@code null} + * @return a {@link Fraction} instance with the resulting values + * @throws NullPointerException if the fraction is {@code null} + * @throws ArithmeticException if the resulting numerator or denominator exceeds + * {@code Integer.MAX_VALUE} + */ + public Fraction multiplyBy(final Fraction fraction) { + Objects.requireNonNull(fraction, "fraction"); + if (numerator == 0 || fraction.numerator == 0) { + return ZERO; + } + // knuth 4.5.1 + // make sure we don't overflow unless the result *must* overflow. + final int d1 = greatestCommonDivisor(numerator, fraction.denominator); + final int d2 = greatestCommonDivisor(fraction.numerator, denominator); + return getReducedFraction(mulAndCheck(numerator / d1, fraction.numerator / d2), mulPosAndCheck(denominator / d2, fraction.denominator / d1)); + } + + /** + * Gets a fraction that is the negative (-fraction) of this one. + *

    + * The returned fraction is not reduced. + *

    + * + * @return a new fraction instance with the opposite signed numerator + */ + public Fraction negate() { + // the positive range is one smaller than the negative range of an int. + if (numerator == Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: too large to negate"); + } + return new Fraction(-numerator, denominator); + } + + /** + * Gets a fraction that is raised to the passed in power. + *

    + * The returned fraction is in reduced form. + *

    + * + * @param power the power to raise the fraction to + * @return {@code this} if the power is one, {@link #ONE} if the power is zero (even if the fraction equals ZERO) or a new fraction instance raised to the + * appropriate power + * @throws ArithmeticException if the resulting numerator or denominator exceeds {@code Integer.MAX_VALUE} + */ + public Fraction pow(final int power) { + if (power == 1) { + return this; + } + if (power == 0) { + return ONE; + } + if (power < 0) { + if (power == Integer.MIN_VALUE) { // MIN_VALUE can't be negated. + return invert().pow(2).pow(-(power / 2)); + } + return invert().pow(-power); + } + final Fraction f = multiplyBy(this); + if (power % 2 == 0) { // if even... + return f.pow(power / 2); + } + return f.pow(power / 2).multiplyBy(this); + } + + /** + * Reduce the fraction to the smallest values for the numerator and denominator, returning the result. + *

    + * For example, if this fraction represents 2/4, then the result will be 1/2. + *

    + * + * @return a new reduced fraction instance, or this if no simplification possible + */ + public Fraction reduce() { + if (numerator == 0) { + return equals(ZERO) ? this : ZERO; + } + final int gcd = greatestCommonDivisor(Math.abs(numerator), denominator); + if (gcd == 1) { + return this; + } + return getFraction(numerator / gcd, denominator / gcd); + } + + /** + * Subtracts the value of another fraction from the value of this one, + * returning the result in reduced form. + * + * @param fraction the fraction to subtract, must not be {@code null} + * @return a {@link Fraction} instance with the resulting values + * @throws NullPointerException if the fraction is {@code null} + * @throws ArithmeticException if the resulting numerator or denominator + * cannot be represented in an {@code int}. + */ + public Fraction subtract(final Fraction fraction) { + return addSub(fraction, false /* subtract */); + } + + /** + * Gets the fraction as a proper {@link String} in the format X Y/Z. + *

    + * The format used in 'wholeNumber numerator/denominator'. If the whole number is zero it will be omitted. If the numerator is + * zero, only the whole number is returned. + *

    + * + * @return a {@link String} form of the fraction + */ + public String toProperString() { + if (toProperString == null) { + if (numerator == 0) { + toProperString = "0"; + } else if (numerator == denominator) { + toProperString = "1"; + } else if (numerator == -1 * denominator) { + toProperString = "-1"; + } else if ((numerator > 0 ? -numerator : numerator) < -denominator) { + // note that we do the magnitude comparison test above with + // NEGATIVE (not positive) numbers, since negative numbers + // have a larger range. otherwise numerator == Integer.MIN_VALUE + // is handled incorrectly. + final int properNumerator = getProperNumerator(); + if (properNumerator == 0) { + toProperString = Integer.toString(getProperWhole()); + } else { + toProperString = getProperWhole() + " " + properNumerator + "/" + getDenominator(); + } + } else { + toProperString = getNumerator() + "/" + getDenominator(); + } + } + return toProperString; + } + + /** + * Gets the fraction as a {@link String}. + *

    + * The format used is 'numerator/denominator' always. + *

    + * + * @return a {@link String} form of the fraction + */ + @Override + public String toString() { + if (toString == null) { + toString = getNumerator() + "/" + getDenominator(); + } + return toString; + } +} \ No newline at end of file From b52d76b3a7b2ae5b961ebac53942d0b670b7db72 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 11 Jul 2025 07:59:11 +0200 Subject: [PATCH 393/399] Use adventure if available Fixes #897 --- pom.xml | 6 + .../java/de/diddiz/LogBlock/BlockChange.java | 198 +++++++-------- .../java/de/diddiz/LogBlock/ChatMessage.java | 19 +- .../de/diddiz/LogBlock/CommandsHandler.java | 65 +++-- .../java/de/diddiz/LogBlock/EntityChange.java | 52 ++-- src/main/java/de/diddiz/LogBlock/Kill.java | 28 +- .../diddiz/LogBlock/LookupCacheElement.java | 6 +- .../diddiz/LogBlock/SummedBlockChanges.java | 8 +- .../diddiz/LogBlock/SummedEntityChanges.java | 8 +- .../java/de/diddiz/LogBlock/SummedKills.java | 8 +- .../java/de/diddiz/LogBlock/WorldEditor.java | 11 +- .../LogBlock/blockstate/BlockStateCodec.java | 4 +- .../blockstate/BlockStateCodecBanner.java | 4 +- .../blockstate/BlockStateCodecLectern.java | 10 +- .../blockstate/BlockStateCodecShulkerBox.java | 8 +- .../blockstate/BlockStateCodecSign.java | 72 +++--- .../blockstate/BlockStateCodecSkull.java | 15 +- .../blockstate/BlockStateCodecSpawner.java | 8 +- .../LogBlock/blockstate/BlockStateCodecs.java | 4 +- .../LogBlock/componentwrapper/ChatColor.java | 54 ++++ .../LogBlock/componentwrapper/Click.java | 7 + .../LogBlock/componentwrapper/Component.java | 63 +++++ .../LogBlock/componentwrapper/Components.java | 239 ++++++++++++++++++ .../LogBlock/componentwrapper/Hover.java | 17 ++ .../LogBlock/componentwrapper/ItemHover.java | 15 ++ .../componentwrapper/RunCommandClick.java | 13 + .../componentwrapper/TextComponent.java | 41 +++ .../LogBlock/componentwrapper/TextHover.java | 13 + .../de/diddiz/LogBlock/util/ActionColor.java | 2 +- .../de/diddiz/LogBlock/util/BukkitUtils.java | 25 +- .../diddiz/LogBlock/util/MessagingUtil.java | 87 +++---- .../de/diddiz/LogBlock/util/TypeColor.java | 2 +- 32 files changed, 785 insertions(+), 327 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/componentwrapper/ChatColor.java create mode 100644 src/main/java/de/diddiz/LogBlock/componentwrapper/Click.java create mode 100644 src/main/java/de/diddiz/LogBlock/componentwrapper/Component.java create mode 100644 src/main/java/de/diddiz/LogBlock/componentwrapper/Components.java create mode 100644 src/main/java/de/diddiz/LogBlock/componentwrapper/Hover.java create mode 100644 src/main/java/de/diddiz/LogBlock/componentwrapper/ItemHover.java create mode 100644 src/main/java/de/diddiz/LogBlock/componentwrapper/RunCommandClick.java create mode 100644 src/main/java/de/diddiz/LogBlock/componentwrapper/TextComponent.java create mode 100644 src/main/java/de/diddiz/LogBlock/componentwrapper/TextHover.java diff --git a/pom.xml b/pom.xml index 5c5d8265..248b6b56 100644 --- a/pom.xml +++ b/pom.xml @@ -59,6 +59,12 @@ 7.1.0-SNAPSHOT provided
    + + net.kyori + adventure-api + 4.23.0 + provided + junit junit diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 8cc33285..054206d9 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -11,14 +11,14 @@ import static de.diddiz.LogBlock.util.TypeColor.DEFAULT; import de.diddiz.LogBlock.blockstate.BlockStateCodecs; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; 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; import java.util.logging.Level; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Note; @@ -83,12 +83,12 @@ public BlockChange(ResultSet rs, QueryParams p) throws SQLException { ca = catemp; } - private BaseComponent getTypeDetails(BlockData type, byte[] typeState) { + private Component getTypeDetails(BlockData type, byte[] typeState) { return getTypeDetails(type, typeState, null, null); } - private BaseComponent getTypeDetails(BlockData type, byte[] typeState, BlockData oldType, byte[] oldTypeState) { - BaseComponent typeDetails = null; + private Component getTypeDetails(BlockData type, byte[] typeState, BlockData oldType, byte[] oldTypeState) { + Component typeDetails = null; if (BlockStateCodecs.hasCodec(type.getMaterial())) { try { @@ -99,160 +99,160 @@ private BaseComponent getTypeDetails(BlockData type, byte[] typeState, BlockData } if (typeDetails == null) { - return new TextComponent(""); + return Components.empty(); } else { - TextComponent component = new TextComponent(" "); - component.addExtra(typeDetails); + Component component = Components.space(); + component = component.append(typeDetails); return component; } } @Override public String toString() { - return BaseComponent.toPlainText(getLogMessage(-1)); + return Components.toPlainText(getLogMessage(-1)); } @Override - public BaseComponent getLogMessage(int entry) { - TextComponent msg = new TextComponent(); + public Component getLogMessage(int entry) { + Component msg = Components.empty(); if (date > 0) { - msg.addExtra(prettyDate(date)); - msg.addExtra(" "); + msg = msg.append(prettyDate(date)); + msg = msg.append(" "); } if (actor != null) { - msg.addExtra(actor.getName()); - msg.addExtra(" "); + msg = msg.append(actor.getName()); + msg = msg.append(" "); } BlockData type = getBlockSet(); BlockData replaced = getBlockReplaced(); if (type == null || replaced == null) { - msg.addExtra("did an unknown block modification"); + msg = msg.append("did an unknown block modification"); return msg; } // Process type details once for later use. - BaseComponent typeDetails = getTypeDetails(type, typeState, replaced, replacedState); - BaseComponent replacedDetails = getTypeDetails(replaced, replacedState); + Component typeDetails = getTypeDetails(type, typeState, replaced, replacedState); + Component replacedDetails = getTypeDetails(replaced, replacedState); if (type.getMaterial().equals(replaced.getMaterial()) || (type.getMaterial() == Material.CAKE && BukkitUtils.isCandleCake(replaced.getMaterial()))) { if (BukkitUtils.isEmpty(type.getMaterial())) { - msg.addExtra(createTextComponentWithColor("did an unspecified action", INTERACT.getColor())); + msg = msg.append(createTextComponentWithColor("did an unspecified action", INTERACT.getColor())); } else if (ca != null) { if (ca.itemStack == null) { - msg.addExtra(createTextComponentWithColor("looked inside ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor("looked inside ", INTERACT.getColor())); + msg = msg.append(prettyMaterial(type)); } else if (ca.remove) { - msg.addExtra(createTextComponentWithColor("took ", DESTROY.getColor())); - msg.addExtra(BukkitUtils.toString(ca.itemStack)); - msg.addExtra(createTextComponentWithColor(" from ", DESTROY.getColor())); - msg.addExtra(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor("took ", DESTROY.getColor())); + msg = msg.append(BukkitUtils.toString(ca.itemStack)); + msg = msg.append(createTextComponentWithColor(" from ", DESTROY.getColor())); + msg = msg.append(prettyMaterial(type)); } else { - msg.addExtra(createTextComponentWithColor("put ", CREATE.getColor())); - msg.addExtra(BukkitUtils.toString(ca.itemStack)); - msg.addExtra(createTextComponentWithColor(" into ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor("put ", CREATE.getColor())); + msg = msg.append(BukkitUtils.toString(ca.itemStack)); + msg = msg.append(createTextComponentWithColor(" into ", CREATE.getColor())); + msg = msg.append(prettyMaterial(type)); } } else if (type instanceof Waterlogged && ((Waterlogged) type).isWaterlogged() != ((Waterlogged) replaced).isWaterlogged()) { if (((Waterlogged) type).isWaterlogged()) { - msg.addExtra(createTextComponentWithColor("waterlogged ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor("waterlogged ", CREATE.getColor())); + msg = msg.append(prettyMaterial(type)); } else { - msg.addExtra(createTextComponentWithColor("dried ", DESTROY.getColor())); - msg.addExtra(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor("dried ", DESTROY.getColor())); + msg = msg.append(prettyMaterial(type)); } } else if (BukkitUtils.isContainerBlock(type.getMaterial())) { - msg.addExtra(createTextComponentWithColor("opened ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor("opened ", INTERACT.getColor())); + msg = msg.append(prettyMaterial(type)); } else if (type instanceof Openable && ((Openable) type).isOpen() != ((Openable) replaced).isOpen()) { // Door, Trapdoor, Fence gate - msg.addExtra(createTextComponentWithColor(((Openable) type).isOpen() ? "opened " : "closed ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor(((Openable) type).isOpen() ? "opened " : "closed ", INTERACT.getColor())); + msg = msg.append(prettyMaterial(type)); } else if (type.getMaterial() == Material.LEVER && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) { - msg.addExtra(createTextComponentWithColor("switched ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(prettyState(((Switch) type).isPowered() ? " on" : " off")); + msg = msg.append(createTextComponentWithColor("switched ", INTERACT.getColor())); + msg = msg.append(prettyMaterial(type)); + msg = msg.append(prettyState(((Switch) type).isPowered() ? " on" : " off")); } else if (type instanceof Switch && ((Switch) type).isPowered() != ((Switch) replaced).isPowered()) { - msg.addExtra(createTextComponentWithColor("pressed ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor("pressed ", INTERACT.getColor())); + msg = msg.append(prettyMaterial(type)); } else if (type.getMaterial() == Material.CAKE) { - msg.addExtra(createTextComponentWithColor("ate a piece of ", DESTROY.getColor())); - msg.addExtra(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor("ate a piece of ", DESTROY.getColor())); + msg = msg.append(prettyMaterial(type)); } else if (type.getMaterial() == Material.NOTE_BLOCK) { Note note = ((NoteBlock) type).getNote(); - msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(" to "); - msg.addExtra(prettyState(note.getTone().name() + (note.isSharped() ? "#" : ""))); + msg = msg.append(createTextComponentWithColor("set ", INTERACT.getColor())); + msg = msg.append(prettyMaterial(type)); + msg = msg.append(" to "); + msg = msg.append(prettyState(note.getTone().name() + (note.isSharped() ? "#" : ""))); } else if (type.getMaterial() == Material.REPEATER) { - msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(" to "); - msg.addExtra(prettyState(((Repeater) type).getDelay())); - msg.addExtra(createTextComponentWithColor(" ticks delay", DEFAULT.getColor())); + msg = msg.append(createTextComponentWithColor("set ", INTERACT.getColor())); + msg = msg.append(prettyMaterial(type)); + msg = msg.append(" to "); + msg = msg.append(prettyState(((Repeater) type).getDelay())); + msg = msg.append(createTextComponentWithColor(" ticks delay", DEFAULT.getColor())); } else if (type.getMaterial() == Material.COMPARATOR) { - msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(" to "); - msg.addExtra(prettyState(((Comparator) type).getMode())); + msg = msg.append(createTextComponentWithColor("set ", INTERACT.getColor())); + msg = msg.append(prettyMaterial(type)); + msg = msg.append(" to "); + msg = msg.append(prettyState(((Comparator) type).getMode())); } else if (type.getMaterial() == Material.DAYLIGHT_DETECTOR) { - msg.addExtra(createTextComponentWithColor("set ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(" to "); - msg.addExtra(prettyState(((DaylightDetector) type).isInverted() ? "inverted" : "normal")); + msg = msg.append(createTextComponentWithColor("set ", INTERACT.getColor())); + msg = msg.append(prettyMaterial(type)); + msg = msg.append(" to "); + msg = msg.append(prettyState(((DaylightDetector) type).isInverted() ? "inverted" : "normal")); } else if (type instanceof Lectern) { - msg.addExtra(createTextComponentWithColor("changed the book on a ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(" to"); - msg.addExtra(prettyState(typeDetails)); + msg = msg.append(createTextComponentWithColor("changed the book on a ", INTERACT.getColor())); + msg = msg.append(prettyMaterial(type)); + msg = msg.append(" to"); + msg = msg.append(prettyState(typeDetails)); } else if (type instanceof Powerable) { - msg.addExtra(createTextComponentWithColor("stepped on ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor("stepped on ", INTERACT.getColor())); + msg = msg.append(prettyMaterial(type)); } else if (type.getMaterial() == Material.TRIPWIRE) { - msg.addExtra(createTextComponentWithColor("ran into ", INTERACT.getColor())); - msg.addExtra(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor("ran into ", INTERACT.getColor())); + msg = msg.append(prettyMaterial(type)); } else if (type instanceof Sign || type instanceof WallSign) { - msg.addExtra(createTextComponentWithColor("edited a ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(createTextComponentWithColor(" to", CREATE.getColor())); - msg.addExtra(prettyState(typeDetails)); + msg = msg.append(createTextComponentWithColor("edited a ", CREATE.getColor())); + msg = msg.append(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor(" to", CREATE.getColor())); + msg = msg.append(prettyState(typeDetails)); } else if (type instanceof Candle && ((Candle) type).getCandles() != ((Candle) replaced).getCandles()) { - msg.addExtra(createTextComponentWithColor("added a candle to ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor("added a candle to ", CREATE.getColor())); + msg = msg.append(prettyMaterial(type)); } else if ((type instanceof Candle || BukkitUtils.isCandleCake(type.getMaterial())) && ((Lightable) type).isLit() != ((Lightable) replaced).isLit()) { if (((Lightable) type).isLit()) { - msg.addExtra(createTextComponentWithColor("lit a ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor("lit a ", CREATE.getColor())); + msg = msg.append(prettyMaterial(type)); } else { - msg.addExtra(createTextComponentWithColor("extinguished a ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); + msg = msg.append(createTextComponentWithColor("extinguished a ", CREATE.getColor())); + msg = msg.append(prettyMaterial(type)); } } else { - msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor())); - msg.addExtra(prettyMaterial(replaced)); - msg.addExtra(prettyState(replacedDetails)); - msg.addExtra(createTextComponentWithColor(" with ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(prettyState(typeDetails)); + msg = msg.append(createTextComponentWithColor("replaced ", CREATE.getColor())); + msg = msg.append(prettyMaterial(replaced)); + msg = msg.append(prettyState(replacedDetails)); + msg = msg.append(createTextComponentWithColor(" with ", CREATE.getColor())); + msg = msg.append(prettyMaterial(type)); + msg = msg.append(prettyState(typeDetails)); } } else if (BukkitUtils.isEmpty(type.getMaterial())) { - msg.addExtra(createTextComponentWithColor("destroyed ", DESTROY.getColor())); - msg.addExtra(prettyMaterial(replaced)); - msg.addExtra(prettyState(replacedDetails)); + msg = msg.append(createTextComponentWithColor("destroyed ", DESTROY.getColor())); + msg = msg.append(prettyMaterial(replaced)); + msg = msg.append(prettyState(replacedDetails)); } else if (BukkitUtils.isEmpty(replaced.getMaterial())) { - msg.addExtra(createTextComponentWithColor("created ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(prettyState(typeDetails)); + msg = msg.append(createTextComponentWithColor("created ", CREATE.getColor())); + msg = msg.append(prettyMaterial(type)); + msg = msg.append(prettyState(typeDetails)); } else { - msg.addExtra(createTextComponentWithColor("replaced ", CREATE.getColor())); - msg.addExtra(prettyMaterial(replaced)); - msg.addExtra(prettyState(replacedDetails)); - msg.addExtra(createTextComponentWithColor(" with ", CREATE.getColor())); - msg.addExtra(prettyMaterial(type)); - msg.addExtra(prettyState(typeDetails)); + msg = msg.append(createTextComponentWithColor("replaced ", CREATE.getColor())); + msg = msg.append(prettyMaterial(replaced)); + msg = msg.append(prettyState(replacedDetails)); + msg = msg.append(createTextComponentWithColor(" with ", CREATE.getColor())); + msg = msg.append(prettyMaterial(type)); + msg = msg.append(prettyState(typeDetails)); } if (loc != null) { - msg.addExtra(" at "); - msg.addExtra(prettyLocation(loc, entry)); + msg = msg.append(" at "); + msg = msg.append(prettyLocation(loc, entry)); } return msg; } diff --git a/src/main/java/de/diddiz/LogBlock/ChatMessage.java b/src/main/java/de/diddiz/LogBlock/ChatMessage.java index e7ccc1c7..eec06798 100644 --- a/src/main/java/de/diddiz/LogBlock/ChatMessage.java +++ b/src/main/java/de/diddiz/LogBlock/ChatMessage.java @@ -4,12 +4,13 @@ import static de.diddiz.LogBlock.util.MessagingUtil.brackets; import static de.diddiz.LogBlock.util.MessagingUtil.prettyDate; +import de.diddiz.LogBlock.componentwrapper.ChatColor; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; import de.diddiz.LogBlock.util.MessagingUtil; import de.diddiz.LogBlock.util.MessagingUtil.BracketType; import java.sql.ResultSet; import java.sql.SQLException; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Location; public class ChatMessage implements LookupCacheElement { @@ -39,18 +40,18 @@ public Location getLocation() { } @Override - public BaseComponent getLogMessage(int entry) { - TextComponent msg = new TextComponent(); + public Component getLogMessage(int entry) { + Component msg = Components.empty(); if (date > 0) { - msg.addExtra(prettyDate(date)); - msg.addExtra(" "); + msg = msg.append(prettyDate(date)); + msg = msg.append(" "); } if (playerName != null) { - msg.addExtra(brackets(BracketType.ANGLE, MessagingUtil.createTextComponentWithColor(playerName, net.md_5.bungee.api.ChatColor.WHITE))); - msg.addExtra(" "); + msg = msg.append(brackets(BracketType.ANGLE, MessagingUtil.createTextComponentWithColor(playerName, ChatColor.WHITE))); + msg = msg.append(" "); } if (message != null) { - msg.addExtra(TextComponent.fromLegacy(message)); + msg = msg.append(Components.fromLegacy(message)); } return msg; } diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 2a57c5ae..a1070c5f 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -25,6 +25,9 @@ import de.diddiz.LogBlock.QueryParams.BlockChangeType; import de.diddiz.LogBlock.QueryParams.Order; import de.diddiz.LogBlock.QueryParams.SummarizationMode; +import de.diddiz.LogBlock.componentwrapper.Click; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.LogBlock.util.MessagingUtil; @@ -44,9 +47,6 @@ import java.util.Arrays; import java.util.List; import java.util.logging.Level; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.ClickEvent; -import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.ChatColor; import org.bukkit.GameMode; import org.bukkit.Location; @@ -73,34 +73,34 @@ public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, if (args.length == 0) { sender.sendMessage(ChatColor.YELLOW + "------------------[ " + ChatColor.WHITE + "LogBlock" + ChatColor.YELLOW + " ]-------------------"); sender.sendMessage(ChatColor.GOLD + "LogBlock " + ChatColor.WHITE + "v" + logblock.getDescription().getVersion() + ChatColor.GOLD + " by DiddiZ"); - TextComponent message = MessagingUtil.createTextComponentWithColor("Type ", net.md_5.bungee.api.ChatColor.GOLD); - TextComponent clickable = MessagingUtil.createTextComponentWithColor("/lb help", net.md_5.bungee.api.ChatColor.WHITE); - clickable.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/lb help")); - message.addExtra(clickable); - message.addExtra(" for help"); - sender.spigot().sendMessage(message); + Component message = MessagingUtil.createTextComponentWithColor("Type ", de.diddiz.LogBlock.componentwrapper.ChatColor.GOLD); + Component clickable = MessagingUtil.createTextComponentWithColor("/lb help", de.diddiz.LogBlock.componentwrapper.ChatColor.WHITE); + clickable = clickable.click(Click.run("/lb help")); + message = message.append(clickable); + message = message.append(" for help"); + Components.sendTo(sender, message); } else { final String command = args[0].toLowerCase(); if (command.equals("help")) { sender.sendMessage(ChatColor.YELLOW + "----------------[ " + ChatColor.WHITE + "LogBlock Help" + ChatColor.YELLOW + " ]----------------"); - TextComponent message = MessagingUtil.createTextComponentWithColor("For the commands list type ", net.md_5.bungee.api.ChatColor.GOLD); - TextComponent clickable = MessagingUtil.createTextComponentWithColor("/lb commands", net.md_5.bungee.api.ChatColor.WHITE); - clickable.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/lb commands")); - message.addExtra(clickable); - sender.spigot().sendMessage(message); + Component message = MessagingUtil.createTextComponentWithColor("For the commands list type ", de.diddiz.LogBlock.componentwrapper.ChatColor.GOLD); + Component clickable = MessagingUtil.createTextComponentWithColor("/lb commands", de.diddiz.LogBlock.componentwrapper.ChatColor.WHITE); + clickable = clickable.click(Click.run("/lb commands")); + message = message.append(clickable); + Components.sendTo(sender, message); - message = MessagingUtil.createTextComponentWithColor("For the parameters list type ", net.md_5.bungee.api.ChatColor.GOLD); - clickable = MessagingUtil.createTextComponentWithColor("/lb params", net.md_5.bungee.api.ChatColor.WHITE); - clickable.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/lb params")); - message.addExtra(clickable); - sender.spigot().sendMessage(message); + message = MessagingUtil.createTextComponentWithColor("For the parameters list type ", de.diddiz.LogBlock.componentwrapper.ChatColor.GOLD); + clickable = MessagingUtil.createTextComponentWithColor("/lb params", de.diddiz.LogBlock.componentwrapper.ChatColor.WHITE); + clickable = clickable.click(Click.run("/lb params")); + message = message.append(clickable); + Components.sendTo(sender, message); - message = MessagingUtil.createTextComponentWithColor("For the list of permissions you got type ", net.md_5.bungee.api.ChatColor.GOLD); - clickable = MessagingUtil.createTextComponentWithColor("/lb permissions", net.md_5.bungee.api.ChatColor.WHITE); - clickable.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/lb permissions")); - message.addExtra(clickable); - sender.spigot().sendMessage(message); + message = MessagingUtil.createTextComponentWithColor("For the list of permissions you got type ", de.diddiz.LogBlock.componentwrapper.ChatColor.GOLD); + clickable = MessagingUtil.createTextComponentWithColor("/lb permissions", de.diddiz.LogBlock.componentwrapper.ChatColor.WHITE); + clickable = clickable.click(Click.run("/lb permissions")); + message = message.append(clickable); + Components.sendTo(sender, message); } else if (command.equals("commands")) { sender.sendMessage(ChatColor.YELLOW + "--------------[ " + ChatColor.WHITE + "LogBlock Commands" + ChatColor.YELLOW + " ]--------------"); sender.sendMessage(ChatColor.GOLD + "/lb tool " + ChatColor.WHITE + "-- Gives you the lb tool"); @@ -435,25 +435,24 @@ private static void showPage(CommandSender sender, int page, LookupCacheElement[ final int stoppos = startpos + linesPerPage >= lookupElements.length ? lookupElements.length - 1 : startpos + linesPerPage - 1; final int numberOfPages = (int) Math.ceil(lookupElements.length / (double) linesPerPage); if (numberOfPages != 1) { - sender.sendMessage(HEADER + "Page " + page + "/" + numberOfPages); + Components.sendTo(sender, Components.text("Page " + page + "/" + numberOfPages, HEADER.getColor())); } for (int i = startpos; i <= stoppos; i++) { - TextComponent message = new TextComponent(); - message.setColor(DEFAULT.getColor()); + Component message = Components.text("", DEFAULT.getColor()); if (lookupElements[i].getLocation() != null) { - message.addExtra(new TextComponent("(" + (i + 1) + ") ")); + message = message.append(Components.text("(" + (i + 1) + ") ")); } - message.addExtra(lookupElements[i].getLogMessage(i + 1)); - sender.spigot().sendMessage(message); + message = message.append(lookupElements[i].getLogMessage(i + 1)); + Components.sendTo(sender, message); } if (setSessionPage) { getSession(sender).page = page; } } else { - sender.sendMessage(ERROR + "There isn't a page '" + page + "'"); + Components.sendTo(sender, Components.text("There isn't a page '" + page + "'", ERROR.getColor())); } } else { - sender.sendMessage(ERROR + "No blocks in lookup cache"); + Components.sendTo(sender, Components.text("No blocks in lookup cache", ERROR.getColor())); } } @@ -640,7 +639,7 @@ public void run() { } final LookupCacheElementFactory factory = new LookupCacheElementFactory(params, sender instanceof Player ? 2 / 3f : 1); while (rs.next()) { - writer.write(BaseComponent.toPlainText(factory.getLookupCacheElement(rs).getLogMessage()) + newline); + writer.write(Components.toPlainText(factory.getLookupCacheElement(rs).getLogMessage()) + newline); counter++; } writer.close(); diff --git a/src/main/java/de/diddiz/LogBlock/EntityChange.java b/src/main/java/de/diddiz/LogBlock/EntityChange.java index 385b9ba2..59d5f175 100644 --- a/src/main/java/de/diddiz/LogBlock/EntityChange.java +++ b/src/main/java/de/diddiz/LogBlock/EntityChange.java @@ -9,12 +9,12 @@ import static de.diddiz.LogBlock.util.MessagingUtil.prettyLocation; import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; import de.diddiz.LogBlock.util.Utils; import java.sql.ResultSet; import java.sql.SQLException; import java.util.UUID; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Location; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.ArmorStand; @@ -73,60 +73,60 @@ public EntityChange(ResultSet rs, QueryParams p) throws SQLException { @Override public String toString() { - return BaseComponent.toPlainText(getLogMessage()); + return Components.toPlainText(getLogMessage()); } @Override - public BaseComponent getLogMessage(int entry) { - TextComponent msg = new TextComponent(); + public Component getLogMessage(int entry) { + Component msg = Components.empty(); if (date > 0) { - msg.addExtra(prettyDate(date)); - msg.addExtra(" "); + msg = msg.append(prettyDate(date)); + msg = msg.append(" "); } if (actor != null) { - msg.addExtra(actor.getName()); - msg.addExtra(" "); + msg = msg.append(actor.getName()); + msg = msg.append(" "); } if (changeType == EntityChangeType.CREATE) { - msg.addExtra(createTextComponentWithColor("created ", CREATE.getColor())); + msg = msg.append(createTextComponentWithColor("created ", CREATE.getColor())); } else if (changeType == EntityChangeType.KILL) { boolean living = type != null && LivingEntity.class.isAssignableFrom(type.getEntityClass()) && !ArmorStand.class.isAssignableFrom(type.getDeclaringClass()); - msg.addExtra(createTextComponentWithColor(living ? "killed " : "destroyed ", DESTROY.getColor())); + msg = msg.append(createTextComponentWithColor(living ? "killed " : "destroyed ", DESTROY.getColor())); } else if (changeType == EntityChangeType.ADDEQUIP) { YamlConfiguration conf = Utils.deserializeYamlConfiguration(data); ItemStack stack = conf == null ? null : conf.getItemStack("item"); if (stack == null) { - msg.addExtra(createTextComponentWithColor("added an item to ", CREATE.getColor())); + msg = msg.append(createTextComponentWithColor("added an item to ", CREATE.getColor())); } else { - msg.addExtra(createTextComponentWithColor("added ", CREATE.getColor())); - msg.addExtra(prettyMaterial(stack.getType())); - msg.addExtra(" to "); + msg = msg.append(createTextComponentWithColor("added ", CREATE.getColor())); + msg = msg.append(prettyMaterial(stack.getType())); + msg = msg.append(" to "); } } else if (changeType == EntityChangeType.REMOVEEQUIP) { YamlConfiguration conf = Utils.deserializeYamlConfiguration(data); ItemStack stack = conf == null ? null : conf.getItemStack("item"); if (stack == null) { - msg.addExtra(createTextComponentWithColor("removed an item from ", DESTROY.getColor())); + msg = msg.append(createTextComponentWithColor("removed an item from ", DESTROY.getColor())); } else { - msg.addExtra(createTextComponentWithColor("removed ", DESTROY.getColor())); - msg.addExtra(prettyMaterial(stack.getType())); - msg.addExtra(" from "); + msg = msg.append(createTextComponentWithColor("removed ", DESTROY.getColor())); + msg = msg.append(prettyMaterial(stack.getType())); + msg = msg.append(" from "); } } else if (changeType == EntityChangeType.MODIFY) { - msg.addExtra(createTextComponentWithColor("modified ", INTERACT.getColor())); + msg = msg.append(createTextComponentWithColor("modified ", INTERACT.getColor())); } else if (changeType == EntityChangeType.GET_STUNG) { - msg.addExtra(createTextComponentWithColor("got stung by ", DESTROY.getColor())); + msg = msg.append(createTextComponentWithColor("got stung by ", DESTROY.getColor())); } else { - msg.addExtra(createTextComponentWithColor("did an unknown action to ", INTERACT.getColor())); + msg = msg.append(createTextComponentWithColor("did an unknown action to ", INTERACT.getColor())); } if (type != null) { - msg.addExtra(prettyEntityType(type)); + msg = msg.append(prettyEntityType(type)); } else { - msg.addExtra(prettyMaterial("an unknown entity")); + msg = msg.append(prettyMaterial("an unknown entity")); } if (loc != null) { - msg.addExtra(" at "); - msg.addExtra(prettyLocation(loc, entry)); + msg = msg.append(" at "); + msg = msg.append(prettyLocation(loc, entry)); } return msg; } diff --git a/src/main/java/de/diddiz/LogBlock/Kill.java b/src/main/java/de/diddiz/LogBlock/Kill.java index ff6287eb..7da36b75 100755 --- a/src/main/java/de/diddiz/LogBlock/Kill.java +++ b/src/main/java/de/diddiz/LogBlock/Kill.java @@ -5,12 +5,12 @@ import static de.diddiz.LogBlock.util.MessagingUtil.prettyLocation; import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; import de.diddiz.LogBlock.util.BukkitUtils; import de.diddiz.LogBlock.util.MessagingUtil; import java.sql.ResultSet; import java.sql.SQLException; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Location; import org.bukkit.Material; @@ -40,7 +40,7 @@ public Kill(ResultSet rs, QueryParams p) throws SQLException { @Override public String toString() { - return BaseComponent.toPlainText(getLogMessage()); + return Components.toPlainText(getLogMessage()); } @Override @@ -49,26 +49,26 @@ public Location getLocation() { } @Override - public BaseComponent getLogMessage(int entry) { - TextComponent msg = new TextComponent(); + public Component getLogMessage(int entry) { + Component msg = Components.empty(); if (date > 0) { - msg.addExtra(prettyDate(date)); - msg.addExtra(" "); + msg = msg.append(prettyDate(date)); + msg = msg.append(" "); } - msg.addExtra(MessagingUtil.createTextComponentWithColor(killerName + " killed ", DESTROY.getColor())); - msg.addExtra(new TextComponent(victimName)); + msg = msg.append(MessagingUtil.createTextComponentWithColor(killerName + " killed ", DESTROY.getColor())); + msg = msg.append(Components.text(victimName)); if (loc != null) { - msg.addExtra(" at "); - msg.addExtra(prettyLocation(loc, entry)); + msg = msg.append(" at "); + msg = msg.append(prettyLocation(loc, entry)); } if (weapon != 0) { - msg.addExtra(" with "); - msg.addExtra(prettyItemName(MaterialConverter.getMaterial(weapon))); + msg = msg.append(" with "); + msg = msg.append(prettyItemName(MaterialConverter.getMaterial(weapon))); } return msg; } - public TextComponent prettyItemName(Material t) { + public Component prettyItemName(Material t) { if (t == null || BukkitUtils.isEmpty(t)) { return prettyMaterial("fist"); } diff --git a/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java b/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java index 88fc1c25..ae072b5f 100644 --- a/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java +++ b/src/main/java/de/diddiz/LogBlock/LookupCacheElement.java @@ -1,16 +1,16 @@ package de.diddiz.LogBlock; -import net.md_5.bungee.api.chat.BaseComponent; +import de.diddiz.LogBlock.componentwrapper.Component; import org.bukkit.Location; public interface LookupCacheElement { public Location getLocation(); - public default BaseComponent getLogMessage() { + public default Component getLogMessage() { return getLogMessage(-1); } - public BaseComponent getLogMessage(int entry); + public Component getLogMessage(int entry); public default int getNumChanges() { return 1; diff --git a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java index 08dfe8dc..1549355d 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java @@ -3,12 +3,12 @@ import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; import de.diddiz.LogBlock.QueryParams.SummarizationMode; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; import de.diddiz.LogBlock.util.MessagingUtil; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Objects; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Location; public class SummedBlockChanges implements LookupCacheElement { @@ -32,8 +32,8 @@ public Location getLocation() { } @Override - 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); + public Component getLogMessage(int entry) { + return MessagingUtil.formatSummarizedChanges(created, destroyed, actor != null ? Components.text(actor.getName()) : prettyMaterial(Objects.toString(MaterialConverter.getMaterial(type))), 10, 10, spaceFactor); } @Override diff --git a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java index 015978ca..4e9d6bd6 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedEntityChanges.java @@ -3,14 +3,14 @@ import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; import de.diddiz.LogBlock.QueryParams.SummarizationMode; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; import de.diddiz.LogBlock.util.MessagingUtil; import org.bukkit.Location; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Objects; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; public class SummedEntityChanges implements LookupCacheElement { private final int type; @@ -33,8 +33,8 @@ public Location getLocation() { } @Override - 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); + public Component getLogMessage(int entry) { + return MessagingUtil.formatSummarizedChanges(created, destroyed, actor != null ? Components.text(actor.getName()) : prettyMaterial(Objects.toString(EntityTypeConverter.getEntityType(type))), 10, 10, spaceFactor); } @Override diff --git a/src/main/java/de/diddiz/LogBlock/SummedKills.java b/src/main/java/de/diddiz/LogBlock/SummedKills.java index 2e366e04..20cd14d9 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedKills.java +++ b/src/main/java/de/diddiz/LogBlock/SummedKills.java @@ -1,10 +1,10 @@ package de.diddiz.LogBlock; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; import de.diddiz.LogBlock.util.MessagingUtil; import java.sql.ResultSet; import java.sql.SQLException; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Location; public class SummedKills implements LookupCacheElement { @@ -25,8 +25,8 @@ public Location getLocation() { } @Override - public BaseComponent getLogMessage(int entry) { - return MessagingUtil.formatSummarizedChanges(kills, killed, new TextComponent(player.getName()), 6, 7, spaceFactor); + public Component getLogMessage(int entry) { + return MessagingUtil.formatSummarizedChanges(kills, killed, Components.text(player.getName()), 6, 7, spaceFactor); } @Override diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 8bb41a2c..1ba2431e 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -29,6 +29,8 @@ import de.diddiz.LogBlock.QueryParams.Order; import de.diddiz.LogBlock.blockstate.BlockStateCodecs; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; import de.diddiz.LogBlock.util.BukkitUtils; import de.diddiz.LogBlock.util.Utils; import de.diddiz.LogBlock.worldedit.WorldEditHelper; @@ -45,9 +47,6 @@ import java.util.List; import java.util.UUID; import java.util.logging.Level; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; - import static de.diddiz.LogBlock.config.Config.dontRollback; import static de.diddiz.LogBlock.config.Config.replaceAnyway; import static de.diddiz.LogBlock.util.BukkitUtils.*; @@ -194,7 +193,7 @@ public synchronized void run() { final File file = new File(errorDir, "WorldEditor-" + new SimpleDateFormat("yy-MM-dd-HH-mm-ss").format(System.currentTimeMillis()) + ".log"); final PrintWriter writer = new PrintWriter(file); for (final WorldEditorException err : errorList) { - writer.println(BaseComponent.toPlainText(err.getLogMessage())); + writer.println(Components.toPlainText(err.getLogMessage())); err.printStackTrace(writer); writer.println(); writer.println(); @@ -493,8 +492,8 @@ public Location getLocation() { } @Override - public BaseComponent getLogMessage(int entry) { - return TextComponent.fromLegacy(getMessage()); + public Component getLogMessage(int entry) { + return Components.fromLegacy(getMessage()); } } } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java index 65ed64b4..cfc86076 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodec.java @@ -1,6 +1,6 @@ package de.diddiz.LogBlock.blockstate; -import net.md_5.bungee.api.chat.BaseComponent; +import de.diddiz.LogBlock.componentwrapper.Component; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.configuration.file.YamlConfiguration; @@ -12,5 +12,5 @@ public interface BlockStateCodec { void deserialize(BlockState state, YamlConfiguration conf); - BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState); + Component getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState); } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java index 890c34d1..5a4b2ba2 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecBanner.java @@ -1,8 +1,8 @@ package de.diddiz.LogBlock.blockstate; +import de.diddiz.LogBlock.componentwrapper.Component; 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; @@ -75,7 +75,7 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { + public Component getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { return null; } } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java index 6c897bc4..4752dd3d 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecLectern.java @@ -1,7 +1,7 @@ package de.diddiz.LogBlock.blockstate; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.block.Lectern; @@ -45,10 +45,10 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { + public Component getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { if (conf != null) { - return new TextComponent("[book]"); + return Components.text("[book]"); } - return new TextComponent("empty"); + return Components.text("empty"); } } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java index 1325a862..70b2cd1a 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecShulkerBox.java @@ -3,10 +3,10 @@ import static de.diddiz.LogBlock.config.Config.getWorldConfig; import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.LogBlock.util.BukkitUtils; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.block.ShulkerBox; @@ -62,7 +62,7 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { + public Component getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { if (conf != null) { StringBuilder sb = new StringBuilder(); sb.append("["); @@ -80,7 +80,7 @@ public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfigura } } sb.append("]"); - return anySlot ? new TextComponent(sb.toString()) : null; + return anySlot ? Components.text(sb.toString()) : null; } return null; } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java index 442ffcb5..be42fa35 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSign.java @@ -1,13 +1,11 @@ package de.diddiz.LogBlock.blockstate; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; import de.diddiz.LogBlock.util.BukkitUtils; -import java.awt.Color; import java.util.Arrays; import java.util.Collections; import java.util.List; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.block.BlockState; @@ -133,14 +131,14 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public BaseComponent getChangesAsComponent(YamlConfiguration state, YamlConfiguration oldState) { + public Component getChangesAsComponent(YamlConfiguration state, YamlConfiguration oldState) { if (state != null) { - TextComponent tc = new TextComponent(); + Component tc = Components.empty(); // StringBuilder sb = new StringBuilder(); boolean isWaxed = state.getBoolean("waxed"); boolean oldWaxed = oldState != null && oldState.getBoolean("waxed"); if (isWaxed != oldWaxed) { - tc.addExtra(isWaxed ? "(waxed)" : "(not waxed)"); + tc = tc.append(isWaxed ? "(waxed)" : "(not waxed)"); } for (Side side : Side.values()) { boolean sideHeaderAdded = false; @@ -175,38 +173,46 @@ public BaseComponent getChangesAsComponent(YamlConfiguration state, YamlConfigur } if (!lines.equals(oldLines)) { - sideHeaderAdded = addSideHeaderText(tc, side, sideHeaderAdded); + if (!sideHeaderAdded) { + tc = addSideHeaderText(tc, side); + sideHeaderAdded = true; + } for (String line : lines) { - if (tc.getExtra() != null && !tc.getExtra().isEmpty()) { - tc.addExtra(" "); + if (!tc.getChildren().isEmpty()) { + tc = tc.append(Components.space()); } - tc.addExtra("["); + tc = tc.append("["); if (line != null && !line.isEmpty()) { - tc.addExtra(TextComponent.fromLegacy(line)); + tc = tc.append(Components.fromLegacy(line)); } - tc.addExtra("]"); + tc = tc.append("]"); } } if (signColor != oldSignColor) { - sideHeaderAdded = addSideHeaderText(tc, side, sideHeaderAdded); - if (tc.getExtra() != null && !tc.getExtra().isEmpty()) { - tc.addExtra(" "); - } - tc.addExtra("(color: "); - TextComponent colorText = new TextComponent(signColor.name().toLowerCase()); - colorText.setColor(ChatColor.of(new Color(signColor.getColor().asARGB()))); - tc.addExtra(colorText); - tc.addExtra(")"); + if (!sideHeaderAdded) { + tc = addSideHeaderText(tc, side); + sideHeaderAdded = true; + } + if (!tc.getChildren().isEmpty()) { + tc = tc.append(Components.space()); + } + tc = tc.append("(color: "); + Component colorText = Components.text(signColor.name().toLowerCase(), de.diddiz.LogBlock.componentwrapper.ChatColor.from(signColor.getColor().asARGB())); + tc = tc.append(colorText); + tc = tc.append(")"); } if (glowing != oldGlowing) { - sideHeaderAdded = addSideHeaderText(tc, side, sideHeaderAdded); - if (tc.getExtra() != null && !tc.getExtra().isEmpty()) { - tc.addExtra(" "); + if (!sideHeaderAdded) { + tc = addSideHeaderText(tc, side); + sideHeaderAdded = true; + } + if (!tc.getChildren().isEmpty()) { + tc = tc.append(Components.space()); } if (glowing) { - tc.addExtra("(glowing)"); + tc = tc.append("(glowing)"); } else { - tc.addExtra("(not glowing)"); + tc = tc.append("(not glowing)"); } } } @@ -215,13 +221,11 @@ public BaseComponent getChangesAsComponent(YamlConfiguration state, YamlConfigur return null; } - private static boolean addSideHeaderText(TextComponent tc, Side side, boolean wasAdded) { - if (!wasAdded) { - if (tc.getExtra() != null && !tc.getExtra().isEmpty()) { - tc.addExtra(" "); - } - tc.addExtra(side.name() + ":"); + private static Component addSideHeaderText(Component tc, Side side) { + if (!tc.getChildren().isEmpty()) { + tc = tc.append(Components.space()); } - return true; + tc = tc.append(side.name() + ":"); + return tc; } } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java index 310a72e6..adc4c508 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSkull.java @@ -1,10 +1,9 @@ package de.diddiz.LogBlock.blockstate; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; +import de.diddiz.LogBlock.componentwrapper.Hover; import java.util.UUID; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.HoverEvent; -import net.md_5.bungee.api.chat.TextComponent; -import net.md_5.bungee.api.chat.hover.content.Text; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.OfflinePlayer; @@ -68,13 +67,13 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { + public Component getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { if (HAS_PROFILE_API && conf != null) { PlayerProfile profile = (PlayerProfile) conf.get("profile"); if (profile != null) { - TextComponent tc = new TextComponent("[" + (profile.getName() != null ? profile.getName() : (profile.getUniqueId() != null ? profile.getUniqueId().toString() : "~unknown~")) + "]"); + Component tc = Components.text("[" + (profile.getName() != null ? profile.getName() : (profile.getUniqueId() != null ? profile.getUniqueId().toString() : "~unknown~")) + "]"); if (profile.getName() != null && profile.getUniqueId() != null) { - tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("UUID: " + profile.getUniqueId().toString()))); + tc = tc.hover(Hover.text("UUID: " + profile.getUniqueId().toString())); } return tc; } @@ -83,7 +82,7 @@ public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfigura UUID ownerId = ownerIdString == null ? null : UUID.fromString(ownerIdString); if (ownerId != null) { OfflinePlayer owner = Bukkit.getOfflinePlayer(ownerId); - return new TextComponent("[" + (owner.getName() != null ? owner.getName() : owner.getUniqueId().toString()) + "]"); + return Components.text("[" + (owner.getName() != null ? owner.getName() : owner.getUniqueId().toString()) + "]"); } return null; } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java index 1146e639..c2c2a07f 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecSpawner.java @@ -1,8 +1,8 @@ package de.diddiz.LogBlock.blockstate; import de.diddiz.LogBlock.LogBlock; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.TextComponent; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.block.CreatureSpawner; @@ -62,13 +62,13 @@ public void deserialize(BlockState state, YamlConfiguration conf) { } @Override - public BaseComponent getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { + public Component getChangesAsComponent(YamlConfiguration conf, YamlConfiguration oldState) { if (conf != null) { String spawnedTypeString = conf.getString("spawnedType"); if (spawnedTypeString != null) { EntityType entity = EntityType.valueOf(spawnedTypeString); if (entity != null) { - return new TextComponent("[" + entity.getKey().getKey() + "]"); + return Components.text("[" + entity.getKey().getKey() + "]"); } } } diff --git a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java index 4f1ed7c8..00e59a94 100644 --- a/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java +++ b/src/main/java/de/diddiz/LogBlock/blockstate/BlockStateCodecs.java @@ -1,8 +1,8 @@ package de.diddiz.LogBlock.blockstate; +import de.diddiz.LogBlock.componentwrapper.Component; import java.util.HashMap; import java.util.Map; -import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.configuration.file.YamlConfiguration; @@ -51,7 +51,7 @@ public static void deserialize(BlockState block, YamlConfiguration state) { } } - public static BaseComponent getChangesAsComponent(Material material, YamlConfiguration state, YamlConfiguration oldState) { + public static Component getChangesAsComponent(Material material, YamlConfiguration state, YamlConfiguration oldState) { BlockStateCodec codec = codecs.get(material); if (codec != null) { return codec.getChangesAsComponent(state, oldState); diff --git a/src/main/java/de/diddiz/LogBlock/componentwrapper/ChatColor.java b/src/main/java/de/diddiz/LogBlock/componentwrapper/ChatColor.java new file mode 100644 index 00000000..7adc17da --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/componentwrapper/ChatColor.java @@ -0,0 +1,54 @@ +package de.diddiz.LogBlock.componentwrapper; + +import java.awt.Color; + +public class ChatColor { + public static final ChatColor BLACK = ChatColor.named("black"); + public static final ChatColor DARK_BLUE = ChatColor.named("dark_blue"); + public static final ChatColor DARK_GREEN = ChatColor.named("dark_green"); + public static final ChatColor DARK_AQUA = ChatColor.named("dark_aqua"); + public static final ChatColor DARK_RED = ChatColor.named("dark_red"); + public static final ChatColor DARK_PURPLE = ChatColor.named("dark_purple"); + public static final ChatColor GOLD = ChatColor.named("gold"); + public static final ChatColor GRAY = ChatColor.named("gray"); + public static final ChatColor DARK_GRAY = ChatColor.named("dark_gray"); + public static final ChatColor BLUE = ChatColor.named("blue"); + public static final ChatColor GREEN = ChatColor.named("green"); + public static final ChatColor AQUA = ChatColor.named("aqua"); + public static final ChatColor RED = ChatColor.named("red"); + public static final ChatColor LIGHT_PURPLE = ChatColor.named("light_purple"); + public static final ChatColor YELLOW = ChatColor.named("yellow"); + public static final ChatColor WHITE = ChatColor.named("white"); + + private final String name; + private final int color; + + public ChatColor(String name, int color) { + this.name = name; + this.color = color; + } + + private static ChatColor named(String name) { + return new ChatColor(name, 0); + } + + public static ChatColor from(Color color) { + return new ChatColor(null, color.getRGB() & 0xffffff); + } + + public static ChatColor from(int color) { + return new ChatColor(null, color & 0xffffff); + } + + public boolean hasName() { + return name != null; + } + + public String getName() { + return name; + } + + public int getColor() { + return color; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/componentwrapper/Click.java b/src/main/java/de/diddiz/LogBlock/componentwrapper/Click.java new file mode 100644 index 00000000..9b43674a --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/componentwrapper/Click.java @@ -0,0 +1,7 @@ +package de.diddiz.LogBlock.componentwrapper; + +public interface Click { + public static RunCommandClick run(String command) { + return new RunCommandClick(command); + } +} diff --git a/src/main/java/de/diddiz/LogBlock/componentwrapper/Component.java b/src/main/java/de/diddiz/LogBlock/componentwrapper/Component.java new file mode 100644 index 00000000..e48a846f --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/componentwrapper/Component.java @@ -0,0 +1,63 @@ +package de.diddiz.LogBlock.componentwrapper; + +import java.util.List; + +public abstract class Component { + private final ChatColor color; + private final Hover hover; + private final Click click; + private final List children; + + Component(ChatColor color, Hover hover, Click click, Component... children) { + this(color, hover, click, List.of(children)); + for (Component e : this.children) { + if (e == null) { + throw new NullPointerException("no null children allowed"); + } + } + } + + Component(ChatColor color, Hover hover, Click click, List children) { + this.color = color; + this.hover = hover; + this.click = click; + this.children = children; + } + + public ChatColor getColor() { + return color; + } + + public List getChildren() { + return children; + } + + public Hover getHover() { + return hover; + } + + public Click getClick() { + return click; + } + + public abstract Component append(Component child); + + public abstract Component append(String text); + + public abstract Component hover(Hover hover); + + public abstract Component click(Click click); + + protected Component[] addChildInternal(Component child) { + if (child == null) { + throw new NullPointerException("no null children allowed"); + } + if (children.isEmpty()) { + return new Component[] { child }; + } + int size = children.size(); + Component[] array = children.toArray(new Component[size + 1]); + array[size] = child; + return array; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/componentwrapper/Components.java b/src/main/java/de/diddiz/LogBlock/componentwrapper/Components.java new file mode 100644 index 00000000..91d83d93 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/componentwrapper/Components.java @@ -0,0 +1,239 @@ +package de.diddiz.LogBlock.componentwrapper; + +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.util.MessagingUtil; +import de.diddiz.LogBlock.util.TypeColor; +import java.awt.Color; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.event.HoverEventSource; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextColor; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ItemTag; +import net.md_5.bungee.api.chat.hover.content.Item; +import net.md_5.bungee.api.chat.hover.content.Text; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; + +public class Components { + private static final boolean HAS_ADVENTURE; + private static final Component EMPTY = text(""); + private static final Component SPACE = text(" "); + + static { + boolean hasAdventure = false; + try { + Class audienceInterface = Class.forName("net.kyori.adventure.audience.Audience"); + hasAdventure = audienceInterface.isAssignableFrom(Player.class); + LogBlock.getInstance().getLogger().info("Using adventure components"); + } catch (Throwable t) { + LogBlock.getInstance().getLogger().info("Using bungee components"); + } + HAS_ADVENTURE = hasAdventure; + } + + public static Component empty() { + return EMPTY; + } + + public static Component space() { + return SPACE; + } + + public static TextComponent text(String text) { + return text(text, null); + } + + public static TextComponent text(String text, ChatColor color, Component... children) { + return text(text, color, null, null, children); + } + + public static TextComponent text(String text, ChatColor color, Hover hover, Click click, Component... children) { + return new TextComponent(text, color, hover, click, children); + } + + public static void sendTo(CommandSender target, Component message) { + if (HAS_ADVENTURE) { + AdventureSender.sendTo(target, message); + } else { + BungeeSender.sendTo(target, message); + } + } + + private static class AdventureSender { + private static final Map colorMap; + static { + colorMap = new HashMap<>(); + colorMap.put(ChatColor.BLACK, NamedTextColor.BLACK); + colorMap.put(ChatColor.DARK_BLUE, NamedTextColor.DARK_BLUE); + colorMap.put(ChatColor.DARK_GREEN, NamedTextColor.DARK_GREEN); + colorMap.put(ChatColor.DARK_AQUA, NamedTextColor.DARK_AQUA); + colorMap.put(ChatColor.DARK_RED, NamedTextColor.DARK_RED); + colorMap.put(ChatColor.DARK_PURPLE, NamedTextColor.DARK_PURPLE); + colorMap.put(ChatColor.GOLD, NamedTextColor.GOLD); + colorMap.put(ChatColor.GRAY, NamedTextColor.GRAY); + colorMap.put(ChatColor.DARK_GRAY, NamedTextColor.DARK_GRAY); + colorMap.put(ChatColor.BLUE, NamedTextColor.BLUE); + colorMap.put(ChatColor.GREEN, NamedTextColor.GREEN); + colorMap.put(ChatColor.AQUA, NamedTextColor.AQUA); + colorMap.put(ChatColor.RED, NamedTextColor.RED); + colorMap.put(ChatColor.LIGHT_PURPLE, NamedTextColor.LIGHT_PURPLE); + colorMap.put(ChatColor.YELLOW, NamedTextColor.YELLOW); + colorMap.put(ChatColor.WHITE, NamedTextColor.WHITE); + } + + public static void sendTo(CommandSender target, Component message) { + Audience targetAudience = (Audience) target; + targetAudience.sendMessage(toAdventure(message)); + } + + private static net.kyori.adventure.text.Component toAdventure(Component message) { + net.kyori.adventure.text.Component result = net.kyori.adventure.text.Component.text(((TextComponent) message).getText(), toAdventure(message.getColor())); + if (!message.getChildren().isEmpty()) { + result = result.children(message.getChildren().parallelStream().map(AdventureSender::toAdventure).toList()); + } + if (message.getHover() != null) { + result = result.hoverEvent(toAdventure(message.getHover())); + } + if (message.getClick() != null) { + result = result.clickEvent(toAdventure(message.getClick())); + } + // TODO formatings + return result; + } + + private static @Nullable ClickEvent toAdventure(Click click) { + if (click instanceof RunCommandClick run) { + return ClickEvent.runCommand(run.getCommand()); + } + return null; + } + + private static HoverEventSource toAdventure(Hover hover) { + if (hover instanceof TextHover text) { + return HoverEvent.showText(toAdventure(text.getText())); + } else if (hover instanceof ItemHover item) { + return (HoverEventSource) item.getItem(); + } + return null; + } + + private static TextColor toAdventure(ChatColor color) { + return color == null ? null : colorMap.getOrDefault(color, TextColor.color(color.getColor())); + } + } + + private static class BungeeSender { + private static final Map colorMap; + private static final Map inverseColorMap; + static { + colorMap = new HashMap<>(); + colorMap.put(ChatColor.BLACK, net.md_5.bungee.api.ChatColor.BLACK); + colorMap.put(ChatColor.DARK_BLUE, net.md_5.bungee.api.ChatColor.DARK_BLUE); + colorMap.put(ChatColor.DARK_GREEN, net.md_5.bungee.api.ChatColor.DARK_GREEN); + colorMap.put(ChatColor.DARK_AQUA, net.md_5.bungee.api.ChatColor.DARK_AQUA); + colorMap.put(ChatColor.DARK_RED, net.md_5.bungee.api.ChatColor.DARK_RED); + colorMap.put(ChatColor.DARK_PURPLE, net.md_5.bungee.api.ChatColor.DARK_PURPLE); + colorMap.put(ChatColor.GOLD, net.md_5.bungee.api.ChatColor.GOLD); + colorMap.put(ChatColor.GRAY, net.md_5.bungee.api.ChatColor.GRAY); + colorMap.put(ChatColor.DARK_GRAY, net.md_5.bungee.api.ChatColor.DARK_GRAY); + colorMap.put(ChatColor.BLUE, net.md_5.bungee.api.ChatColor.BLUE); + colorMap.put(ChatColor.GREEN, net.md_5.bungee.api.ChatColor.GREEN); + colorMap.put(ChatColor.AQUA, net.md_5.bungee.api.ChatColor.AQUA); + colorMap.put(ChatColor.RED, net.md_5.bungee.api.ChatColor.RED); + colorMap.put(ChatColor.LIGHT_PURPLE, net.md_5.bungee.api.ChatColor.LIGHT_PURPLE); + colorMap.put(ChatColor.YELLOW, net.md_5.bungee.api.ChatColor.YELLOW); + colorMap.put(ChatColor.WHITE, net.md_5.bungee.api.ChatColor.WHITE); + + inverseColorMap = new HashMap<>(); + for (Entry e : colorMap.entrySet()) { + inverseColorMap.put(e.getValue(), e.getKey()); + } + } + + public static void sendTo(CommandSender target, Component message) { + target.spigot().sendMessage(toBungee(message)); + } + + private static BaseComponent toBungee(Component message) { + BaseComponent result = new net.md_5.bungee.api.chat.TextComponent(((TextComponent) message).getText()); + result.setColor(toBungee(message.getColor())); + if (!message.getChildren().isEmpty()) { + for (Component child : message.getChildren()) { + result.addExtra(toBungee(child)); + } + } + if (message.getHover() != null) { + result.setHoverEvent(toBungee(message.getHover())); + } + if (message.getClick() != null) { + result.setClickEvent(toBungee(message.getClick())); + } + // TODO formatings + return result; + } + + private static net.md_5.bungee.api.chat.ClickEvent toBungee(Click click) { + if (click instanceof RunCommandClick run) { + return new net.md_5.bungee.api.chat.ClickEvent(net.md_5.bungee.api.chat.ClickEvent.Action.RUN_COMMAND, run.getCommand()); + } + return null; + } + + @SuppressWarnings("deprecation") + private static net.md_5.bungee.api.chat.HoverEvent toBungee(Hover hover) { + if (hover instanceof TextHover text) { + return new net.md_5.bungee.api.chat.HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, new Text(toBungee(text.getText()))); + } else if (hover instanceof ItemHover item) { + ItemStack stack = item.getItem(); + try { + String itemTag = stack.getItemMeta().getAsString(); + return new net.md_5.bungee.api.chat.HoverEvent(net.md_5.bungee.api.chat.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); + return new net.md_5.bungee.api.chat.HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, new Text(new BaseComponent[] { toBungee(MessagingUtil.createTextComponentWithColor("Error", TypeColor.ERROR.getColor())) })); + } + } + return null; + } + + private static net.md_5.bungee.api.ChatColor toBungee(ChatColor color) { + return color == null ? null : colorMap.getOrDefault(color, net.md_5.bungee.api.ChatColor.of(new Color(color.getColor()))); + } + + public static Component toComponent(BaseComponent component) { + Component result = Components.text(((net.md_5.bungee.api.chat.TextComponent) component).getText(), toComponent(component.getColorRaw())); + if (component.getExtra() != null) { + for (BaseComponent child : component.getExtra()) { + result = result.append(toComponent(child)); + } + } + // TODO formatings + // ignored: hover, click + return result; + } + + private static ChatColor toComponent(net.md_5.bungee.api.ChatColor color) { + return color == null ? null : inverseColorMap.getOrDefault(color, ChatColor.from(color.getColor())); + } + } + + public static Component fromLegacy(String text) { + // use bungee component converter for now + BaseComponent component = net.md_5.bungee.api.chat.TextComponent.fromLegacy(text); + return BungeeSender.toComponent(component); + } + + public static String toPlainText(Component component) { + // use bungee component converter for now + return BungeeSender.toBungee(component).toPlainText(); + } +} diff --git a/src/main/java/de/diddiz/LogBlock/componentwrapper/Hover.java b/src/main/java/de/diddiz/LogBlock/componentwrapper/Hover.java new file mode 100644 index 00000000..2ad09835 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/componentwrapper/Hover.java @@ -0,0 +1,17 @@ +package de.diddiz.LogBlock.componentwrapper; + +import org.bukkit.inventory.ItemStack; + +public interface Hover { + public static TextHover text(String text) { + return new TextHover(Components.text(text)); + } + + public static TextHover text(Component text) { + return new TextHover(text); + } + + public static ItemHover item(ItemStack item) { + return new ItemHover(item); + } +} diff --git a/src/main/java/de/diddiz/LogBlock/componentwrapper/ItemHover.java b/src/main/java/de/diddiz/LogBlock/componentwrapper/ItemHover.java new file mode 100644 index 00000000..8f843bf2 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/componentwrapper/ItemHover.java @@ -0,0 +1,15 @@ +package de.diddiz.LogBlock.componentwrapper; + +import org.bukkit.inventory.ItemStack; + +public class ItemHover implements Hover { + private final ItemStack item; + + ItemHover(ItemStack item) { + this.item = item; + } + + public ItemStack getItem() { + return item; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/componentwrapper/RunCommandClick.java b/src/main/java/de/diddiz/LogBlock/componentwrapper/RunCommandClick.java new file mode 100644 index 00000000..dd2b7d3b --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/componentwrapper/RunCommandClick.java @@ -0,0 +1,13 @@ +package de.diddiz.LogBlock.componentwrapper; + +public class RunCommandClick implements Click { + private final String command; + + public RunCommandClick(String command) { + this.command = command; + } + + public String getCommand() { + return command; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/componentwrapper/TextComponent.java b/src/main/java/de/diddiz/LogBlock/componentwrapper/TextComponent.java new file mode 100644 index 00000000..9512e387 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/componentwrapper/TextComponent.java @@ -0,0 +1,41 @@ +package de.diddiz.LogBlock.componentwrapper; + +import java.util.List; + +public class TextComponent extends Component { + private final String text; + + TextComponent(String text, ChatColor color, Hover hover, Click click, Component... children) { + super(color, hover, click, children); + this.text = text; + } + + TextComponent(String text, ChatColor color, Hover hover, Click click, List children) { + super(color, hover, click, children); + this.text = text; + } + + public String getText() { + return text; + } + + @Override + public TextComponent append(String child) { + return append(Components.text(child)); + } + + @Override + public TextComponent append(Component child) { + return Components.text(text, getColor(), getHover(), getClick(), addChildInternal(child)); + } + + @Override + public TextComponent hover(Hover hover) { + return new TextComponent(text, getColor(), hover, getClick(), getChildren()); + } + + @Override + public TextComponent click(Click click) { + return new TextComponent(text, getColor(), getHover(), click, getChildren()); + } +} diff --git a/src/main/java/de/diddiz/LogBlock/componentwrapper/TextHover.java b/src/main/java/de/diddiz/LogBlock/componentwrapper/TextHover.java new file mode 100644 index 00000000..3adfdf88 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/componentwrapper/TextHover.java @@ -0,0 +1,13 @@ +package de.diddiz.LogBlock.componentwrapper; + +public class TextHover implements Hover { + private final Component text; + + TextHover(Component text) { + this.text = text; + } + + public Component getText() { + return text; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/util/ActionColor.java b/src/main/java/de/diddiz/LogBlock/util/ActionColor.java index fa69d50a..eb277549 100644 --- a/src/main/java/de/diddiz/LogBlock/util/ActionColor.java +++ b/src/main/java/de/diddiz/LogBlock/util/ActionColor.java @@ -1,6 +1,6 @@ package de.diddiz.LogBlock.util; -import net.md_5.bungee.api.ChatColor; +import de.diddiz.LogBlock.componentwrapper.ChatColor; public enum ActionColor { DESTROY(ChatColor.RED), diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 2e25bbbb..2f1e5549 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -3,6 +3,8 @@ import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial; import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Hover; import java.io.File; import java.util.ArrayList; import java.util.Collection; @@ -15,13 +17,6 @@ import java.util.logging.Level; import java.util.Set; import java.util.UUID; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.HoverEvent; -import net.md_5.bungee.api.chat.HoverEvent.Action; -import net.md_5.bungee.api.chat.ItemTag; -import net.md_5.bungee.api.chat.TextComponent; -import net.md_5.bungee.api.chat.hover.content.Item; -import net.md_5.bungee.api.chat.hover.content.Text; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Chunk; @@ -658,21 +653,13 @@ public static boolean isEmpty(Material m) { return m == Material.AIR || m == Material.CAVE_AIR || m == Material.VOID_AIR; } - public static TextComponent toString(ItemStackAndAmount stack) { + public static Component toString(ItemStackAndAmount stack) { if (stack == null || stack.stack() == null || stack.amount() == 0 || isEmpty(stack.stack().getType())) { return prettyMaterial("nothing"); } - TextComponent msg = MessagingUtil.createTextComponentWithColor(stack.amount() + "x ", TypeColor.DEFAULT.getColor()); - msg.addExtra(prettyMaterial(stack.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))); - } 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()) }))); - } - + Component msg = MessagingUtil.createTextComponentWithColor(stack.amount() + "x ", TypeColor.DEFAULT.getColor()); + msg = msg.append(prettyMaterial(stack.stack().getType())); + msg = msg.hover(Hover.item(stack.stack())); return msg; } diff --git a/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java b/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java index cbef43bb..690a29a2 100644 --- a/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java +++ b/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java @@ -5,8 +5,12 @@ import static de.diddiz.LogBlock.util.TypeColor.DEFAULT; import static de.diddiz.LogBlock.util.Utils.spaces; +import de.diddiz.LogBlock.componentwrapper.ChatColor; +import de.diddiz.LogBlock.componentwrapper.Click; +import de.diddiz.LogBlock.componentwrapper.Component; +import de.diddiz.LogBlock.componentwrapper.Components; +import de.diddiz.LogBlock.componentwrapper.Hover; import de.diddiz.LogBlock.config.Config; -import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.HoverEvent; @@ -18,98 +22,95 @@ import org.bukkit.entity.EntityType; public class MessagingUtil { - 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); + public static Component formatSummarizedChanges(int created, int destroyed, Component actor, int createdWidth, int destroyedWidth, float spaceFactor) { + Component textCreated = createTextComponentWithColor(created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)), CREATE.getColor()); + Component textDestroyed = createTextComponentWithColor(destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)), DESTROY.getColor()); + Component result = Components.empty(); + result = result.append(textCreated); + result = result.append(textDestroyed); + result = result.append(actor); return result; } - public static TextComponent createTextComponentWithColor(String text, ChatColor color) { - TextComponent tc = new TextComponent(text); - tc.setColor(color); - return tc; + public static Component createTextComponentWithColor(String text, ChatColor color) { + return Components.text(text, color); } - public static TextComponent brackets(BracketType type, BaseComponent... content) { - TextComponent tc = createTextComponentWithColor(type.getStarting(), TypeColor.BRACKETS.getColor()); - for (BaseComponent c : content) { - tc.addExtra(c); + public static Component brackets(BracketType type, Component... content) { + Component tc = createTextComponentWithColor(type.getStarting(), TypeColor.BRACKETS.getColor()); + for (Component c : content) { + tc = tc.append(c); } - tc.addExtra(new TextComponent(type.getEnding())); + tc = tc.append(Components.text(type.getEnding())); return tc; } - public static TextComponent prettyDate(long date) { - TextComponent tc = brackets(BracketType.STANDARD, createTextComponentWithColor(Config.formatterShort.format(date), TypeColor.DATE.getColor())); - tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(Config.formatter.format(date)))); + public static Component prettyDate(long date) { + Component tc = brackets(BracketType.STANDARD, createTextComponentWithColor(Config.formatterShort.format(date), TypeColor.DATE.getColor())); + tc = tc.hover(Hover.text(Config.formatter.format(date))); return tc; } - public static TextComponent prettyState(String stateName) { + public static Component prettyState(String stateName) { return createTextComponentWithColor(stateName, TypeColor.STATE.getColor()); } - public static TextComponent prettyState(BaseComponent stateName) { - TextComponent tc = new TextComponent(); - tc.setColor(TypeColor.STATE.getColor()); + public static Component prettyState(Component stateName) { + Component tc = Components.text("", TypeColor.STATE.getColor()); if (stateName != null) { - tc.addExtra(stateName); + tc = tc.append(stateName); } return tc; } - public static TextComponent prettyState(int stateValue) { + public static Component prettyState(int stateValue) { return prettyState(Integer.toString(stateValue)); } - public static > TextComponent prettyState(E enumerator) { + public static > Component prettyState(E enumerator) { return prettyState(enumerator.toString()); } - public static TextComponent prettyMaterial(String materialName) { + public static Component prettyMaterial(String materialName) { return createTextComponentWithColor(materialName.toUpperCase(), TypeColor.MATERIAL.getColor()); } - public static TextComponent prettyMaterial(Material material) { + public static Component prettyMaterial(Material material) { return prettyMaterial(material.name()); } - public static TextComponent prettyMaterial(BlockData material) { - TextComponent tc = prettyMaterial(material.getMaterial()); + public static Component prettyMaterial(BlockData material) { + Component tc = prettyMaterial(material.getMaterial()); String bdString = material.getAsString(); int bracket = bdString.indexOf("["); if (bracket >= 0) { int bracket2 = bdString.indexOf("]", bracket); if (bracket2 >= 0) { String state = bdString.substring(bracket + 1, bracket2).replace(',', '\n'); - tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(state))); + tc = tc.hover(Hover.text(state)); } } return tc; } - public static TextComponent prettyEntityType(EntityType type) { + public static Component prettyEntityType(EntityType type) { return prettyMaterial(type.name()); } - public static TextComponent prettyLocation(Location loc, int entryId) { + public static Component prettyLocation(Location loc, int entryId) { return prettyLocation(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), entryId); } - public static TextComponent prettyLocation(int x, int y, int z, int entryId) { - TextComponent tc = createTextComponentWithColor("", DEFAULT.getColor()); - tc.addExtra(createTextComponentWithColor(Integer.toString(x), TypeColor.COORDINATE.getColor())); - tc.addExtra(createTextComponentWithColor(", ", DEFAULT.getColor())); - tc.addExtra(createTextComponentWithColor(Integer.toString(y), TypeColor.COORDINATE.getColor())); - tc.addExtra(createTextComponentWithColor(", ", DEFAULT.getColor())); - tc.addExtra(createTextComponentWithColor(Integer.toString(z), TypeColor.COORDINATE.getColor())); + public static Component prettyLocation(int x, int y, int z, int entryId) { + Component tc = createTextComponentWithColor("", DEFAULT.getColor()); + tc = tc.append(createTextComponentWithColor(Integer.toString(x), TypeColor.COORDINATE.getColor())); + tc = tc.append(createTextComponentWithColor(", ", DEFAULT.getColor())); + tc = tc.append(createTextComponentWithColor(Integer.toString(y), TypeColor.COORDINATE.getColor())); + tc = tc.append(createTextComponentWithColor(", ", DEFAULT.getColor())); + tc = tc.append(createTextComponentWithColor(Integer.toString(z), TypeColor.COORDINATE.getColor())); if (entryId > 0) { - tc.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/lb tp " + entryId)); - tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Teleport here"))); + tc = tc.click(Click.run("/lb tp " + entryId)); + tc = tc.hover(Hover.text("Teleport here")); } return tc; } diff --git a/src/main/java/de/diddiz/LogBlock/util/TypeColor.java b/src/main/java/de/diddiz/LogBlock/util/TypeColor.java index db62b567..f1a56845 100644 --- a/src/main/java/de/diddiz/LogBlock/util/TypeColor.java +++ b/src/main/java/de/diddiz/LogBlock/util/TypeColor.java @@ -1,6 +1,6 @@ package de.diddiz.LogBlock.util; -import net.md_5.bungee.api.ChatColor; +import de.diddiz.LogBlock.componentwrapper.ChatColor; public enum TypeColor { DEFAULT(ChatColor.YELLOW), From d5088af00b6d31136babeb3965e92d536b9ff7e6 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 11 Jul 2025 08:11:34 +0200 Subject: [PATCH 394/399] cleanup imports --- src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java b/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java index 690a29a2..f861c090 100644 --- a/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java +++ b/src/main/java/de/diddiz/LogBlock/util/MessagingUtil.java @@ -11,11 +11,6 @@ import de.diddiz.LogBlock.componentwrapper.Components; import de.diddiz.LogBlock.componentwrapper.Hover; import de.diddiz.LogBlock.config.Config; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.ClickEvent; -import net.md_5.bungee.api.chat.HoverEvent; -import net.md_5.bungee.api.chat.TextComponent; -import net.md_5.bungee.api.chat.hover.content.Text; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.data.BlockData; From 888b447008647c462fccea2c5b9e3306b43bc0d6 Mon Sep 17 00:00:00 2001 From: Dieu Date: Sat, 19 Jul 2025 18:38:34 +0200 Subject: [PATCH 395/399] Fix BukkitUtils#entityName for NPCs and custom Entities, fixes: com.destroystokyo.paper.exception.ServerEventException: Could not pass event EntityChangeBlockEvent to LogBlock v1.20.0.0-SNAPSHOT (build #222) at io.papermc.paper.plugin.manager.PaperEventManager.callEvent(PaperEventManager.java:72) at io.papermc.paper.plugin.manager.PaperPluginManagerImpl.callEvent(PaperPluginManagerImpl.java:131) at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:628) at org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(CraftEventFactory.java:1238) at org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(CraftEventFactory.java:1230) at net.minecraft.world.level.block.BigDripleafBlock.setTilt(BigDripleafBlock.java:273) at net.minecraft.world.level.block.BigDripleafBlock.setTiltAndScheduleTick(BigDripleafBlock.java:249) at net.minecraft.world.level.block.BigDripleafBlock.entityInside(BigDripleafBlock.java:210) at net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase.entityInside(BlockBehaviour.java:895) at net.minecraft.world.entity.Entity.lambda$checkInsideBlocks$2(Entity.java:2005) at net.minecraft.world.level.BlockGetter.forEachBlockIntersectedBetween(BlockGetter.java:225) at net.minecraft.world.entity.Entity.checkInsideBlocks(Entity.java:1970) at net.minecraft.world.entity.Entity.checkInsideBlocks(Entity.java:1949) at net.minecraft.world.entity.Entity.applyEffectsFromBlocks(Entity.java:1479) at net.minecraft.world.entity.Entity.applyEffectsFromBlocks(Entity.java:1440) at net.minecraft.world.entity.LivingEntity.aiStep(LivingEntity.java:3633) at net.minecraft.world.entity.Mob.aiStep(Mob.java:504) at net.minecraft.world.entity.LivingEntity.tick(LivingEntity.java:3353) at net.minecraft.world.entity.Mob.tick(Mob.java:381) at SimplePets.jar//simplepets.brainsynder.versions.v1_21_7.entity.EntityPet.tick(EntityPet.java:453) at net.minecraft.server.level.ServerLevel.tickNonPassenger(ServerLevel.java:1306) at net.minecraft.world.level.Level.guardEntityTick(Level.java:1511) at net.minecraft.server.level.ServerLevel.lambda$tick$5(ServerLevel.java:840) at net.minecraft.world.level.entity.EntityTickList.forEach(EntityTickList.java:39) at net.minecraft.server.level.ServerLevel.tick(ServerLevel.java:813) at net.minecraft.server.MinecraftServer.tickChildren(MinecraftServer.java:1741) at net.minecraft.server.MinecraftServer.tickServer(MinecraftServer.java:1548) at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1269) at net.minecraft.server.MinecraftServer.lambda$spin$2(MinecraftServer.java:311) at java.base/java.lang.Thread.run(Thread.java:1583) Caused by: java.lang.StringIndexOutOfBoundsException: Range [5, 0) out of bounds for length 0 at java.base/jdk.internal.util.Preconditions$1.apply(Preconditions.java:55) at java.base/jdk.internal.util.Preconditions$1.apply(Preconditions.java:52) at java.base/jdk.internal.util.Preconditions$4.apply(Preconditions.java:213) at java.base/jdk.internal.util.Preconditions$4.apply(Preconditions.java:210) at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:98) at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckFromToIndex(Preconditions.java:112) at java.base/jdk.internal.util.Preconditions.checkFromToIndex(Preconditions.java:349) at java.base/java.lang.String.checkBoundsBeginEnd(String.java:4865) at java.base/java.lang.String.substring(String.java:2834) at java.base/java.lang.String.substring(String.java:2807) at LogBlock.jar//de.diddiz.LogBlock.util.BukkitUtils.entityName(BukkitUtils.java:567) at LogBlock.jar//de.diddiz.LogBlock.Actor.actorFromEntity(Actor.java:122) at LogBlock.jar//de.diddiz.LogBlock.listeners.EntityChangeBlockLogging.onEntityChangeBlock(EntityChangeBlockLogging.java:42) at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:80) at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:71) at io.papermc.paper.plugin.manager.PaperEventManager.callEvent(PaperEventManager.java:54) ... 29 more --- src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 2f1e5549..4d0a76cf 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -564,7 +564,12 @@ public static String entityName(Entity entity) { if (entity instanceof TNTPrimed) { return "TNT"; } - return entity.getClass().getSimpleName().substring(5); + + String simpleClassName = entity.getClass().getSimpleName(); + if(simpleClassName.startsWith("Craft")) + return simpleClassName.substring(5); + + return simpleClassName; } public static void giveTool(Player player, Material type) { From 0318459203e29ce823ac15850010ed09f42f6def Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 22 Jul 2025 09:13:04 +0200 Subject: [PATCH 396/399] Minecraft 1.21.8 --- pom.xml | 2 +- src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 248b6b56..24afdbbc 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ org.spigotmc spigot-api - 1.21.5-R0.1-SNAPSHOT + 1.21.8-R0.1-SNAPSHOT provided diff --git a/src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java b/src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java index 6decf6c3..2a916881 100644 --- a/src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java +++ b/src/main/java/de/diddiz/LogBlock/util/UUIDFetcher.java @@ -5,6 +5,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.gson.Strictness; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; @@ -20,7 +21,7 @@ public class UUIDFetcher { private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft"; - private static final Gson gson = new GsonBuilder().setLenient().create(); + private static final Gson gson = new GsonBuilder().setStrictness(Strictness.LENIENT).create(); public static Map getUUIDs(List names) throws Exception { Map uuidMap = new HashMap<>(); From 2bb06539e2be0d75cd991f9d48ba52ac191255e0 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 19 Dec 2025 08:19:14 +0100 Subject: [PATCH 397/399] Compile against Spigot 1.21.11 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 24afdbbc..97486b23 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ org.spigotmc spigot-api - 1.21.8-R0.1-SNAPSHOT + 1.21.11-R0.1-SNAPSHOT provided From 3197c6e4874e74eca4b5161136b66ad168c84349 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 19 Dec 2025 08:19:48 +0100 Subject: [PATCH 398/399] Shelf access logging + adapt for changes with bookshelf slots --- .../listeners/ChestAccessLogging.java | 98 ++++++++++++++++--- .../de/diddiz/LogBlock/util/BukkitUtils.java | 13 ++- .../LogBlock/util/PaperCompatibility.java | 32 ++++++ .../util/SelectableSlotContainerHelper.java | 24 +++++ 4 files changed, 155 insertions(+), 12 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/util/PaperCompatibility.java create mode 100644 src/main/java/de/diddiz/LogBlock/util/SelectableSlotContainerHelper.java diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index a8b11ab7..f74294a6 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -3,17 +3,22 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.util.BukkitUtils; import de.diddiz.LogBlock.util.Fraction; import de.diddiz.LogBlock.util.ItemStackAndAmount; +import de.diddiz.LogBlock.util.PaperCompatibility; +import de.diddiz.LogBlock.util.SelectableSlotContainerHelper; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Tag; import org.bukkit.block.Beehive; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; 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.block.data.type.Shelf; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -30,6 +35,7 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.ShelfInventory; import org.bukkit.inventory.meta.BlockStateMeta; import org.bukkit.inventory.meta.BundleMeta; import org.bukkit.inventory.meta.ItemMeta; @@ -452,17 +458,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { 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; - + int slot = SelectableSlotContainerHelper.getHitSlot(blockData.getFacing(), pos, 2, 3); ItemStack currentInSlot = bookshelf.getSnapshotInventory().getItem(slot); if (blockData.isSlotOccupied(slot)) { // not empty: always take @@ -479,6 +475,86 @@ public void onPlayerInteract(PlayerInteractEvent event) { } } } + } else if (Tag.WOODEN_SHELVES.isTagged(type) && clicked.getBlockData() instanceof Shelf blockData && event.getBlockFace() == blockData.getFacing() && clicked.getState() instanceof org.bukkit.block.Shelf shelf) { + Vector pos = event.getClickedPosition(); + if (pos == null) { + return; // some plugins create this event without a clicked pos + } + int slot = SelectableSlotContainerHelper.getHitSlot(blockData.getFacing(), pos, 1, 3); + // player.sendMessage("Clicked slot: " + slot); + ItemStack currentInSlot = shelf.getSnapshotInventory().getItem(slot); + if (!blockData.isPowered()) { + // swap single slot + if (currentInSlot != null && currentInSlot.getType() != Material.AIR) { + consumer.queueChestAccess(Actor.actorFromEntity(player), clicked.getLocation(), clicked.getBlockData(), ItemStackAndAmount.fromStack(currentInSlot), true); + } + ItemStack mainHand = player.getInventory().getItemInMainHand(); + if (mainHand != null && mainHand.getType() != Material.AIR) { + consumer.queueChestAccess(Actor.actorFromEntity(player), clicked.getLocation(), clicked.getBlockData(), ItemStackAndAmount.fromStack(mainHand), false); + } + } else { + // swap hotbar + // find neighbours - up to 3 blocks total, priorize right side (up to 2) then left side + // stop when not shelf, not powered or not connected to the current (to the right must have "sidechain.right" and vv + // stop after the block if not center or limit reached + // swap with hotbar from the right + BlockFace side = BukkitUtils.rotateClockwise(blockData.getFacing()).getOppositeFace(); + // to the right + ArrayList blockChain = new ArrayList<>(); + blockChain.add(clicked); + for (int i = 1; i < 3; i++) { + Block neighbour = clicked.getRelative(side, i); + if (!(neighbour.getBlockData() instanceof Shelf neighbourData) || !neighbourData.isPowered() || neighbourData.getFacing() != blockData.getFacing()) { + break; + } + PaperCompatibility.SideChain sideChain = PaperCompatibility.getShelfSideChain(neighbourData); + if (sideChain != PaperCompatibility.SideChain.CENTER && sideChain != PaperCompatibility.SideChain.RIGHT) { + break; + } + blockChain.add(neighbour); + if (sideChain != PaperCompatibility.SideChain.CENTER) { + break; + } + } + // to the left + side = side.getOppositeFace(); + for (int i = 1; i < 3 && blockChain.size() < 3; i++) { + Block neighbour = clicked.getRelative(side, i); + if (!(neighbour.getBlockData() instanceof Shelf neighbourData) || !neighbourData.isPowered() || neighbourData.getFacing() != blockData.getFacing()) { + break; + } + PaperCompatibility.SideChain sideChain = PaperCompatibility.getShelfSideChain(neighbourData); + if (sideChain != PaperCompatibility.SideChain.CENTER && sideChain != PaperCompatibility.SideChain.LEFT) { + break; + } + blockChain.add(0, neighbour); + if (sideChain != PaperCompatibility.SideChain.CENTER) { + break; + } + } + int chainedCount = blockChain.size(); + int startSlot = 9 - chainedCount * 3; + Inventory playerInventory = player.getInventory(); + for (int i = 0; i < chainedCount; i++) { + Block chainBlock = blockChain.get(i); + ShelfInventory blockInventory = ((org.bukkit.block.Shelf) chainBlock.getState()).getSnapshotInventory(); + // player.sendMessage("Block " + chainBlock.getLocation().toVector()); + for (int slotInBlock = 0; slotInBlock < 3; slotInBlock++) { + ItemStack blockItem = blockInventory.getItem(slotInBlock); + if (blockItem != null && blockItem.getType() != Material.AIR) { + // player.sendMessage(" Item -> Player: " + blockItem.getType()); + consumer.queueChestAccess(Actor.actorFromEntity(player), chainBlock.getLocation(), chainBlock.getBlockData(), ItemStackAndAmount.fromStack(blockItem), true); + } + } + for (int slotInBlock = 0; slotInBlock < 3; slotInBlock++) { + ItemStack playerInvItem = playerInventory.getItem(startSlot + slotInBlock + i * 3); + if (playerInvItem != null && playerInvItem.getType() != Material.AIR) { + // player.sendMessage(" Item -> Block: " + playerInvItem.getType()); + consumer.queueChestAccess(Actor.actorFromEntity(player), chainBlock.getLocation(), chainBlock.getBlockData(), ItemStackAndAmount.fromStack(playerInvItem), false); + } + } + } + } } } diff --git a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java index 4d0a76cf..3fe7fb27 100644 --- a/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/LogBlock/util/BukkitUtils.java @@ -566,8 +566,9 @@ public static String entityName(Entity entity) { } String simpleClassName = entity.getClass().getSimpleName(); - if(simpleClassName.startsWith("Craft")) + if (simpleClassName.startsWith("Craft")) { return simpleClassName.substring(5); + } return simpleClassName; } @@ -1054,4 +1055,14 @@ public static Side getFacingSignSide(Entity entity, Block sign) { return Math.abs(Utils.warpDegrees(f - yRotationDegree)) <= 90.0 ? Side.FRONT : Side.BACK; } + + public static BlockFace rotateClockwise(BlockFace direction) { + return switch (direction) { + case NORTH -> BlockFace.EAST; + case SOUTH -> BlockFace.WEST; + case WEST -> BlockFace.NORTH; + case EAST -> BlockFace.SOUTH; + default -> throw new IllegalArgumentException("direction must be cardinal"); + }; + } } diff --git a/src/main/java/de/diddiz/LogBlock/util/PaperCompatibility.java b/src/main/java/de/diddiz/LogBlock/util/PaperCompatibility.java new file mode 100644 index 00000000..254353f5 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/util/PaperCompatibility.java @@ -0,0 +1,32 @@ +package de.diddiz.LogBlock.util; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import org.bukkit.block.data.type.Shelf; + +public class PaperCompatibility { + private static final Method method_Shelf_getSideChain; + static { + try { + method_Shelf_getSideChain = Shelf.class.getMethod("getSideChain"); + } catch (NoSuchMethodException e) { + throw new RuntimeException("method missing: Shelf.getSideChain", e); + } + } + + public static enum SideChain { + LEFT, + CENTER, + RIGHT, + UNCONNECTED; + } + + public static SideChain getShelfSideChain(Shelf shelf) { + try { + return SideChain.valueOf(method_Shelf_getSideChain.invoke(shelf).toString()); + } catch (IllegalAccessException | InvocationTargetException | NullPointerException e) { + throw new RuntimeException("could not invoke: Shelf.getSideChain", e); + } + } + +} diff --git a/src/main/java/de/diddiz/LogBlock/util/SelectableSlotContainerHelper.java b/src/main/java/de/diddiz/LogBlock/util/SelectableSlotContainerHelper.java new file mode 100644 index 00000000..d5bdd36b --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/util/SelectableSlotContainerHelper.java @@ -0,0 +1,24 @@ +package de.diddiz.LogBlock.util; + +import org.bukkit.block.BlockFace; +import org.bukkit.util.Vector; + +public class SelectableSlotContainerHelper { + public static int getHitSlot(BlockFace face, Vector clickPosition, int rows, int columns) { + double clickX = switch (face) { + case NORTH -> 1 - clickPosition.getX(); + case SOUTH -> clickPosition.getX(); + case EAST -> 1 - clickPosition.getZ(); + case WEST -> clickPosition.getZ(); + default -> throw new IllegalArgumentException("Unexpected facing for SelectableSlotContainer: " + face); + }; + double clickY = clickPosition.getY(); + int sectionY = getSection(1.0F - clickY, rows); + int sectionX = getSection(clickX, columns); + return sectionX + sectionY * columns; + } + + private static int getSection(double x, int slots) { + return Math.clamp((int) Math.floor(x * slots), 0, slots - 1); + } +} From 97f3cc4fd5ae5a9cbb6c6fbc526c4473043c7478 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sat, 20 Dec 2025 21:23:39 +0100 Subject: [PATCH 399/399] add logging the click type when there is an unknown inventory action --- .../java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index f74294a6..7e48170d 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -398,7 +398,7 @@ public void onInventoryClick(InventoryClickEvent event) { } } else { // unable to log something we don't know - consumer.getLogblock().getLogger().warning("Unknown inventory action by " + event.getWhoClicked().getName() + ": " + event.getAction() + " Slot: " + event.getSlot() + " Slot type: " + event.getSlotType()); + consumer.getLogblock().getLogger().warning("Unknown inventory action by " + event.getWhoClicked().getName() + ": " + event.getAction() + " Click type: " + event.getClick() + " Slot: " + event.getSlot() + " Slot type: " + event.getSlotType()); } break; }