From 3c4f9f6c7af22408f5ef9bcab66e949e6069176a Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 6 Mar 2020 00:39:18 +0100 Subject: [PATCH] Reload cmd fix, parameter tabcomplete Made reload cmd only for ButtonPlugins Implemented parameter tabcomplete using Commodore Only works for one subcommand at the moment #82 --- Chroma-Core/pom.xml | 36 ++++++-- .../buttondevteam/core/ChromaCommand.java | 10 +-- .../java/buttondevteam/lib/chat/Command2.java | 17 ++-- .../buttondevteam/lib/chat/Command2MC.java | 84 +++++++++++++++++-- 4 files changed, 124 insertions(+), 23 deletions(-) diff --git a/Chroma-Core/pom.xml b/Chroma-Core/pom.xml index 2a452f7..fe76a44 100755 --- a/Chroma-Core/pom.xml +++ b/Chroma-Core/pom.xml @@ -29,17 +29,27 @@ org.apache.maven.plugins maven-shade-plugin - 2.4.2 + 3.2.1 package shade - - - - + + + + me.lucko:commodore + + + + + me.lucko.commodore + + buttondevteam.core.commodore + + + @@ -106,7 +116,7 @@ ess-repo https://ci.ender.zone/plugin/repository/everything/ - + Votifier https://dl.bintray.com/nuvotifier/maven/ @@ -115,7 +125,11 @@ Multiverse-Core http://repo.onarandombox.com/content/repositories/multiverse/ - + + minecraft-repo + https://libraries.minecraft.net/ + + org.reflections @@ -176,7 +190,13 @@ 4.0.1 provided - + + me.lucko + commodore + 1.5 + compile + + TBMCPlugins https://github.com/TBMCPlugins diff --git a/Chroma-Core/src/main/java/buttondevteam/core/ChromaCommand.java b/Chroma-Core/src/main/java/buttondevteam/core/ChromaCommand.java index 7eea87d..3d6465e 100644 --- a/Chroma-Core/src/main/java/buttondevteam/core/ChromaCommand.java +++ b/Chroma-Core/src/main/java/buttondevteam/core/ChromaCommand.java @@ -11,12 +11,12 @@ import org.bukkit.plugin.Plugin; public class ChromaCommand extends ICommand2MC { @Command2.Subcommand public void reload(CommandSender sender, @Command2.OptionalArg Plugin plugin) { - if(plugin==null) - plugin=MainPlugin.Instance; - if(!(plugin instanceof ButtonPlugin)) - plugin.reloadConfig(); + if (plugin == null) + plugin = MainPlugin.Instance; + if (!(plugin instanceof ButtonPlugin)) //Probably not a good idea to allow reloading any plugin's config + sender.sendMessage("§c" + plugin.getName() + " doesn't support this."); else if (((ButtonPlugin) plugin).tryReloadConfig()) - sender.sendMessage("§b"+plugin.getName()+" config reloaded."); + sender.sendMessage("§b" + plugin.getName() + " config reloaded."); else sender.sendMessage("§cFailed to reload config. Check console."); } diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.java b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.java index ba90b17..7ba6ede 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.java @@ -94,7 +94,7 @@ public abstract class Command2 helpText[0] = "§6---- Subcommands ----"; //TODO: There may be more to the help text int i = 1; for (Iterator iterator = ht.iterator(); - iterator.hasNext() && i < helpText.length; i++) { + iterator.hasNext() && i < helpText.length; i++) { String e = iterator.next(); helpText[i] = e; } @@ -274,7 +274,7 @@ public abstract class Command2 public abstract void registerCommand(TC command); - protected void registerCommand(TC command, @SuppressWarnings("SameParameterValue") char commandChar) { + protected List> registerCommand(TC command, @SuppressWarnings("SameParameterValue") char commandChar) { this.commandChar = commandChar; val path = command.getCommandPath(); int x = path.indexOf(' '); @@ -298,6 +298,7 @@ public abstract class Command2 } catch (Exception e) { TBMCCoreAPI.SendException("Could not register default handler for command /" + path, e); } + var addedSubcommands = new ArrayList>(); for (val method : command.getClass().getMethods()) { val ann = method.getAnnotation(Subcommand.class); if (ann == null) continue; //Don't call the method on non-subcommands because they're not in the yaml @@ -306,15 +307,20 @@ public abstract class Command2 val subcommand = commandChar + path + //Add command path (class name by default) getCommandPath(method.getName(), ' '); //Add method name, unless it's 'def' ht = getParameterHelp(method, ht, subcommand); - subcommands.put(subcommand, new SubcommandData<>(method, command, ht)); //Result of the above (def) is that it will show the help text + var sd = new SubcommandData<>(method, command, ht); + subcommands.put(subcommand, sd); //Result of the above (def) is that it will show the help text + addedSubcommands.add(sd); scmdHelpList.add(subcommand); nosubs = false; } } if (nosubs && scmdHelpList.size() > 0) scmdHelpList.remove(scmdHelpList.size() - 1); //Remove Subcommands header - if (mainMethod != null && !subcommands.containsKey(commandChar + path)) //Command specified by the class - subcommands.put(commandChar + path, new SubcommandData<>(mainMethod, command, scmdHelpList.toArray(new String[0]))); + if (mainMethod != null && !subcommands.containsKey(commandChar + path)) { //Command specified by the class + var sd = new SubcommandData<>(mainMethod, command, scmdHelpList.toArray(new String[0])); + subcommands.put(commandChar + path, sd); + addedSubcommands.add(sd); + } if (mainMethod != null && !mainPath.equals(commandChar + path)) { //Main command, typically the same as the above if (isSubcommand) { //The class itself is a subcommand val scmd = subcommands.computeIfAbsent(mainPath, p -> new SubcommandData<>(null, null, new String[]{"§6---- Subcommands ----"})); @@ -325,6 +331,7 @@ public abstract class Command2 } else if (!subcommands.containsKey(mainPath)) subcommands.put(mainPath, new SubcommandData<>(null, null, scmdHelpList.toArray(new String[0]))); } + return addedSubcommands; } private String[] getParameterHelp(Method method, String[] ht, String subcommand) { diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.java b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.java index 466e81f..34484fb 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.java +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.java @@ -4,7 +4,13 @@ import buttondevteam.core.MainPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; +import com.mojang.brigadier.arguments.*; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; import lombok.val; +import me.lucko.commodore.Commodore; +import me.lucko.commodore.CommodoreProvider; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; @@ -20,8 +26,10 @@ import org.bukkit.permissions.PermissionDefault; import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Optional; import java.util.function.Function; @@ -33,7 +41,7 @@ public class Command2MC extends Command2 implemen */ @Override public void registerCommand(ICommand2MC command) { - super.registerCommand(command, '/'); + var subcmds = super.registerCommand(command, '/'); var perm = "chroma.command." + command.getCommandPath().replace(' ', '.'); if (Bukkit.getPluginManager().getPermission(perm) == null) //Check needed for plugin reset Bukkit.getPluginManager().addPermission(new Permission(perm, @@ -55,7 +63,7 @@ public class Command2MC extends Command2 implemen PermissionDefault.OP)); //Do not allow any commands that belong to a group } - registerOfficially(command); + registerOfficially(command, subcmds); } @Override @@ -256,9 +264,14 @@ public class Command2MC extends Command2 implemen } } - private boolean shouldRegisterOfficially=true; - private void registerOfficially(ICommand2MC command) { - if(!shouldRegisterOfficially) return; + private boolean shouldRegisterOfficially = true; + + private void registerOfficially(ICommand2MC command, List> subcmds) { + if (!shouldRegisterOfficially) return; + if (CommodoreProvider.isSupported()) { + TabcompleteHelper.registerTabcomplete(command, subcmds); + return; //Commodore registers the command as well + } try { var cmdmap = (SimpleCommandMap) Bukkit.getServer().getClass().getMethod("getCommandMap").invoke(Bukkit.getServer()); var path = command.getCommandPath(); @@ -282,4 +295,65 @@ public class Command2MC extends Command2 implemen return true; } } + + private static class TabcompleteHelper { + private static Commodore commodore; + + private static void registerTabcomplete(ICommand2MC command2MC, List> subcmds) { + if (commodore == null) + commodore = CommodoreProvider.getCommodore(MainPlugin.Instance); //Register all to the Core, it's easier + System.out.println("Registering tabcomplete for path: " + command2MC.getCommandPath()); + String[] path = command2MC.getCommandPath().split(" "); + var maincmd = LiteralArgumentBuilder.literal(path[0]); + var cmd = maincmd; + for (int i = 1; i < path.length; i++) { + var subcmd = LiteralArgumentBuilder.literal(path[i]); + cmd.then(subcmd); + cmd = subcmd; //Add each part of the path as a child of the previous one + } + for (SubcommandData subcmd : subcmds) { + String[] subpath = ButtonPlugin.getCommand2MC().getCommandPath(subcmd.method.getName(), ' ').trim().split(" "); + ArgumentBuilder scmd = cmd; + if (subpath[0].length() > 0) { //If the method is def, it will contain one empty string + for (String s : subpath) { + var subsubcmd = LiteralArgumentBuilder.literal(s); + scmd.then(subsubcmd); + scmd = subsubcmd; //Add method name part of the path (could_be_multiple()) + } + } + Parameter[] parameters = subcmd.method.getParameters(); + for (int i = 1; i < parameters.length; i++) { //Skip sender + Parameter parameter = parameters[i]; + ArgumentType type; + final Class ptype = parameter.getType(); + if (ptype == String.class) + if (parameter.isAnnotationPresent(TextArg.class)) + type = StringArgumentType.greedyString(); + else + type = StringArgumentType.word(); + else if (ptype == int.class || ptype == Integer.class) + type = IntegerArgumentType.integer(); //TODO: Min, max + else if (ptype == long.class || ptype == Long.class) + type = LongArgumentType.longArg(); + else if (ptype == float.class || ptype == Float.class) + type = FloatArgumentType.floatArg(); + else if (ptype == double.class || ptype == Double.class) + type = DoubleArgumentType.doubleArg(); + else if (ptype == char.class || ptype == Character.class) + type = StringArgumentType.word(); + else if (ptype == boolean.class || ptype == Boolean.class) + type = BoolArgumentType.bool(); + else //TODO: Custom parameter types + type = StringArgumentType.word(); + var arg = RequiredArgumentBuilder.argument(parameter.getName(), type); + scmd.then(arg); + scmd = arg; + } + } + System.out.println("maincmd: " + maincmd); + System.out.println("Children:"); + maincmd.build().getChildren().forEach(System.out::println); + commodore.register(maincmd); + } + } }