use of net.minecraft.commands.CommandSourceStack in project SpongeCommon by SpongePowered.
the class SpongeCommandDispatcher method parseNodes.
private ParseResults<CommandSourceStack> parseNodes(// Sponge: used in permission checks
final boolean isRoot, // Sponge: needed for handling what we do with defaults.
final boolean isSuggestion, final CommandNode<CommandSourceStack> node, final SpongeStringReader originalReader, final SpongeCommandContextBuilder contextSoFar) {
final CommandSourceStack source = contextSoFar.getSource();
// Sponge Start
Map<CommandNode<CommandSourceStack>, CommandSyntaxException> errors = null;
List<ParseResults<CommandSourceStack>> potentials = null;
// Sponge End
final int cursor = originalReader.getCursor();
// Sponge Start: get relevant nodes if we're completing
final Collection<? extends CommandNode<CommandSourceStack>> nodes;
if (isSuggestion && node instanceof SpongeNode) {
nodes = ((SpongeNode) node).getRelevantNodesForSuggestions(originalReader);
} else if (originalReader.canRead()) {
nodes = node.getRelevantNodes(originalReader);
} else {
// Reader cannot read anymore so ONLY nodes with parsers that do not read can be processed
nodes = node.getChildren().stream().filter(n -> n instanceof SpongeArgumentCommandNode && (((SpongeArgumentCommandNode<?>) n).getParser().doesNotRead())).collect(Collectors.toList());
}
for (final CommandNode<CommandSourceStack> child : nodes) {
final boolean doesNotRead = child instanceof SpongeArgumentCommandNode && ((SpongeArgumentCommandNode<?>) child).getParser().doesNotRead();
// if (!child.canUse(source)) {
if (!SpongeNodePermissionCache.canUse(isRoot, this, child, source)) {
// Sponge End
continue;
}
// Sponge Start
final SpongeCommandContextBuilder context = contextSoFar.copy();
final SpongeStringReader reader = new SpongeStringReader(originalReader);
// Sponge End
try {
try {
child.parse(reader, context);
} catch (final RuntimeException ex) {
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherParseException().createWithContext(reader, ex.getMessage());
}
// Sponge Start: if we didn't consume anything we don't want Brig to complain at us.
if (reader.getCursor() == cursor) {
// of suggestions.
if (isSuggestion && !reader.canRead()) {
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherExpectedArgumentSeparator().createWithContext(reader);
}
reader.unskipWhitespace();
} else if (reader.canRead()) {
// Sponge End
if (reader.peek() != CommandDispatcher.ARGUMENT_SEPARATOR_CHAR) {
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherExpectedArgumentSeparator().createWithContext(reader);
}
}
} catch (final CommandSyntaxException ex) {
if (errors == null) {
errors = new LinkedHashMap<>();
}
errors.put(child, ex);
reader.setCursor(cursor);
continue;
}
context.withCommand(child.getCommand());
// must let it do so.
if (this.shouldContinueTraversing(reader, child)) {
// if (reader.canRead(child.getRedirect() == null ? 2 : 1)) {
// Sponge End
reader.skip();
// Sponge Start: redirect is now in a local variable as we use it a fair bit
final CommandNode<CommandSourceStack> redirect = child.getRedirect();
if (redirect != null) {
// If we've redirected to the root node, we may need to head back to our command
// manager - so we should check to see if that's going to actually be the case.
final boolean redirectingToRoot = redirect == this.getRoot();
final SpongeCommandContextBuilder childContext = new SpongeCommandContextBuilder(this, source, child.getRedirect(), reader.getCursor());
// For a redirect, we want to ensure all of our currently parsed information is available.
context.applySpongeElementsTo(childContext, false);
ParseResults<CommandSourceStack> parse = null;
if (redirectingToRoot) {
// check to see if we can get an element
final ArgumentReader.Immutable snapshot = reader.immutable();
try {
final String commandToAttempt = reader.peekString();
final int offset = reader.cursor();
if (redirect.getChild(commandToAttempt) == null) {
// The redirect fails, so we intercept here, and reroute to our command
// manager with the rest of the string and the new context.
reader.parseString();
final boolean hasMore = reader.canRead();
reader.skipWhitespace();
final Optional<CommandMapping> optionalMapping = this.commandManager.commandMapping(commandToAttempt);
if (optionalMapping.isPresent()) {
final CommandMapping mapping = optionalMapping.get();
final String remaining = reader.remaining();
childContext.withCommand(commandContext -> {
final SpongeCommandContext spongeContext = (SpongeCommandContext) commandContext;
try {
return mapping.registrar().process(spongeContext.cause(), mapping, commandToAttempt, remaining).result();
} catch (final CommandException e) {
throw new SpongeCommandSyntaxException(e, spongeContext);
}
});
childContext.withNode(new DummyCommandNode(childContext.getCommand()), StringRange.between(offset, reader.totalLength()));
childContext.setNonBrigCommand(hasMore ? new String[] { commandToAttempt, remaining } : new String[] { commandToAttempt });
reader.setCursor(reader.totalLength());
parse = new ParseResults<>(childContext, reader, Collections.emptyMap());
} else {
// We'll just let this parser fail as normal.
reader.setState(snapshot);
}
}
} catch (final ArgumentParseException ignored) {
// ignore it, it'll handle it later.
reader.setState(snapshot);
}
}
if (parse == null) {
parse = this.parseNodes(redirect instanceof RootCommandNode, isSuggestion, child.getRedirect(), reader, childContext);
}
// It worked out, so let's apply it back. We clear and reapply, it's simpler than comparing and conditional adding.
childContext.applySpongeElementsTo(context, true);
// Sponge End
context.withChild(parse.getContext());
final ParseResults<CommandSourceStack> parse2 = new ParseResults<>(context, parse.getReader(), parse.getExceptions());
if (doesNotRead && potentials != null) {
// If this is a optional or default parameter we only add the redirect as a potential option
potentials.add(parse2);
continue;
}
return parse2;
} else {
final ParseResults<CommandSourceStack> parse = this.parseNodes(false, isSuggestion, child, reader, context);
if (potentials == null) {
potentials = new ArrayList<>(1);
}
potentials.add(parse);
}
} else {
if (potentials == null) {
potentials = new ArrayList<>(1);
}
potentials.add(new ParseResults<>(context, reader, Collections.emptyMap()));
}
}
if (potentials != null) {
if (potentials.size() > 1) {
potentials.sort((a, b) -> {
if (!a.getReader().canRead() && b.getReader().canRead()) {
return -1;
}
if (a.getReader().canRead() && !b.getReader().canRead()) {
return 1;
}
if (a.getExceptions().isEmpty() && !b.getExceptions().isEmpty()) {
return -1;
}
if (!a.getExceptions().isEmpty() && b.getExceptions().isEmpty()) {
return 1;
}
// If we get here both potentials parsed everything and there was no exception
// BUT if parsing stopped at a non-terminal node this will cause an error later
// see at the end of #execute() where !foundCommand
// Instead we attempt to sort commands before that happens
final Command<CommandSourceStack> aCommand = SpongeCommandDispatcher.getCommand(a.getContext());
final Command<CommandSourceStack> bCommand = SpongeCommandDispatcher.getCommand(b.getContext());
if (aCommand == null && bCommand != null) {
return 1;
} else if (aCommand != null && bCommand == null) {
return -1;
}
return 0;
});
}
return potentials.get(0);
}
return new ParseResults<>(contextSoFar, originalReader, errors == null ? Collections.emptyMap() : errors);
}
use of net.minecraft.commands.CommandSourceStack in project SpongeCommon by SpongePowered.
the class SpongeCommandDispatcher method execute.
@Override
public int execute(final ParseResults<CommandSourceStack> parse) throws CommandSyntaxException {
if (parse.getReader().canRead()) {
// TODO plugin exception handling here
if (parse.getExceptions().size() == 1) {
throw parse.getExceptions().values().iterator().next();
} else if (parse.getContext().getRange().isEmpty()) {
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand().createWithContext(parse.getReader());
} else {
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().createWithContext(parse.getReader());
// throw new SimpleCommandExceptionType(new LiteralMessage("Too many arguments")).createWithContext(parse.getReader());
}
}
int result = 0;
int successfulForks = 0;
boolean forked = false;
boolean foundCommand = false;
final String command = parse.getReader().getString();
final CommandContext<CommandSourceStack> original = parse.getContext().build(command);
List<CommandContext<CommandSourceStack>> contexts = Collections.singletonList(original);
ArrayList<CommandContext<CommandSourceStack>> next = null;
while (contexts != null) {
final int size = contexts.size();
for (int i = 0; i < size; i++) {
final CommandContext<CommandSourceStack> context = contexts.get(i);
final CommandContext<CommandSourceStack> child = context.getChild();
if (child != null) {
forked |= context.isForked();
if (child.hasNodes()) {
// Sponge Start
//
// Basically, no we haven't Mojang. Getting here is no guarantee that a
// command executes. I imagine what's happened is that this was originally
// recursive and called itself, by doing so, setting this true made sense
// while the child method handled whether something worked out or not, but
// design reasons would mean that wouldn't work.
//
// It's not obvious what this is really meant to achieve, because by setting
// this true here, context.onCommandComplete(...) may never be called.
//
// We want a command to run, that's only in the else if down below.
//
// foundCommand = true
// Sponge End
final RedirectModifier<CommandSourceStack> modifier = context.getRedirectModifier();
if (modifier == null) {
if (next == null) {
next = new ArrayList<>(1);
}
next.add(child.copyFor(context.getSource()));
} else {
try {
final Collection<CommandSourceStack> results = modifier.apply(context);
if (!results.isEmpty()) {
if (next == null) {
next = new ArrayList<>(results.size());
}
for (final CommandSourceStack source : results) {
next.add(child.copyFor(source));
}
}
} catch (final CommandSyntaxException ex) {
// Sponge Start: They probably meant to do this here - the consumer is notified at this point.
foundCommand = true;
// Soonge End
this.resultConsumer.onCommandComplete(context, false, 0);
if (!forked) {
throw ex;
}
}
}
}
} else if (context.getCommand() != null) {
foundCommand = true;
try {
final int value = context.getCommand().run(context);
result += value;
this.resultConsumer.onCommandComplete(context, true, value);
successfulForks++;
} catch (final CommandSyntaxException ex) {
this.resultConsumer.onCommandComplete(context, false, 0);
if (!forked) {
throw ex;
}
}
}
}
contexts = next;
next = null;
}
if (!foundCommand) {
this.resultConsumer.onCommandComplete(original, false, 0);
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand().createWithContext(parse.getReader());
}
return forked ? successfulForks : result;
}
use of net.minecraft.commands.CommandSourceStack in project SpongeCommon by SpongePowered.
the class SpongeArgumentCommandNode method parse.
@Override
public final void parse(final StringReader reader, final CommandContextBuilder<CommandSourceStack> contextBuilder) throws CommandSyntaxException {
final int start = reader.getCursor();
final SpongeCommandContextBuilder builder = (SpongeCommandContextBuilder) contextBuilder;
final T result = this.parser.parse(this.key, builder, (SpongeStringReader) reader, this.modifier);
if (result != null) {
builder.putEntry(this.key, result);
final ParsedArgument<CommandSourceStack, T> parsed = new ParsedArgument<>(start, reader.getCursor(), result);
builder.withArgumentInternal(this.getName(), parsed, false);
builder.withNode(this, parsed.getRange());
} else if (this.parser.doesNotRead()) {
// Assume this is a null "optional" parser and add the node as read so that we dont end up with an empty context
builder.withNode(this, StringRange.at(start));
}
}
use of net.minecraft.commands.CommandSourceStack 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;
}
use of net.minecraft.commands.CommandSourceStack in project SpongeCommon by SpongePowered.
the class SpongeParameterTranslator method createCommandTree.
@SuppressWarnings({ "unchecked", "rawtypes" })
public Collection<LiteralCommandNode<CommandSourceStack>> createCommandTree(final Command.Parameterized command, final Collection<String> aliases) {
if (aliases.isEmpty()) {
throw new IllegalArgumentException("Aliases must not be empty.");
}
// create the first literal.
final Collection<String> sortedAliases = aliases.stream().sorted().collect(Collectors.toList());
final Iterator<String> aliasIterator = sortedAliases.iterator();
final String baseAlias = aliasIterator.next();
final SpongeCommandExecutorWrapper executor = command.executor().map(SpongeCommandExecutorWrapper::new).orElse(null);
// Create the defining characteristics of the node.
final LiteralArgumentBuilder<CommandSourceStack> basicNode = LiteralArgumentBuilder.literal(baseAlias);
basicNode.requires((Predicate) command.executionRequirements());
if (command.isTerminal() && executor != null) {
basicNode.executes(executor);
}
final SpongeLiteralCommandNode commandNode = new SpongeLiteralCommandNode(basicNode);
if (executor != null) {
this.createAndAttachNode(Collections.singleton(commandNode), command.parameters(), executor, true, true);
}
for (final Parameter.Subcommand subcommand : command.subcommands()) {
final Collection<LiteralCommandNode<CommandSourceStack>> builtSubcommand = this.createCommandTree(subcommand.command(), subcommand.aliases());
builtSubcommand.forEach(commandNode::addChild);
}
this.createFlags(commandNode, command.flags(), executor);
final List<LiteralCommandNode<CommandSourceStack>> allCommandNodes = new ArrayList<>();
allCommandNodes.add(commandNode);
final Collection<CommandNode<CommandSourceStack>> children = commandNode.getChildren();
while (aliasIterator.hasNext()) {
final LiteralArgumentBuilder<CommandSourceStack> redirectedNode = LiteralArgumentBuilder.literal(aliasIterator.next());
redirectedNode.executes(commandNode.getCommand());
redirectedNode.requires(commandNode.getRequirement());
// merged, the above can be substituted in here.
for (final CommandNode<CommandSourceStack> child : children) {
redirectedNode.then(child);
}
allCommandNodes.add(new SpongeLiteralCommandNode(redirectedNode));
}
return Collections.unmodifiableCollection(allCommandNodes);
}
Aggregations