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
This commit is contained in:
Norbi Peti 2020-03-06 00:39:18 +01:00
parent 2cca2e2096
commit 3c4f9f6c7a
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
4 changed files with 124 additions and 23 deletions

View file

@ -29,17 +29,27 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>2.4.2</version> <version>3.2.1</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
<goals> <goals>
<goal>shade</goal> <goal>shade</goal>
</goals> </goals>
<configuration> <configuration>
<artifactSet> <artifactSet>
</artifactSet> <includes>
</configuration> <include>me.lucko:commodore</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>me.lucko.commodore</pattern>
<!-- vvv Replace with the package of your plugin vvv -->
<shadedPattern>buttondevteam.core.commodore</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
@ -106,7 +116,7 @@
<repository> <repository>
<id>ess-repo</id> <id>ess-repo</id>
<url>https://ci.ender.zone/plugin/repository/everything/</url> <url>https://ci.ender.zone/plugin/repository/everything/</url>
</repository> </repository>
<repository> <repository>
<id>Votifier</id> <id>Votifier</id>
<url>https://dl.bintray.com/nuvotifier/maven/</url> <url>https://dl.bintray.com/nuvotifier/maven/</url>
@ -115,7 +125,11 @@
<id>Multiverse-Core</id> <id>Multiverse-Core</id>
<url>http://repo.onarandombox.com/content/repositories/multiverse/</url> <url>http://repo.onarandombox.com/content/repositories/multiverse/</url>
</repository> </repository>
</repositories> <repository>
<id>minecraft-repo</id>
<url>https://libraries.minecraft.net/</url>
</repository>
</repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.reflections</groupId> <groupId>org.reflections</groupId>
@ -176,7 +190,13 @@
<version>4.0.1</version> <version>4.0.1</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> <dependency>
<groupId>me.lucko</groupId>
<artifactId>commodore</artifactId>
<version>1.5</version>
<scope>compile</scope>
</dependency>
</dependencies>
<organization> <organization>
<name>TBMCPlugins</name> <name>TBMCPlugins</name>
<url>https://github.com/TBMCPlugins</url> <url>https://github.com/TBMCPlugins</url>

View file

@ -11,12 +11,12 @@ import org.bukkit.plugin.Plugin;
public class ChromaCommand extends ICommand2MC { public class ChromaCommand extends ICommand2MC {
@Command2.Subcommand @Command2.Subcommand
public void reload(CommandSender sender, @Command2.OptionalArg Plugin plugin) { public void reload(CommandSender sender, @Command2.OptionalArg Plugin plugin) {
if(plugin==null) if (plugin == null)
plugin=MainPlugin.Instance; plugin = MainPlugin.Instance;
if(!(plugin instanceof ButtonPlugin)) if (!(plugin instanceof ButtonPlugin)) //Probably not a good idea to allow reloading any plugin's config
plugin.reloadConfig(); sender.sendMessage("§c" + plugin.getName() + " doesn't support this.");
else if (((ButtonPlugin) plugin).tryReloadConfig()) else if (((ButtonPlugin) plugin).tryReloadConfig())
sender.sendMessage("§b"+plugin.getName()+" config reloaded."); sender.sendMessage("§b" + plugin.getName() + " config reloaded.");
else else
sender.sendMessage("§cFailed to reload config. Check console."); sender.sendMessage("§cFailed to reload config. Check console.");
} }

View file

@ -94,7 +94,7 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
helpText[0] = "§6---- Subcommands ----"; //TODO: There may be more to the help text helpText[0] = "§6---- Subcommands ----"; //TODO: There may be more to the help text
int i = 1; int i = 1;
for (Iterator<String> iterator = ht.iterator(); for (Iterator<String> iterator = ht.iterator();
iterator.hasNext() && i < helpText.length; i++) { iterator.hasNext() && i < helpText.length; i++) {
String e = iterator.next(); String e = iterator.next();
helpText[i] = e; helpText[i] = e;
} }
@ -274,7 +274,7 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
public abstract void registerCommand(TC command); public abstract void registerCommand(TC command);
protected void registerCommand(TC command, @SuppressWarnings("SameParameterValue") char commandChar) { protected List<SubcommandData<TC>> registerCommand(TC command, @SuppressWarnings("SameParameterValue") char commandChar) {
this.commandChar = commandChar; this.commandChar = commandChar;
val path = command.getCommandPath(); val path = command.getCommandPath();
int x = path.indexOf(' '); int x = path.indexOf(' ');
@ -298,6 +298,7 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Could not register default handler for command /" + path, e); TBMCCoreAPI.SendException("Could not register default handler for command /" + path, e);
} }
var addedSubcommands = new ArrayList<SubcommandData<TC>>();
for (val method : command.getClass().getMethods()) { for (val method : command.getClass().getMethods()) {
val ann = method.getAnnotation(Subcommand.class); 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 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<TC extends ICommand2, TP extends Command2Sender>
val subcommand = commandChar + path + //Add command path (class name by default) val subcommand = commandChar + path + //Add command path (class name by default)
getCommandPath(method.getName(), ' '); //Add method name, unless it's 'def' getCommandPath(method.getName(), ' '); //Add method name, unless it's 'def'
ht = getParameterHelp(method, ht, subcommand); 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); scmdHelpList.add(subcommand);
nosubs = false; nosubs = false;
} }
} }
if (nosubs && scmdHelpList.size() > 0) if (nosubs && scmdHelpList.size() > 0)
scmdHelpList.remove(scmdHelpList.size() - 1); //Remove Subcommands header scmdHelpList.remove(scmdHelpList.size() - 1); //Remove Subcommands header
if (mainMethod != null && !subcommands.containsKey(commandChar + path)) //Command specified by the class 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]))); 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 (mainMethod != null && !mainPath.equals(commandChar + path)) { //Main command, typically the same as the above
if (isSubcommand) { //The class itself is a subcommand if (isSubcommand) { //The class itself is a subcommand
val scmd = subcommands.computeIfAbsent(mainPath, p -> new SubcommandData<>(null, null, new String[]{"§6---- Subcommands ----"})); val scmd = subcommands.computeIfAbsent(mainPath, p -> new SubcommandData<>(null, null, new String[]{"§6---- Subcommands ----"}));
@ -325,6 +331,7 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
} else if (!subcommands.containsKey(mainPath)) } else if (!subcommands.containsKey(mainPath))
subcommands.put(mainPath, new SubcommandData<>(null, null, scmdHelpList.toArray(new String[0]))); subcommands.put(mainPath, new SubcommandData<>(null, null, scmdHelpList.toArray(new String[0])));
} }
return addedSubcommands;
} }
private String[] getParameterHelp(Method method, String[] ht, String subcommand) { private String[] getParameterHelp(Method method, String[] ht, String subcommand) {

View file

@ -4,7 +4,13 @@ import buttondevteam.core.MainPlugin;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.ButtonPlugin;
import buttondevteam.lib.architecture.Component; 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 lombok.val;
import me.lucko.commodore.Commodore;
import me.lucko.commodore.CommodoreProvider;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command; import org.bukkit.command.Command;
@ -20,8 +26,10 @@ import org.bukkit.permissions.PermissionDefault;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
@ -33,7 +41,7 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
*/ */
@Override @Override
public void registerCommand(ICommand2MC command) { public void registerCommand(ICommand2MC command) {
super.registerCommand(command, '/'); var subcmds = super.registerCommand(command, '/');
var perm = "chroma.command." + command.getCommandPath().replace(' ', '.'); var perm = "chroma.command." + command.getCommandPath().replace(' ', '.');
if (Bukkit.getPluginManager().getPermission(perm) == null) //Check needed for plugin reset if (Bukkit.getPluginManager().getPermission(perm) == null) //Check needed for plugin reset
Bukkit.getPluginManager().addPermission(new Permission(perm, Bukkit.getPluginManager().addPermission(new Permission(perm,
@ -55,7 +63,7 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
PermissionDefault.OP)); //Do not allow any commands that belong to a group PermissionDefault.OP)); //Do not allow any commands that belong to a group
} }
registerOfficially(command); registerOfficially(command, subcmds);
} }
@Override @Override
@ -256,9 +264,14 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
} }
} }
private boolean shouldRegisterOfficially=true; private boolean shouldRegisterOfficially = true;
private void registerOfficially(ICommand2MC command) {
if(!shouldRegisterOfficially) return; private void registerOfficially(ICommand2MC command, List<SubcommandData<ICommand2MC>> subcmds) {
if (!shouldRegisterOfficially) return;
if (CommodoreProvider.isSupported()) {
TabcompleteHelper.registerTabcomplete(command, subcmds);
return; //Commodore registers the command as well
}
try { try {
var cmdmap = (SimpleCommandMap) Bukkit.getServer().getClass().getMethod("getCommandMap").invoke(Bukkit.getServer()); var cmdmap = (SimpleCommandMap) Bukkit.getServer().getClass().getMethod("getCommandMap").invoke(Bukkit.getServer());
var path = command.getCommandPath(); var path = command.getCommandPath();
@ -282,4 +295,65 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
return true; return true;
} }
} }
private static class TabcompleteHelper {
private static Commodore commodore;
private static void registerTabcomplete(ICommand2MC command2MC, List<SubcommandData<ICommand2MC>> 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<ICommand2MC> subcmd : subcmds) {
String[] subpath = ButtonPlugin.getCommand2MC().getCommandPath(subcmd.method.getName(), ' ').trim().split(" ");
ArgumentBuilder<Object, ?> 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);
}
}
} }