Search in sources :

Example 1 with Parameter

use of org.spongepowered.api.command.parameter.Parameter in project SpongeCommon by SpongePowered.

the class CommandTest method onRegisterSpongeCommand.

@Listener
public void onRegisterSpongeCommand(final RegisterCommandEvent<Command.Parameterized> event) {
    final Parameter.Value<ServerPlayer> playerKey = Parameter.player().key("player").usage(key -> "[any player]").build();
    event.register(this.plugin, Command.builder().addParameter(playerKey).executor(context -> {
        final ServerPlayer player = context.one(playerKey).orElse(context.cause().root() instanceof ServerPlayer ? ((ServerPlayer) context.cause().root()) : null);
        this.logger.info(player.name());
        return CommandResult.success();
    }).build(), "getplayer");
    final Parameter.Value<String> playerParameterKey = Parameter.string().key("name").optional().build();
    event.register(this.plugin, Command.builder().addParameter(playerParameterKey).executor(context -> {
        final Optional<String> result = context.one(playerParameterKey);
        final Collection<GameProfile> collection;
        if (result.isPresent()) {
            // check to see if the string matches
            collection = Sponge.game().server().userManager().streamOfMatches(result.get().toLowerCase(Locale.ROOT)).collect(Collectors.toList());
        } else {
            collection = Sponge.game().server().userManager().streamAll().collect(Collectors.toList());
        }
        collection.forEach(x -> this.logger.info("GameProfile - UUID: {}, Name - {}", x.uniqueId().toString(), x.name().orElse("---")));
        return CommandResult.success();
    }).build(), "checkuser");
    final Parameter.Value<String> choicesKey = Parameter.choices("bacon", "eggs", "spam", "spam spam spam").key("choices").build();
    event.register(this.plugin, Command.builder().addParameter(choicesKey).executor(context -> {
        context.sendMessage(Identity.nil(), Component.text(context.requireOne(choicesKey)));
        return CommandResult.success();
    }).build(), "testchoices");
    final Parameter.Key<String> testKey = Parameter.key("testKey", String.class);
    final Parameter.Key<Component> requiredKey = Parameter.key("requiredKey", Component.class);
    event.register(this.plugin, Command.builder().addFlag(Flag.builder().alias("f").alias("flag").build()).addFlag(Flag.builder().alias("t").alias("text").setParameter(Parameter.string().key(testKey).build()).build()).addParameter(Parameter.formattingCodeText().key(requiredKey).build()).executor(context -> {
        context.sendMessage(Identity.nil(), Component.text(context.flagInvocationCount("flag")));
        context.sendMessage(Identity.nil(), Component.text(context.flagInvocationCount("t")));
        context.all(testKey).forEach(x -> context.sendMessage(Identity.nil(), Component.text(x)));
        context.sendMessage(Identity.nil(), context.requireOne(requiredKey));
        return CommandResult.success();
    }).build(), "flagtest");
    event.register(this.plugin, Command.builder().addFlag(Flag.builder().alias("t").alias("text").setParameter(Parameter.string().key(testKey).build()).build()).addParameter(Parameter.formattingCodeText().key(requiredKey).build()).executor(context -> {
        context.sendMessage(Identity.nil(), Component.text("optional_test"));
        context.sendMessage(Identity.nil(), Component.text(context.flagInvocationCount("t")));
        context.all(testKey).forEach(x -> context.sendMessage(Identity.nil(), Component.text(x)));
        context.sendMessage(Identity.nil(), context.requireOne(requiredKey));
        return CommandResult.success();
    }).build(), "optionalflagtest");
    event.register(this.plugin, Command.builder().executor(x -> {
        x.sendMessage(Identity.nil(), Component.text().content("Click Me").clickEvent(SpongeComponents.executeCallback(ctx -> ctx.sendMessage(Identity.nil(), Component.text("Hello")))).build());
        return CommandResult.success();
    }).build(), "testCallback");
    event.register(this.plugin, Command.builder().executor(x -> {
        final Collection<Entity> collection = Selector.builder().applySelectorType(SelectorTypes.ALL_ENTITIES.get()).addEntityType(EntityTypes.PLAYER.get(), false).addGameMode(GameModes.CREATIVE.get()).limit(1).includeSelf().build().select(x.cause());
        for (final Entity entity : collection) {
            x.sendMessage(Identity.nil(), Component.text(entity.toString()));
        }
        return CommandResult.success();
    }).build(), "testselector");
    final Parameter.Key<ServerLocation> serverLocationKey = Parameter.key("serverLocation", ServerLocation.class);
    final Parameter.Value<ServerLocation> serverLocationParameter = Parameter.location().key(serverLocationKey).build();
    event.register(this.plugin, Command.builder().addParameter(serverLocationParameter).executor(x -> {
        x.sendMessage(Identity.nil(), Component.text(x.requireOne(serverLocationKey).toString()));
        return CommandResult.success();
    }).build(), "testlocation");
    final Parameter.Key<ValueParameter<?>> commandParameterKey = Parameter.key("valueParameter", new TypeToken<ValueParameter<?>>() {
    });
    final TypeToken<ValueParameter<?>> typeToken = new TypeToken<ValueParameter<?>>() {
    };
    event.register(this.plugin, Command.builder().addParameter(serverLocationParameter).addParameter(Parameter.registryElement(typeToken, commandContext -> Sponge.game(), RegistryTypes.REGISTRY_KEYED_VALUE_PARAMETER, "sponge").key(commandParameterKey).build()).executor(x -> {
        x.sendMessage(Identity.nil(), Component.text(x.requireOne(serverLocationKey).toString()));
        x.sendMessage(Identity.nil(), Component.text(x.requireOne(commandParameterKey).toString()));
        return CommandResult.success();
    }).build(), "testcatalogcompletion");
    final Parameter.Key<TestEnum> enumParameterKey = Parameter.key("enum", TestEnum.class);
    final Parameter.Key<String> stringKey = Parameter.key("stringKey", String.class);
    event.register(this.plugin, Command.builder().addParameter(Parameter.enumValue(TestEnum.class).key(enumParameterKey).build()).addParameter(Parameter.string().key(stringKey).completer((context, currentInput) -> Arrays.asList("bacon", "eggs", "spam").stream().map(CommandCompletion::of).collect(Collectors.toList())).build()).executor(x -> {
        x.sendMessage(Identity.nil(), Component.text(x.one(enumParameterKey).orElse(TestEnum.ONE).name()));
        return CommandResult.success();
    }).build(), "testenum");
    final Parameter.Key<ResourceKey> resourceKeyKey = Parameter.key("rk", ResourceKey.class);
    event.register(this.plugin, Command.builder().addParameter(Parameter.resourceKey().key(resourceKeyKey).build()).executor(x -> {
        x.sendMessage(Identity.nil(), Component.text(x.requireOne(resourceKeyKey).formatted()));
        return CommandResult.success();
    }).build(), "testrk");
    final Parameter.Key<UUID> userKey = Parameter.key("user", UUID.class);
    event.register(this.plugin, Command.builder().addParameter(Parameter.user().key(userKey).build()).executor(context -> {
        Sponge.server().userManager().load(context.requireOne(userKey)).thenAcceptAsync(x -> context.sendMessage(Identity.nil(), Component.text(x.map(User::name).orElse("unknown"))), Sponge.server().scheduler().executor(this.plugin));
        return CommandResult.success();
    }).build(), "getuser");
    final Parameter.Key<String> stringLiteralKey = Parameter.key("literal", String.class);
    event.register(this.plugin, Command.builder().executor(context -> {
        context.sendMessage(Identity.nil(), Component.text("Collected literals: " + String.join(", ", context.all(stringLiteralKey))));
        return CommandResult.success();
    }).terminal(true).addParameter(Parameter.firstOfBuilder(Parameter.literal(String.class, "1", "1").key(stringLiteralKey).build()).or(Parameter.literal(String.class, "2", "2").key(stringLiteralKey).build()).terminal().build()).addParameter(Parameter.seqBuilder(Parameter.literal(String.class, "3", "3").key(stringLiteralKey).build()).then(Parameter.literal(String.class, "4", "4").key(stringLiteralKey).build()).terminal().build()).addParameter(Parameter.literal(String.class, "5", "5").optional().key(stringLiteralKey).build()).addParameter(Parameter.literal(String.class, "6", "6").key(stringLiteralKey).build()).build(), "testnesting");
    final Parameter.Value<SystemSubject> systemSubjectValue = Parameter.builder(SystemSubject.class).key("systemsubject").addParser(VariableValueParameters.literalBuilder(SystemSubject.class).literal(Collections.singleton("-")).returnValue(Sponge::systemSubject).build()).build();
    event.register(this.plugin, Command.builder().addParameter(Parameter.firstOf(systemSubjectValue, CommonParameters.PLAYER)).addParameter(Parameter.remainingJoinedStrings().key(stringKey).build()).executor(context -> {
        final Audience audience;
        final String name;
        if (context.hasAny(systemSubjectValue)) {
            audience = context.requireOne(systemSubjectValue);
            name = "Console";
        } else {
            final ServerPlayer player = context.requireOne(CommonParameters.PLAYER);
            name = player.name();
            audience = player;
        }
        final String message = context.requireOne(stringKey);
        context.sendMessage(Identity.nil(), Component.text("To " + name + "> " + message));
        final Object root = context.cause().root();
        final Identity identity = root instanceof ServerPlayer ? ((ServerPlayer) root).identity() : Identity.nil();
        audience.sendMessage(identity, Component.text("From " + name + "> " + message));
        return CommandResult.success();
    }).build(), "testmessage");
    event.register(this.plugin, Command.builder().addParameter(CommonParameters.BOOLEAN).executor(ctx -> {
        if (ctx.requireOne(CommonParameters.BOOLEAN)) {
            // custom error
            return CommandResult.error(Component.text("custom error"));
        }
        return CommandResult.builder().error(null).build();
    }).build(), "errormessage");
    final Command.Builder builder = Command.builder();
    final ValueCompleter stringValueCompleter = (c, s) -> s.isEmpty() ? Collections.singletonList(CommandCompletion.of("x")) : Arrays.asList(s, s + "bar", "foo_" + s).stream().map(CommandCompletion::of).collect(Collectors.toList());
    // final ValueCompleter stringValueCompleter = null;
    final Parameter.Value<String> r_opt = Parameter.remainingJoinedStrings().key("r_def").optional().build();
    final Parameter.Value<String> r_req = Parameter.remainingJoinedStrings().key("r_req").completer(stringValueCompleter).build();
    final Parameter.Value<String> opt1 = Parameter.string().optional().key("opt1").build();
    final Parameter.Value<String> opt2 = Parameter.string().optional().key("opt2").build();
    final Parameter.Value<String> topt = Parameter.string().optional().key("topt").terminal().build();
    final Parameter.Value<String> req1 = Parameter.string().key("req1").completer(stringValueCompleter).build();
    final Parameter.Value<String> req2 = Parameter.string().key("req2").build();
    final Parameter.Value<Boolean> lit1 = Parameter.literal(Boolean.class, true, "lit1").key("lit1").build();
    final Parameter.Value<Boolean> lit2 = Parameter.literal(Boolean.class, true, "lit2").key("lit2").build();
    final Parameter optSeq_lit_req1 = Parameter.seqBuilder(lit1).then(req1).optional().build();
    final Parameter optSeq_lit_req2 = Parameter.seqBuilder(lit2).then(req2).optional().build();
    final Parameter seq_req_2 = Parameter.seqBuilder(req1).then(req2).build();
    final Parameter seq_opt_2 = Parameter.seqBuilder(opt1).then(opt2).build();
    final Parameter seq_opt_2_req = Parameter.seqBuilder(opt1).then(opt2).then(req1).build();
    // <req1>
    builder.addChild(Command.builder().executor(context -> CommandTest.printParameters(context, req1)).addParameter(req1).build(), "required");
    // subcommand|<r_def>
    builder.addChild(Command.builder().executor(context -> CommandTest.printParameters(context, r_opt)).addParameter(r_opt).addChild(Command.builder().executor(c -> CommandTest.printParameters(c, r_opt)).build(), "subcommand").build(), "optional_or_subcmd");
    // https://bugs.mojang.com/browse/MC-165562 usage does not show up after a space if there are no completions
    // [def1] <r_req>
    // TODO missing executed command when only providing a single value
    builder.addChild(Command.builder().executor(context -> CommandTest.printParameters(context, opt1, r_req)).addParameters(opt1, r_req).build(), "optional_r_required");
    // [opt1] [opt2] <r_req>
    // TODO missing executed command when only providing a single value
    builder.addChild(Command.builder().executor(context -> CommandTest.printParameters(context, opt1, opt2, r_req)).addParameters(opt1, opt2, r_req).build(), "optional_optional_required");
    // [opt1] [opt2]
    // TODO some redundancy in generated nodes because opt1 node can terminate early
    builder.addChild(Command.builder().executor(context -> CommandTest.printParameters(context, opt1, opt2)).addParameters(opt1, opt2).build(), "optional_optional");
    // [opt1] [literal <req1>]
    // TODO completion does not include req1 when opt1/literal is ambigous
    builder.addChild(Command.builder().executor(c -> CommandTest.printParameters(c, opt1, lit1, req1)).addParameters(opt1, optSeq_lit_req1).build(), "optional_optsequence_literal_required");
    // [literal <req1>] [literal2 <req2>]
    // TODO sequences are not optional
    builder.addChild(Command.builder().executor(c -> CommandTest.printParameters(c, lit1, req1, lit2, req2)).addParameters(optSeq_lit_req1, optSeq_lit_req2).build(), "opt_sequence_2_literal_required");
    // <<req1> <req2>>
    builder.addChild(Command.builder().executor(c -> CommandTest.printParameters(c, req1, req2)).addParameters(seq_req_2).build(), "seq_required_required");
    // <[opt1] [opt2]>
    // TODO some redundancy in generated nodes because opt1 node can terminate early
    builder.addChild(Command.builder().executor(c -> CommandTest.printParameters(c, opt1, opt2)).addParameters(seq_opt_2).build(), "seq_optional_optional");
    // <[opt1] [opt2] <req>>
    builder.addChild(Command.builder().executor(c -> CommandTest.printParameters(c, opt1, opt2, req1)).addParameters(seq_opt_2_req).build(), "seq_optional_optional_required");
    // [opt1] <req> [opt2]
    // TODO some redundancy in generated nodes because req1 node can terminate early
    builder.addChild(Command.builder().executor(c -> CommandTest.printParameters(c, opt1, req1, opt2)).addParameters(opt1, req1, opt2).build(), "optional_required_optional");
    // [opt1] [topt] !terminal
    // or
    // [opt1] [topt] <req1>
    builder.addChild(Command.builder().executor(c -> CommandTest.printParameters(c, opt1, topt, req1)).addParameters(opt1, topt, req1).build(), "optional_toptional_optional");
    event.register(this.plugin, builder.build(), "testcommand", "testcmd");
    // Adapted from https://github.com/SpongePowered/Sponge/issues/3238#issuecomment-750456173
    final Command.Parameterized firstSub = Command.builder().addParameter(CommonParameters.BOOLEAN).executor(c -> {
        c.sendMessage(Identity.nil(), Component.text("first"));
        return CommandResult.success();
    }).build();
    final Command.Parameterized secondSub = Command.builder().addParameter(CommonParameters.BOOLEAN).executor(c -> {
        c.sendMessage(Identity.nil(), Component.text("second"));
        return CommandResult.success();
    }).build();
    final Command.Parameterized parent = Command.builder().executor(c -> {
        c.sendMessage(Identity.nil(), Component.text("parent"));
        return CommandResult.success();
    }).addParameters(CommonParameters.WORLD).addParameters(Parameter.firstOf(Parameter.subcommand(firstSub, "first"), Parameter.subcommand(secondSub, "second"))).terminal(true).build();
    event.register(this.plugin, parent, "testterminal");
    // exceptions
    event.register(this.plugin, Command.builder().shortDescription(Component.text("test throwing execptions")).addChild(Command.builder().executor(ctx -> {
        throw new CommandException(Component.text("Exit via exception"));
    }).build(), "exception").addChild(Command.builder().executor(ctx -> {
        return CommandResult.error(Component.text("Exit via failed result"));
    }).build(), "failedresult").build(), "testfailure");
    event.register(this.plugin, Command.builder().addParameter(Parameter.enumValue(TestEnum.class).modifier(new ValueParameterModifier<TestEnum>() {

        @Override
        @NotNull
        public Optional<? extends TestEnum> modifyResult(final Parameter.@NotNull Key<? super TestEnum> parameterKey, final ArgumentReader.@NotNull Immutable reader, final CommandContext.@NotNull Builder context, @Nullable final TestEnum value) throws ArgumentParseException {
            if (value == TestEnum.THREE) {
                throw reader.createException(Component.text("Can't select three!"));
            }
            return Optional.ofNullable(value);
        }

        @Override
        public List<CommandCompletion> modifyCompletion(@NotNull final CommandContext context, @NotNull final String currentInput, final List<CommandCompletion> completions) {
            return completions.stream().filter(x -> !x.completion().equalsIgnoreCase(TestEnum.THREE.name())).collect(Collectors.toList());
        }

        @Override
        @Nullable
        public Component modifyExceptionMessage(@Nullable final Component exceptionMessage) {
            if (exceptionMessage == null) {
                return null;
            }
            return exceptionMessage.replaceText(builder -> {
                builder.match(", three").replacement("").once();
            });
        }
    }).key(enumParameterKey).build()).executor(x -> {
        x.sendMessage(Identity.nil(), Component.text(x.one(enumParameterKey).orElse(TestEnum.ONE).name()));
        return CommandResult.success();
    }).build(), "testenummodified");
    final Parameter.Value<String> testString = Parameter.string().key("string").build();
    final Parameter.Value<Component> jsonTextParameter = Parameter.jsonText().key("text").build();
    event.register(this.plugin, Command.builder().addParameter(jsonTextParameter).addParameter(testString).executor(ctx -> {
        ctx.sendMessage(Identity.nil(), ctx.requireOne(jsonTextParameter));
        ctx.sendMessage(Identity.nil(), Component.text(ctx.requireOne(testString)));
        return CommandResult.success();
    }).build(), "testcomponentjson");
    final Parameter.Value<Integer> firstIntParameter = Parameter.integerNumber().key("int1").build();
    final Parameter.Value<Integer> secondIntParameter = Parameter.integerNumber().key("int2").build();
    final Parameter.Value<Operator> operatorParameter = Parameter.operator().key("operator").build();
    event.register(this.plugin, Command.builder().addParameter(firstIntParameter).addParameter(operatorParameter).addParameter(secondIntParameter).executor(ctx -> {
        final int first = ctx.requireOne(firstIntParameter);
        final int second = ctx.requireOne(secondIntParameter);
        final Operator operator = ctx.requireOne(operatorParameter);
        ctx.sendMessage(Identity.nil(), Component.text(first));
        ctx.sendMessage(Identity.nil(), RegistryTypes.OPERATOR.get().findValueKey(operator).map(key -> Component.text(key.asString())).orElse(Component.text("Not set")));
        ctx.sendMessage(Identity.nil(), Component.text(second));
        if (operator instanceof Operator.Simple) {
            ctx.sendMessage(Identity.nil(), Component.text(((Operator.Simple) operator).apply(first, second)));
        }
        return CommandResult.success();
    }).build(), "testoperator");
    final Parameter.Value<Color> colorParameter = Parameter.color().key("color").build();
    event.register(this.plugin, Command.builder().addParameter(colorParameter).executor(ctx -> {
        final Color color = ctx.requireOne(colorParameter);
        final TextColor textColor = TextColor.color(color);
        final String colorString = color.toString();
        ctx.sendMessage(Identity.nil(), Component.text().color(textColor).content(colorString).build());
        return CommandResult.success();
    }).build(), "textcolor");
    final Parameter.Value<Integer> rangedInt1 = Parameter.rangedInteger(1, Integer.MAX_VALUE).key("quantity").build();
    event.register(this.plugin, Command.builder().addParameter(Parameter.firstOf(playerKey, Parameter.user().key(userKey).build())).addParameter(choicesKey).addParameter(rangedInt1).executor(ctx -> {
        if (ctx.hasAny(playerKey)) {
            ctx.sendMessage(Identity.nil(), Component.text(ctx.requireOne(playerKey).name()));
        } else {
            ctx.sendMessage(Identity.nil(), Component.text(ctx.requireOne(userKey).toString()));
        }
        ctx.sendMessage(Identity.nil(), Component.text(ctx.requireOne(choicesKey)));
        ctx.sendMessage(Identity.nil(), Component.text(ctx.requireOne(rangedInt1)));
        return CommandResult.success();
    }).build(), "firstoftest");
}
Also used : Operator(org.spongepowered.api.command.parameter.managed.operator.Operator) Arrays(java.util.Arrays) Command(org.spongepowered.api.command.Command) Inject(com.google.inject.Inject) ValueCompleter(org.spongepowered.api.command.parameter.managed.ValueCompleter) Locale(java.util.Locale) GameProfile(org.spongepowered.api.profile.GameProfile) Selector(org.spongepowered.api.command.selector.Selector) Plugin(org.spongepowered.plugin.builtin.jvm.Plugin) CommandCompletion(org.spongepowered.api.command.CommandCompletion) User(org.spongepowered.api.entity.living.player.User) TextColor(net.kyori.adventure.text.format.TextColor) Collection(java.util.Collection) Sponge(org.spongepowered.api.Sponge) ArgumentReader(org.spongepowered.api.command.parameter.ArgumentReader) UUID(java.util.UUID) TypeToken(io.leangen.geantyref.TypeToken) Collectors(java.util.stream.Collectors) NamedTextColor(net.kyori.adventure.text.format.NamedTextColor) List(java.util.List) Logger(org.apache.logging.log4j.Logger) ArgumentParseException(org.spongepowered.api.command.exception.ArgumentParseException) Optional(java.util.Optional) NotNull(org.jetbrains.annotations.NotNull) ValueParameter(org.spongepowered.api.command.parameter.managed.ValueParameter) ServerLocation(org.spongepowered.api.world.server.ServerLocation) Flag(org.spongepowered.api.command.parameter.managed.Flag) GameModes(org.spongepowered.api.entity.living.player.gamemode.GameModes) EntityTypes(org.spongepowered.api.entity.EntityTypes) Parameter(org.spongepowered.api.command.parameter.Parameter) Component(net.kyori.adventure.text.Component) ResourceKey(org.spongepowered.api.ResourceKey) Nullable(org.checkerframework.checker.nullness.qual.Nullable) CommonParameters(org.spongepowered.api.command.parameter.CommonParameters) RegisterCommandEvent(org.spongepowered.api.event.lifecycle.RegisterCommandEvent) CommandResult(org.spongepowered.api.command.CommandResult) Identity(net.kyori.adventure.identity.Identity) Entity(org.spongepowered.api.entity.Entity) RegistryTypes(org.spongepowered.api.registry.RegistryTypes) ValueParameterModifier(org.spongepowered.api.command.parameter.managed.ValueParameterModifier) VariableValueParameters(org.spongepowered.api.command.parameter.managed.standard.VariableValueParameters) SelectorTypes(org.spongepowered.api.command.selector.SelectorTypes) PluginContainer(org.spongepowered.plugin.PluginContainer) Audience(net.kyori.adventure.audience.Audience) CommandContext(org.spongepowered.api.command.parameter.CommandContext) SystemSubject(org.spongepowered.api.SystemSubject) Color(org.spongepowered.api.util.Color) SpongeComponents(org.spongepowered.api.adventure.SpongeComponents) Listener(org.spongepowered.api.event.Listener) Collections(java.util.Collections) CommandException(org.spongepowered.api.command.exception.CommandException) ServerPlayer(org.spongepowered.api.entity.living.player.server.ServerPlayer) Entity(org.spongepowered.api.entity.Entity) CommandContext(org.spongepowered.api.command.parameter.CommandContext) ServerLocation(org.spongepowered.api.world.server.ServerLocation) CommandCompletion(org.spongepowered.api.command.CommandCompletion) List(java.util.List) TextColor(net.kyori.adventure.text.format.TextColor) NamedTextColor(net.kyori.adventure.text.format.NamedTextColor) UUID(java.util.UUID) Identity(net.kyori.adventure.identity.Identity) Optional(java.util.Optional) Audience(net.kyori.adventure.audience.Audience) TextColor(net.kyori.adventure.text.format.TextColor) NamedTextColor(net.kyori.adventure.text.format.NamedTextColor) Color(org.spongepowered.api.util.Color) ArgumentReader(org.spongepowered.api.command.parameter.ArgumentReader) ResourceKey(org.spongepowered.api.ResourceKey) GameProfile(org.spongepowered.api.profile.GameProfile) ServerPlayer(org.spongepowered.api.entity.living.player.server.ServerPlayer) Nullable(org.checkerframework.checker.nullness.qual.Nullable) Operator(org.spongepowered.api.command.parameter.managed.operator.Operator) User(org.spongepowered.api.entity.living.player.User) ArgumentParseException(org.spongepowered.api.command.exception.ArgumentParseException) NotNull(org.jetbrains.annotations.NotNull) ValueParameter(org.spongepowered.api.command.parameter.managed.ValueParameter) Component(net.kyori.adventure.text.Component) ValueCompleter(org.spongepowered.api.command.parameter.managed.ValueCompleter) SystemSubject(org.spongepowered.api.SystemSubject) CommandException(org.spongepowered.api.command.exception.CommandException) Command(org.spongepowered.api.command.Command) TypeToken(io.leangen.geantyref.TypeToken) ValueParameter(org.spongepowered.api.command.parameter.managed.ValueParameter) Parameter(org.spongepowered.api.command.parameter.Parameter) Listener(org.spongepowered.api.event.Listener)

Example 2 with Parameter

use of org.spongepowered.api.command.parameter.Parameter 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

Parameter (org.spongepowered.api.command.parameter.Parameter)2 Inject (com.google.inject.Inject)1 CommandNode (com.mojang.brigadier.tree.CommandNode)1 LiteralCommandNode (com.mojang.brigadier.tree.LiteralCommandNode)1 TypeToken (io.leangen.geantyref.TypeToken)1 Arrays (java.util.Arrays)1 Collection (java.util.Collection)1 Collections (java.util.Collections)1 HashSet (java.util.HashSet)1 List (java.util.List)1 Locale (java.util.Locale)1 Optional (java.util.Optional)1 UUID (java.util.UUID)1 Collectors (java.util.stream.Collectors)1 Audience (net.kyori.adventure.audience.Audience)1 Identity (net.kyori.adventure.identity.Identity)1 Component (net.kyori.adventure.text.Component)1 NamedTextColor (net.kyori.adventure.text.format.NamedTextColor)1 TextColor (net.kyori.adventure.text.format.TextColor)1 CommandSourceStack (net.minecraft.commands.CommandSourceStack)1