mirror of https://github.com/Minestom/Minestom.git
Make Node and NodeGraph records and extend them as a preparation for parsing support
This commit is contained in:
parent
ba73c742f4
commit
eebb9b832f
|
@ -1,27 +1,33 @@
|
|||
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.*;
|
||||
import net.minestom.server.command.builder.arguments.number.ArgumentDouble;
|
||||
import net.minestom.server.command.builder.arguments.number.ArgumentFloat;
|
||||
import net.minestom.server.command.builder.arguments.number.ArgumentInteger;
|
||||
import net.minestom.server.command.builder.arguments.number.ArgumentLong;
|
||||
import net.minestom.server.command.builder.condition.CommandCondition;
|
||||
import net.minestom.server.command.builder.exception.IllegalCommandStructureException;
|
||||
import net.minestom.server.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
final class GraphBuilder {
|
||||
private static final List<Class<? extends Argument<?>>> argPriorities = List.of(
|
||||
ArgumentInteger.class, ArgumentLong.class, ArgumentFloat.class, ArgumentDouble.class //TODO the rest
|
||||
);
|
||||
private final AtomicInteger idSource = new AtomicInteger();
|
||||
private final ObjectSet<Node> nodes = new ObjectOpenHashSet<>();
|
||||
private final ObjectList<Node> nodes = new ObjectArrayList<>();
|
||||
private final ObjectSet<Supplier<Boolean>> redirectWaitList = new ObjectOpenHashSet<>();
|
||||
private final Node root = rootNode();
|
||||
|
||||
|
@ -30,21 +36,20 @@ final class GraphBuilder {
|
|||
}
|
||||
|
||||
private Node rootNode() {
|
||||
final Node rootNode = new Node(idSource.getAndIncrement());
|
||||
final Node rootNode = Node.root(idSource.getAndIncrement());
|
||||
nodes.add(rootNode);
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
private Node createLiteralNode(String name, @Nullable Node parent, boolean executable, @Nullable String[] aliases, @Nullable Integer redirectTo) {
|
||||
private Node createLiteralNode(String name, @Nullable Node parent, boolean executable, @Nullable String[] aliases, @Nullable AtomicInteger redirectTo) {
|
||||
if (aliases != null) {
|
||||
final Node node = createLiteralNode(name, parent, executable, null, null);
|
||||
for (String alias : aliases) {
|
||||
createLiteralNode(alias, parent, executable, null, node.id());
|
||||
createLiteralNode(alias, parent, executable, null, new AtomicInteger(node.id()));
|
||||
}
|
||||
return node;
|
||||
} else {
|
||||
final Node literalNode = new Node(idSource.getAndIncrement(), name, redirectTo);
|
||||
literalNode.setExecutable(executable);
|
||||
final Node literalNode = Node.literal(idSource.getAndIncrement(), name, executable, redirectTo);
|
||||
nodes.add(literalNode);
|
||||
if (parent != null) parent.addChild(literalNode);
|
||||
return literalNode;
|
||||
|
@ -63,20 +68,21 @@ final class GraphBuilder {
|
|||
nodes = argumentLoop.arguments().stream().map(x -> createArgumentNode(x, executable)).flatMap(Stream::of).toArray(Node[]::new);
|
||||
} else {
|
||||
if (argument instanceof ArgumentCommand) {
|
||||
return new Node[]{createLiteralNode(argument.getId(), null, false, null, 0)};
|
||||
return new Node[]{createLiteralNode(argument.getId(), null, false, null, new AtomicInteger(0))};
|
||||
}
|
||||
final int id = idSource.getAndIncrement();
|
||||
nodes = new Node[] {argument instanceof ArgumentLiteral ? new Node(id, argument.getId(), null) : new Node(id, argument)};
|
||||
nodes = new Node[] {argument instanceof ArgumentLiteral ?
|
||||
Node.literal(id, argument.getId(), executable, null) :
|
||||
Node.argument(id, argument, executable, null)};
|
||||
}
|
||||
for (Node node : nodes) {
|
||||
node.setExecutable(executable);
|
||||
this.nodes.add(node);
|
||||
Integer finalOverrideRedirectTarget = overrideRedirectTarget;
|
||||
if (finalOverrideRedirectTarget != null) {
|
||||
redirectWaitList.add(() -> {
|
||||
int target = finalOverrideRedirectTarget;
|
||||
if (target != -1) {
|
||||
node.setRedirectTarget(target);
|
||||
node.redirectTarget().set(target);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -105,11 +111,20 @@ final class GraphBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
private void finalizeStructure() {
|
||||
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) {
|
||||
for (Node node : nodes) {
|
||||
node.children().sort((k1, k2) -> Integer.compare(argPriorities.indexOf(nodes.get(k1).arg().getClass()),
|
||||
argPriorities.indexOf(nodes.get(k2).arg().getClass())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -193,9 +208,9 @@ final class GraphBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
builder.finalizeStructure();
|
||||
builder.finalizeStructure(player == null);
|
||||
|
||||
return new NodeGraph(builder.nodes, builder.root.id());
|
||||
return new NodeGraph(builder.nodes, builder.root);
|
||||
}
|
||||
|
||||
public static NodeGraph forServer(@NotNull Set<Command> commands) {
|
||||
|
|
|
@ -1,56 +1,27 @@
|
|||
package net.minestom.server.command;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSets;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
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.Nullable;
|
||||
|
||||
final class Node {
|
||||
private final int id;
|
||||
private final IntSet children = new IntOpenHashSet();
|
||||
private final IntSet childrenView = IntSets.unmodifiable(children);
|
||||
private final DeclareCommandsPacket.NodeType type;
|
||||
private String name;
|
||||
private Integer redirectTarget;
|
||||
private Argument<?> argument;
|
||||
private boolean executable;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
Node(int id, DeclareCommandsPacket.NodeType type) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
record Node(int id, IntList children, NodeType type, String name, boolean executable, Argument<?> arg,
|
||||
AtomicInteger redirectTarget) {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Node(int id) {
|
||||
this(id, DeclareCommandsPacket.NodeType.ROOT);
|
||||
}
|
||||
|
||||
Node(int id, String name, Integer redirectTarget) {
|
||||
this(id, DeclareCommandsPacket.NodeType.LITERAL);
|
||||
setName(name);
|
||||
setRedirectTarget(redirectTarget);
|
||||
}
|
||||
|
||||
Node(int id, Argument<?> argument) {
|
||||
this(id, DeclareCommandsPacket.NodeType.ARGUMENT);
|
||||
setName(argument.getId());
|
||||
this.argument = argument;
|
||||
}
|
||||
|
||||
public void setExecutable(boolean executable) {
|
||||
this.executable = executable;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setRedirectTarget(Integer redirectTarget) {
|
||||
this.redirectTarget = 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);
|
||||
}
|
||||
|
||||
public void addChild(Node ...nodes) {
|
||||
|
@ -63,41 +34,25 @@ final class Node {
|
|||
return children.contains(node.id());
|
||||
}
|
||||
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public DeclareCommandsPacket.NodeType type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public IntSet children() {
|
||||
return childrenView;
|
||||
}
|
||||
|
||||
public Integer redirectTarget() {
|
||||
return redirectTarget;
|
||||
}
|
||||
|
||||
public boolean isRoot() {
|
||||
return type == DeclareCommandsPacket.NodeType.ROOT;
|
||||
return type == NodeType.ROOT;
|
||||
}
|
||||
|
||||
public DeclareCommandsPacket.Node getPacketNode() {
|
||||
final DeclareCommandsPacket.Node node = new DeclareCommandsPacket.Node();
|
||||
node.children = children.toIntArray();
|
||||
node.flags = DeclareCommandsPacket.getFlag(type, executable, redirectTarget != null,
|
||||
type == DeclareCommandsPacket.NodeType.ARGUMENT && argument.hasSuggestion());
|
||||
type == NodeType.ARGUMENT && arg.hasSuggestion());
|
||||
node.name = name;
|
||||
if (redirectTarget != null) {
|
||||
node.redirectedNode = redirectTarget;
|
||||
node.redirectedNode = redirectTarget.get();
|
||||
}
|
||||
if (type == DeclareCommandsPacket.NodeType.ARGUMENT) {
|
||||
node.properties = argument.nodeProperties();
|
||||
node.parser = argument.parser();
|
||||
if (argument.hasSuggestion()) {
|
||||
if (type == NodeType.ARGUMENT) {
|
||||
node.properties = arg.nodeProperties();
|
||||
node.parser = arg.parser();
|
||||
if (arg.hasSuggestion()) {
|
||||
//noinspection ConstantConditions
|
||||
node.suggestionsType = argument.suggestionType().getIdentifier();
|
||||
node.suggestionsType = arg.suggestionType().getIdentifier();
|
||||
}
|
||||
}
|
||||
return node;
|
||||
|
|
|
@ -1,25 +1,12 @@
|
|||
package net.minestom.server.command;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectImmutableList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||
import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
class NodeGraph {
|
||||
private final ObjectList<Node> nodes;
|
||||
private final Node root;
|
||||
|
||||
NodeGraph(ObjectSet<Node> nodes, int rootId) {
|
||||
this.nodes = new ObjectImmutableList<>(nodes.stream().sorted(Comparator.comparing(Node::id)).toList());
|
||||
this.root = this.nodes.get(rootId);
|
||||
assert root.isRoot() : "rootId doesn't point to the root node";
|
||||
assert this.nodes.stream().filter(Node::isRoot).count() == 1 : "Invalid root node count!";
|
||||
}
|
||||
record NodeGraph(List<Node> nodes, Node root) {
|
||||
|
||||
public Node resolveId(int id) {
|
||||
return nodes.get(id);
|
||||
|
@ -30,8 +17,8 @@ class NodeGraph {
|
|||
}
|
||||
|
||||
public @Nullable Node getRedirectTarget(Node node) {
|
||||
final Integer target = node.redirectTarget();
|
||||
return target == null ? null : resolveId(target);
|
||||
if (node.redirectTarget() == null) return null;
|
||||
return resolveId(node.redirectTarget().get());
|
||||
}
|
||||
|
||||
@Contract("-> new")
|
||||
|
|
Loading…
Reference in New Issue