From 63353c620593f34b9f6ddc52fc42a3a5e7febafe Mon Sep 17 00:00:00 2001 From: alexcrea Date: Mon, 2 Mar 2026 03:24:42 +0100 Subject: [PATCH] progress on diagnostic command --- src/main/kotlin/io/delilaheve/CustomAnvil.kt | 11 +- .../alexcrea/cuanvil/command/CASubCommand.kt | 6 +- .../cuanvil/command/CustomAnvilCmd.kt | 22 +- .../alexcrea/cuanvil/command/DebugExecutor.kt | 25 +++ .../alexcrea/cuanvil/command/Diagnostic.kt | 77 ------- .../cuanvil/command/DiagnosticExecutor.kt | 195 ++++++++++++++++++ 6 files changed, 243 insertions(+), 93 deletions(-) create mode 100644 src/main/kotlin/xyz/alexcrea/cuanvil/command/DebugExecutor.kt delete mode 100644 src/main/kotlin/xyz/alexcrea/cuanvil/command/Diagnostic.kt create mode 100644 src/main/kotlin/xyz/alexcrea/cuanvil/command/DiagnosticExecutor.kt diff --git a/src/main/kotlin/io/delilaheve/CustomAnvil.kt b/src/main/kotlin/io/delilaheve/CustomAnvil.kt index e870bf0..902b76d 100644 --- a/src/main/kotlin/io/delilaheve/CustomAnvil.kt +++ b/src/main/kotlin/io/delilaheve/CustomAnvil.kt @@ -68,6 +68,8 @@ open class CustomAnvil : JavaPlugin() { // Chat message listener lateinit var chatListener: ChatEventListener + var latestVer: String? = null + /** * Logging handler */ @@ -195,10 +197,11 @@ open class CustomAnvil : JavaPlugin() { ModrinthUpdateChecker(modrinthPluginID, loader, null) .setFeatured(featured) .setOnError { logger.log(Level.WARNING, "error trying to fetch latest update", it) } - .checkVersion { latestver: String? -> - if(latestver == null || version.contains(latestver)) return@checkVersion + .checkVersion { latestVer: String? -> + CustomAnvil.latestVer = latestVer + if(latestVer == null || version.contains(latestVer)) return@checkVersion - logger.warning("An update may be available: $latestver") + logger.warning("An update may be available: $latestVer") } } @@ -296,8 +299,6 @@ open class CustomAnvil : JavaPlugin() { command = getCommand(commandConfigName) command?.setExecutor(EditConfigExecutor()) - println(getCommand("customanvil")) - println(getCommand("customanvila")) CustomAnvilCmd(this) } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/command/CASubCommand.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/command/CASubCommand.kt index 7558127..85c1a58 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/command/CASubCommand.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/command/CASubCommand.kt @@ -33,8 +33,10 @@ abstract class CASubCommand: CommandExecutor { return true } - open fun tabCompleter(list: MutableList) { - + open fun tabCompleter( + sender: CommandSender, + args: Array, + list: MutableList) { } } \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/command/CustomAnvilCmd.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/command/CustomAnvilCmd.kt index 5de1c04..421ec7b 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/command/CustomAnvilCmd.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/command/CustomAnvilCmd.kt @@ -17,14 +17,14 @@ class CustomAnvilCmd(plugin: CustomAnvil) : CommandExecutor, TabCompleter { } private val editConfigCommand = EditConfigExecutor() - private val commands: ImmutableMap + private val commands = ImmutableMap.of( + "gui", editConfigCommand, + "reload", ReloadExecutor(), + "diagnostic", DiagnosticExecutor(), + //"debug", DebugExecutor(), + ) init { - commands = ImmutableMap.of( - "gui", editConfigCommand, - "reload", ReloadExecutor(), - "diagnostic", Diagnostic(), - ) println(plugin.getCommand(genericCommandName)) val self = plugin.getCommand(genericCommandName)!! @@ -61,13 +61,17 @@ class CustomAnvilCmd(plugin: CustomAnvil) : CommandExecutor, TabCompleter { args: Array ): MutableList { val result = ArrayList() - if(args.isEmpty()) { + if(args.size < 3) { for (cmd in commands) { result.add(cmd.key) } } else { - val subcmd = commands[args[0].lowercase()] - subcmd?.tabCompleter(result) + val subcmd = commands[args[1].lowercase()] + + if(subcmd != null) { + val newArgs = args.copyOfRange(1, args.size) + subcmd.tabCompleter(sender, newArgs, result) + } } //assumed all provided tab completed string are lowercase diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/command/DebugExecutor.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/command/DebugExecutor.kt new file mode 100644 index 0000000..e7cbe9e --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/command/DebugExecutor.kt @@ -0,0 +1,25 @@ +package xyz.alexcrea.cuanvil.command + +import io.delilaheve.CustomAnvil +import org.bukkit.command.Command +import org.bukkit.command.CommandSender +import java.util.logging.Level + +class DebugExecutor : CASubCommand() { + + override fun executeCommand( + sender: CommandSender, + cmd: Command, + cmdstr: String, + args: Array + ): Boolean { + CustomAnvil.instance.logger.log(Level.SEVERE, "aaaaaaaaaaaaaaaaaaa"); + return true + } + + override fun tabCompleter(sender: CommandSender, args: Array, list: MutableList) { + //TODO + + } + +} diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/command/Diagnostic.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/command/Diagnostic.kt deleted file mode 100644 index 9752894..0000000 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/command/Diagnostic.kt +++ /dev/null @@ -1,77 +0,0 @@ -package xyz.alexcrea.cuanvil.command - -import io.delilaheve.CustomAnvil -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.Bukkit -import org.bukkit.ChatColor -import org.bukkit.command.Command -import org.bukkit.command.CommandSender -import org.bukkit.entity.HumanEntity - -class Diagnostic: CASubCommand() { - - companion object{ - private const val NO_DIAG_PERM = "You do not have permission to diagnostic this server" - } - - override fun executeCommand( - sender: CommandSender, - cmd: Command, - cmdstr: String, - args: Array - ): Boolean { - if (!allowed(sender)) { - sender.sendMessage(NO_DIAG_PERM) - return false - } - - val stb = StringBuilder("```\n") - try { - diagnostic(stb) - } catch(e: Exception){ - // TODO append error message to diag - TODO("error not handled yet $e") - } - - stb.append("\n```") - - if (sender is HumanEntity) { - val message = TextComponent(ChatColor.GREEN.toString() + "Click to copy diagnostic data") - - message.clickEvent = ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, stb.toString()) - message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, Text("§7Click to copy")) - - sender.spigot().sendMessage(message); - } else { - sender.sendMessage(stb.toString()); - } - - return true - } - - override fun allowed(sender: CommandSender): Boolean { - return sender.hasPermission(CustomAnvil.diagnosticPermission) - } - - fun diagnostic(stb: StringBuilder){ - stb.append("Server Info\n"); - stb.append("Plugin Version: ").append(CustomAnvil.instance.description.version).append("\n"); - stb.append("Server Version: ").append(Bukkit.getVersion()).append(" (").append(Bukkit.getName()).append(')').append("\n"); - stb.append("Plugin Enabled: ").append(if(CustomAnvil.instance.isEnabled) "Yes" else "No").append("\n"); - //stb.append("NMS type: ").append(NMSMapper.hasNMS() ? "Yes" : "No").append("\n"); - stb.append("Java Version: ").append(System.getProperty("java.version")).append("\n"); - stb.append("OS: ").append(System.getProperty("os.name")).append(" ") - .append(System.getProperty("os.version")) - .append(System.getProperty("os.arch")) - .append("\n\n"); - stb.append("Architecture: ").append(System.getProperty("os.arch")).append("\n\n"); - - - - } - - -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/command/DiagnosticExecutor.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/command/DiagnosticExecutor.kt new file mode 100644 index 0000000..23ab4b9 --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/command/DiagnosticExecutor.kt @@ -0,0 +1,195 @@ +package xyz.alexcrea.cuanvil.command + +import io.delilaheve.CustomAnvil +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.Bukkit +import org.bukkit.ChatColor +import org.bukkit.command.Command +import org.bukkit.command.CommandSender +import org.bukkit.entity.HumanEntity +import org.bukkit.event.inventory.PrepareAnvilEvent +import org.bukkit.plugin.Plugin +import org.bukkit.plugin.RegisteredListener +import xyz.alexcrea.cuanvil.dependency.DependencyManager +import xyz.alexcrea.cuanvil.dependency.packet.NoPacketManager +import xyz.alexcrea.cuanvil.dependency.packet.ProtocoLibWrapper +import xyz.alexcrea.cuanvil.dependency.packet.versions.PaperPacketManager +import java.util.* +import java.util.stream.Collectors + + +class DiagnosticExecutor: CASubCommand() { + + companion object{ + private const val NO_DIAG_PERM = "You do not have permission to diagnostic this server" + } + + enum class DiagParams(val value: String) { + OS_PRIVACY("os_privacy"), + PLUGIN_PRIVACY("plugin_privacy"), + //NO_TEST("no_anvil_test"), + } + + private fun fetchParameters(args: Array): EnumSet { + val result = EnumSet.noneOf(DiagParams::class.java) + val argSet = HashSet() + + for (string in args) { + argSet.add(string.lowercase()) + } + + for (param in DiagParams.entries) { + if(argSet.contains(param.value)) + result.add(param) + } + + return result + } + + override fun tabCompleter( + sender: CommandSender, + args: Array, + list: MutableList) { + if(!allowed(sender)) return + + val map = fetchParameters(args) + for (param in DiagParams.entries) { + if(!map.contains(param)) + list.add(param.value) + } + + } + + override fun executeCommand( + sender: CommandSender, + cmd: Command, + cmdstr: String, + args: Array + ): Boolean { + if (!allowed(sender)) { + sender.sendMessage(NO_DIAG_PERM) + return false + } + + val stb = StringBuilder("```\n") + val params = fetchParameters(args) + try { + diagnostic(stb, params) + } catch(e: Exception){ + stb.append("\n\nError happened trying to get diagnostic data:\n") + .append(e.message).append("\n") + .append(e.stackTrace.joinToString("\n")) + } + + stb.append("\n```") + + if (sender is HumanEntity) { + val message = TextComponent(ChatColor.GREEN.toString() + "Click to copy diagnostic data") + + message.clickEvent = ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, stb.toString()) + message.hoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, Text("§7Click to copy")) + + sender.spigot().sendMessage(message); + } else { + sender.sendMessage(stb.toString()); + } + + return true + } + + override fun allowed(sender: CommandSender): Boolean { + return sender.hasPermission(CustomAnvil.diagnosticPermission) + } + + fun diagnostic(stb: StringBuilder, params: Set){ + stb.append("Server Info\n") + stb.append("Plugin Version: ").append(CustomAnvil.instance.description.version).append("\n") + stb.append("Latest Update: ").append(CustomAnvil.latestVer).append('\n') + stb.append("Server Version: ").append(Bukkit.getVersion()).append(" (").append(Bukkit.getName()).append(')').append("\n") + stb.append("Plugin Enabled: ").append(if(CustomAnvil.instance.isEnabled) "Yes" else "No").append("\n") + stb.append("NMS type: ").append(fetchNMSType()) + if(!params.contains(DiagParams.OS_PRIVACY)) { + stb.append("Java Version: ").append(System.getProperty("java.version")).append("\n") + stb.append("OS: ").append(System.getProperty("os.name")).append(" ") + .append(System.getProperty("os.version")) + .append(System.getProperty("os.arch")) + .append("\n\n") + } + + if(!params.contains(DiagParams.PLUGIN_PRIVACY)) { + pluginListDiag(stb) + } + prepareAnvilListeners(stb) + + stb.append("\n\n") + } + + private fun fetchNMSType(): String { + val packetManager = DependencyManager.packetManager + val packetManagerClass = packetManager.javaClass + + val result: String + if(packetManagerClass == PaperPacketManager::class.java) { + result = "Paper NMS" + } else if(packetManagerClass == ProtocoLibWrapper::class.java) { + result = "Protocolib" + } else if(packetManagerClass == NoPacketManager::class.java) { + result = "None" + } else { + result = "Version Specific" + } + + return "$result ${if(packetManager.canSetInstantBuild) '✅' else '❌'}" + } + + private val Plugin.pluginNameDisplay: String + get() { + return this.name + " v" + this.description.version + } + + private fun pluginListDiag(stb: StringBuilder) { + val enabledPlugins: MutableList = ArrayList() + val disabledPlugins: MutableList = ArrayList() + for (plugin in Bukkit.getPluginManager().plugins) { + if (plugin.isEnabled) { + enabledPlugins.add(plugin) + } else { + disabledPlugins.add(plugin) + } + } + + stb.append("Enabled Plugins: ").append( + enabledPlugins.stream() + .map { plugin -> plugin!!.pluginNameDisplay } + .reduce { a: String?, b: String? -> "$a, $b" }.orElse("None") + ).append("\n") + + stb.append("Disabled Plugins: ").append( + disabledPlugins.stream() + .map { plugin -> plugin!!.pluginNameDisplay } + .reduce { a: String?, b: String? -> "$a, $b" }.orElse("None") + ).append("\n") + } + + fun prepareAnvilListeners(stb: StringBuilder) { + val eventListeners: MutableSet = Arrays + .stream( + PrepareAnvilEvent + .getHandlerList() + .getRegisteredListeners() + ) + .map { obj: RegisteredListener? -> obj!!.plugin } + .collect(Collectors.toSet()) + + eventListeners.remove(CustomAnvil.instance) + stb.append("Prepare Anvil Listeners: ").append( + if (eventListeners.isEmpty()) "None" else eventListeners.stream() + .map { plugin -> plugin!!.pluginNameDisplay } + .reduce { a: String?, b: String? -> "$a, $b" }.orElse("None") + ).append("\n\n") + } + +} \ No newline at end of file