use of com.mojang.brigadier.context.CommandContext in project Bookshelf by Darkhax-Minecraft.
the class CommandHand method hand.
private int hand(CommandContext<CommandSource> context) throws CommandSyntaxException {
final OutputType type = context.getArgument("type", OutputType.class);
final ServerPlayerEntity player = context.getSource().getPlayerOrException();
final String outputText = type.converter.apply(player.getMainHandItem());
final ITextComponent component = TextComponentUtils.wrapInSquareBrackets(new StringTextComponent(outputText).withStyle((style) -> {
return style.withColor(TextFormatting.GREEN).withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, outputText)).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TranslationTextComponent("chat.copy.click"))).withInsertion(outputText);
}));
context.getSource().sendSuccess(component, false);
return 0;
}
use of com.mojang.brigadier.context.CommandContext 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 com.mojang.brigadier.context.CommandContext 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;
}
Aggregations