All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cloud.commandframework.Command Maven / Gradle / Ivy

There is a newer version: 1.8.4
Show newest version
//
// MIT License
//
// Copyright (c) 2022 Alexander Söderberg & Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package cloud.commandframework;

import cloud.commandframework.arguments.CommandArgument;
import cloud.commandframework.arguments.StaticArgument;
import cloud.commandframework.arguments.compound.ArgumentPair;
import cloud.commandframework.arguments.compound.ArgumentTriplet;
import cloud.commandframework.arguments.compound.FlagArgument;
import cloud.commandframework.arguments.flags.CommandFlag;
import cloud.commandframework.execution.CommandExecutionHandler;
import cloud.commandframework.meta.CommandMeta;
import cloud.commandframework.meta.SimpleCommandMeta;
import cloud.commandframework.permission.CommandPermission;
import cloud.commandframework.permission.Permission;
import cloud.commandframework.permission.PredicatePermission;
import cloud.commandframework.types.tuples.Pair;
import cloud.commandframework.types.tuples.Triplet;
import io.leangen.geantyref.TypeToken;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.apiguardian.api.API;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * A command consists out of a chain of {@link CommandArgument command arguments}.
 *
 * @param  Command sender type
 */
@API(status = API.Status.STABLE)
public class Command {

    private final List<@NonNull CommandComponent> components;
    private final List<@NonNull CommandArgument> arguments;
    private final @Nullable FlagArgument flagArgument;
    private final CommandExecutionHandler commandExecutionHandler;
    private final Class senderType;
    private final CommandPermission commandPermission;
    private final CommandMeta commandMeta;

    /**
     * Construct a new command
     *
     * @param commandComponents       Command component argument and description
     * @param commandExecutionHandler Execution handler
     * @param senderType              Required sender type. May be {@code null}
     * @param commandPermission       Command permission
     * @param commandMeta             Command meta instance
     * @since 1.3.0
     */
    @API(status = API.Status.STABLE, since = "1.3.0")
    @SuppressWarnings("unchecked")
    public Command(
            final @NonNull List<@NonNull CommandComponent> commandComponents,
            final @NonNull CommandExecutionHandler<@NonNull C> commandExecutionHandler,
            final @Nullable Class senderType,
            final @NonNull CommandPermission commandPermission,
            final @NonNull CommandMeta commandMeta
    ) {
        this.components = Objects.requireNonNull(commandComponents, "Command components may not be null");
        this.arguments = this.components.stream().map(CommandComponent::getArgument).collect(Collectors.toList());
        if (this.components.isEmpty()) {
            throw new IllegalArgumentException("At least one command component is required");
        }

        this.flagArgument =
                this.arguments.stream()
                        .filter(ca -> ca instanceof FlagArgument)
                        .map(ca -> (FlagArgument) ca)
                        .findFirst()
                        .orElse(null);

        // Enforce ordering of command arguments
        boolean foundOptional = false;
        for (final CommandArgument argument : this.arguments) {
            if (argument.getName().isEmpty()) {
                throw new IllegalArgumentException("Argument names may not be empty");
            }
            if (foundOptional && argument.isRequired()) {
                throw new IllegalArgumentException(
                        String.format(
                                "Command argument '%s' cannot be placed after an optional argument",
                                argument.getName()
                        ));
            } else if (!argument.isRequired()) {
                foundOptional = true;
            }
        }
        this.commandExecutionHandler = commandExecutionHandler;
        this.senderType = senderType;
        this.commandPermission = commandPermission;
        this.commandMeta = commandMeta;
    }

    /**
     * Construct a new command
     *
     * @param commandComponents       Command components
     * @param commandExecutionHandler Execution handler
     * @param senderType              Required sender type. May be {@code null}
     * @param commandMeta             Command meta instance
     * @since 1.3.0
     */
    @API(status = API.Status.STABLE, since = "1.3.0")
    public Command(
            final @NonNull List<@NonNull CommandComponent> commandComponents,
            final @NonNull CommandExecutionHandler<@NonNull C> commandExecutionHandler,
            final @Nullable Class senderType,
            final @NonNull CommandMeta commandMeta
    ) {
        this(commandComponents, commandExecutionHandler, senderType, Permission.empty(), commandMeta);
    }

    /**
     * Construct a new command
     *
     * @param commandComponents       Command components
     * @param commandExecutionHandler Execution handler
     * @param commandPermission       Command permission
     * @param commandMeta             Command meta instance
     * @since 1.3.0
     */
    @API(status = API.Status.STABLE, since = "1.3.0")
    public Command(
            final @NonNull List<@NonNull CommandComponent> commandComponents,
            final @NonNull CommandExecutionHandler<@NonNull C> commandExecutionHandler,
            final @NonNull CommandPermission commandPermission,
            final @NonNull CommandMeta commandMeta
    ) {
        this(commandComponents, commandExecutionHandler, null, commandPermission, commandMeta);
    }

    /**
     * Construct a new command
     *
     * @param commandArguments        Command argument and description pairs
     * @param commandExecutionHandler Execution handler
     * @param senderType              Required sender type. May be {@code null}
     * @param commandPermission       Command permission
     * @param commandMeta             Command meta instance
     * @see #Command(List, CommandExecutionHandler, Class, CommandPermission, CommandMeta)
     * @deprecated Map does not allow for the same literal or variable argument name to repeat
     */
    @Deprecated
    @API(status = API.Status.DEPRECATED)
    public Command(
            final @NonNull Map<@NonNull CommandArgument, @NonNull Description> commandArguments,
            final @NonNull CommandExecutionHandler<@NonNull C> commandExecutionHandler,
            final @Nullable Class senderType,
            final @NonNull CommandPermission commandPermission,
            final @NonNull CommandMeta commandMeta
    ) {
        this(mapToComponents(commandArguments), commandExecutionHandler, senderType, commandPermission, commandMeta);
    }

    /**
     * Construct a new command
     *
     * @param commandArguments        Command arguments
     * @param commandExecutionHandler Execution handler
     * @param senderType              Required sender type. May be {@code null}
     * @param commandMeta             Command meta instance
     * @see #Command(List, CommandExecutionHandler, Class, CommandMeta)
     * @deprecated Map does not allow for the same literal or variable argument name to repeat
     */
    @Deprecated
    @API(status = API.Status.DEPRECATED)
    public Command(
            final @NonNull Map<@NonNull CommandArgument, @NonNull Description> commandArguments,
            final @NonNull CommandExecutionHandler<@NonNull C> commandExecutionHandler,
            final @Nullable Class senderType,
            final @NonNull CommandMeta commandMeta
    ) {
        this(mapToComponents(commandArguments), commandExecutionHandler, senderType, commandMeta);
    }

    /**
     * Construct a new command
     *
     * @param commandArguments        Command arguments
     * @param commandExecutionHandler Execution handler
     * @param commandPermission       Command permission
     * @param commandMeta             Command meta instance
     * @see #Command(List, CommandExecutionHandler, CommandPermission, CommandMeta)
     * @deprecated Map does not allow for the same literal or variable argument name to repeat
     */
    @Deprecated
    @API(status = API.Status.DEPRECATED)
    public Command(
            final @NonNull Map<@NonNull CommandArgument, @NonNull Description> commandArguments,
            final @NonNull CommandExecutionHandler<@NonNull C> commandExecutionHandler,
            final @NonNull CommandPermission commandPermission,
            final @NonNull CommandMeta commandMeta
    ) {
        this(mapToComponents(commandArguments), commandExecutionHandler, commandPermission, commandMeta);
    }

    // Converts a map of CommandArgument and Description pairs to a List of CommandComponent
    // Used for backwards-compatibility
    @SuppressWarnings("deprecation")
    private static  @NonNull List<@NonNull CommandComponent> mapToComponents(
            final @NonNull Map<@NonNull CommandArgument, @NonNull Description> commandArguments
    ) {
        return commandArguments.entrySet().stream()
                .map(e -> CommandComponent.of(e.getKey(), e.getValue()))
                .collect(Collectors.toList());
    }

    /**
     * Create a new command builder. Is recommended to use the builder methods
     * in {@link CommandManager} rather than invoking this method directly.
     *
     * @param commandName Base command argument
     * @param commandMeta Command meta instance
     * @param description Command description
     * @param aliases     Command aliases
     * @param          Command sender type
     * @return Command builder
     * @deprecated for removal since 1.4.0. Use {@link #newBuilder(String, CommandMeta, ArgumentDescription, String...)} instead.
     */
    @Deprecated
    @API(status = API.Status.DEPRECATED, since = "1.4.0")
    public static  @NonNull Builder newBuilder(
            final @NonNull String commandName,
            final @NonNull CommandMeta commandMeta,
            final @NonNull Description description,
            final @NonNull String... aliases
    ) {
        return newBuilder(commandName, commandMeta, (ArgumentDescription) description, aliases);
    }

    /**
     * Create a new command builder. Is recommended to use the builder methods
     * in {@link CommandManager} rather than invoking this method directly.
     *
     * @param commandName Base command argument
     * @param commandMeta Command meta instance
     * @param description Command description
     * @param aliases     Command aliases
     * @param          Command sender type
     * @return Command builder
     * @since 1.4.0
     */
    @API(status = API.Status.STABLE, since = "1.4.0")
    public static  @NonNull Builder newBuilder(
            final @NonNull String commandName,
            final @NonNull CommandMeta commandMeta,
            final @NonNull ArgumentDescription description,
            final @NonNull String... aliases
    ) {
        final List> commands = new ArrayList<>();
        commands.add(CommandComponent.of(StaticArgument.of(commandName, aliases), description));
        return new Builder<>(
                null,
                commandMeta,
                null,
                commands,
                new CommandExecutionHandler.NullCommandExecutionHandler<>(),
                Permission.empty(),
                Collections.emptyList()
        );
    }

    /**
     * Create a new command builder. Is recommended to use the builder methods
     * in {@link CommandManager} rather than invoking this method directly.
     *
     * @param commandName Base command argument
     * @param commandMeta Command meta instance
     * @param aliases     Command aliases
     * @param          Command sender type
     * @return Command builder
     */
    public static  @NonNull Builder newBuilder(
            final @NonNull String commandName,
            final @NonNull CommandMeta commandMeta,
            final @NonNull String... aliases
    ) {
        final List> commands = new ArrayList<>();
        commands.add(CommandComponent.of(StaticArgument.of(commandName, aliases), ArgumentDescription.empty()));
        return new Builder<>(
                null,
                commandMeta,
                null,
                commands,
                new CommandExecutionHandler.NullCommandExecutionHandler<>(),
                Permission.empty(),
                Collections.emptyList()
        );
    }

    /**
     * Return a copy of the command argument array
     *
     * @return Copy of the command argument array.  This List is mutable.
     */
    public @NonNull List> getArguments() {
        return new ArrayList<>(this.arguments);
    }

    /**
     * Return a mutable copy of the command arguments, ignoring flag arguments.
     *
     * @return argument list
     * @since 1.8.0
     */
    @API(status = API.Status.EXPERIMENTAL, since = "1.8.0")
    public @NonNull List> nonFlagArguments() {
        List> arguments = new ArrayList<>(this.arguments);
        if (this.flagArgument != null) {
            arguments.remove(this.flagArgument);
        }
        return arguments;
    }

    /**
     * Returns the flag argument for this command, or null if no flags are supported.
     *
     * @return flag argument or null
     * @since 1.8.0
     */
    @API(status = API.Status.EXPERIMENTAL, since = "1.8.0")
    public @Nullable FlagArgument<@NonNull C> flagArgument() {
        return this.flagArgument;
    }

    /**
     * Returns a copy of the command component array
     *
     * @return Copy of the command component array. This List is mutable
     * @since 1.3.0
     */
    @API(status = API.Status.STABLE, since = "1.3.0")
    public @NonNull List> getComponents() {
        return new ArrayList<>(this.components);
    }

    /**
     * Get the command execution handler
     *
     * @return Command execution handler
     */
    public CommandExecutionHandler<@NonNull C> getCommandExecutionHandler() {
        return this.commandExecutionHandler;
    }

    /**
     * Get the required sender type, if one has been specified
     *
     * @return Required sender type
     */
    public @NonNull Optional> getSenderType() {
        return Optional.ofNullable(this.senderType);
    }

    /**
     * Get the command permission
     *
     * @return Command permission
     */
    public @NonNull CommandPermission getCommandPermission() {
        return this.commandPermission;
    }

    /**
     * Get the command meta instance
     *
     * @return Command meta
     */
    public @NonNull CommandMeta getCommandMeta() {
        return this.commandMeta;
    }

    /**
     * Get the description for an argument
     *
     * @param argument Argument
     * @return Argument description
     * @throws IllegalArgumentException If the command argument does not exist
     * @deprecated More than one matching command argument may exist per command.
     *         Use {@link #getArguments()} and search in that, instead.
     */
    @Deprecated
    @API(status = API.Status.DEPRECATED)
    public @NonNull String getArgumentDescription(final @NonNull CommandArgument argument) {
        for (final CommandComponent component : this.components) {
            if (component.getArgument().equals(argument)) {
                return component.getArgumentDescription().getDescription();
            }
        }
        throw new IllegalArgumentException("Command argument not found: " + argument);
    }

    @Override
    public final String toString() {
        final StringBuilder stringBuilder = new StringBuilder();
        for (final CommandArgument argument : this.getArguments()) {
            stringBuilder.append(argument.getName()).append(' ');
        }
        final String build = stringBuilder.toString();
        return build.substring(0, build.length() - 1);
    }

    /**
     * Check whether the command is hidden
     *
     * @return {@code true} if the command is hidden, {@code false} if not
     */
    public boolean isHidden() {
        return this.getCommandMeta().getOrDefault(CommandMeta.HIDDEN, false);
    }


    /**
     * Builder for {@link Command} instances. The builder is immutable, and each
     * setter method will return a new builder instance.
     *
     * @param  Command sender type
     */
    @API(status = API.Status.STABLE)
    public static final class Builder {

        private final CommandMeta commandMeta;
        private final List> commandComponents;
        private final CommandExecutionHandler commandExecutionHandler;
        private final Class senderType;
        private final CommandPermission commandPermission;
        private final CommandManager commandManager;
        private final Collection> flags;

        private Builder(
                final @Nullable CommandManager commandManager,
                final @NonNull CommandMeta commandMeta,
                final @Nullable Class senderType,
                final @NonNull List<@NonNull CommandComponent> commandComponents,
                final @NonNull CommandExecutionHandler<@NonNull C> commandExecutionHandler,
                final @NonNull CommandPermission commandPermission,
                final @NonNull Collection> flags
        ) {
            this.commandManager = commandManager;
            this.senderType = senderType;
            this.commandComponents = Objects.requireNonNull(commandComponents, "Components may not be null");
            this.commandExecutionHandler = Objects.requireNonNull(commandExecutionHandler, "Execution handler may not be null");
            this.commandPermission = Objects.requireNonNull(commandPermission, "Permission may not be null");
            this.commandMeta = Objects.requireNonNull(commandMeta, "Meta may not be null");
            this.flags = Objects.requireNonNull(flags, "Flags may not be null");
        }

        /**
         * Get the required sender type for this builder
         * 

* Returns {@code null} when there is not a specific required sender type * * @return required sender type * @since 1.3.0 */ @API(status = API.Status.STABLE, since = "1.3.0") public @Nullable Class senderType() { return this.senderType; } /** * Get the required command permission for this builder *

* Will return {@link Permission#empty()} if there is no required permission * * @return required permission * @since 1.3.0 */ @API(status = API.Status.STABLE, since = "1.3.0") public @NonNull CommandPermission commandPermission() { return this.commandPermission; } /** * Applies the provided {@link Applicable} to this {@link Builder}, and returns the result. * * @param applicable operation * @return operation result * @since 1.8.0 */ @API(status = API.Status.STABLE, since = "1.8.0") public @NonNull Builder<@NonNull C> apply( final @NonNull Applicable<@NonNull C> applicable ) { return applicable.applyToCommandBuilder(this); } /** * Add command meta to the internal command meta map * * @param key Meta key * @param value Meta value * @return New builder instance using the inserted meta key-value pair * @deprecated for removal since 1.2.0, use the typesafe variant at {@link #meta(CommandMeta.Key, Object)} instead. */ @Deprecated @API(status = API.Status.DEPRECATED, since = "1.2.0") public @NonNull Builder meta(final @NonNull String key, final @NonNull String value) { final CommandMeta commandMeta = SimpleCommandMeta.builder().with(this.commandMeta).with(key, value).build(); return new Builder<>( this.commandManager, commandMeta, this.senderType, this.commandComponents, this.commandExecutionHandler, this.commandPermission, this.flags ); } /** * Add command meta to the internal command meta map * * @param Meta value type * @param key Meta key * @param value Meta value * @return New builder instance using the inserted meta key-value pair * @since 1.3.0 */ @API(status = API.Status.STABLE, since = "1.3.0") public @NonNull Builder meta(final CommandMeta.@NonNull Key key, final @NonNull V value) { final CommandMeta commandMeta = SimpleCommandMeta.builder().with(this.commandMeta).with(key, value).build(); return new Builder<>( this.commandManager, commandMeta, this.senderType, this.commandComponents, this.commandExecutionHandler, this.commandPermission, this.flags ); } /** * Supply a command manager instance to the builder. This will be used when attempting to * retrieve command argument parsers, in the case that they're needed. This * is optional * * @param commandManager Command manager * @return New builder instance using the provided command manager */ public @NonNull Builder manager(final @Nullable CommandManager commandManager) { return new Builder<>( commandManager, this.commandMeta, this.senderType, this.commandComponents, this.commandExecutionHandler, this.commandPermission, this.flags ); } /** * Inserts a required {@link StaticArgument} into the command chain * * @param main Main argument name * @param aliases Argument aliases * @return New builder instance with the modified command chain */ public @NonNull Builder literal( final @NonNull String main, final @NonNull String... aliases ) { return this.argument(StaticArgument.of(main, aliases)); } /** * Inserts a required {@link StaticArgument} into the command chain * * @param main Main argument name * @param description Literal description * @param aliases Argument aliases * @return New builder instance with the modified command chain * @deprecated for removal since 1.4.0. Use {@link #literal(String, ArgumentDescription, String...)} instead. */ @Deprecated @API(status = API.Status.DEPRECATED, since = "1.4.0") public @NonNull Builder literal( final @NonNull String main, final @NonNull Description description, final @NonNull String... aliases ) { return this.argument(StaticArgument.of(main, aliases), description); } /** * Inserts a required {@link StaticArgument} into the command chain * * @param main Main argument name * @param description Literal description * @param aliases Argument aliases * @return New builder instance with the modified command chain * @since 1.4.0 */ @API(status = API.Status.STABLE, since = "1.4.0") public @NonNull Builder literal( final @NonNull String main, final @NonNull ArgumentDescription description, final @NonNull String... aliases ) { return this.argument(StaticArgument.of(main, aliases), description); } /** * Add a new command argument with an empty description to the command * * @param builder Argument to add. {@link CommandArgument.Builder#build()} will be invoked * and the result will be registered in the command. * @param Argument type * @return New builder instance with the command argument inserted into the argument list */ public @NonNull Builder argument(final CommandArgument.@NonNull Builder builder) { return this.argument(builder.build()); } /** * Add a new command argument with an empty description to the command * * @param argument Argument to add * @param Argument type * @return New builder instance with the command argument inserted into the argument list */ public @NonNull Builder argument(final @NonNull CommandArgument argument) { return this.argument(argument, argument.getDefaultDescription()); } /** * Add a new command argument to the command * * @param argument Argument to add * @param description Argument description * @param Argument type * @return New builder instance with the command argument inserted into the argument list * @deprecated for removal since 1.4.0. Use {@link #argument(CommandArgument, ArgumentDescription)} instead. */ @Deprecated @API(status = API.Status.DEPRECATED, since = "1.4.0") public @NonNull Builder argument( final @NonNull CommandArgument argument, final @NonNull Description description ) { return this.argument(argument, (ArgumentDescription) description); } /** * Add a new command argument to the command * * @param argument Argument to add * @param description Argument description * @param Argument type * @return New builder instance with the command argument inserted into the argument list * @since 1.4.0 */ @API(status = API.Status.STABLE, since = "1.4.0") public @NonNull Builder argument( final @NonNull CommandArgument argument, final @NonNull ArgumentDescription description ) { if (argument.isArgumentRegistered()) { throw new IllegalArgumentException("The provided argument has already been associated with a command." + " Use CommandArgument#copy to create a copy of the argument."); } argument.setArgumentRegistered(); final List> commandComponents = new ArrayList<>(this.commandComponents); commandComponents.add(CommandComponent.of(argument, description)); return new Builder<>( this.commandManager, this.commandMeta, this.senderType, commandComponents, this.commandExecutionHandler, this.commandPermission, this.flags ); } /** * Add a new command argument to the command * * @param builder Argument to add. {@link CommandArgument.Builder#build()} will be invoked * and the result will be registered in the command. * @param description Argument description * @param Argument type * @return New builder instance with the command argument inserted into the argument list * @deprecated for removal since 1.4.0. Use {@link #argument(CommandArgument.Builder, ArgumentDescription)} instead. */ @Deprecated @API(status = API.Status.DEPRECATED, since = "1.4.0") public @NonNull Builder argument( final CommandArgument.@NonNull Builder builder, final @NonNull Description description ) { return this.argument(builder, (ArgumentDescription) description); } /** * Add a new command argument to the command * * @param builder Argument to add. {@link CommandArgument.Builder#build()} will be invoked * and the result will be registered in the command. * @param description Argument description * @param Argument type * @return New builder instance with the command argument inserted into the argument list * @since 1.4.0 */ @API(status = API.Status.STABLE, since = "1.4.0") public @NonNull Builder argument( final CommandArgument.@NonNull Builder builder, final @NonNull ArgumentDescription description ) { final List> commandComponents = new ArrayList<>(this.commandComponents); commandComponents.add(CommandComponent.of(builder.build(), description)); return new Builder<>( this.commandManager, this.commandMeta, this.senderType, commandComponents, this.commandExecutionHandler, this.commandPermission, this.flags ); } /** * Add a new command argument by interacting with a constructed command argument builder * * @param clazz Argument class * @param name Argument name * @param builderConsumer Builder consumer * @param Argument type * @return New builder instance with the command argument inserted into the argument list */ public @NonNull Builder argument( final @NonNull Class clazz, final @NonNull String name, final @NonNull Consumer> builderConsumer ) { final CommandArgument.Builder builder = CommandArgument.ofType(clazz, name); if (this.commandManager != null) { builder.manager(this.commandManager); } builderConsumer.accept(builder); return this.argument(builder.build()); } // Compound helper methods /** * Create a new argument pair that maps to {@link Pair} *

* For this to work, there must be a {@link CommandManager} * attached to the command builder. To guarantee this, it is recommended to get the command builder instance * using {@link CommandManager#commandBuilder(String, String...)} * * @param name Name of the argument * @param names Pair containing the names of the sub-arguments * @param parserPair Pair containing the types of the sub-arguments. There must be parsers for these types registered * in the {@link cloud.commandframework.arguments.parser.ParserRegistry} used by the * {@link CommandManager} attached to this command * @param description Description of the argument * @param First type * @param Second type * @return Builder instance with the argument inserted * @deprecated for removal since 1.4.0. Use {@link #argumentPair(String, Pair, Pair, ArgumentDescription)} instead. */ @Deprecated @API(status = API.Status.DEPRECATED, since = "1.4.0") public @NonNull Builder argumentPair( final @NonNull String name, final @NonNull Pair<@NonNull String, @NonNull String> names, final @NonNull Pair<@NonNull Class, @NonNull Class> parserPair, final @NonNull Description description ) { return this.argumentPair(name, names, parserPair, (ArgumentDescription) description); } /** * Create a new argument pair that maps to {@link Pair} *

* For this to work, there must be a {@link CommandManager} * attached to the command builder. To guarantee this, it is recommended to get the command builder instance * using {@link CommandManager#commandBuilder(String, String...)} * * @param name Name of the argument * @param names Pair containing the names of the sub-arguments * @param parserPair Pair containing the types of the sub-arguments. There must be parsers for these types registered * in the {@link cloud.commandframework.arguments.parser.ParserRegistry} used by the * {@link CommandManager} attached to this command * @param description Description of the argument * @param First type * @param Second type * @return Builder instance with the argument inserted * @since 1.4.0 */ @API(status = API.Status.STABLE, since = "1.4.0") public @NonNull Builder argumentPair( final @NonNull String name, final @NonNull Pair<@NonNull String, @NonNull String> names, final @NonNull Pair<@NonNull Class, @NonNull Class> parserPair, final @NonNull ArgumentDescription description ) { if (this.commandManager == null) { throw new IllegalStateException("This cannot be called from a command that has no command manager attached"); } return this.argument(ArgumentPair.of(this.commandManager, name, names, parserPair).simple(), description); } /** * Create a new argument pair that maps to a custom type. *

* For this to work, there must be a {@link CommandManager} * attached to the command builder. To guarantee this, it is recommended to get the command builder instance * using {@link CommandManager#commandBuilder(String, String...)} * * @param name Name of the argument * @param outputType The output type * @param names Pair containing the names of the sub-arguments * @param parserPair Pair containing the types of the sub-arguments. There must be parsers for these types registered * in the {@link cloud.commandframework.arguments.parser.ParserRegistry} used by the * {@link CommandManager} attached to this command * @param mapper Mapper that maps from {@link Pair} to the custom type * @param description Description of the argument * @param First type * @param Second type * @param Output type * @return Builder instance with the argument inserted * @deprecated for removal since 1.4.0. Use * {@link #argumentPair(String, TypeToken, Pair, Pair, BiFunction, ArgumentDescription)} instead. */ @Deprecated @API(status = API.Status.DEPRECATED, since = "1.4.0") public @NonNull Builder argumentPair( final @NonNull String name, final @NonNull TypeToken outputType, final @NonNull Pair names, final @NonNull Pair, Class> parserPair, final @NonNull BiFunction, O> mapper, final @NonNull Description description ) { return this.argumentPair(name, outputType, names, parserPair, mapper, (ArgumentDescription) description); } /** * Create a new argument pair that maps to a custom type. *

* For this to work, there must be a {@link CommandManager} * attached to the command builder. To guarantee this, it is recommended to get the command builder instance * using {@link CommandManager#commandBuilder(String, String...)} * * @param name Name of the argument * @param outputType The output type * @param names Pair containing the names of the sub-arguments * @param parserPair Pair containing the types of the sub-arguments. There must be parsers for these types registered * in the {@link cloud.commandframework.arguments.parser.ParserRegistry} used by the * {@link CommandManager} attached to this command * @param mapper Mapper that maps from {@link Pair} to the custom type * @param description Description of the argument * @param First type * @param Second type * @param Output type * @return Builder instance with the argument inserted * @since 1.4.0 */ @API(status = API.Status.STABLE, since = "1.4.0") public @NonNull Builder argumentPair( final @NonNull String name, final @NonNull TypeToken outputType, final @NonNull Pair names, final @NonNull Pair, Class> parserPair, final @NonNull BiFunction, O> mapper, final @NonNull ArgumentDescription description ) { if (this.commandManager == null) { throw new IllegalStateException("This cannot be called from a command that has no command manager attached"); } return this.argument( ArgumentPair.of(this.commandManager, name, names, parserPair).withMapper(outputType, mapper), description ); } /** * Create a new argument pair that maps to {@link cloud.commandframework.types.tuples.Triplet} *

* For this to work, there must be a {@link CommandManager} * attached to the command builder. To guarantee this, it is recommended to get the command builder instance * using {@link CommandManager#commandBuilder(String, String...)} * * @param name Name of the argument * @param names Triplet containing the names of the sub-arguments * @param parserTriplet Triplet containing the types of the sub-arguments. There must be parsers for these types * registered in the {@link cloud.commandframework.arguments.parser.ParserRegistry} * used by the {@link CommandManager} attached to this command * @param description Description of the argument * @param First type * @param Second type * @param Third type * @return Builder instance with the argument inserted * @deprecated for removal since 1.4.0. Use {@link #argumentTriplet(String, Triplet, Triplet, ArgumentDescription)} * instead. */ @Deprecated @API(status = API.Status.DEPRECATED, since = "1.4.0") public @NonNull Builder argumentTriplet( final @NonNull String name, final @NonNull Triplet names, final @NonNull Triplet, Class, Class> parserTriplet, final @NonNull Description description ) { return this.argumentTriplet(name, names, parserTriplet, (ArgumentDescription) description); } /** * Create a new argument pair that maps to {@link cloud.commandframework.types.tuples.Triplet} *

* For this to work, there must be a {@link CommandManager} * attached to the command builder. To guarantee this, it is recommended to get the command builder instance * using {@link CommandManager#commandBuilder(String, String...)} * * @param name Name of the argument * @param names Triplet containing the names of the sub-arguments * @param parserTriplet Triplet containing the types of the sub-arguments. There must be parsers for these types * registered in the {@link cloud.commandframework.arguments.parser.ParserRegistry} * used by the {@link CommandManager} attached to this command * @param description Description of the argument * @param First type * @param Second type * @param Third type * @return Builder instance with the argument inserted * @since 1.4.0 */ @API(status = API.Status.STABLE, since = "1.4.0") public @NonNull Builder argumentTriplet( final @NonNull String name, final @NonNull Triplet names, final @NonNull Triplet, Class, Class> parserTriplet, final @NonNull ArgumentDescription description ) { if (this.commandManager == null) { throw new IllegalStateException("This cannot be called from a command that has no command manager attached"); } return this.argument(ArgumentTriplet.of(this.commandManager, name, names, parserTriplet).simple(), description); } /** * Create a new argument triplet that maps to a custom type. *

* For this to work, there must be a {@link CommandManager} * attached to the command builder. To guarantee this, it is recommended to get the command builder instance * using {@link CommandManager#commandBuilder(String, String...)} * * @param name Name of the argument * @param outputType The output type * @param names Triplet containing the names of the sub-arguments * @param parserTriplet Triplet containing the types of the sub-arguments. There must be parsers for these types * registered in the {@link cloud.commandframework.arguments.parser.ParserRegistry} used by * the {@link CommandManager} attached to this command * @param mapper Mapper that maps from {@link Triplet} to the custom type * @param description Description of the argument * @param First type * @param Second type * @param Third type * @param Output type * @return Builder instance with the argument inserted * @deprecated for removal since 1.4.0, use * {@link #argumentTriplet(String, TypeToken, Triplet, Triplet, BiFunction, ArgumentDescription)} instead. */ @Deprecated @API(status = API.Status.DEPRECATED, since = "1.4.0") public @NonNull Builder argumentTriplet( final @NonNull String name, final @NonNull TypeToken outputType, final @NonNull Triplet names, final @NonNull Triplet, Class, Class> parserTriplet, final @NonNull BiFunction, O> mapper, final @NonNull Description description ) { return this.argumentTriplet( name, outputType, names, parserTriplet, mapper, (ArgumentDescription) description ); } /** * Create a new argument triplet that maps to a custom type. *

* For this to work, there must be a {@link CommandManager} * attached to the command builder. To guarantee this, it is recommended to get the command builder instance * using {@link CommandManager#commandBuilder(String, String...)} * * @param name Name of the argument * @param outputType The output type * @param names Triplet containing the names of the sub-arguments * @param parserTriplet Triplet containing the types of the sub-arguments. There must be parsers for these types * registered in the {@link cloud.commandframework.arguments.parser.ParserRegistry} used by * the {@link CommandManager} attached to this command * @param mapper Mapper that maps from {@link Triplet} to the custom type * @param description Description of the argument * @param First type * @param Second type * @param Third type * @param Output type * @return Builder instance with the argument inserted * @since 1.4.0 */ @API(status = API.Status.STABLE, since = "1.4.0") public @NonNull Builder argumentTriplet( final @NonNull String name, final @NonNull TypeToken outputType, final @NonNull Triplet names, final @NonNull Triplet, Class, Class> parserTriplet, final @NonNull BiFunction, O> mapper, final @NonNull ArgumentDescription description ) { if (this.commandManager == null) { throw new IllegalStateException("This cannot be called from a command that has no command manager attached"); } return this.argument( ArgumentTriplet.of(this.commandManager, name, names, parserTriplet).withMapper(outputType, mapper), description ); } // End of compound helper methods /** * Specify the command execution handler * * @param commandExecutionHandler New execution handler * @return New builder instance using the command execution handler */ public @NonNull Builder handler(final @NonNull CommandExecutionHandler commandExecutionHandler) { return new Builder<>( this.commandManager, this.commandMeta, this.senderType, this.commandComponents, commandExecutionHandler, this.commandPermission, this.flags ); } /** * Returns the current command execution handler. * * @return the current handler * @since 1.7.0 */ @API(status = API.Status.STABLE, since = "1.7.0") public @NonNull CommandExecutionHandler handler() { return this.commandExecutionHandler; } /** * Specify a required sender type * * @param senderType Required sender type * @return New builder instance using the required sender type */ public @NonNull Builder senderType(final @NonNull Class senderType) { return new Builder<>( this.commandManager, this.commandMeta, senderType, this.commandComponents, this.commandExecutionHandler, this.commandPermission, this.flags ); } /** * Specify a command permission * * @param permission Command permission * @return New builder instance using the command permission */ public @NonNull Builder permission(final @NonNull CommandPermission permission) { return new Builder<>( this.commandManager, this.commandMeta, this.senderType, this.commandComponents, this.commandExecutionHandler, permission, this.flags ); } /** * Specify a command permission * * @param permission Command permission * @return New builder instance using the command permission */ public @NonNull Builder permission(final @NonNull PredicatePermission permission) { return new Builder<>( this.commandManager, this.commandMeta, this.senderType, this.commandComponents, this.commandExecutionHandler, permission, this.flags ); } /** * Specify a command permission * * @param permission Command permission * @return New builder instance using the command permission */ public @NonNull Builder permission(final @NonNull String permission) { return new Builder<>( this.commandManager, this.commandMeta, this.senderType, this.commandComponents, this.commandExecutionHandler, Permission.of(permission), this.flags ); } /** * Make the current command be a proxy of the supplied command. This means that * all of the proxied command's variable command arguments will be inserted into this * builder instance, in the order they are declared in the proxied command. Furthermore, * the proxied command's command handler will be shown by the command that is currently * being built. If the current command builder does not have a permission node set, this * too will be copied. * * @param command Command to proxy * @return New builder that proxies the given command */ public @NonNull Builder proxies(final @NonNull Command command) { Builder builder = this; for (final CommandComponent component : command.getComponents()) { final CommandArgument argument = component.getArgument(); if (argument instanceof StaticArgument) { continue; } final CommandArgument builtArgument = argument.copy(); builder = builder.argument(builtArgument, component.getArgumentDescription()); } if (this.commandPermission.toString().isEmpty()) { builder = builder.permission(command.getCommandPermission()); } return builder.handler(command.commandExecutionHandler); } /** * Indicate that the command should be hidden from help menus * and other places where commands are exposed to users * * @return New builder instance that indicates that the constructed command should be hidden */ public @NonNull Builder hidden() { return this.meta(CommandMeta.HIDDEN, true); } /** * Register a new command flag * * @param flag Flag * @param Flag value type * @return New builder instance that uses the provided flag */ public @NonNull Builder flag(final @NonNull CommandFlag flag) { final List> flags = new ArrayList<>(this.flags); flags.add(flag); return new Builder<>( this.commandManager, this.commandMeta, this.senderType, this.commandComponents, this.commandExecutionHandler, this.commandPermission, Collections.unmodifiableList(flags) ); } /** * Register a new command flag * * @param builder Flag builder. {@link CommandFlag.Builder#build()} will be invoked. * @param Flag value type * @return New builder instance that uses the provided flag */ public @NonNull Builder flag(final CommandFlag.@NonNull Builder builder) { return this.flag(builder.build()); } /** * Build a command using the builder instance * * @return Built command */ public @NonNull Command build() { final List> commandComponents = new ArrayList<>(this.commandComponents); /* Construct flag node */ if (!this.flags.isEmpty()) { final FlagArgument flagArgument = new FlagArgument<>(this.flags); commandComponents.add(CommandComponent.of(flagArgument, ArgumentDescription.of("Command flags"))); } return new Command<>( Collections.unmodifiableList(commandComponents), this.commandExecutionHandler, this.senderType, this.commandPermission, this.commandMeta ); } /** * Essentially a {@link java.util.function.UnaryOperator} for {@link Builder}, * but as a separate interface to avoid conflicts. * * @param sender type * @since 1.8.0 */ @API(status = API.Status.STABLE, since = "1.8.0") @FunctionalInterface public interface Applicable { /** * Accepts a {@link Builder} and returns either the same or a modified {@link Builder} instance. * * @param builder builder * @return possibly modified builder * @since 1.8.0 */ @API(status = API.Status.STABLE, since = "1.8.0") @NonNull Builder applyToCommandBuilder(@NonNull Builder builder); } } }