From 3954261f74f3c889d78d3ac579ebd2afe909b4a9 Mon Sep 17 00:00:00 2001 From: Dmitry Rendov Date: Mon, 5 Jan 2026 15:35:41 +0100 Subject: [PATCH 1/3] 12 - Added xrm check alias, fixed materials --- .github/ISSUE_TEMPLATE/bug-report.md | 4 +- pom.xml | 2 +- src/main/java/me/drendov/XRayMonitor/Cmd.java | 83 +++++++++++-------- .../me/drendov/XRayMonitor/Listeners.java | 72 ++++++++-------- .../drendov/XRayMonitor/lookups/Checkers.java | 14 +++- .../XRayMonitor/lookups/LogBlockLookup.java | 58 +++++++++---- 6 files changed, 143 insertions(+), 90 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index bf1660e..2a3cb2a 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -25,9 +25,9 @@ about: Create a report to help us improve XRayMonitor ### Server Information * **Server version/platform:** -* **XRayMonitor Version:** +* **XRayMonitor Version:** * **LogBlock Version:** -* **Other plugins(if any):** + ### Additional Info diff --git a/pom.xml b/pom.xml index 468298d..092bd96 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ me.drendov.xRayMonitor XRayMonitor - 1.1.1 + 1.1.2 jar XRayMonitor Let's fight X-Ray cheat with simple Math! diff --git a/src/main/java/me/drendov/XRayMonitor/Cmd.java b/src/main/java/me/drendov/XRayMonitor/Cmd.java index 6978062..6d3d334 100644 --- a/src/main/java/me/drendov/XRayMonitor/Cmd.java +++ b/src/main/java/me/drendov/XRayMonitor/Cmd.java @@ -28,36 +28,67 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String // xrm if (cmd.getName().equalsIgnoreCase("xrm")) { if (sender.hasPermission("xrm.check") || sender.isOp()) { + + // Handle subcommands + if (args.length == 1 && args[0].equalsIgnoreCase("reload")) { + plugin.config.load(); + XRayMonitor.sendMessage(player, TextMode.Success, Messages.Reloaded); + return true; + } + if (args.length == 1 && args[0].equalsIgnoreCase("help")) { + plugin.showHelp(sender); + return true; + } + if (args.length == 2 && args[0].equalsIgnoreCase("clear")) { + if (sender.hasPermission("xrm.clear") || sender.isOp()) { + try { + plugin.clearPlayer(sender, args[1]); + } catch (Exception e) { + e.printStackTrace(); + } + return true; + } + XRayMonitor.sendMessage(player, TextMode.Err, Messages.NoPermissionForCommand); + return true; + } + + // Handle "check" subcommand - shift args if it's present + String[] shiftedArgs = args; + if (args.length > 0 && args[0].equalsIgnoreCase("check")) { + if (args.length < 2) { + plugin.showInfo(sender); + return true; + } + // Remove "check" from args, shift everything down + shiftedArgs = new String[args.length - 1]; + System.arraycopy(args, 1, shiftedArgs, 0, args.length - 1); + } + String playerName = ""; - if (args.length > 0) { - if (!args[0].contains(":")) { - playerName = args[0]; + if (shiftedArgs.length > 0) { + if (!shiftedArgs[0].contains(":")) { + playerName = shiftedArgs[0]; } } else { plugin.showInfo(sender); return true; } + String world = ""; int hours = -1; String oreName = ""; float rate = 0.0f; HashMap hm = new HashMap(); - String[] nonPlayerArgs = new String[args.length]; + String[] nonPlayerArgs = new String[shiftedArgs.length]; try { int i; - if (!args[0].contains(":")) { - if (args[0].equals("clear")) { - for (i = 2; i < args.length; ++i) { - nonPlayerArgs[i - 2] = args[i]; - } - } else { - for (i = 1; i < args.length; ++i) { - nonPlayerArgs[i - 1] = args[i]; - } + if (!shiftedArgs[0].contains(":")) { + for (i = 1; i < shiftedArgs.length; ++i) { + nonPlayerArgs[i - 1] = shiftedArgs[i]; } } else { - for (i = 0; i < args.length; ++i) { - nonPlayerArgs[i] = args[i]; + for (i = 0; i < shiftedArgs.length; ++i) { + nonPlayerArgs[i] = shiftedArgs[i]; } } for (String arg : nonPlayerArgs) { @@ -94,27 +125,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String oreName = hm.get("ore"); logger.info("DEBUG: oreName=" + oreName); } - if (args.length == 1 && args[0].equalsIgnoreCase("reload")) { - plugin.config.load(); - XRayMonitor.sendMessage(player, TextMode.Success, Messages.Reloaded); - return true; - } - if (args.length == 1 && args[0].equalsIgnoreCase("help")) { - plugin.showHelp(sender); - return true; - } - if (args.length == 2 && args[0].equalsIgnoreCase("clear")) { - if (sender.hasPermission("xrm.clear") || sender.isOp()) { - try { - plugin.clearPlayer(sender, args[1]); - } catch (Exception e) { - e.printStackTrace(); - } - return true; - } - XRayMonitor.sendMessage(player, TextMode.Err, Messages.NoPermissionForCommand); - return true; - } + if (playerName.length() == 0) { this.plugin.showInfo(sender); return true; diff --git a/src/main/java/me/drendov/XRayMonitor/Listeners.java b/src/main/java/me/drendov/XRayMonitor/Listeners.java index c72a3c7..06b84d1 100644 --- a/src/main/java/me/drendov/XRayMonitor/Listeners.java +++ b/src/main/java/me/drendov/XRayMonitor/Listeners.java @@ -67,40 +67,46 @@ public void run() { int count_netherrack = 0; int count_basalt = 0; if (Listeners.this.plugin.getConfig().getString("logging_plugin").equalsIgnoreCase("logblock")) { - count_stone = Listeners.this.lb.oreLookup(playerName, "stone", world, hours); - count_andesite = Listeners.this.lb.oreLookup(playerName, "andesite", world, hours); - count_diorite = Listeners.this.lb.oreLookup(playerName, "diorite", world, hours); - count_granite = Listeners.this.lb.oreLookup(playerName, "granite", world, hours); - count_deepslate = Listeners.this.lb.oreLookup(playerName, "deepslate", world, hours); - count_deepslate_bricks = Listeners.this.lb.oreLookup(playerName, "deepslate_bricks", world, hours); - count_deepslate_tiles = Listeners.this.lb.oreLookup(playerName, "deepslate_tiles", world, hours); - count_polished_deepslate = Listeners.this.lb.oreLookup(playerName, "polished_deepslate", world, hours); - count_chiseled_deepslate = Listeners.this.lb.oreLookup(playerName, "chiseled_deepslate", world, hours); - count_calcite = Listeners.this.lb.oreLookup(playerName, "calcite", world, hours); - count_blackstone = Listeners.this.lb.oreLookup(playerName, "blackstone", world, hours); - count_stones = count_stone + count_andesite + count_diorite + count_granite + count_deepslate + count_deepslate_bricks + count_deepslate_tiles + count_polished_deepslate + count_chiseled_deepslate + count_calcite + count_blackstone; - - diamond_count = Listeners.this.lb.oreLookup(playerName, "diamond_ore", world, hours); - diamond_count += Listeners.this.lb.oreLookup(playerName, "deepslate_diamond_ore", world, hours); - gold_count = Listeners.this.lb.oreLookup(playerName, "gold_ore", world, hours); - gold_count += Listeners.this.lb.oreLookup(playerName, "deepslate_gold_ore", world, hours); - gold_count += Listeners.this.lb.oreLookup(playerName, "nether_gold_ore", world, hours); - lapis_count = Listeners.this.lb.oreLookup(playerName, "lapis_ore", world, hours); - lapis_count += Listeners.this.lb.oreLookup(playerName, "deepslate_lapis_ore", world, hours); - copper_count = Listeners.this.lb.oreLookup(playerName, "copper_ore", world, hours); - copper_count += Listeners.this.lb.oreLookup(playerName, "deepslate_copper_ore", world, hours); - iron_count = Listeners.this.lb.oreLookup(playerName, "iron_ore", world, hours); - iron_count += Listeners.this.lb.oreLookup(playerName, "deepslate_iron_ore", world, hours); redstone_count = Listeners.this.lb.oreLookup(playerName, "redstone_ore", world, hours); - coal_count = Listeners.this.lb.oreLookup(playerName, "coal_ore", world, hours); - coal_count += Listeners.this.lb.oreLookup(playerName, "deepslate_coal_ore", world, hours); - mossy_count = Listeners.this.lb.oreLookup(playerName, "mossy_cobblestone", world, hours); - emerald_count = Listeners.this.lb.oreLookup(playerName, "emerald_ore", world, hours); - emerald_count += Listeners.this.lb.oreLookup(playerName, "deepslate_emerald_ore", world, hours); - ancient_debris_count = Listeners.this.lb.oreLookup(playerName, "ancient_debris", world, hours); - spawner_count = Listeners.this.lb.oreLookup(playerName, "spawner", world, hours); - count_netherrack = Listeners.this.lb.oreLookup(playerName, "netherrack", world, hours); - count_basalt = Listeners.this.lb.oreLookup(playerName, "basalt", world, hours); + try { + count_stone = Listeners.this.lb.oreLookup(playerName, "stone", world, hours); + count_andesite = Listeners.this.lb.oreLookup(playerName, "andesite", world, hours); + count_diorite = Listeners.this.lb.oreLookup(playerName, "diorite", world, hours); + count_granite = Listeners.this.lb.oreLookup(playerName, "granite", world, hours); + count_deepslate = Listeners.this.lb.oreLookup(playerName, "deepslate", world, hours); + count_deepslate_bricks = Listeners.this.lb.oreLookup(playerName, "deepslate_bricks", world, hours); + count_deepslate_tiles = Listeners.this.lb.oreLookup(playerName, "deepslate_tiles", world, hours); + count_polished_deepslate = Listeners.this.lb.oreLookup(playerName, "polished_deepslate", world, hours); + count_chiseled_deepslate = Listeners.this.lb.oreLookup(playerName, "chiseled_deepslate", world, hours); + count_calcite = Listeners.this.lb.oreLookup(playerName, "calcite", world, hours); + count_blackstone = Listeners.this.lb.oreLookup(playerName, "blackstone", world, hours); + count_stones = count_stone + count_andesite + count_diorite + count_granite + count_deepslate + count_deepslate_bricks + count_deepslate_tiles + count_polished_deepslate + count_chiseled_deepslate + count_calcite + count_blackstone; + diamond_count = Listeners.this.lb.oreLookup(playerName, "diamond_ore", world, hours); + diamond_count += Listeners.this.lb.oreLookup(playerName, "deepslate_diamond_ore", world, hours); + gold_count = Listeners.this.lb.oreLookup(playerName, "gold_ore", world, hours); + gold_count += Listeners.this.lb.oreLookup(playerName, "deepslate_gold_ore", world, hours); + gold_count += Listeners.this.lb.oreLookup(playerName, "nether_gold_ore", world, hours); + lapis_count = Listeners.this.lb.oreLookup(playerName, "lapis_ore", world, hours); + lapis_count += Listeners.this.lb.oreLookup(playerName, "deepslate_lapis_ore", world, hours); + copper_count = Listeners.this.lb.oreLookup(playerName, "copper_ore", world, hours); + copper_count += Listeners.this.lb.oreLookup(playerName, "deepslate_copper_ore", world, hours); + iron_count = Listeners.this.lb.oreLookup(playerName, "iron_ore", world, hours); + iron_count += Listeners.this.lb.oreLookup(playerName, "deepslate_iron_ore", world, hours); + redstone_count = Listeners.this.lb.oreLookup(playerName, "redstone_ore", world, hours); + redstone_count += Listeners.this.lb.oreLookup(playerName, "deepslate_redstone_ore", world, hours); + coal_count = Listeners.this.lb.oreLookup(playerName, "coal_ore", world, hours); + coal_count += Listeners.this.lb.oreLookup(playerName, "deepslate_coal_ore", world, hours); + mossy_count = Listeners.this.lb.oreLookup(playerName, "mossy_cobblestone", world, hours); + emerald_count = Listeners.this.lb.oreLookup(playerName, "emerald_ore", world, hours); + emerald_count += Listeners.this.lb.oreLookup(playerName, "deepslate_emerald_ore", world, hours); + ancient_debris_count = Listeners.this.lb.oreLookup(playerName, "ancient_debris", world, hours); + spawner_count = Listeners.this.lb.oreLookup(playerName, "spawner", world, hours); + count_netherrack = Listeners.this.lb.oreLookup(playerName, "netherrack", world, hours); + count_basalt = Listeners.this.lb.oreLookup(playerName, "basalt", world, hours); + } catch (Exception ex) { + Listeners.this.plugin.getLogger().severe("Error during ore lookup for player " + playerName + ": " + ex.getMessage()); + ex.printStackTrace(); + } } String dia = ""; String gld = ""; diff --git a/src/main/java/me/drendov/XRayMonitor/lookups/Checkers.java b/src/main/java/me/drendov/XRayMonitor/lookups/Checkers.java index 09caa00..c88040d 100644 --- a/src/main/java/me/drendov/XRayMonitor/lookups/Checkers.java +++ b/src/main/java/me/drendov/XRayMonitor/lookups/Checkers.java @@ -259,8 +259,20 @@ private ChatColor determineOreColor(String oreType, float percentage) { * Format percentage to 2 decimal places */ private String formatPercentage(float percentage) { + // Handle special cases + if (Float.isInfinite(percentage) || Float.isNaN(percentage) || percentage < 0) { + return "0.00"; + } + if (percentage > 100) { + return "100.00"; + } + String s = percentage + "000000000"; - return String.valueOf(Float.parseFloat(s.substring(0, s.lastIndexOf('.') + 3))); + int dotIndex = s.lastIndexOf('.'); + if (dotIndex == -1) { + return String.valueOf((int) percentage); + } + return String.valueOf(Float.parseFloat(s.substring(0, dotIndex + 3))); } /** diff --git a/src/main/java/me/drendov/XRayMonitor/lookups/LogBlockLookup.java b/src/main/java/me/drendov/XRayMonitor/lookups/LogBlockLookup.java index 03db405..d196e4c 100644 --- a/src/main/java/me/drendov/XRayMonitor/lookups/LogBlockLookup.java +++ b/src/main/java/me/drendov/XRayMonitor/lookups/LogBlockLookup.java @@ -16,25 +16,49 @@ public class LogBlockLookup { private XRayMonitor plugin = XRayMonitor.getInstance(); public int oreLookup(String player, String oreName, String world, int hours) throws SQLException { - LogBlock logBlock = (LogBlock)this.plugin.getServer().getPluginManager().getPlugin("LogBlock"); - QueryParams params = new QueryParams(logBlock); - params.setPlayer(player); - params.bct = QueryParams.BlockChangeType.DESTROYED; - params.limit = -1; - params.since = hours * 60; - params.world = this.plugin.getServer().getWorld(world); + try { + LogBlock logBlock = (LogBlock)this.plugin.getServer().getPluginManager().getPlugin("LogBlock"); + if (logBlock == null) { + this.plugin.getLogger().warning("LogBlockLookup: LogBlock plugin not found!"); + return 0; + } - final Material mat = Material.matchMaterial(oreName); - if (mat == null) { - throw new IllegalArgumentException("No material matching: '" + oreName + "'"); - } - ArrayList lookupListTypes = new ArrayList<>(); - lookupListTypes.add(mat); - params.types = lookupListTypes; + QueryParams params = new QueryParams(logBlock); + params.setPlayer(player); + params.bct = QueryParams.BlockChangeType.DESTROYED; + params.limit = -1; + params.since = hours * 60; + params.world = this.plugin.getServer().getWorld(world); + + if (params.world == null) { + this.plugin.getLogger().warning("LogBlockLookup: World '" + world + "' not found!"); + return 0; + } + + final Material mat = Material.matchMaterial(oreName); + if (mat == null) { + this.plugin.getLogger().warning("LogBlockLookup: No material matching '" + oreName + "' for player " + player); + return 0; + } - params.needCount = true; - int count = logBlock.getCount(params); - return count; + ArrayList lookupListTypes = new ArrayList<>(); + lookupListTypes.add(mat); + params.types = lookupListTypes; + + params.needCount = true; + int count = logBlock.getCount(params); + + // Debug logging + if (count > 0 || "stone".equals(oreName) || "deepslate".equals(oreName)) { + this.plugin.getLogger().info("[DEBUG] LogBlock lookup - Player: " + player + ", Ore: " + oreName + " (" + mat + "), World: " + world + ", Hours: " + hours + ", Count: " + count); + } + + return count; + } catch (Exception e) { + this.plugin.getLogger().severe("Error in oreLookup for player " + player + ", ore " + oreName + ": " + e.getMessage()); + e.printStackTrace(); + return 0; + } } public List playerLookup(CommandSender sender, String oreName, String world) { From dda8790ac66fb88294aac6f58ec439ca39b5c779 Mon Sep 17 00:00:00 2001 From: Dmitry Rendov Date: Mon, 5 Jan 2026 16:20:33 +0100 Subject: [PATCH 2/3] 12 - Added DEBUG option to config --- pom.xml | 2 +- src/config.yml | 1 + src/main/java/me/drendov/XRayMonitor/Cmd.java | 40 ++++++++++++++----- .../java/me/drendov/XRayMonitor/Config.java | 5 +++ .../XRayMonitor/lookups/LogBlockLookup.java | 7 +++- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index 092bd96..feaf7b0 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ me.drendov.xRayMonitor XRayMonitor - 1.1.2 + 1.2.0 jar XRayMonitor Let's fight X-Ray cheat with simple Math! diff --git a/src/config.yml b/src/config.yml index 50ecdac..fee2b25 100644 --- a/src/config.yml +++ b/src/config.yml @@ -49,3 +49,4 @@ logOreBreaks: mossy: false spawners: false logging_plugin: logblock +debug: false diff --git a/src/main/java/me/drendov/XRayMonitor/Cmd.java b/src/main/java/me/drendov/XRayMonitor/Cmd.java index 6d3d334..d7827b3 100644 --- a/src/main/java/me/drendov/XRayMonitor/Cmd.java +++ b/src/main/java/me/drendov/XRayMonitor/Cmd.java @@ -103,7 +103,9 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String } if (hm.containsKey("rate")) { rate = Float.parseFloat(hm.get("rate")); - logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " rate=" + rate); + if (plugin.config.isDebug()) { + logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " rate=" + rate); + } if ( rate <= 0 ) { XRayMonitor.sendMessage(player, TextMode.Err, Messages.ErrRatePositive); return true; @@ -111,11 +113,15 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String } if (hm.containsKey("since")) { hours = Integer.parseInt(hm.get("since")); - logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " hours=" + hours); + if (plugin.config.isDebug()) { + logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " hours=" + hours); + } } if (hm.containsKey("world")) { world = hm.get("world"); - logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " world=" + world); + if (plugin.config.isDebug()) { + logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " world=" + world); + } if (!plugin.checkWorld(world)) { XRayMonitor.sendMessage(player, TextMode.Err, Messages.WorldNotFound); return true; @@ -123,7 +129,9 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String } if (hm.containsKey("ore")) { oreName = hm.get("ore"); - logger.info("DEBUG: oreName=" + oreName); + if (plugin.config.isDebug()) { + logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " oreName=" + oreName); + } } if (playerName.length() == 0) { @@ -134,7 +142,9 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String try { if (ClearedPlayerFile.wasPlayerCleared(playerName)) { hours = ClearedPlayerFile.getHoursFromClear(playerName); - logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " hours for cleared playerName=" + hours); + if (plugin.config.isDebug()) { + logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " hours for cleared playerName=" + hours); + } } world = Config.defaultWorld; if (world != null && !plugin.checkWorld(world)) { @@ -142,7 +152,9 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String return true; } - logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " Run global check for " + playerName + " world=" + world + " hours=" + hours); + if (plugin.config.isDebug()) { + logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " Run global check for " + playerName + " world=" + world + " hours=" + hours); + } this.checker.checkGlobal(playerName, sender, world, hours); return true; } catch (Exception e) { @@ -158,7 +170,9 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String if (ClearedPlayerFile.wasPlayerCleared(playerName)) { hours = ClearedPlayerFile.getHoursFromClear(playerName); } - logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " Run global check for " + playerName + " sender=" + sender + " world=" + world + " hours=" + hours); + if (plugin.config.isDebug()) { + logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " Run global check for " + playerName + " sender=" + sender + " world=" + world + " hours=" + hours); + } this.checker.checkGlobal(playerName, sender, world, hours); return true; } catch (Exception e) { @@ -167,12 +181,16 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String } if (world.length() > 0 && !oreName.isEmpty()) { if (playerName.equalsIgnoreCase("all") && rate > 0.0f) { - logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " List All XRay-ers check for world=" + world + " oreName=" + oreName + " rate=" + rate + " hours=" + hours); + if (plugin.config.isDebug()) { + logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " List All XRay-ers check for world=" + world + " oreName=" + oreName + " rate=" + rate + " hours=" + hours); + } new Thread(new CustomRunnable(sender, world, oreName, rate, hours) { @Override public void run() { - logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " List All XRay-ers check for world=" + this.world + " this.oreName=" + this.oreName + " this.rate=" + this.rate + " this.hours=" + this.hours); + if (plugin.config.isDebug()) { + logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " List All XRay-ers check for world=" + this.world + " this.oreName=" + this.oreName + " this.rate=" + this.rate + " this.hours=" + this.hours); + } Cmd.this.checker.listAllXRayers(this.sender, this.world, this.oreName, this.rate, this.hours); } }).start(); @@ -181,7 +199,9 @@ public void run() { if (ClearedPlayerFile.wasPlayerCleared(playerName)) { hours = ClearedPlayerFile.getHoursFromClear(playerName); } - logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " Run checkSingle for " + playerName + " oreName=" + oreName + " world=" + world + " hours=" + hours); + if (plugin.config.isDebug()) { + logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " Run checkSingle for " + playerName + " oreName=" + oreName + " world=" + world + " hours=" + hours); + } this.checker.checkSingle(playerName, sender, oreName, world, hours); return true; } diff --git a/src/main/java/me/drendov/XRayMonitor/Config.java b/src/main/java/me/drendov/XRayMonitor/Config.java index e314f68..cdcc975 100644 --- a/src/main/java/me/drendov/XRayMonitor/Config.java +++ b/src/main/java/me/drendov/XRayMonitor/Config.java @@ -15,6 +15,7 @@ void load() { this.plugin.reloadConfig(); this.config = this.plugin.getConfig(); this.config.addDefault("logging_plugin", "logblock"); + this.config.addDefault("debug", false); this.config.addDefault("default_world", "world"); this.config.addDefault("checkOnPlayerJoin", true); this.config.addDefault("checkOnPlayerJoin.warningMessage", "%player% has higher than average stats for %ores% and may be a cheater. Watch carefully."); @@ -77,6 +78,10 @@ public double getRate(String type, String ore) { return this.config.getDouble(ore + "_" + type); } + public boolean isDebug() { + return this.config.getBoolean("debug"); + } + String getCmd(String name) { return this.config.getString(name); } diff --git a/src/main/java/me/drendov/XRayMonitor/lookups/LogBlockLookup.java b/src/main/java/me/drendov/XRayMonitor/lookups/LogBlockLookup.java index d196e4c..1eebf04 100644 --- a/src/main/java/me/drendov/XRayMonitor/lookups/LogBlockLookup.java +++ b/src/main/java/me/drendov/XRayMonitor/lookups/LogBlockLookup.java @@ -9,11 +9,14 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.logging.Logger; +import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.command.CommandSender; public class LogBlockLookup { private XRayMonitor plugin = XRayMonitor.getInstance(); + private Logger logger = plugin.getLogger(); public int oreLookup(String player, String oreName, String world, int hours) throws SQLException { try { @@ -49,8 +52,8 @@ public int oreLookup(String player, String oreName, String world, int hours) thr int count = logBlock.getCount(params); // Debug logging - if (count > 0 || "stone".equals(oreName) || "deepslate".equals(oreName)) { - this.plugin.getLogger().info("[DEBUG] LogBlock lookup - Player: " + player + ", Ore: " + oreName + " (" + mat + "), World: " + world + ", Hours: " + hours + ", Count: " + count); + if (this.plugin.config.isDebug()) { + logger.info(ChatColor.RED + "[DEBUG]" + ChatColor.WHITE + " LogBlock lookup - Player: " + player + ", Ore: " + oreName + " (" + mat + "), World: " + world + ", Hours: " + hours + ", Count: " + count); } return count; From 4412e1303c757c8ccaf1fc79a68d88459ac15258 Mon Sep 17 00:00:00 2001 From: Dmitry Rendov Date: Mon, 5 Jan 2026 16:34:09 +0100 Subject: [PATCH 3/3] Prepare new tests for future --- .../java/me/drendov/XRayMonitor/CmdTest.java | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 src/test/java/me/drendov/XRayMonitor/CmdTest.java diff --git a/src/test/java/me/drendov/XRayMonitor/CmdTest.java b/src/test/java/me/drendov/XRayMonitor/CmdTest.java new file mode 100644 index 0000000..51f254a --- /dev/null +++ b/src/test/java/me/drendov/XRayMonitor/CmdTest.java @@ -0,0 +1,119 @@ +package me.drendov.XRayMonitor; + +import org.junit.jupiter.api.DisplayName; + +/** + * Unit Test Cases for Cmd Command Handler + * + * This test class documents all potential command scenarios and their expected behavior. + * + * XRayMonitor provides the following commands: + * + * 1. /xrm reload + * - Reloads the configuration file + * - Requires: xrm.check permission or OP status + * - Expected: true (command handled) + * - Action: Calls plugin.config.load() + * + * 2. /xrm help + * - Displays help information + * - Requires: xrm.check permission or OP status + * - Expected: true (command handled) + * - Action: Calls plugin.showHelp() + * + * 3. /xrm clear + * - Clears player's recorded data + * - Requires: xrm.check AND xrm.clear permissions or OP status + * - Expected: true (command handled) + * - Action: Calls plugin.clearPlayer(player) + * + * 4. /xrm check [params...] + * - Checks for suspicious ore mining patterns + * - Optional subcommand: "check" can be omitted + * - Requires: xrm.check permission or OP status + * + * Parameters (all optional, use key:value format): + * - world: - Specify which world to check (default: default world) + * - ore: - Check specific ore type (default: global check for all ores) + * - since: - Check last N hours (default: -1 for all time) + * - rate: - Confidence threshold for listing (default: 0.0) + * + * Examples: + * - /xrm check WaterDemon + * - /xrm check WaterDemon world:world ore:diamond + * - /xrm check WaterDemon ore:diamond world:world since:24 rate:3.5 + * - /xrm WaterDemon (check is implicit) + * - /xrm all ore:diamond rate:3.5 world:world + * (Special: when player name is "all", lists all players matching criteria) + * + * TEST SCENARIOS: + * + * A. SUBCOMMAND TESTS + * 1. Reload command succeeds with permission + * 2. Help command succeeds + * 3. Clear command with both permissions + * 4. Clear command without xrm.clear permission + * 5. Clear command missing player argument (ignored) + * 6. Command fails without xrm.check permission + * 7. Command succeeds with OP status (bypasses permissions) + * + * B. CHECK COMMAND PARAMETER TESTS + * 1. Check with player name only (implicit check) + * 2. Check with "check" subcommand explicit + * 3. Check without "check" subcommand (implicit) + * 4. Check with world parameter + * 5. Check with ore parameter + * 6. Check with rate parameter + * 7. Check with since parameter + * 8. Check with all parameters combined + * 9. Check invalid world (should fail silently or show error) + * 10. Check rate = 0 (invalid, triggers error message) + * 11. Check rate < 0 (invalid, triggers error message) + * + * C. SPECIAL CASES + * 1. Player name "all" with ore and rate (lists all matching players) + * 2. Player name "all" without rate (does single check for all) + * 3. Missing player name shows info + * 4. Check without any arguments shows info + * 5. Parameter without colon is ignored + * 6. Parameter with multiple colons (only first one splits key:value) + * + * D. CASE SENSITIVITY TESTS + * 1. "reload", "RELOAD", "Reload" all work + * 2. "help", "HELP", "Help" all work + * 3. "check", "CHECK", "Check" all work + * 4. "clear", "CLEAR", "Clear" all work + * + * E. EDGE CASES + * 1. Very large arguments array (100+ items) + * 2. Empty player name string + * 3. Player name with special characters (_-123) + * 4. Non-xrm command returns false + * 5. Rate parameter with many decimals (3.14159265) + * 6. Since parameter with very large hours (99999) + * 7. Multiple parameters in different orders + * + * F. DEBUG LOGGING + * 1. DEBUG logs output when config.isDebug() = true + * 2. DEBUG logs suppressed when config.isDebug() = false + * + * G. PERMISSION TESTS + * 1. xrm.check allows check commands + * 2. xrm.clear allows clear command + * 3. OP status bypasses all permission checks + * 4. Missing both permission and OP denies command + * + * IMPLEMENTATION NOTES: + * - The Cmd class uses a static initializer that requires XRayMonitor singleton + * - For integration testing, use the full plugin environment + * - Unit test coverage focuses on command parsing logic and parameter handling + * - Parameter parsing handles malformed input gracefully + * - All commands are case-insensitive via equalsIgnoreCase() + */ +@DisplayName("Cmd Command Handler - Test Case Documentation") +public class CmdTest { + // This file serves as documentation for all command test scenarios + // For actual test execution, use integration tests with the full plugin environment + // or use Bukkit test frameworks that support the full server initialization +} +