Initial command syntaxes tree attempt

This commit is contained in:
TheMode 2021-05-04 23:00:38 +02:00
parent 22eb5c6bcd
commit dfcf908abc
1 changed files with 113 additions and 4 deletions

View File

@ -1,11 +1,10 @@
package net.minestom.server.command.builder;
import com.google.common.annotations.Beta;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.arguments.ArgumentDynamicStringArray;
import net.minestom.server.command.builder.arguments.ArgumentDynamicWord;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.command.builder.arguments.*;
import net.minestom.server.command.builder.arguments.minecraft.SuggestionType;
import net.minestom.server.command.builder.condition.CommandCondition;
import org.apache.commons.lang3.StringUtils;
@ -15,6 +14,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;
@ -330,6 +331,78 @@ public class Command {
return syntaxes;
}
@Beta
public @NotNull String getSyntaxesTree() {
Node commandNode = new Node();
commandNode.names.addAll(Arrays.asList(getNames()));
// current node, literal = returned node
BiFunction<Node, Set<String>, Node> findNode = (currentNode, literals) -> {
for (Node node : currentNode.nodes) {
final var names = node.names;
// Verify if at least one literal is shared
final boolean shared = names.stream().anyMatch(literals::contains);
if (shared) {
names.addAll(literals);
return node;
}
}
// Create a new node
Node node = new Node();
node.names.addAll(literals);
currentNode.nodes.add(node);
return node;
};
BiConsumer<CommandSyntax, Node> syntaxProcessor = (syntax, node) -> {
List<String> arguments = new ArrayList<>();
BiConsumer<Node, List<String>> addArguments = (n, args) -> {
if (!args.isEmpty()) {
n.arguments.add(args);
}
};
for (Argument<?> argument : syntax.getArguments()) {
if (argument instanceof ArgumentLiteral) {
final String literal = argument.getId();
addArguments.accept(node, arguments);
arguments = new ArrayList<>();
node = findNode.apply(node, Collections.singleton(literal));
} else if (argument instanceof ArgumentWord) {
ArgumentWord argumentWord = (ArgumentWord) argument;
if (argumentWord.hasRestrictions()) {
addArguments.accept(node, arguments);
arguments = new ArrayList<>();
node = findNode.apply(node, Set.of(argumentWord.getRestrictions()));
}
} else {
arguments.add(argument.toString());
}
}
addArguments.accept(node, arguments);
};
// Subcommands
this.subcommands.forEach(command -> {
final Node node = findNode.apply(commandNode, Set.of(command.getNames()));
command.getSyntaxes().forEach(syntax -> syntaxProcessor.accept(syntax, node));
});
// Syntaxes
this.syntaxes.forEach(syntax -> syntaxProcessor.accept(syntax, commandNode));
JsonObject jsonObject = new JsonObject();
processNode(commandNode, jsonObject);
return jsonObject.toString();
}
public static boolean isValidName(@NotNull Command command, @NotNull String name) {
for (String commandName : command.getNames()) {
if (commandName.equals(name)) {
@ -339,4 +412,40 @@ public class Command {
return false;
}
private void processNode(@NotNull Node node, @NotNull JsonObject jsonObject) {
BiConsumer<String, Consumer<JsonArray>> processor = (s, consumer) -> {
JsonArray array = new JsonArray();
consumer.accept(array);
if (array.size() != 0) {
jsonObject.add(s, array);
}
};
// Names
{
processor.accept("names", array -> node.names.forEach(array::add));
}
// Nodes
{
processor.accept("nodes", array ->
node.nodes.forEach(n -> {
JsonObject nodeObject = new JsonObject();
processNode(n, nodeObject);
array.add(nodeObject);
}));
}
// Arguments
{
processor.accept("arguments", array ->
node.arguments.forEach(arguments ->
array.add(String.join(StringUtils.SPACE, arguments))));
}
}
private static final class Node {
private final Set<String> names = new HashSet<>();
private final Set<Node> nodes = new HashSet<>();
private final List<List<String>> arguments = new ArrayList<>();
}
}