Rewrite of the command nodes creation

This commit is contained in:
themode 2021-02-11 06:37:09 +01:00
parent ab9ddebfea
commit f639ac83f7
5 changed files with 76 additions and 90 deletions

View File

@ -418,7 +418,7 @@ public final class CommandManager {
// Contains the arguments of the already-parsed syntaxes
List<Argument<?>[]> syntaxesArguments = new ArrayList<>();
// Contains the nodes of an argument
Map<Argument<?>, DeclareCommandsPacket.Node[]> storedArgumentsNodes = new HashMap<>();
Map<Argument<?>, List<DeclareCommandsPacket.Node[]>> storedArgumentsNodes = new HashMap<>();
for (CommandSyntax syntax : syntaxes) {
final CommandCondition commandCondition = syntax.getCommandCondition();
@ -430,77 +430,70 @@ public final class CommandManager {
NodeMaker nodeMaker = new NodeMaker();
// Represent the last nodes computed in the last iteration
//DeclareCommandsPacket.Node[] lastNodes = null;
DeclareCommandsPacket.Node[] lastNodes = new DeclareCommandsPacket.Node[]{literalNode};
// Represent the children of the last node
IntList argChildren = null;
IntList argChildren = cmdChildren;
int lastArgumentNodeIndex = 0;
final Argument<?>[] arguments = syntax.getArguments();
for (int i = 0; i < arguments.length; i++) {
final Argument<?> argument = arguments[i];
final boolean isFirst = i == 0;
final boolean isLast = i == arguments.length - 1;
// Find shared part
boolean foundSharedPart = false;
for (Argument<?>[] parsedArguments : syntaxesArguments) {
if (ArrayUtils.sameStart(arguments, parsedArguments, i + 1)) {
final Argument<?> sharedArgument = parsedArguments[i];
// Search previously parsed syntaxes to find identical part in order to create a node between those
{
// Find shared part
boolean foundSharedPart = false;
for (Argument<?>[] parsedArguments : syntaxesArguments) {
if (ArrayUtils.sameStart(arguments, parsedArguments, i + 1)) {
final Argument<?> sharedArgument = parsedArguments[i];
final List<DeclareCommandsPacket.Node[]> storedNodes = storedArgumentsNodes.get(sharedArgument);
argChildren = new IntArrayList();
nodeMaker.setLastNodes(storedArgumentsNodes.get(sharedArgument));
foundSharedPart = true;
}
}
if (foundSharedPart) {
continue;
}
argument.processNodes(nodeMaker, isLast);
final DeclareCommandsPacket.Node[] argumentNodes = nodeMaker.getCurrentNodes();
storedArgumentsNodes.put(argument, argumentNodes);
for (DeclareCommandsPacket.Node node : argumentNodes) {
final int childId = nodes.size();
if (isFirst) {
// Add to main command child
cmdChildren.add(childId);
} else {
// Add to previous argument children
argChildren.add(childId);
}
final DeclareCommandsPacket.Node[] lastNodes = nodeMaker.getLastNodes();
if (lastNodes != null) {
final int[] children = ArrayUtils.toArray(argChildren);
for (DeclareCommandsPacket.Node lastNode : lastNodes) {
lastNode.children = lastNode.children == null ?
children :
ArrayUtils.concatenateIntArrays(lastNode.children, children);
argChildren = new IntArrayList();
lastNodes = storedNodes.get(storedNodes.size() - Math.max(arguments.length, parsedArguments.length));
foundSharedPart = true;
}
}
// Always add to the main node list
nodes.add(node);
if (foundSharedPart) {
continue;
}
}
//System.out.println("debug: " + argument.getId() + " : " + isFirst + " : " + isLast);
//System.out.println("debug2: " + i);
//System.out.println("size: " + (argChildren != null ? argChildren.size() : "NULL"));
// Process the nodes for the argument
{
argument.processNodes(nodeMaker, isLast);
if (isLast) {
// Last argument doesn't have children
final int[] children = new int[0];
// Each node array represent a layer
final List<DeclareCommandsPacket.Node[]> nodesLayer = nodeMaker.getNodes();
storedArgumentsNodes.put(argument, nodesLayer);
for (int nodeIndex = lastArgumentNodeIndex; nodeIndex < nodesLayer.size(); nodeIndex++) {
final DeclareCommandsPacket.Node[] argumentNodes = nodesLayer.get(nodeIndex);
for (DeclareCommandsPacket.Node node : argumentNodes) {
node.children = children;
for (DeclareCommandsPacket.Node argumentNode : argumentNodes) {
final int childId = nodes.size();
argChildren.add(childId);
// Append to the last node
{
final int[] children = ArrayUtils.toArray(argChildren);
for (DeclareCommandsPacket.Node lastNode : lastNodes) {
lastNode.children = lastNode.children == null ?
children :
ArrayUtils.concatenateIntArrays(lastNode.children, children);
}
}
nodes.add(argumentNode);
}
lastNodes = argumentNodes;
argChildren = new IntArrayList();
}
} else {
// Create children list which will be filled during next iteration
argChildren = new IntArrayList();
nodeMaker.setLastNodes(argumentNodes);
// Used to do not re-compute the previous arguments
lastArgumentNodeIndex = nodesLayer.size();
}
}

View File

@ -2,32 +2,26 @@ package net.minestom.server.command.builder;
import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class NodeMaker {
private DeclareCommandsPacket.Node[] lastNodes;
private DeclareCommandsPacket.Node[] currentNodes;
private final List<DeclareCommandsPacket.Node[]> nodes = new ArrayList<>(2);
public DeclareCommandsPacket.Node[] getCurrentNodes() {
return currentNodes;
public DeclareCommandsPacket.Node[] getLatestNodes() {
if (nodes.isEmpty())
return null;
return nodes.get(nodes.size() - 1);
}
public void addNodes(@NotNull DeclareCommandsPacket.Node[] nodes) {
this.currentNodes = nodes;
this.nodes.add(nodes);
}
/**
* Represents the nodes computed in the last iteration.
*
* @return the previous nodes, null if none
*/
@Nullable
public DeclareCommandsPacket.Node[] getLastNodes() {
return lastNodes;
}
public void setLastNodes(DeclareCommandsPacket.Node[] lastNodes) {
this.lastNodes = lastNodes;
@NotNull
public List<DeclareCommandsPacket.Node[]> getNodes() {
return nodes;
}
}

View File

@ -23,7 +23,6 @@ public abstract class Argument<T> {
private final String id;
private final boolean allowSpace;
private final boolean useRemaining;
private Argument<?> redirect;
private ArgumentCallback callback;
@ -195,4 +194,18 @@ public abstract class Argument<T> {
return callback != null;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Argument<?> argument = (Argument<?>) o;
return id.equals(argument.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
}

View File

@ -30,7 +30,7 @@ public class ArgumentCommand extends Argument<CommandResult> {
@Override
public void processNodes(@NotNull NodeMaker nodeMaker, boolean executable) {
final DeclareCommandsPacket.Node[] lastNodes = nodeMaker.getLastNodes();
final DeclareCommandsPacket.Node[] lastNodes = nodeMaker.getLatestNodes();
// FIXME check if lastNodes is null
for (DeclareCommandsPacket.Node node : lastNodes) {

View File

@ -8,7 +8,6 @@ import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.function.Consumer;
/**
@ -126,17 +125,4 @@ public class ArgumentWord extends Argument<String> {
public String[] getRestrictions() {
return restrictions;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ArgumentWord that = (ArgumentWord) o;
return Arrays.equals(restrictions, that.restrictions);
}
@Override
public int hashCode() {
return Arrays.hashCode(restrictions);
}
}