mirror of https://github.com/Minestom/Minestom.git
Fix building and add graphviz exporter
This commit is contained in:
parent
eebb9b832f
commit
3d5721e8f2
|
@ -55,6 +55,7 @@ public class Main {
|
|||
commandManager.register(new ExecuteCommand());
|
||||
commandManager.register(new RedirectTestCommand());
|
||||
|
||||
MinecraftServer.getCommandManager().createDeclareCommandsPacket(null);
|
||||
|
||||
commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage(Component.text("Unknown command", NamedTextColor.RED)));
|
||||
|
||||
|
|
|
@ -157,6 +157,8 @@ public final class CommandManager {
|
|||
* @return the {@link DeclareCommandsPacket} for {@code player}
|
||||
*/
|
||||
public @NotNull DeclareCommandsPacket createDeclareCommandsPacket(@NotNull Player player) {
|
||||
return GraphBuilder.forPlayer(this.dispatcher.getCommands(), player).createPacket();
|
||||
final NodeGraph nodeGraph = GraphBuilder.forPlayer(this.dispatcher.getCommands(), player);
|
||||
System.out.println(nodeGraph.exportGarphvizDot()); //TODO remove before merging
|
||||
return nodeGraph.createPacket();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ package net.minestom.server.command;
|
|||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.command.builder.CommandSyntax;
|
||||
import net.minestom.server.command.builder.arguments.*;
|
||||
|
@ -19,7 +17,6 @@ import org.jetbrains.annotations.Nullable;
|
|||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
final class GraphBuilder {
|
||||
|
@ -28,7 +25,6 @@ final class GraphBuilder {
|
|||
);
|
||||
private final AtomicInteger idSource = new AtomicInteger();
|
||||
private final ObjectList<Node> nodes = new ObjectArrayList<>();
|
||||
private final ObjectSet<Supplier<Boolean>> redirectWaitList = new ObjectOpenHashSet<>();
|
||||
private final Node root = rootNode();
|
||||
|
||||
private GraphBuilder() {
|
||||
|
@ -51,72 +47,31 @@ final class GraphBuilder {
|
|||
} else {
|
||||
final Node literalNode = Node.literal(idSource.getAndIncrement(), name, executable, redirectTo);
|
||||
nodes.add(literalNode);
|
||||
if (parent != null) parent.addChild(literalNode);
|
||||
if (parent != null) parent.addChildren(literalNode);
|
||||
return literalNode;
|
||||
}
|
||||
}
|
||||
|
||||
private Node[] createArgumentNode(Argument<?> argument, boolean executable) {
|
||||
private Node[] createArgumentNode(Argument<?> argument, boolean executable, @Nullable AtomicInteger redirectTarget) {
|
||||
final Node[] nodes;
|
||||
Integer overrideRedirectTarget = null;
|
||||
if (argument instanceof ArgumentEnum<?> argumentEnum) {
|
||||
nodes = argumentEnum.entries().stream().map(x -> createLiteralNode(x, null, executable, null, null)).toArray(Node[]::new);
|
||||
return argumentEnum.entries().stream().map(x -> createLiteralNode(x, null, executable, null, null)).toArray(Node[]::new);
|
||||
} else if (argument instanceof ArgumentGroup argumentGroup) {
|
||||
nodes = argumentGroup.group().stream().map(x -> createArgumentNode(x, executable)).flatMap(Stream::of).toArray(Node[]::new);
|
||||
return argumentGroup.group().stream().map(x -> createArgumentNode(x, executable, redirectTarget)).flatMap(Stream::of).toArray(Node[]::new);
|
||||
} else if (argument instanceof ArgumentLoop<?> argumentLoop) {
|
||||
overrideRedirectTarget = idSource.get()-1;
|
||||
nodes = argumentLoop.arguments().stream().map(x -> createArgumentNode(x, executable)).flatMap(Stream::of).toArray(Node[]::new);
|
||||
final AtomicInteger target = new AtomicInteger(idSource.get() - 1);
|
||||
return argumentLoop.arguments().stream().map(x -> createArgumentNode(x, executable, target)).flatMap(Stream::of).toArray(Node[]::new);
|
||||
} else {
|
||||
if (argument instanceof ArgumentCommand) {
|
||||
return new Node[]{createLiteralNode(argument.getId(), null, false, null, new AtomicInteger(0))};
|
||||
}
|
||||
final int id = idSource.getAndIncrement();
|
||||
nodes = new Node[] {argument instanceof ArgumentLiteral ?
|
||||
Node.literal(id, argument.getId(), executable, null) :
|
||||
Node.argument(id, argument, executable, null)};
|
||||
}
|
||||
for (Node node : nodes) {
|
||||
this.nodes.add(node);
|
||||
Integer finalOverrideRedirectTarget = overrideRedirectTarget;
|
||||
if (finalOverrideRedirectTarget != null) {
|
||||
redirectWaitList.add(() -> {
|
||||
int target = finalOverrideRedirectTarget;
|
||||
if (target != -1) {
|
||||
node.redirectTarget().set(target);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
nodes = new Node[] {Node.argument(idSource.getAndIncrement(), argument, executable, redirectTarget)};
|
||||
}
|
||||
this.nodes.addAll(Arrays.asList(nodes));
|
||||
return nodes;
|
||||
}
|
||||
|
||||
private int tryResolveId(String[] path) {
|
||||
if (path.length == 0) {
|
||||
return root.id();
|
||||
} else {
|
||||
Node target = root;
|
||||
for (String next : path) {
|
||||
Node finalTarget = target;
|
||||
final Optional<Node> result = nodes.stream().filter(finalTarget::isParentOf)
|
||||
.filter(x -> x.name().equals(next)).findFirst();
|
||||
if (result.isEmpty()) {
|
||||
return -1;
|
||||
} else {
|
||||
target = result.get();
|
||||
}
|
||||
}
|
||||
return target.id();
|
||||
}
|
||||
}
|
||||
|
||||
private void finalizeStructure(boolean forParsing) {
|
||||
redirectWaitList.removeIf(Supplier::get);
|
||||
if (redirectWaitList.size() > 0)
|
||||
throw new IllegalCommandStructureException("Could not set redirects for all arguments! Did you provide a " +
|
||||
"correct id path which doesn't rely on redirects?");
|
||||
|
||||
nodes.sort(Comparator.comparing(Node::id));
|
||||
|
||||
if (forParsing) {
|
||||
|
@ -168,9 +123,9 @@ final class GraphBuilder {
|
|||
executable = true;
|
||||
}
|
||||
// Append current node to previous
|
||||
final Node[] argNodes = createArgumentNode(argument, executable);
|
||||
final Node[] argNodes = createArgumentNode(argument, executable, null);
|
||||
for (Node lastArgNode : lastArgNodes) {
|
||||
lastArgNode.addChild(argNodes);
|
||||
lastArgNode.addChildren(argNodes);
|
||||
}
|
||||
lastArgNodes = argNodes;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import net.minestom.server.command.builder.arguments.Argument;
|
|||
import net.minestom.server.command.builder.arguments.ArgumentLiteral;
|
||||
import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
|
||||
import net.minestom.server.network.packet.server.play.DeclareCommandsPacket.NodeType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
@ -16,15 +17,21 @@ record Node(int id, IntList children, NodeType type, String name, boolean execut
|
|||
public static Node root(int id) {
|
||||
return new Node(id, new IntArrayList(), NodeType.ROOT, null, false, null, null);
|
||||
}
|
||||
|
||||
public static Node literal(int id, String name, boolean executable, @Nullable AtomicInteger redirectTarget) {
|
||||
return new Node(id, new IntArrayList(), NodeType.LITERAL, name, executable, new ArgumentLiteral(name), redirectTarget);
|
||||
return literal(id, name, executable, new ArgumentLiteral(name), redirectTarget);
|
||||
}
|
||||
|
||||
public static Node literal(int id, String name, boolean executable, @NotNull Argument<?> backingArg, @Nullable AtomicInteger redirectTarget) {
|
||||
return new Node(id, new IntArrayList(), NodeType.LITERAL, name, executable, backingArg, redirectTarget);
|
||||
}
|
||||
|
||||
public static Node argument(int id, Argument<?> argument, boolean executable, @Nullable AtomicInteger redirectTarget) {
|
||||
return new Node(id, new IntArrayList(), NodeType.ARGUMENT, argument.getId(), executable, argument, redirectTarget);
|
||||
return new Node(id, new IntArrayList(), argument instanceof ArgumentLiteral ? NodeType.LITERAL :
|
||||
NodeType.ARGUMENT, argument.getId(), executable, argument, redirectTarget);
|
||||
}
|
||||
|
||||
public void addChild(Node ...nodes) {
|
||||
public void addChildren(Node ...nodes) {
|
||||
for (Node node : nodes) {
|
||||
children.add(node.id);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import org.jetbrains.annotations.Contract;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
record NodeGraph(List<Node> nodes, Node root) {
|
||||
|
||||
|
@ -25,4 +27,41 @@ record NodeGraph(List<Node> nodes, Node root) {
|
|||
public DeclareCommandsPacket createPacket() {
|
||||
return new DeclareCommandsPacket(nodes.stream().map(Node::getPacketNode).toList(), root.id());
|
||||
}
|
||||
|
||||
public String exportGarphvizDot() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final char statementSeparator = ';';
|
||||
builder.append("digraph G {");
|
||||
builder.append("rankdir=LR");
|
||||
builder.append(statementSeparator);
|
||||
for (Node node : nodes) {
|
||||
final AtomicInteger redirectTarget = node.redirectTarget();
|
||||
builder.append(node.id());
|
||||
builder.append(" [label=");
|
||||
builder.append(graphvizName(node));
|
||||
if (node.isRoot()) {
|
||||
builder.append(",shape=rectangle");
|
||||
}
|
||||
builder.append("]");
|
||||
builder.append(statementSeparator);
|
||||
if (node.children().isEmpty() && redirectTarget == null) continue;
|
||||
builder.append(node.id());
|
||||
builder.append(" -> { ");
|
||||
if (!node.children().isEmpty()) {
|
||||
builder.append(node.children().intStream().mapToObj(String::valueOf).collect(Collectors.joining(" ")));
|
||||
builder.append(" }");
|
||||
builder.append(statementSeparator);
|
||||
} else {
|
||||
builder.append(redirectTarget.get());
|
||||
builder.append(" } [style = dotted]");
|
||||
builder.append(statementSeparator);
|
||||
}
|
||||
}
|
||||
builder.append("}");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static String graphvizName(Node node) {
|
||||
return '"' + (node.isRoot() ? "root" : node.name()) + '"';
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue