From dfcf908abc142ab8d64c28a9a13a42cf7c6eca2b Mon Sep 17 00:00:00 2001 From: TheMode Date: Tue, 4 May 2021 23:00:38 +0200 Subject: [PATCH] Initial command syntaxes tree attempt --- .../server/command/builder/Command.java | 117 +++++++++++++++++- 1 file changed, 113 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/minestom/server/command/builder/Command.java b/src/main/java/net/minestom/server/command/builder/Command.java index 1f4218389..67623e4e8 100644 --- a/src/main/java/net/minestom/server/command/builder/Command.java +++ b/src/main/java/net/minestom/server/command/builder/Command.java @@ -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> 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 syntaxProcessor = (syntax, node) -> { + List arguments = new ArrayList<>(); + BiConsumer> 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> 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 names = new HashSet<>(); + private final Set nodes = new HashSet<>(); + private final List> arguments = new ArrayList<>(); + } + }