From cb5dce6724fb5a4cc6118b0ac2c1862148a904d3 Mon Sep 17 00:00:00 2001 From: Geph Date: Tue, 8 Apr 2025 00:51:27 -0600 Subject: [PATCH 01/11] Tracking spam-clicking the air --- pom.xml | 2 +- .../listeners/PlayerInteractListener.java | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index ee5ce28..b861394 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.emicb ContainerTracker - 1.3.1 + 1.3.2 jar ContainerTracker diff --git a/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java b/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java index 73dff37..0ceca96 100644 --- a/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java +++ b/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java @@ -27,7 +27,9 @@ public class PlayerInteractListener implements Listener { private final String PRESSURE_PLATE = "PRESSURE_PLATE"; private final String LEVER = "LEVER"; private final String BUTTON = "BUTTON"; - private final String OBSERVER = "OBSERVER"; + private Integer AIR_CLICK = 0; + String regionNames = ""; + //private final String OBSERVER = "OBSERVER"; @EventHandler @@ -35,19 +37,26 @@ public void OnPlayerInteract(PlayerInteractEvent event) { if (config.getBoolean("debug")) { log.info("[ContainerTracker] Interact Event triggered"); } + /* if (event.getClickedBlock() == null){ if (config.getBoolean("debug")) { log.info("[ContainerTracker] Interact Event ignored: action did not interact with a block"); } return; - } + }*/ Block clickedBlock = event.getClickedBlock(); Material blockMaterial = clickedBlock.getType(); if(blockMaterial == Material.AIR){ + AIR_CLICK += 1; + if (AIR_CLICK > 5) { + log.info("[ContainerTracker] Interact Event: clicked air over 5 times"); + ContainerTracker.getInstance().getQueryer().logNewPhysicalInteraction(event.getPlayer(), event.getClickedBlock(), regionNames); + AIR_CLICK = 0; + } return; } String blockName = blockMaterial.toString().toUpperCase(); - /** + /* // exit if not a physical interaction if (event.getAction() != Action.PHYSICAL) { if (config.getBoolean("debug")) { @@ -66,7 +75,6 @@ public void OnPlayerInteract(PlayerInteractEvent event) { Location blockLocation = BukkitAdapter.adapt(clickedBlock.getLocation()); RegionQuery query = container.createQuery(); ApplicableRegionSet set = query.getApplicableRegions(blockLocation); - String regionNames = ""; for (ProtectedRegion region : set) { regionNames += region.getId() + " "; } From 73749193cabe16095612d587afbe22783c749ff2 Mon Sep 17 00:00:00 2001 From: Geph Date: Tue, 8 Apr 2025 10:18:26 -0600 Subject: [PATCH 02/11] Tracking spam-clicking the air; now logs to database, each click a separate entry --- pom.xml | 2 +- .../listeners/PlayerInteractListener.java | 17 ++++++++--------- .../containertracker/utils/sql/Queryer.java | 6 +++++- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index b861394..6b825ca 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.emicb ContainerTracker - 1.3.2 + 1.3.3 jar ContainerTracker diff --git a/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java b/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java index 0ceca96..5766b44 100644 --- a/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java +++ b/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java @@ -27,7 +27,6 @@ public class PlayerInteractListener implements Listener { private final String PRESSURE_PLATE = "PRESSURE_PLATE"; private final String LEVER = "LEVER"; private final String BUTTON = "BUTTON"; - private Integer AIR_CLICK = 0; String regionNames = ""; //private final String OBSERVER = "OBSERVER"; @@ -44,17 +43,17 @@ public void OnPlayerInteract(PlayerInteractEvent event) { } return; }*/ - Block clickedBlock = event.getClickedBlock(); - Material blockMaterial = clickedBlock.getType(); - if(blockMaterial == Material.AIR){ - AIR_CLICK += 1; - if (AIR_CLICK > 5) { - log.info("[ContainerTracker] Interact Event: clicked air over 5 times"); + + //if(blockMaterial == Material.AIR){ + if (event.getClickedBlock() == null){ + if (config.getBoolean("debug")) { + log.info("[ContainerTracker] Interact Event: clicked air"); ContainerTracker.getInstance().getQueryer().logNewPhysicalInteraction(event.getPlayer(), event.getClickedBlock(), regionNames); - AIR_CLICK = 0; } return; } + Block clickedBlock = event.getClickedBlock(); + Material blockMaterial = clickedBlock.getType(); String blockName = blockMaterial.toString().toUpperCase(); /* // exit if not a physical interaction @@ -67,7 +66,7 @@ public void OnPlayerInteract(PlayerInteractEvent event) { */ if(!(blockName.contains(PRESSURE_PLATE) || blockName.contains(LEVER) || blockName.contains(BUTTON))){ if (config.getBoolean("debug")) { - log.info("[ContainerTracker] Interact Event ignored: action not with pressure plate, lever, or button"); + log.info("[ContainerTracker] Interact Event ignored: action was " + blockName); } return; } diff --git a/src/main/java/com/emicb/containertracker/utils/sql/Queryer.java b/src/main/java/com/emicb/containertracker/utils/sql/Queryer.java index 2acf379..59135b8 100644 --- a/src/main/java/com/emicb/containertracker/utils/sql/Queryer.java +++ b/src/main/java/com/emicb/containertracker/utils/sql/Queryer.java @@ -263,7 +263,11 @@ private PreparedStatement insertPhysicalInteraction(Connection connection, Playe statement.setDouble(5, player.getLocation().getY()); statement.setDouble(6, player.getLocation().getZ()); statement.setLong(7, System.currentTimeMillis()); - statement.setString(8, clickedBlock.getType().toString()); + if (clickedBlock != null) { + statement.setString(8, clickedBlock.getType().toString()); + } else { + statement.setString(8, "AIR CLICK"); + } statement.setString(9, regionNames); return statement; } From b57533710f5cf08796744e7f945120bca56cc912 Mon Sep 17 00:00:00 2001 From: Geph Date: Tue, 8 Apr 2025 10:21:12 -0600 Subject: [PATCH 03/11] Updating documentation --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 368f02b..f49bf9a 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,10 @@ A Minecraft plugin to track the contents (items and their positions) of container inventories. It will also track [physical actions](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/event/block/Action.html). +## Prerequisites + +See [WHIMC Server Documentation](https://docs.google.com/document/d/1T7UQParX9wVa3cVV-rwUFM5pJ7poIgMXGPR2lR-aAuo/edit?tab=t.0#bookmark=id.725lg2utykbb). + ## Building Compile a `.jar` from the commandline by doing an `install` via Maven: ``` From 52ee8c3e4015d840a6c9d0484728221ba4aa25cf Mon Sep 17 00:00:00 2001 From: Geph Date: Wed, 28 May 2025 22:59:13 -0600 Subject: [PATCH 04/11] Logging punch events between players, only works if PVP is not disabled upstream (globally at the server level or via worldguard) --- README.md | 4 +--- pom.xml | 2 +- .../listeners/PlayerInteractListener.java | 22 +++++++++++++++++- .../containertracker/utils/sql/Queryer.java | 23 ++++++++++++++++--- 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f49bf9a..6661b94 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ # ContainerTracker -[![GitHub release (latest by date)](https://img.shields.io/github/v/release/EmiCB/LockBar?label=Download&logo=github)](https://github.com/EmiCB/ContainerTracker/releases/latest) - A Minecraft plugin to track the contents (items and their positions) of container inventories. It will also track [physical actions](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/event/block/Action.html). @@ -69,7 +67,7 @@ Tracks when and where players interact with pressure plates, levers, or buttons. | `y` | `double` | The y position of the interaction (up/down height) | | `z` | `double` | The z position of the interaction | | `time` | `big int` | The unix time stamp when the interaction occurred | -| `type` | `string` | The type of block interacted with (pressure plate, lever, or button) | +| `type` | `string` | The type of block interacted with (air, pressure plate, lever, or button) | | `region_name` | `string` | The names of the regions where the interaction took place (regions names are separated by spaces) | ### whimc_barrelbot_outcome diff --git a/pom.xml b/pom.xml index 6b825ca..cdcef91 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.emicb ContainerTracker - 1.3.3 + 1.3.4 jar ContainerTracker diff --git a/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java b/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java index 5766b44..b97b574 100644 --- a/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java +++ b/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java @@ -8,13 +8,14 @@ import com.sk89q.worldguard.protection.regions.ProtectedRegion; import com.sk89q.worldguard.protection.regions.RegionContainer; import com.sk89q.worldguard.protection.regions.RegionQuery; +import org.bukkit.entity.Player; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.inventory.EquipmentSlot; import java.util.logging.Logger; @@ -31,6 +32,25 @@ public class PlayerInteractListener implements Listener { //private final String OBSERVER = "OBSERVER"; + @EventHandler + public void onPlayerPunchPlayer(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Player)) return; + if (!(event.getEntity() instanceof Player)) return; + + Player player = (Player) event.getDamager(); + Player target = (Player) event.getEntity(); + + String regionNames = ""; // You can optionally compute WorldGuard regions here if needed + + String interactionType = "PUNCH " + target.getName(); + + ContainerTracker.getInstance().getQueryer().logNewPhysicalInteraction(player, interactionType, regionNames); + + if (config.getBoolean("debug")) { + log.info("[ContainerTracker] " + player.getName() + " punched " + target.getName()); + } + } + @EventHandler public void OnPlayerInteract(PlayerInteractEvent event) { if (config.getBoolean("debug")) { diff --git a/src/main/java/com/emicb/containertracker/utils/sql/Queryer.java b/src/main/java/com/emicb/containertracker/utils/sql/Queryer.java index 59135b8..77b8786 100644 --- a/src/main/java/com/emicb/containertracker/utils/sql/Queryer.java +++ b/src/main/java/com/emicb/containertracker/utils/sql/Queryer.java @@ -16,6 +16,8 @@ import java.util.function.Consumer; import java.util.logging.Logger; +import static java.sql.DriverManager.getConnection; + /** * Handles storing position data * @@ -253,7 +255,7 @@ public void getInventoryID(Player player, Consumer callback) { * @return the generated PreparedStatement * @throws SQLException */ - private PreparedStatement insertPhysicalInteraction(Connection connection, Player player, Block clickedBlock, String regionNames) throws SQLException { + private PreparedStatement insertPhysicalInteraction(Connection connection, Player player, Block clickedBlock, String regionNames, String interactionTypeOverride) throws SQLException { PreparedStatement statement = connection.prepareStatement(QUERY_SAVE_ACTION_PHYSICAL, Statement.RETURN_GENERATED_KEYS); statement.setString(1, player.getUniqueId().toString()); @@ -263,11 +265,16 @@ private PreparedStatement insertPhysicalInteraction(Connection connection, Playe statement.setDouble(5, player.getLocation().getY()); statement.setDouble(6, player.getLocation().getZ()); statement.setLong(7, System.currentTimeMillis()); - if (clickedBlock != null) { + + // ✅ Use the override if provided, else fall back to block type or "AIR CLICK" + if (interactionTypeOverride != null) { + statement.setString(8, interactionTypeOverride); + } else if (clickedBlock != null) { statement.setString(8, clickedBlock.getType().toString()); } else { statement.setString(8, "AIR CLICK"); } + statement.setString(9, regionNames); return statement; } @@ -275,7 +282,7 @@ private PreparedStatement insertPhysicalInteraction(Connection connection, Playe public void logNewPhysicalInteraction(Player player, Block clickedBlock, String regionNames) { async(() -> { try (Connection connection = this.sqlConnection.getConnection()) { - try (PreparedStatement statement = insertPhysicalInteraction(connection, player, clickedBlock, regionNames)) { + try (PreparedStatement statement = insertPhysicalInteraction(connection, player, clickedBlock, regionNames, null)) { String query = statement.toString().substring(statement.toString().indexOf(" ") + 1); Utils.debug(" " + query); statement.executeUpdate(); @@ -289,6 +296,16 @@ public void logNewPhysicalInteraction(Player player, Block clickedBlock, String }); } + public void logNewPhysicalInteraction(Player player, String interactionTypeOverride, String regionNames) { + try (Connection connection = this.sqlConnection.getConnection()) { + PreparedStatement statement = insertPhysicalInteraction(connection, player, null, regionNames, interactionTypeOverride); + statement.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + private void loadTemporaryInventoryID(String query, Consumer prepare, Consumer callback) { async(() -> { try (Connection connection = this.sqlConnection.getConnection()) { From c551a4980780f2f362a7b6fa5258b18a6918b50a Mon Sep 17 00:00:00 2001 From: Geph Date: Mon, 2 Jun 2025 12:15:25 -0600 Subject: [PATCH 05/11] Log player deaths as a physical_action type event (it's indirect but still considered to be in the same category) Eliminated warnings about code (string concatination, local variables, etc) - dependency security problems require updates we can't do without version number shifts. --- README.md | 2 +- pom.xml | 2 +- .../listeners/PlayerInteractListener.java | 79 ++++++++++--------- 3 files changed, 44 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 6661b94..59e655d 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Tracks when and where players interact with pressure plates, levers, or buttons. | `y` | `double` | The y position of the interaction (up/down height) | | `z` | `double` | The z position of the interaction | | `time` | `big int` | The unix time stamp when the interaction occurred | -| `type` | `string` | The type of block interacted with (air, pressure plate, lever, or button) | +| `type` | `string` | The type of block interacted with (air, death, pressure plate, lever, or button) | | `region_name` | `string` | The names of the regions where the interaction took place (regions names are separated by spaces) | ### whimc_barrelbot_outcome diff --git a/pom.xml b/pom.xml index cdcef91..2c46563 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.emicb ContainerTracker - 1.3.4 + 1.3.5 jar ContainerTracker diff --git a/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java b/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java index b97b574..a49c8f6 100644 --- a/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java +++ b/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java @@ -8,13 +8,14 @@ import com.sk89q.worldguard.protection.regions.ProtectedRegion; import com.sk89q.worldguard.protection.regions.RegionContainer; import com.sk89q.worldguard.protection.regions.RegionQuery; -import org.bukkit.entity.Player; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.PlayerInteractEvent; import java.util.logging.Logger; @@ -25,12 +26,24 @@ public class PlayerInteractListener implements Listener { // Set up logger private final Logger log = Logger.getLogger("Minecraft"); - private final String PRESSURE_PLATE = "PRESSURE_PLATE"; - private final String LEVER = "LEVER"; - private final String BUTTON = "BUTTON"; - String regionNames = ""; - //private final String OBSERVER = "OBSERVER"; + private static final String PRESSURE_PLATE = "PRESSURE_PLATE"; + private static final String LEVER = "LEVER"; + private static final String BUTTON = "BUTTON"; + + @EventHandler + public void onPlayerDeath(PlayerDeathEvent event) { + Player player = event.getEntity(); + String regionNames = getRegionNamesAt(player.getLocation()); + + // Log "DEATH" as the interaction type + ContainerTracker.getInstance().getQueryer() + .logNewPhysicalInteraction(player, "DEATH", regionNames); + + if (config.getBoolean("debug")) { + log.info("[ContainerTracker] " + player.getName() + " has had a death event logged."); + } + } @EventHandler public void onPlayerPunchPlayer(EntityDamageByEntityEvent event) { @@ -40,7 +53,7 @@ public void onPlayerPunchPlayer(EntityDamageByEntityEvent event) { Player player = (Player) event.getDamager(); Player target = (Player) event.getEntity(); - String regionNames = ""; // You can optionally compute WorldGuard regions here if needed + String regionNames = getRegionNamesAt(player.getLocation()); String interactionType = "PUNCH " + target.getName(); @@ -56,58 +69,50 @@ public void OnPlayerInteract(PlayerInteractEvent event) { if (config.getBoolean("debug")) { log.info("[ContainerTracker] Interact Event triggered"); } - /* - if (event.getClickedBlock() == null){ - if (config.getBoolean("debug")) { - log.info("[ContainerTracker] Interact Event ignored: action did not interact with a block"); - } - return; - }*/ - //if(blockMaterial == Material.AIR){ - if (event.getClickedBlock() == null){ + if (event.getClickedBlock() == null) { if (config.getBoolean("debug")) { log.info("[ContainerTracker] Interact Event: clicked air"); - ContainerTracker.getInstance().getQueryer().logNewPhysicalInteraction(event.getPlayer(), event.getClickedBlock(), regionNames); } + ContainerTracker.getInstance().getQueryer().logNewPhysicalInteraction(event.getPlayer(), event.getClickedBlock(), ""); return; } + Block clickedBlock = event.getClickedBlock(); Material blockMaterial = clickedBlock.getType(); String blockName = blockMaterial.toString().toUpperCase(); - /* - // exit if not a physical interaction - if (event.getAction() != Action.PHYSICAL) { - if (config.getBoolean("debug")) { - log.info("[ContainerTracker] Interact Event ignored: action was not of type PHYSICAL"); - } - return; - } - */ - if(!(blockName.contains(PRESSURE_PLATE) || blockName.contains(LEVER) || blockName.contains(BUTTON))){ + + if (!(blockName.contains(PRESSURE_PLATE) || blockName.contains(LEVER) || blockName.contains(BUTTON))) { if (config.getBoolean("debug")) { log.info("[ContainerTracker] Interact Event ignored: action was " + blockName); } return; } - RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); - Location blockLocation = BukkitAdapter.adapt(clickedBlock.getLocation()); - RegionQuery query = container.createQuery(); - ApplicableRegionSet set = query.getApplicableRegions(blockLocation); - for (ProtectedRegion region : set) { - regionNames += region.getId() + " "; - } + String regionNames = getRegionNamesAt(clickedBlock.getLocation()); if (config.getBoolean("debug")) { log.info("[ContainerTracker] Logging Information:\n" + "Timestamp: " + System.currentTimeMillis() + "\n" + "Player: " + event.getPlayer().getName() + " : " + event.getPlayer().getUniqueId() + "\n" + "Location: " + event.getPlayer().getLocation() + "\n" - + "Block Type: " + event.getClickedBlock().getType() + "\n" - + "Region Name: " + regionNames + "\n" + + "Block Type: " + event.getClickedBlock().getType() + "\n" + + "Region Name: " + regionNames + "\n" ); } ContainerTracker.getInstance().getQueryer().logNewPhysicalInteraction(event.getPlayer(), event.getClickedBlock(), regionNames); } -} \ No newline at end of file + + private String getRegionNamesAt(org.bukkit.Location bukkitLocation) { + RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); + Location adaptedLocation = BukkitAdapter.adapt(bukkitLocation); + RegionQuery query = container.createQuery(); + ApplicableRegionSet set = query.getApplicableRegions(adaptedLocation); + + StringBuilder regionNamesBuilder = new StringBuilder(); + for (ProtectedRegion region : set) { + regionNamesBuilder.append(region.getId()).append(" "); + } + return regionNamesBuilder.toString().trim(); + } +} From 3665c27e38e3a67f8a489b68343b343d3ac84eb9 Mon Sep 17 00:00:00 2001 From: Geph Date: Mon, 2 Jun 2025 15:08:01 -0600 Subject: [PATCH 06/11] Just changing the name --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2c46563..59e219d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.emicb - ContainerTracker + WHIMC-ContainerTracker 1.3.5 jar From c8338f5123687818444cbe5317e983b3d32885dc Mon Sep 17 00:00:00 2001 From: Geph Date: Mon, 2 Jun 2025 15:08:33 -0600 Subject: [PATCH 07/11] Just changing the name --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 59e219d..95aa1a3 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.emicb - WHIMC-ContainerTracker + WHIMC-ContainerActionTracker 1.3.5 jar From cbfe4b9b58c938423edd6e85035c1d1042e7f9ba Mon Sep 17 00:00:00 2001 From: Jeff Ginger Date: Mon, 2 Jun 2025 15:24:14 -0600 Subject: [PATCH 08/11] Update README.md Renaming to reflect what it actually does --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 59e655d..6eea9be 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ContainerTracker +# ContainerActionTracker A Minecraft plugin to track the contents (items and their positions) of container inventories. It will also track [physical actions](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/event/block/Action.html). @@ -108,4 +108,4 @@ Tracks when and where players close a shulker or barrel and all the items that w - Weighted pressure plates spam the database - Citizens can trigger physical interactions (working on an optional toggle for this) - Double chests ar not supported -- Containers that are under the size of 27 slots throw an error and the contents do not get stored \ No newline at end of file +- Containers that are under the size of 27 slots throw an error and the contents do not get stored From f990efe1c23b1cd8973a4ebcada69c800ebcfe1d Mon Sep 17 00:00:00 2001 From: Jeff Ginger Date: Mon, 2 Jun 2025 15:26:22 -0600 Subject: [PATCH 09/11] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6eea9be..a42a6f5 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Tracks when and where players interact with pressure plates, levers, or buttons. | `y` | `double` | The y position of the interaction (up/down height) | | `z` | `double` | The z position of the interaction | | `time` | `big int` | The unix time stamp when the interaction occurred | -| `type` | `string` | The type of block interacted with (air, death, pressure plate, lever, or button) | +| `type` | `string` | The type of block or action (air click, death, pressure plate, lever, or button) | | `region_name` | `string` | The names of the regions where the interaction took place (regions names are separated by spaces) | ### whimc_barrelbot_outcome From 0080ea79f892242deef91141e240409a196fc269 Mon Sep 17 00:00:00 2001 From: jeffginger Date: Mon, 7 Jul 2025 16:13:51 -0500 Subject: [PATCH 10/11] suppressing logs, death type recorded --- pom.xml | 2 +- .../listeners/PlayerInteractListener.java | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 95aa1a3..c0bfe12 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.emicb WHIMC-ContainerActionTracker - 1.3.5 + 1.3.6 jar ContainerTracker diff --git a/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java b/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java index a49c8f6..af27cb0 100644 --- a/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java +++ b/src/main/java/com/emicb/containertracker/listeners/PlayerInteractListener.java @@ -36,12 +36,19 @@ public void onPlayerDeath(PlayerDeathEvent event) { String regionNames = getRegionNamesAt(player.getLocation()); - // Log "DEATH" as the interaction type + // Get the death cause + String causeType = "UNKNOWN"; + if (player.getLastDamageCause() != null) { + causeType = player.getLastDamageCause().getCause().toString(); + } + + String interactionType = "DEATH " + causeType; + ContainerTracker.getInstance().getQueryer() - .logNewPhysicalInteraction(player, "DEATH", regionNames); + .logNewPhysicalInteraction(player, interactionType, regionNames); if (config.getBoolean("debug")) { - log.info("[ContainerTracker] " + player.getName() + " has had a death event logged."); + log.info("[ContainerTracker] " + player.getName() + " died (" + causeType + ") and it was logged."); } } @@ -72,7 +79,7 @@ public void OnPlayerInteract(PlayerInteractEvent event) { if (event.getClickedBlock() == null) { if (config.getBoolean("debug")) { - log.info("[ContainerTracker] Interact Event: clicked air"); + /*log.info("[ContainerTracker] Interact Event: clicked air");*/ } ContainerTracker.getInstance().getQueryer().logNewPhysicalInteraction(event.getPlayer(), event.getClickedBlock(), ""); return; @@ -84,7 +91,7 @@ public void OnPlayerInteract(PlayerInteractEvent event) { if (!(blockName.contains(PRESSURE_PLATE) || blockName.contains(LEVER) || blockName.contains(BUTTON))) { if (config.getBoolean("debug")) { - log.info("[ContainerTracker] Interact Event ignored: action was " + blockName); + /*log.info("[ContainerTracker] Interact Event ignored: action was " + blockName);*/ } return; } From 62cdcceaf37ae23ebe73b33995bbfb3cc0b1f447 Mon Sep 17 00:00:00 2001 From: Geph Date: Wed, 10 Jun 2026 15:11:31 -0600 Subject: [PATCH 11/11] Prepare WHIMC-Container-Tracker 1.4.0 for Minecraft 1.21.11 with automated GitHub releases. Co-authored-by: Cursor --- .github/workflows/release.yml | 51 +++++ README.md | 213 +++++++++++------- pom.xml | 109 +++------ .../containertracker/ContainerTracker.java | 4 +- .../containertracker/utils/sql/Queryer.java | 87 +++---- src/main/resources/plugin.yml | 11 +- 6 files changed, 256 insertions(+), 219 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..14d696d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,51 @@ +name: Build and Release + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '21' + cache: maven + + - name: Get current version + id: version + run: | + VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) + NEXT=$(echo "$VERSION" | awk -F. '{print $1"."$2"."$3+1}') + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "next=$NEXT" >> "$GITHUB_OUTPUT" + + - name: Build + run: mvn -B clean package + + - name: Create release + uses: softprops/action-gh-release@v2 + with: + tag_name: v${{ steps.version.outputs.version }} + name: v${{ steps.version.outputs.version }} + files: target/WHIMC-Container-Tracker-${{ steps.version.outputs.version }}.jar + generate_release_notes: true + + - name: Bump version for next release + run: | + mvn -B versions:set -DnewVersion=${{ steps.version.outputs.next }} -DgenerateBackupPoms=false + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add pom.xml + git commit -m "Bump version to ${{ steps.version.outputs.next }} [skip ci]" + git push diff --git a/README.md b/README.md index a42a6f5..ba94c8c 100644 --- a/README.md +++ b/README.md @@ -1,111 +1,162 @@ -# ContainerActionTracker -A Minecraft plugin to track the contents (items and their positions) of container inventories. -It will also track [physical actions](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/event/block/Action.html). +# WHIMC-Container-Tracker + +**Version:** 1.4.0 +**Minecraft:** 1.21.11 (Spigot/Paper API `1.21.11-R0.1-SNAPSHOT`) + +A WHIMC Minecraft plugin that logs container inventories and player physical interactions to MySQL. It is used alongside other WHIMC data-collection plugins (for example WHIMC-StudentFeedback) that read the tables this plugin writes. + +## Download + +Grab the latest built jar from the [latest release](https://github.com/whimc/WHIMC-ContainerTracker/releases/latest). A new release is published automatically on every push to `main`, and the version number in `pom.xml` is bumped by 0.1 after each release (for example 1.4.0 → 1.4.1). + +The release artifact is named `WHIMC-Container-Tracker-.jar`. On the server, plugin configuration is stored in `plugins/WHIMC-Container-Tracker/`. ## Prerequisites -See [WHIMC Server Documentation](https://docs.google.com/document/d/1T7UQParX9wVa3cVV-rwUFM5pJ7poIgMXGPR2lR-aAuo/edit?tab=t.0#bookmark=id.725lg2utykbb). +- Minecraft **1.21.11** server (Spigot or Paper) +- **JDK 21** on the build machine; the server runtime also requires Java 21 for 1.21.x +- **ProtocolLib** (required) +- **WorldGuard** (required at runtime for region names on logged events) +- **MySQL** database reachable from the server -## Building -Compile a `.jar` from the commandline by doing an `install` via Maven: -``` -$ mvn install -``` -It should show up in the `target` directory. Make sure to update the version number. +See also [WHIMC Server Documentation](https://docs.google.com/document/d/1T7UQParX9wVa3cVV-rwUFM5pJ7poIgMXGPR2lR-aAuo/edit?tab=t.0#bookmark=id.725lg2utykbb). ---- +## What This Plugin Tracks -## Commands +| Category | Trigger | Stored in | +|---|---|---| +| Barrel / shulker contents | Player closes a barrel or shulker box inventory | `whimc_containers` | +| Physical blocks | Player steps on or clicks pressure plates, levers, or buttons | `whimc_action_physical` | +| Air clicks | Player left-clicks empty space (each click is a separate row) | `whimc_action_physical` (`type`: `AIR CLICK`) | +| Player punches | Player damages another player (requires PvP enabled) | `whimc_action_physical` (`type`: `PUNCH `) | +| Player deaths | Player dies | `whimc_action_physical` (`type`: `DEATH `) | +| Barrelbot puzzle success | Server chat message containing `[Barrelbot]` (via ProtocolLib) | `whimc_barrelbot_outcome` | +| In-session puzzle counts | Barrelbot success messages while the server is running | In-memory only (used by `/puzzle-progress`) | + +For container slots, barrelbot instruction items store the instruction name (for example `move_forward`). Other items store serialized item metadata from the Bukkit YAML representation, or the material name when no meta is present. -| Command | Description | -|--------------------|--------------------| -| `/ct-toggle-debug` | toggles debug mode | +## Commands -Note: planning to refactor the command structure and possibly add more commands as needed +| Command | Usage | Description | +|---|---|---| +| `/ct-toggle-debug` | `/ct-toggle-debug` | Toggles debug mode in `config.yml` (also logs extra detail to the server console) | +| `/puzzle-progress` | `/puzzle-progress ` | Lists barrelbot puzzles the given online player has completed on the current world during this server session | ## Config + +Config file: `plugins/WHIMC-Container-Tracker/config.yml` + ### General -| Key | Type | Description | -|----------------|----------------|----------------------------------------------------| -| `debug` | `boolean` | enable / disable debug mode | -####Example +| Key | Type | Description | +|---|---|---| +| `debug` | `boolean` | Enable / disable debug mode | + +Example: + ```yaml debug: true ``` ### MySQL -| Key | Type | Description | -|------------------|-----------|---------------------------------| -| `mysql.host` | `string` | The host of the database | -| `mysql.port` | `integer` | The port of the database | -| `mysql.database` | `string` | The name of the database to use | -| `mysql.username` | `string` | Username for credentials | -| `mysql.password` | `string` | Password for credentials | +| Key | Type | Description | +|---|---|---| +| `mysql.host` | `string` | Database host | +| `mysql.port` | `integer` | Database port | +| `mysql.database` | `string` | Database name | +| `mysql.username` | `string` | Database username | +| `mysql.password` | `string` | Database password | + +Example: -####Example ```yaml mysql: - host: localhost - port: 3306 - database: minecraft - username: user - password: pass + host: localhost + port: 3306 + database: minecraft + username: user + password: pass ``` + ## Database Tables + ### whimc_action_physical -Tracks when and where players interact with pressure plates, levers, or buttons. - -| Column | Type | Description | -|---------------|-----------|---------------------------------------------------------------------------------------------------| -| `rowid` | `int` | Unique row id for db entry | -| `uuid` | `string` | UUID of player causing the interaction | -| `username` | `string` | Name of the player causing the interaction | -| `world` | `string` | Name of the world where the interaction occurred | -| `x` | `double` | The x position of the interaction | -| `y` | `double` | The y position of the interaction (up/down height) | -| `z` | `double` | The z position of the interaction | -| `time` | `big int` | The unix time stamp when the interaction occurred | -| `type` | `string` | The type of block or action (air click, death, pressure plate, lever, or button) | -| `region_name` | `string` | The names of the regions where the interaction took place (regions names are separated by spaces) | + +Tracks player physical interactions and related events. + +| Column | Type | Description | +|---|---|---| +| `rowid` | `int` | Unique row id | +| `uuid` | `string` | Player UUID | +| `username` | `string` | Player name | +| `world` | `string` | World name | +| `x` | `double` | Player x position | +| `y` | `double` | Player y position | +| `z` | `double` | Player z position | +| `time` | `bigint` | Unix timestamp (ms) | +| `type` | `string` | Block type, `AIR CLICK`, `DEATH `, or `PUNCH ` | +| `region_name` | `string` | WorldGuard region ids (space-separated) | ### whimc_barrelbot_outcome -Tracks when and where players complete Barrelbot puzzles and the last inventory that they closed. - -| Column | Type | Description | -|--------------------|-----------|-----------------------------------------------------------------------------| -| `rowid` | `int` | Unique row id for db entry | -| `uuid` | `string` | UUID of player who completed the puzzle | -| `username` | `string` | Name of the player who completed the puzzle | -| `world` | `string` | Name of the world where the puzzle was completed | -| `x` | `double` | The x position of the player | -| `y` | `double` | The y position of the player (up/down height) | -| `z` | `double` | The z position of the player | -| `time` | `big int` | The unix time stamp when the puzzle was completed | -| `outcome` | `string` | The outcome of the puzzle (currently only has Success) | -| `inventory_row_id` | `int` | The last rowid in whimc_containers from the player before puzzle completion | -| `puzzle_name` | `string` | The name of puzzle that the player completed | + +Tracks barrelbot puzzle completions detected from chat. + +| Column | Type | Description | +|---|---|---| +| `rowid` | `int` | Unique row id | +| `uuid` | `string` | Player UUID | +| `username` | `string` | Player name | +| `world` | `string` | World name | +| `x` | `double` | Player x position | +| `y` | `double` | Player y position | +| `z` | `double` | Player z position | +| `time` | `bigint` | Unix timestamp (ms) | +| `outcome` | `string` | Puzzle outcome (`Success` or `Failure`) | +| `inventory_row_id` | `int` | Latest `whimc_containers.rowid` for the player before completion | +| `puzzle_name` | `string` | Puzzle name from the barrelbot chat message | ### whimc_containers -Tracks when and where players close a shulker or barrel and all the items that were in it when closed. - -| Column | Type | Description | -|------------------|-----------|-------------------------------------------------------------------------------------------------| -| `rowid` | `int` | Unique row id for db entry | -| `uuid` | `string` | UUID of player who closed an inventory | -| `username` | `string` | Name of the player who closed an inventory | -| `world` | `string` | Name of the world where the inventory was closed | -| `x` | `double` | The x position of the inventory | -| `y` | `double` | The y position of the inventory (up/down height) | -| `z` | `double` | The z position of the inventory | -| `time` | `big int` | The unix time stamp when the inventory was closed | -| `slot1-27` | `string` | The name of the block in the inventory slot (1 is the top left and 27 is the bottom right) | -| `inventory_type` | `string` | Name of the inventory (barrel or shulker) | -| `region_name` | `string` | The names of the regions where the inventory is located (regions names are separated by spaces) | + +Tracks barrel and shulker box contents when the inventory is closed. + +| Column | Type | Description | +|---|---|---| +| `rowid` | `int` | Unique row id | +| `uuid` | `string` | Player UUID | +| `username` | `string` | Player name | +| `world` | `string` | World name | +| `x` | `double` | Container x position | +| `y` | `double` | Container y position | +| `z` | `double` | Container z position | +| `time` | `bigint` | Unix timestamp (ms) | +| `slot1`–`slot27` | `string` | Item data per slot (top-left = slot1, bottom-right = slot27) | +| `inventory_type` | `string` | Inventory type (`BARREL` or shulker box type) | +| `region_name` | `string` | WorldGuard region ids (space-separated) | + +## Building + +Requires JDK 21+. + +```bash +mvn clean package +``` + +Output: `target/WHIMC-Container-Tracker-1.4.0.jar` (version matches `pom.xml`). + +## Releases + +Pushes to `main` trigger the GitHub Actions **Build and Release** workflow: + +1. Builds the jar at the current `pom.xml` version +2. Creates a GitHub release tagged `v` with the jar attached +3. Commits a version bump (+0.1) to `pom.xml` for the next release + +To cut a release manually, run the workflow from the Actions tab (**workflow_dispatch**). ## Known Issues -- Weighted pressure plates spam the database -- Citizens can trigger physical interactions (working on an optional toggle for this) -- Double chests ar not supported -- Containers that are under the size of 27 slots throw an error and the contents do not get stored + +- Weighted pressure plates can spam the database +- Citizens NPCs can trigger physical interactions (optional toggle planned) +- Double chests are not supported +- Containers with fewer than 27 slots may error and contents may not be stored diff --git a/pom.xml b/pom.xml index c0bfe12..8d069e2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,102 +4,46 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.emicb - WHIMC-ContainerActionTracker - 1.3.6 + edu.whimc + WHIMC-Container-Tracker + 1.4.0 jar - ContainerTracker + WHIMC Container Tracker + Tracks container inventories and physical player actions for WHIMC - 1.8 + 21 UTF-8 + ${project.artifactId}-${project.version} + + + src/main/resources + true + + org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.13.0 - ${java.version} - ${java.version} + 21 - - org.apache.maven.plugins - maven-shade-plugin - 3.2.4 - - - package - - shade - - - false - - - - - - net.md-5 - specialsource-maven-plugin - 1.2.2 - - - package - - remap - - remap-obf - - org.spigotmc:minecraft-server:1.20.4-R0.1-SNAPSHOT:txt:maps-mojang - true - org.spigotmc:spigot:1.20.4-R0.1-SNAPSHOT:jar:remapped-mojang - true - remapped-obf - - - - package - - remap - - remap-spigot - - ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar - org.spigotmc:minecraft-server:1.20.4-R0.1-SNAPSHOT:csrg:maps-spigot - org.spigotmc:spigot:1.20.4-R0.1-SNAPSHOT:jar:remapped-obf - - - - - - - src/main/resources - true - - - spigotmc-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - - - sonatype - https://oss.sonatype.org/content/groups/public/ - - - dmulloy2-repo - https://repo.dmulloy2.net/repository/public/ + spigot-repo + https://hub.spigotmc.org/nexus/content/groups/public/ - sk89q-repo + enginehub-repo https://maven.enginehub.org/repo/ @@ -107,21 +51,26 @@ org.spigotmc - spigot - 1.20.4-R0.1-SNAPSHOT + spigot-api + 1.21.11-R0.1-SNAPSHOT provided - remapped-mojang - com.comphenix.protocol + net.dmulloy2 ProtocolLib - 5.1.0 + 5.4.0 provided com.sk89q.worldguard worldguard-bukkit - 7.0.9 + 7.0.15 + provided + + + com.google.code.gson + gson + 2.11.0 provided diff --git a/src/main/java/com/emicb/containertracker/ContainerTracker.java b/src/main/java/com/emicb/containertracker/ContainerTracker.java index 1097c56..38c5db7 100644 --- a/src/main/java/com/emicb/containertracker/ContainerTracker.java +++ b/src/main/java/com/emicb/containertracker/ContainerTracker.java @@ -14,14 +14,12 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import org.apache.commons.lang.StringUtils; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; -import java.util.ArrayList; import java.util.HashMap; import java.util.logging.Logger; @@ -86,7 +84,7 @@ public void onPacketSending(PacketEvent event) { if(message.contains(BARRELBOTFLAG)) { log.info("[ContainerTracker] Chat Event triggered"); JsonObject jsonMessage; - jsonMessage = new JsonParser().parse(message).getAsJsonObject(); + jsonMessage = JsonParser.parseString(message).getAsJsonObject(); JsonElement jsonElement = jsonMessage.get(JSONMESSAGEKEY); if(jsonElement != null) { JsonArray jsonArray = jsonElement.getAsJsonArray(); diff --git a/src/main/java/com/emicb/containertracker/utils/sql/Queryer.java b/src/main/java/com/emicb/containertracker/utils/sql/Queryer.java index 77b8786..9d4bd92 100644 --- a/src/main/java/com/emicb/containertracker/utils/sql/Queryer.java +++ b/src/main/java/com/emicb/containertracker/utils/sql/Queryer.java @@ -2,12 +2,11 @@ import com.emicb.containertracker.ContainerTracker; import com.emicb.containertracker.utils.Utils; -import net.minecraft.nbt.CompoundTag; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -15,6 +14,8 @@ import java.util.function.Consumer; import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static java.sql.DriverManager.getConnection; @@ -25,6 +26,10 @@ */ public class Queryer { + private static final int CHEST_SIZE = 27; + private static final Pattern BARRELBOT_INSTRUCTION = + Pattern.compile("instruction:\\s*['\"]?([^'\"\\r\\n]+)['\"]?"); + //Query for inserting skills into the database. private static final String QUERY_SAVE_INVENTORY = "INSERT INTO whimc_containers " + @@ -86,7 +91,6 @@ private PreparedStatement insertInventory(Connection connection, Player player, ItemStack[] contents = inventory.getContents(); String inventoryType = inventory.getType().name(); Location inventoryLocation = inventory.getLocation(); - final int CHEST_SIZE = 27; statement.setString(1, player.getUniqueId().toString()); statement.setString(2, player.getName()); statement.setString(3, inventoryLocation.getWorld().getName()); @@ -96,59 +100,18 @@ private PreparedStatement insertInventory(Connection connection, Player player, statement.setLong(7, System.currentTimeMillis()); for (int i = 0; i < contents.length; i++) { ItemStack item = contents[i]; - //Safety check for larger chests can't store in our db - if(i >= CHEST_SIZE){ + if (i >= CHEST_SIZE) { if (config.getBoolean("debug")) { - log.info("[ContainerTracker] slot " + i + " is larger than what can be stored in the db and won't be tracked"); - } - net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item); - CompoundTag tag = nmsItem.getTag(); - if (item == null && config.getBoolean("debug")) { - log.info("[ContainerTracker] slot " + i + " has: nothing"); - } else if (tag != null && config.getBoolean("debug")) { - log.info("[ContainerTracker] slot " + i + " has: " + tag); - } else { - if (config.getBoolean("debug")) { - log.info("[ContainerTracker] slot " + i + " has: " + nmsItem); - } + log.info("[WHIMC-Container-Tracker] slot " + i + " is larger than what can be stored in the db and won't be tracked"); } continue; } - if (item == null) { - if (config.getBoolean("debug")) { - log.info("[ContainerTracker] slot " + i + " has: nothing"); - } - statement.setString(i+8, null); - continue; - } - net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item); - CompoundTag tag = nmsItem.getTag(); - if(tag != null){ - //Parse nbttag as string ex: {CustomModelData:130000,barrelbot:{instruction:"move_forward"},display:{Lore:['{"text":"Moves the barrelbot forward","color":"gray","italic":false}','{"text":"1 tile, if it is open","color":"gray","italic":false}','{"text":" "}','{"text":"Instruction","color":"blue","italic":false}'],Name:'{"text":"Move Forward","color":"#FFAA00","italic":false}'}} - String text = ""; - final String BARRELBOTKEY = "barrelbot"; - final String INSTRUCTIONKEY = "instruction"; - if(tag.contains(BARRELBOTKEY)) { - CompoundTag barrelbot = tag.getCompound(BARRELBOTKEY); - if (barrelbot.contains(INSTRUCTIONKEY)) { - text = barrelbot.getString(INSTRUCTIONKEY); - } else { - text = barrelbot.toString(); - } - } else { - text = tag.toString(); - } - if (config.getBoolean("debug")) { - log.info("[ContainerTracker] slot " + i + " has: " + text); - } - statement.setString(i + 8, text); - } else { - if (config.getBoolean("debug")) { - log.info("[ContainerTracker] slot " + i + " has: " + nmsItem); - } - statement.setString(i + 8, nmsItem.toString()); + String slotValue = itemToStorageString(item); + if (config.getBoolean("debug")) { + log.info("[WHIMC-Container-Tracker] slot " + i + " has: " + slotValue); } + statement.setString(i + 8, slotValue); } statement.setString(35, inventoryType); statement.setString(36, regionNames); @@ -336,4 +299,28 @@ private void sync(Runnable runnable) { private void async(Runnable runnable) { Bukkit.getScheduler().runTaskAsynchronously(this.plugin, runnable); } + + private String itemToStorageString(ItemStack item) { + if (item == null || item.getType().isAir()) { + return null; + } + + YamlConfiguration yaml = new YamlConfiguration(); + yaml.set("item", item); + String serialized = yaml.saveToString(); + + if (serialized.contains("barrelbot")) { + Matcher matcher = BARRELBOT_INSTRUCTION.matcher(serialized); + if (matcher.find()) { + return matcher.group(1).trim(); + } + return serialized.trim(); + } + + if (item.hasItemMeta()) { + return serialized.trim(); + } + + return item.getType().name(); + } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index e32339e..88676b6 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,12 +1,13 @@ -name: ContainerTracker +name: WHIMC-Container-Tracker version: '${project.version}' main: com.emicb.containertracker.ContainerTracker -api-version: 1.20 +api-version: '1.21' depend: [ProtocolLib] +softdepend: [WorldGuard] commands: ct-toggle-debug: - description: toggles debug mode for ContainerTracker + description: toggles debug mode for WHIMC-Container-Tracker usage: / puzzle-progress: - description: allows players to see what puzzles others have solved - usage: / \ No newline at end of file + description: shows which barrelbot puzzles a player has completed this session + usage: /