2022-07-13 22:45:38 +02:00
|
|
|
package net.minestom.server.command;
|
|
|
|
|
|
|
|
import net.minestom.server.command.builder.Command;
|
2022-07-25 19:34:40 +02:00
|
|
|
import net.minestom.server.command.builder.CommandExecutor;
|
2022-07-13 22:45:38 +02:00
|
|
|
import net.minestom.server.command.builder.CommandSyntax;
|
|
|
|
import net.minestom.server.command.builder.arguments.Argument;
|
|
|
|
import net.minestom.server.command.builder.condition.CommandCondition;
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
2022-07-25 19:34:40 +02:00
|
|
|
import org.jetbrains.annotations.Nullable;
|
2022-07-13 22:45:38 +02:00
|
|
|
|
|
|
|
import java.util.*;
|
|
|
|
import java.util.function.Consumer;
|
|
|
|
import java.util.function.Predicate;
|
|
|
|
|
|
|
|
import static net.minestom.server.command.builder.arguments.ArgumentType.Literal;
|
2022-07-17 23:13:25 +02:00
|
|
|
import static net.minestom.server.command.builder.arguments.ArgumentType.Word;
|
2022-07-13 22:45:38 +02:00
|
|
|
|
|
|
|
record GraphImpl(NodeImpl root) implements Graph {
|
|
|
|
static GraphImpl fromCommand(Command command) {
|
|
|
|
return new GraphImpl(NodeImpl.command(command));
|
|
|
|
}
|
|
|
|
|
|
|
|
static Graph merge(Collection<Command> commands) {
|
|
|
|
return new GraphImpl(NodeImpl.rootCommands(commands));
|
|
|
|
}
|
|
|
|
|
|
|
|
static GraphImpl merge(List<Graph> graphs) {
|
|
|
|
final List<Node> children = graphs.stream().map(Graph::root).toList();
|
|
|
|
final NodeImpl root = new NodeImpl(Literal(""), null, children);
|
|
|
|
return new GraphImpl(root);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean compare(@NotNull Graph graph, @NotNull Comparator comparator) {
|
|
|
|
return compare(root, graph.root(), comparator);
|
|
|
|
}
|
|
|
|
|
2022-07-25 19:34:40 +02:00
|
|
|
record BuilderImpl(Argument<?> argument, List<BuilderImpl> children, Execution execution) implements Graph.Builder {
|
|
|
|
public BuilderImpl(Argument<?> argument, Execution execution) {
|
|
|
|
this(argument, new ArrayList<>(), execution);
|
2022-07-13 22:45:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-07-25 19:34:40 +02:00
|
|
|
public Graph.@NotNull Builder append(@NotNull Argument<?> argument, @Nullable Execution execution,
|
|
|
|
@NotNull Consumer<Graph.Builder> consumer) {
|
|
|
|
BuilderImpl builder = new BuilderImpl(argument, execution);
|
2022-07-13 22:45:38 +02:00
|
|
|
consumer.accept(builder);
|
|
|
|
this.children.add(builder);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-07-25 19:34:40 +02:00
|
|
|
public Graph.@NotNull Builder append(@NotNull Argument<?> argument, @Nullable Execution execution) {
|
|
|
|
this.children.add(new BuilderImpl(argument, List.of(), execution));
|
2022-07-13 22:45:38 +02:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public @NotNull GraphImpl build() {
|
|
|
|
return new GraphImpl(NodeImpl.fromBuilder(this));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-17 22:41:28 +02:00
|
|
|
record NodeImpl(Argument<?> argument, ExecutionImpl execution, List<Graph.Node> next) implements Graph.Node {
|
2022-07-13 22:45:38 +02:00
|
|
|
static NodeImpl fromBuilder(BuilderImpl builder) {
|
|
|
|
final List<BuilderImpl> children = builder.children;
|
|
|
|
Node[] nodes = new NodeImpl[children.size()];
|
|
|
|
for (int i = 0; i < children.size(); i++) nodes[i] = fromBuilder(children.get(i));
|
2022-07-25 19:34:40 +02:00
|
|
|
return new NodeImpl(builder.argument, (ExecutionImpl) builder.execution, List.of(nodes));
|
2022-07-13 22:45:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static NodeImpl command(Command command) {
|
|
|
|
return ConversionNode.fromCommand(command).toNode();
|
|
|
|
}
|
|
|
|
|
|
|
|
static NodeImpl rootCommands(Collection<Command> commands) {
|
|
|
|
return ConversionNode.rootConv(commands).toNode();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-25 19:34:40 +02:00
|
|
|
record ExecutionImpl(Predicate<CommandSender> predicate,
|
|
|
|
CommandExecutor defaultExecutor, CommandExecutor globalListener,
|
|
|
|
CommandExecutor executor, CommandCondition condition) implements Execution {
|
2022-07-13 22:45:38 +02:00
|
|
|
@Override
|
|
|
|
public boolean test(CommandSender commandSender) {
|
|
|
|
return predicate.test(commandSender);
|
|
|
|
}
|
|
|
|
|
2022-07-17 22:41:28 +02:00
|
|
|
static ExecutionImpl fromCommand(Command command) {
|
2022-07-25 19:34:40 +02:00
|
|
|
final CommandExecutor defaultExecutor = command.getDefaultExecutor();
|
|
|
|
final CommandCondition defaultCondition = command.getCondition();
|
|
|
|
|
|
|
|
CommandExecutor executor = defaultExecutor;
|
|
|
|
CommandCondition condition = defaultCondition;
|
|
|
|
for (var syntax : command.getSyntaxes()) {
|
|
|
|
if (syntax.getArguments().length == 0) {
|
|
|
|
executor = syntax.getExecutor();
|
|
|
|
condition = syntax.getCommandCondition();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
final CommandExecutor globalListener = (sender, context) -> command.globalListener(sender, context, context.getInput());
|
|
|
|
|
|
|
|
return new ExecutionImpl(commandSender -> defaultCondition == null || defaultCondition.canUse(commandSender, null),
|
|
|
|
defaultExecutor, globalListener, executor, condition);
|
2022-07-13 22:45:38 +02:00
|
|
|
}
|
|
|
|
|
2022-07-17 22:41:28 +02:00
|
|
|
static ExecutionImpl fromSyntax(CommandSyntax syntax) {
|
2022-07-25 19:34:40 +02:00
|
|
|
final CommandExecutor executor = syntax.getExecutor();
|
2022-07-13 22:45:38 +02:00
|
|
|
final CommandCondition condition = syntax.getCommandCondition();
|
2022-07-25 19:34:40 +02:00
|
|
|
return new ExecutionImpl(commandSender -> condition == null || condition.canUse(commandSender, null),
|
|
|
|
null, null, executor, condition);
|
2022-07-13 22:45:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-17 22:41:28 +02:00
|
|
|
private record ConversionNode(Argument<?> argument, ExecutionImpl execution,
|
2022-07-13 22:45:38 +02:00
|
|
|
Map<Argument<?>, ConversionNode> nextMap) {
|
2022-07-17 22:41:28 +02:00
|
|
|
ConversionNode(Argument<?> argument, ExecutionImpl execution) {
|
|
|
|
this(argument, execution, new LinkedHashMap<>());
|
2022-07-13 22:45:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private NodeImpl toNode() {
|
|
|
|
Node[] nodes = new NodeImpl[nextMap.size()];
|
|
|
|
int i = 0;
|
|
|
|
for (var entry : nextMap.values()) nodes[i++] = entry.toNode();
|
2022-07-17 22:41:28 +02:00
|
|
|
return new NodeImpl(argument, execution, List.of(nodes));
|
2022-07-13 22:45:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static ConversionNode fromCommand(Command command) {
|
2022-07-17 23:13:25 +02:00
|
|
|
ConversionNode root = new ConversionNode(commandToArgument(command), ExecutionImpl.fromCommand(command));
|
2022-07-13 22:45:38 +02:00
|
|
|
// Syntaxes
|
|
|
|
for (CommandSyntax syntax : command.getSyntaxes()) {
|
|
|
|
ConversionNode syntaxNode = root;
|
|
|
|
for (Argument<?> arg : syntax.getArguments()) {
|
|
|
|
boolean last = arg == syntax.getArguments()[syntax.getArguments().length - 1];
|
|
|
|
syntaxNode = syntaxNode.nextMap.computeIfAbsent(arg, argument -> {
|
2022-07-17 22:41:28 +02:00
|
|
|
var ex = last ? ExecutionImpl.fromSyntax(syntax) : null;
|
2022-07-13 22:45:38 +02:00
|
|
|
return new ConversionNode(argument, ex);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Subcommands
|
|
|
|
for (Command subcommand : command.getSubcommands()) {
|
2022-07-17 23:13:25 +02:00
|
|
|
root.nextMap.put(commandToArgument(subcommand), fromCommand(subcommand));
|
2022-07-13 22:45:38 +02:00
|
|
|
}
|
|
|
|
return root;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ConversionNode rootConv(Collection<Command> commands) {
|
|
|
|
Map<Argument<?>, ConversionNode> next = new LinkedHashMap<>(commands.size());
|
|
|
|
for (Command command : commands) {
|
|
|
|
final ConversionNode conv = fromCommand(command);
|
|
|
|
next.put(conv.argument, conv);
|
|
|
|
}
|
|
|
|
return new ConversionNode(Literal(""), null, next);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-17 23:13:25 +02:00
|
|
|
static Argument<String> commandToArgument(Command command) {
|
|
|
|
final String[] aliases = command.getNames();
|
|
|
|
if (aliases.length == 1) return Literal(aliases[0]);
|
|
|
|
return Word(command.getName()).from(command.getNames());
|
|
|
|
}
|
|
|
|
|
2022-07-13 22:45:38 +02:00
|
|
|
static boolean compare(@NotNull Node first, Node second, @NotNull Comparator comparator) {
|
|
|
|
return switch (comparator) {
|
|
|
|
case TREE -> {
|
|
|
|
if (!first.argument().equals(second.argument())) yield false;
|
|
|
|
if (first.next().size() != second.next().size()) yield false;
|
|
|
|
for (int i = 0; i < first.next().size(); i++) {
|
|
|
|
if (!compare(first.next().get(i), second.next().get(i), comparator)) {
|
|
|
|
yield false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
yield true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|