Fix Command2MC command registration
- Tab completion still needs to be fixed - Fixed usage check existence check - Fixed parameter number limits - Added commands to get and remove registered commands
This commit is contained in:
parent
c0c3fc68dc
commit
47178e7f7c
3 changed files with 83 additions and 87 deletions
|
@ -29,7 +29,9 @@ import java.lang.annotation.Target;
|
|||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -276,27 +278,21 @@ public abstract class Command2<TC extends ICommand2<TP>, TP extends Command2Send
|
|||
throw new RuntimeException("No sender parameter for method '" + method + "'");
|
||||
val ret = new CommandArgument[parameters.length];
|
||||
val usage = getParameterHelp(method);
|
||||
if (usage == null) {
|
||||
for (int i = 1; i < parameters.length; i++) {
|
||||
ret[i - 1] = new CommandArgument("param" + i, parameters[i].getType(), false, null, false, "param" + i);
|
||||
}
|
||||
} else {
|
||||
val paramNames = usage.split(" ");
|
||||
for (int i = 1; i < parameters.length; i++) {
|
||||
val numAnn = parameters[i].getAnnotation(NumberArg.class);
|
||||
ret[i - 1] = new CommandArgument(paramNames[i], parameters[i].getType(),
|
||||
parameters[i].isVarArgs() || parameters[i].isAnnotationPresent(TextArg.class),
|
||||
numAnn == null ? null : new Pair<>(numAnn.lowerLimit(), numAnn.upperLimit()),
|
||||
parameters[i].isAnnotationPresent(OptionalArg.class),
|
||||
paramNames[i]); // TODO: Description (JavaDoc?)
|
||||
}
|
||||
val paramNames = usage != null ? usage.split(" ") : null;
|
||||
for (int i = 1; i < parameters.length; i++) {
|
||||
val numAnn = parameters[i].getAnnotation(NumberArg.class);
|
||||
ret[i - 1] = new CommandArgument(paramNames == null ? "param" + i : paramNames[i], parameters[i].getType(),
|
||||
parameters[i].isVarArgs() || parameters[i].isAnnotationPresent(TextArg.class),
|
||||
numAnn == null ? null : new Pair<>(numAnn.lowerLimit(), numAnn.upperLimit()),
|
||||
parameters[i].isAnnotationPresent(OptionalArg.class),
|
||||
paramNames == null ? "param" + i : paramNames[i]); // TODO: Description (JavaDoc?)
|
||||
}
|
||||
return new Pair<>(ret, parameters[0].getType());
|
||||
}
|
||||
|
||||
private ArgumentType<?> getParameterType(CommandArgument arg) {
|
||||
final Class<?> ptype = arg.type;
|
||||
Number lowerLimit = Double.NEGATIVE_INFINITY, upperLimit = Double.POSITIVE_INFINITY;
|
||||
Number lowerLimit = arg.limits.getValue0(), upperLimit = arg.limits.getValue1();
|
||||
if (arg.greedy)
|
||||
return StringArgumentType.greedyString();
|
||||
else if (ptype == String.class)
|
||||
|
@ -382,61 +378,6 @@ public abstract class Command2<TC extends ICommand2<TP>, TP extends Command2Send
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*protected List<SubcommandData<TC>> registerCommand(TC command, @SuppressWarnings("SameParameterValue") char commandChar) {
|
||||
this.commandChar = commandChar;
|
||||
Method mainMethod = null;
|
||||
boolean nosubs = true;
|
||||
boolean isSubcommand = x != -1;
|
||||
try { //Register the default handler first so it can be reliably overwritten
|
||||
mainMethod = command.getClass().getMethod("def", Command2Sender.class);
|
||||
val cc = command.getClass().getAnnotation(CommandClass.class);
|
||||
var ht = cc == null || isSubcommand ? new String[0] : cc.helpText(); //If it's not the main command, don't add it
|
||||
if (ht.length > 0)
|
||||
ht[0] = "§6---- " + ht[0] + " ----";
|
||||
scmdHelpList.addAll(Arrays.asList(ht));
|
||||
if (!isSubcommand)
|
||||
scmdHelpList.add("§6Subcommands:");
|
||||
if (!commandHelp.contains(mainPath))
|
||||
commandHelp.add(mainPath);
|
||||
} catch (Exception e) {
|
||||
TBMCCoreAPI.SendException("Could not register default handler for command /" + path, e, MainPlugin.Instance);
|
||||
}
|
||||
var addedSubcommands = new ArrayList<SubcommandData<TC>>();
|
||||
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
|
||||
var ht = command.getHelpText(method, ann);
|
||||
if (ht != null) { //The method is a subcommand
|
||||
val subcommand = commandChar + path + //Add command path (class name by default)
|
||||
getCommandPath(method.getName(), ' '); //Add method name, unless it's 'def'
|
||||
var params = new String[method.getParameterCount() - 1];
|
||||
ht = getParameterHelp(method, ht, subcommand, params);
|
||||
var sd = new SubcommandData<>(method, command, params, ht);
|
||||
registerCommand(path, method.getName(), ann, sd);
|
||||
for (String p : command.getCommandPaths())
|
||||
registerCommand(p, method.getName(), ann, sd);
|
||||
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
|
||||
var sd = new SubcommandData<>(mainMethod, command, null, scmdHelpList.toArray(new String[0]));
|
||||
subcommands.put(commandChar + path, sd);
|
||||
addedSubcommands.add(sd);
|
||||
}
|
||||
if (isSubcommand) { //The class itself is a subcommand
|
||||
val scmd = subcommands.computeIfAbsent(mainPath, p -> new SubcommandData<>(null, null, new String[0], new String[]{"§6---- Subcommands ----"}));
|
||||
val scmdHelp = Arrays.copyOf(scmd.helpText, scmd.helpText.length + scmdHelpList.size());
|
||||
for (int i = 0; i < scmdHelpList.size(); i++)
|
||||
scmdHelp[scmd.helpText.length + i] = scmdHelpList.get(i);
|
||||
scmd.helpText = scmdHelp;
|
||||
}
|
||||
return addedSubcommands;
|
||||
}*/
|
||||
|
||||
private String getParameterHelp(Method method) {
|
||||
val str = method.getDeclaringClass().getResourceAsStream("/commands.yml");
|
||||
if (str == null)
|
||||
|
@ -469,7 +410,7 @@ public abstract class Command2<TC extends ICommand2<TP>, TP extends Command2Send
|
|||
}
|
||||
|
||||
/**
|
||||
* It will start with the given replace char.
|
||||
* Returns the path of the given subcommand excluding the class' path. It will start with the given replace char.
|
||||
*
|
||||
* @param methodName The method's name, method.getName()
|
||||
* @param replaceChar The character to use between subcommands
|
||||
|
@ -479,4 +420,51 @@ public abstract class Command2<TC extends ICommand2<TP>, TP extends Command2Send
|
|||
public String getCommandPath(String methodName, char replaceChar) {
|
||||
return methodName.equals("def") ? "" : replaceChar + methodName.replace('_', replaceChar).toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all registered command nodes. This returns all registered Chroma commands with all the information about them.
|
||||
*
|
||||
* @return A set of command node objects containing the commands
|
||||
*/
|
||||
public Set<CoreCommandNode<TP, TC>> getCommandNodes() {
|
||||
return dispatcher.getRoot().getChildren().stream().map(node -> (CoreCommandNode<TP, TC>) node).collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a node that belongs to the given command.
|
||||
*
|
||||
* @param command The exact name of the command
|
||||
* @return A command node
|
||||
*/
|
||||
public CoreCommandNode<TP, TC> getCommandNode(String command) {
|
||||
return (CoreCommandNode<TP, TC>) dispatcher.getRoot().getChild(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister all subcommands that were registered with the given command class.
|
||||
*
|
||||
* @param command The command class (object) to unregister
|
||||
*/
|
||||
public void unregisterCommand(ICommand2<TP> command) {
|
||||
dispatcher.getRoot().getChildren().removeIf(node -> ((CoreCommandNode<TP, TC>) node).getData().command == command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters all commands that match the given predicate.
|
||||
*
|
||||
* @param condition The condition for removing a given command
|
||||
*/
|
||||
public void unregisterCommandIf(Predicate<CoreCommandNode<TP, TC>> condition, boolean nested) {
|
||||
dispatcher.getRoot().getChildren().removeIf(node -> condition.test((CoreCommandNode<TP, TC>) node));
|
||||
if (nested)
|
||||
for (var child : dispatcher.getRoot().getChildren())
|
||||
unregisterCommandIf(condition, (CoreCommandNode<TP, TC>) child);
|
||||
}
|
||||
|
||||
private void unregisterCommandIf(Predicate<CoreCommandNode<TP, TC>> condition, CoreCommandNode<TP, TC> root) {
|
||||
// Can't use getCoreChildren() here because the collection needs to be modifiable
|
||||
root.getChildren().removeIf(node -> condition.test((CoreCommandNode<TP, TC>) node));
|
||||
for (var child : root.getCoreChildren())
|
||||
unregisterCommandIf(condition, child);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ import java.util.Optional;
|
|||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
@ -59,9 +58,8 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
|
|||
}*/
|
||||
var commandNode = super.registerCommandSuper(command);
|
||||
var bcmd = registerOfficially(command, commandNode);
|
||||
if (bcmd != null)
|
||||
for (String alias : bcmd.getAliases())
|
||||
super.registerCommand(command, command.getCommandPath().replaceFirst("^" + bcmd.getName(), Matcher.quoteReplacement(alias)), '/');
|
||||
if (bcmd != null) // TODO: Support aliases
|
||||
super.registerCommandSuper(command);
|
||||
|
||||
var perm = "chroma.command." + command.getCommandPath().replace(' ', '.');
|
||||
if (Bukkit.getPluginManager().getPermission(perm) == null) //Check needed for plugin reset
|
||||
|
@ -164,18 +162,12 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
|
|||
}
|
||||
|
||||
public void unregisterCommands(ButtonPlugin plugin) {
|
||||
/*var cmds = subcommands.values().stream().map(sd -> sd.command).filter(cmd -> plugin.equals(cmd.getPlugin())).toArray(ICommand2MC[]::new);
|
||||
for (var cmd : cmds)
|
||||
unregisterCommand(cmd);*/
|
||||
subcommands.values().removeIf(sd -> Optional.ofNullable(sd.command).map(ICommand2MC::getPlugin).map(plugin::equals).orElse(false));
|
||||
unregisterCommandIf(node -> Optional.ofNullable(node.getData().command).map(ICommand2MC::getPlugin).map(plugin::equals).orElse(false), true);
|
||||
}
|
||||
|
||||
public void unregisterCommands(Component<?> component) {
|
||||
/*var cmds = subcommands.values().stream().map(sd -> sd.command).filter(cmd -> component.equals(cmd.getComponent())).toArray(ICommand2MC[]::new);
|
||||
for (var cmd : cmds)
|
||||
unregisterCommand(cmd);*/
|
||||
subcommands.values().removeIf(sd -> Optional.ofNullable(sd.command).map(ICommand2MC::getComponent)
|
||||
.map(comp -> component.getClass().getSimpleName().equals(comp.getClass().getSimpleName())).orElse(false));
|
||||
unregisterCommandIf(node -> Optional.ofNullable(node.getData().command).map(ICommand2MC::getPlugin)
|
||||
.map(comp -> component.getClass().getSimpleName().equals(comp.getClass().getSimpleName())).orElse(false), true);
|
||||
}
|
||||
|
||||
/*@EventHandler
|
||||
|
|
|
@ -7,14 +7,30 @@ import com.mojang.brigadier.tree.CommandNode;
|
|||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CoreCommandNode<T, TC extends ICommand2<?>> extends LiteralCommandNode<T> {
|
||||
public class CoreCommandNode<T extends Command2Sender, TC extends ICommand2<?>> extends LiteralCommandNode<T> {
|
||||
@Getter
|
||||
private final SubcommandData<TC> data;
|
||||
private final SubcommandData<TC, T> data;
|
||||
|
||||
public CoreCommandNode(String literal, Command<T> command, Predicate<T> requirement, CommandNode<T> redirect, RedirectModifier<T> modifier, boolean forks, SubcommandData<TC> data) {
|
||||
public CoreCommandNode(String literal, Command<T> command, Predicate<T> requirement, CommandNode<T> redirect, RedirectModifier<T> modifier, boolean forks, SubcommandData<TC, T> data) {
|
||||
super(literal, command, requirement, redirect, modifier, forks);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getChildren()
|
||||
*/
|
||||
public Collection<CoreCommandNode<T, TC>> getCoreChildren() {
|
||||
return super.getChildren().stream().map(node -> (CoreCommandNode<T, TC>) node).collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getChild(String)
|
||||
*/
|
||||
public CoreCommandNode<T, TC> getCoreChild(String name) {
|
||||
return (CoreCommandNode<T, TC>) super.getChild(name);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue