mirror of https://github.com/Minestom/Minestom.git
Add subcommand support for fast parsing & proper separation between logics
This commit is contained in:
parent
06abbcb7fb
commit
a419d7eb3f
|
@ -306,38 +306,7 @@ public final class CommandManager {
|
|||
|
||||
// Brigadier-like commands
|
||||
for (Command command : dispatcher.getCommands()) {
|
||||
// Check if player should see this command
|
||||
final CommandCondition commandCondition = command.getCondition();
|
||||
if (commandCondition != null) {
|
||||
// Do not show command if return false
|
||||
if (!commandCondition.canUse(player, null)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// The main root of this command
|
||||
IntList cmdChildren = new IntArrayList();
|
||||
final Collection<CommandSyntax> syntaxes = command.getSyntaxes();
|
||||
|
||||
// Create command for main name
|
||||
final int mainNodeIndex = createCommand(player, nodes, cmdChildren,
|
||||
command.getName(), syntaxes, rootChildren);
|
||||
|
||||
// Use redirection to hook aliases with the command
|
||||
final String[] aliases = command.getAliases();
|
||||
if (aliases == null)
|
||||
continue;
|
||||
|
||||
for (String alias : aliases) {
|
||||
DeclareCommandsPacket.Node aliasNode = new DeclareCommandsPacket.Node();
|
||||
aliasNode.flags = DeclareCommandsPacket.getFlag(DeclareCommandsPacket.NodeType.LITERAL,
|
||||
false, true, false);
|
||||
aliasNode.name = alias;
|
||||
aliasNode.redirectedNode = mainNodeIndex;
|
||||
|
||||
addCommandNameNode(aliasNode, rootChildren, nodes);
|
||||
}
|
||||
|
||||
serializeCommand(player, command, nodes, rootChildren);
|
||||
}
|
||||
|
||||
// Pair<CommandName,EnabledTracking>
|
||||
|
@ -394,6 +363,52 @@ public final class CommandManager {
|
|||
return declareCommandsPacket;
|
||||
}
|
||||
|
||||
private int serializeCommand(CommandSender sender, Command command,
|
||||
List<DeclareCommandsPacket.Node> nodes,
|
||||
IntList rootChildren) {
|
||||
// Check if player should see this command
|
||||
final CommandCondition commandCondition = command.getCondition();
|
||||
if (commandCondition != null) {
|
||||
// Do not show command if return false
|
||||
if (!commandCondition.canUse(sender, null)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// The main root of this command
|
||||
IntList cmdChildren = new IntArrayList();
|
||||
final Collection<CommandSyntax> syntaxes = command.getSyntaxes();
|
||||
|
||||
// Create command for main name
|
||||
final DeclareCommandsPacket.Node mainNode = createCommand(sender, nodes, cmdChildren,
|
||||
command.getName(), syntaxes, rootChildren);
|
||||
final int mainNodeIndex = nodes.indexOf(mainNode);
|
||||
|
||||
// Serialize all the subcommands
|
||||
for (Command subcommand : command.getSubcommands()) {
|
||||
final int subNodeIndex = serializeCommand(sender, subcommand, nodes, cmdChildren);
|
||||
if (subNodeIndex != -1) {
|
||||
mainNode.children = ArrayUtils.concatenateIntArrays(mainNode.children, new int[]{subNodeIndex});
|
||||
}
|
||||
}
|
||||
|
||||
// Use redirection to hook aliases with the command
|
||||
final String[] aliases = command.getAliases();
|
||||
if (aliases != null) {
|
||||
for (String alias : aliases) {
|
||||
DeclareCommandsPacket.Node aliasNode = new DeclareCommandsPacket.Node();
|
||||
aliasNode.flags = DeclareCommandsPacket.getFlag(DeclareCommandsPacket.NodeType.LITERAL,
|
||||
false, true, false);
|
||||
aliasNode.name = alias;
|
||||
aliasNode.redirectedNode = mainNodeIndex;
|
||||
|
||||
addCommandNameNode(aliasNode, rootChildren, nodes);
|
||||
}
|
||||
}
|
||||
|
||||
return mainNodeIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the command's syntaxes to the nodes list.
|
||||
*
|
||||
|
@ -405,12 +420,12 @@ public final class CommandManager {
|
|||
* @param rootChildren the children of the main node (all commands name)
|
||||
* @return The index of the main node for alias redirection
|
||||
*/
|
||||
private int createCommand(@NotNull CommandSender sender,
|
||||
@NotNull List<DeclareCommandsPacket.Node> nodes,
|
||||
@NotNull IntList cmdChildren,
|
||||
@NotNull String name,
|
||||
@NotNull Collection<CommandSyntax> syntaxes,
|
||||
@NotNull IntList rootChildren) {
|
||||
private DeclareCommandsPacket.Node createCommand(@NotNull CommandSender sender,
|
||||
@NotNull List<DeclareCommandsPacket.Node> nodes,
|
||||
@NotNull IntList cmdChildren,
|
||||
@NotNull String name,
|
||||
@NotNull Collection<CommandSyntax> syntaxes,
|
||||
@NotNull IntList rootChildren) {
|
||||
|
||||
DeclareCommandsPacket.Node literalNode = createMainNode(name, syntaxes.isEmpty());
|
||||
|
||||
|
@ -511,8 +526,7 @@ public final class CommandManager {
|
|||
}
|
||||
|
||||
literalNode.children = ArrayUtils.toArray(cmdChildren);
|
||||
|
||||
return nodes.indexOf(literalNode);
|
||||
return literalNode;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ public class Command {
|
|||
private CommandExecutor defaultExecutor;
|
||||
private CommandCondition condition;
|
||||
|
||||
private final List<Command> subcommands;
|
||||
private final List<CommandSyntax> syntaxes;
|
||||
|
||||
/**
|
||||
|
@ -58,6 +59,7 @@ public class Command {
|
|||
this.name = name;
|
||||
this.aliases = aliases;
|
||||
|
||||
this.subcommands = new ArrayList<>();
|
||||
this.syntaxes = new ArrayList<>();
|
||||
}
|
||||
|
||||
|
@ -108,6 +110,15 @@ public class Command {
|
|||
argument.setCallback(callback);
|
||||
}
|
||||
|
||||
public void addSubcommand(@NotNull Command command) {
|
||||
this.subcommands.add(command);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Command> getSubcommands() {
|
||||
return Collections.unmodifiableList(subcommands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new syntax in the command.
|
||||
* <p>
|
||||
|
@ -278,4 +289,17 @@ public class Command {
|
|||
public void globalListener(@NotNull CommandSender sender, @NotNull Arguments arguments, @NotNull String command) {
|
||||
}
|
||||
|
||||
public static boolean isValidName(@NotNull Command command, @NotNull String name) {
|
||||
if (command.getName().equals(name))
|
||||
return true;
|
||||
final String[] aliases = command.getAliases();
|
||||
if (aliases == null)
|
||||
return false;
|
||||
for (String alias : aliases) {
|
||||
if (alias.equals(name))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -110,7 +110,10 @@ public class CommandDispatcher {
|
|||
}
|
||||
|
||||
// Removes the command's name + the space after
|
||||
final String[] args = commandString.replaceFirst(Pattern.quote(commandName), "").trim().split(StringUtils.SPACE);
|
||||
String[] args = commandString.replaceFirst(Pattern.quote(commandName), "").trim().split(StringUtils.SPACE);
|
||||
if (args.length == 1 && args[0].length() == 0) {
|
||||
args = new String[0];
|
||||
}
|
||||
|
||||
// Find the used syntax
|
||||
ParsedCommand parsedCommand = findParsedCommand(command, args);
|
||||
|
@ -133,13 +136,26 @@ public class CommandDispatcher {
|
|||
|
||||
@Nullable
|
||||
private ParsedCommand findParsedCommand(@NotNull Command command, @NotNull String[] args) {
|
||||
final boolean hasArgument = args.length > 0;
|
||||
|
||||
// Search for subcommand
|
||||
if (hasArgument) {
|
||||
final String firstArgument = args[0];
|
||||
for (Command subcommand : command.getSubcommands()) {
|
||||
if (Command.isValidName(subcommand, firstArgument)) {
|
||||
return findParsedCommand(subcommand, Arrays.copyOfRange(args, 1, args.length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ParsedCommand parsedCommand = new ParsedCommand();
|
||||
parsedCommand.command = command;
|
||||
|
||||
// The default executor should be used if no argument is provided
|
||||
{
|
||||
final CommandExecutor defaultExecutor = command.getDefaultExecutor();
|
||||
if (defaultExecutor != null && args[0].length() == 0) {
|
||||
if (defaultExecutor != null && !hasArgument) {
|
||||
parsedCommand.executor = defaultExecutor;
|
||||
parsedCommand.arguments = new Arguments();
|
||||
return parsedCommand;
|
||||
|
|
Loading…
Reference in New Issue