Search in sources :

Example 1 with SpongeMultiParameter

use of org.spongepowered.common.command.parameter.multi.SpongeMultiParameter in project SpongeCommon by SpongePowered.

the class SpongeParameterTranslator method createAndAttachNode.

private Collection<? extends CommandNode<CommandSourceStack>> createAndAttachNode(final Collection<? extends CommandNode<CommandSourceStack>> parents, final List<Parameter> children, @Nullable final SpongeCommandExecutorWrapper executorWrapper, final boolean shouldTerminate, final boolean allowSubcommands) {
    final Set<CommandNode<CommandSourceStack>> nodesToAttachTo = new HashSet<>(parents);
    final ListIterator<Parameter> parameterIterator = children.listIterator();
    while (parameterIterator.hasNext()) {
        final Parameter parameter = parameterIterator.next();
        final boolean hasNext = parameterIterator.hasNext();
        if (parameter instanceof Parameter.Subcommand) {
            final Parameter.Subcommand subcommands = ((Parameter.Subcommand) parameter);
            if (!allowSubcommands) {
                throw new IllegalStateException("Subcommands are not allowed for this element (subcommands were " + String.join(", ", subcommands.aliases() + ")!"));
            }
            if (hasNext) {
                // this is a failure condition because there cannot be a parameter after a subcommand.
                throw new IllegalStateException("A parameter cannot be placed after a subcommand parameter!");
            }
            // If the child is a subcommand, get the subcommand and attach it. At this point,
            // we're done with the chain and we break out.
            final Collection<LiteralCommandNode<CommandSourceStack>> nodes = this.createCommandTree(subcommands.command(), subcommands.aliases());
            for (final LiteralCommandNode<CommandSourceStack> node : nodes) {
                nodesToAttachTo.forEach(x -> x.addChild(node));
            }
            // No further attaching should be done in this scenario
            return Collections.emptyList();
        } else {
            final boolean isOptional;
            final boolean isTerminal;
            final Collection<CommandNode<CommandSourceStack>> parametersToAttachTo;
            if (parameter instanceof SpongeMultiParameter) {
                isOptional = parameter.isOptional();
                isTerminal = !hasNext || parameter.isTerminal();
                // In these cases, we delegate to the parameter, which may return here.
                if (parameter instanceof SpongeFirstOfParameter) {
                    // take each parameter in turn and evaluate it, returns the terminal nodes of each block
                    parametersToAttachTo = new ArrayList<>();
                    for (final Parameter p : ((SpongeFirstOfParameter) parameter).childParameters()) {
                        final Collection<? extends CommandNode<CommandSourceStack>> branchNodesToAttachTo = this.createAndAttachNode(nodesToAttachTo, Collections.singletonList(p), executorWrapper, isTerminal, allowSubcommands);
                        parametersToAttachTo.addAll(branchNodesToAttachTo);
                    }
                } else {
                    // not so fancy stuff, it's a sequence, returns the terminal nodes of the block
                    parametersToAttachTo = new ArrayList<>(this.createAndAttachNode(nodesToAttachTo, ((SpongeMultiParameter) parameter).childParameters(), executorWrapper, isTerminal, allowSubcommands));
                }
            } else {
                // We have a Parameter.Value
                parametersToAttachTo = new ArrayList<>();
                final SpongeParameterValue<?> valueParameter = (SpongeParameterValue<?>) parameter;
                final boolean isConsumeAll = valueParameter.willConsumeAllRemaining();
                if (isConsumeAll && hasNext) {
                    // this should not happen.
                    throw new IllegalStateException("A parameter that consumes all must be at the end of a parameter chain.");
                }
                isOptional = valueParameter.isOptional();
                isTerminal = (shouldTerminate && !hasNext) || valueParameter.isTerminal();
                // Process the next element if it exists
                StringBuilder suffix = null;
                final Set<String> names = nodesToAttachTo.stream().flatMap(x -> x.getChildren().stream()).map(CommandNode::getName).collect(Collectors.toSet());
                String key = valueParameter.key().key();
                while (names.contains(key)) {
                    if (suffix == null) {
                        suffix = new StringBuilder(String.valueOf(names.size()));
                    } else {
                        suffix.append("_").append(names.size());
                    }
                    // prevents duplication
                    key = key + suffix;
                }
                final SpongeArgumentCommandNodeBuilder<?> thisNode = SpongeParameterTranslator.createArgumentNodeBuilders(valueParameter, suffix == null ? null : suffix.toString());
                if (isTerminal) {
                    thisNode.executes(executorWrapper);
                }
                // Apply the node to the parent.
                final CommandNode<CommandSourceStack> builtNode = thisNode.build();
                if (isConsumeAll) {
                    // the built child will return to the previous node, which will allow this to be called again.
                    builtNode.addChild(thisNode.redirect(builtNode).build());
                }
                parametersToAttachTo.add(builtNode);
                // Make sure the nodes we need to attach to have the nodes we need to
                nodesToAttachTo.forEach(x -> x.addChild(builtNode));
            }
            // If this is not optional, then we clear the "toAttachTo" list because we do not want to skip the parameter.
            if (!isOptional) {
                nodesToAttachTo.clear();
            }
            nodesToAttachTo.addAll(parametersToAttachTo);
        }
    }
    // If we should make any terminal parameters actually terminal, we do that now.
    if (shouldTerminate) {
        for (final CommandNode<CommandSourceStack> node : nodesToAttachTo) {
            // These are therefore terminal.
            if (node instanceof SpongeNode) {
                // they should be, but just in case
                ((SpongeNode) node).forceExecutor(executorWrapper);
            }
        }
    }
    return nodesToAttachTo;
}
Also used : LiteralCommandNode(com.mojang.brigadier.tree.LiteralCommandNode) SpongeFlagLiteralCommandNode(org.spongepowered.common.command.brigadier.tree.SpongeFlagLiteralCommandNode) SpongeLiteralCommandNode(org.spongepowered.common.command.brigadier.tree.SpongeLiteralCommandNode) CommandNode(com.mojang.brigadier.tree.CommandNode) CommandSourceStack(net.minecraft.commands.CommandSourceStack) LiteralCommandNode(com.mojang.brigadier.tree.LiteralCommandNode) SpongeFlagLiteralCommandNode(org.spongepowered.common.command.brigadier.tree.SpongeFlagLiteralCommandNode) SpongeLiteralCommandNode(org.spongepowered.common.command.brigadier.tree.SpongeLiteralCommandNode) SpongeNode(org.spongepowered.common.command.brigadier.tree.SpongeNode) HashSet(java.util.HashSet) SpongeParameterValue(org.spongepowered.common.command.parameter.SpongeParameterValue) SpongeMultiParameter(org.spongepowered.common.command.parameter.multi.SpongeMultiParameter) Parameter(org.spongepowered.api.command.parameter.Parameter) SpongeMultiParameter(org.spongepowered.common.command.parameter.multi.SpongeMultiParameter) SpongeFirstOfParameter(org.spongepowered.common.command.parameter.multi.SpongeFirstOfParameter) SpongeFirstOfParameter(org.spongepowered.common.command.parameter.multi.SpongeFirstOfParameter)

Aggregations

CommandNode (com.mojang.brigadier.tree.CommandNode)1 LiteralCommandNode (com.mojang.brigadier.tree.LiteralCommandNode)1 HashSet (java.util.HashSet)1 CommandSourceStack (net.minecraft.commands.CommandSourceStack)1 Parameter (org.spongepowered.api.command.parameter.Parameter)1 SpongeFlagLiteralCommandNode (org.spongepowered.common.command.brigadier.tree.SpongeFlagLiteralCommandNode)1 SpongeLiteralCommandNode (org.spongepowered.common.command.brigadier.tree.SpongeLiteralCommandNode)1 SpongeNode (org.spongepowered.common.command.brigadier.tree.SpongeNode)1 SpongeParameterValue (org.spongepowered.common.command.parameter.SpongeParameterValue)1 SpongeFirstOfParameter (org.spongepowered.common.command.parameter.multi.SpongeFirstOfParameter)1 SpongeMultiParameter (org.spongepowered.common.command.parameter.multi.SpongeMultiParameter)1