From e03ebf2ef6f479746e46641f659f0157ed604f4a Mon Sep 17 00:00:00 2001 From: broccoli Date: Thu, 8 Aug 2024 19:18:30 +0100 Subject: [PATCH] chore: delete docs in main project docs have been moved to incendo/cloud-docs --- docs/CloudNew.png | Bin 31213 -> 0 bytes docs/README.adoc | 1251 ------------------------ docs/_config.yml | 1 - docs/image-2021-01-18-16-23-02-480.png | Bin 9765 -> 0 bytes 4 files changed, 1252 deletions(-) delete mode 100644 docs/CloudNew.png delete mode 100644 docs/README.adoc delete mode 100644 docs/_config.yml delete mode 100644 docs/image-2021-01-18-16-23-02-480.png diff --git a/docs/CloudNew.png b/docs/CloudNew.png deleted file mode 100644 index c96e8319ea882deddf34b8204cbeec59497c1bcd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31213 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�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 -v0.1.0, 2020-12-30 -:sectnums: -:cloud-version: 1.7.1 -:toc: left -:toclevels: 4 -:icons: font -:hide-uri-scheme: -:source-highlighter: coderay -:coderay-linenums-mode: inline -:coderay-css: class - -image::CloudNew.png[Logo] -== Introduction to Cloud - -CAUTION: The Cloud documentation is still a work in progress. - -Cloud is a command manager and dispatcher for the JVM. Cloud allows you to define commands in -several ways, most notably using command builders, or annotations. Cloud has platform implementations -for many platforms, including Minecraft server software such as Bukkit or Discord bot frameworks -such as JDA. - -Cloud allows you to customize the command execution pipeline by injecting custom behaviour along -the entire execution path. All of this will be covered in this document. - -This document will first introduce different Cloud concepts using the builder pattern API. -Section 4 will expand upon this by introducing the annotation (declarative) API, which offers -another way of declaring commands. - -This document will not cover every specific detail of Cloud. Instead, the purpose of -this document is to give an introduction to various Cloud concepts and explain how they -can be used to build useful commands. It is very recommended to read the -https://javadoc.io/doc/cloud.commandframework[JavaDocs] and use them as the primary source of information. - -== Getting Started - -Cloud is available through https://search.maven.org/search?q=cloud.commandframework[Maven Central]. - -*Maven* -[source,xml,subs="attributes,verbatim"] ----- - - cloud.commandframework - cloud-core - {cloud-version} - ----- - -*Gradle (Groovy)* -[source,groovy,subs="attributes,verbatim"] ----- -implementation 'cloud.commandframework:cloud-core:{cloud-version}' ----- - -*Gradle (Kotlin)* -[source,kotlin,subs="attributes,verbatim"] ----- -implementation("cloud.commandframework:cloud-core:{cloud-version}") ----- - -If you want to use snapshot builds, then they are available the Sonatype snapshots repository: - -[source,xml] ----- - - sonatype-snapshots - https://oss.sonatype.org/content/repositories/snapshots - ----- - -=== Modules - -cloud-core:: Core Cloud API module. - -cloud-annotations:: Cloud annotation API. - -cloud-services:: Cloud service API. Included in Core. - -cloud-tasks:: Cloud scheduling API. - -cloud-kotlin-extensions:: Cloud extensions for Kotlin. - -cloud-bukkit:: Cloud implementation for the Bukkit API. - -cloud-paper:: Extension of cloud-bukkit for the Paper API. - -cloud-velocity:: Cloud implementation for the Velocity (1.1.0+) API. - -cloud-brigadier:: Cloud utilities for Mojang's Brigadier API. - -cloud-bungee:: Cloud implementation for the BungeeCord API. - -cloud-fabric:: Cloud implementation for Minecraft clients and servers using the Fabric mod loader and API. - -cloud-jda:: Cloud implementation for the JDA API. - -cloud-javacord:: Cloud implementation for the Javacord API. - -cloud-pircbotx:: Cloud implementation for the PircBotX framework. - -cloud-sponge7:: Cloud implementation for Sponge v7. - -== Core - -The core module contains the majority of the API that you will be interacting with when using -Cloud. - -=== Command Manager - -The first step to any Cloud project is to create a command manager. Each supported platform has -its own command manager, but for the most part they look and behave very similarly. It is possible -to support multiple platforms in the same project. - -All command managers have a generic type argument for the command sender type. Most platforms have -their own "native" command sender type, but Cloud allows you to use whatever sender you want, by -supplying a mapping function to the command manager. This sender type will be included in the command context, -which you will be interacting with a lot when using Cloud. - -[title=Creating a command manager instance using Bukkit] -==== -This particular example uses `cloud-bukkit`, though most concepts transfer over to the other command mangers. - -[source,java] ----- -CommandManager manager = new BukkitCommandManager<>( - /* Owning plugin */ this, - CommandExecutionCoordinator.simpleCoordinator(), <1> - Function.identity(), <2> - Function.identity(), <3> -); ----- -<1> The execution coordinator handles the coordination of command parsing and execution. You can read more about this -in section 3.6. -<2> Function that maps the platform command sender to your command sender. -<3> Function that maps your command sender to the platform command sender. -==== - -The command manager is used to register commands, create builders, change command settings, etc. -More information can be found in the CommandManager -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/CommandManager.html[JavaDoc]. - -=== Commands - -Commands consist of chains of arguments that are parsed from user input. These arguments -can be either static literals or variables. Variable arguments are parsed into different -types using argument parsers. Variable arguments may be either required, or they can be -optional. Optional arguments may have default values. - -[title=Example command structure] -==== -[source] ----- -/foo bar one -/foo bar two -/foo <1> ----- -<1> When a variable argument is present next to literals, it will be allowed to catch any -input that isn't caught by the literals. Only one variable may exist at any level, but -there may be many literals. - -This example contains three unique commands. -==== - -=== Argument Types - -==== Literals - -Literals are fixed strings and can be used to create "subcommands". You may use -however many command literals you want at any level of a command. Command literals -may have additional aliases that correspond to the same argument. - -A literal can be created directly in the command builder: - -[source,java] ----- -builder = builder.literal( - "main", <1> - "alias1", "alias2", "alias3" <2> -); ----- -<1> Any literal must have a main "alias". -<2> You may also specify additional aliases. These are optional. - -You can also attach a description to your node, which is used in the command -help system: - -[source,java] ----- -builder = builder.literal( - "main", - Description.of("Your Description") -); ----- - -Literals may also be created using the -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/arguments/StaticArgument.html[StaticArgument] -class. - -==== Standard - -Cloud has built in support for all primitive types, as well as some other commonly -used argument types. - -===== string - -There are three different types of string arguments: - -single:: A single string without any blank spaces. - -greedy:: Consumes all remaining input. - -quoted:: Consumes either a single string, or a string surrounded by `"` or `'`. - -String arguments can be constructed using: - -* `StringArgument.of(name)`: Required single string argument - -* `StringArgument.of(name, mode)`: Required string argument of specified type - -* `StringArgument.optional(name)`: Optional single string argument - -* `StringArgument.optional(name, mode)`: Optional string argument of specified type - -Furthermore, a string argument builder can be constructed using `StringArgument.builder(name)`. -This allows you to provide a custom suggestion generator, using `StringArgument.Builder#withSuggestionProvider(BiFunction, List>)`. - -===== byte/short/int/long - -There are four different integer argument types: - -- byte -- short -- int -- long - -All integer types are created the same way, the only difference is the class. These examples will use `IntegerArgument`, but the same -methods are available in `ByteArgument`, `ShortArgument`, and `LongArgument`. - -Integer arguments can be constructed using: - -* `IntegerArgument.of(name)`: Required integer argument without a range - -* `IntegerArgument.optional(name)`: Optional integer argument without a range - -* `IntegerArgument.optional(name, default)`: Optional integer argument without a range, with a default value - -Furthermore, an integer argument builder can be constructed using `IntegerArgument.builder(name)`. This allows you to provide a - custom suggestion generator, using `IntegerArgument.Builder#withSuggestionProvider(SuggestionProvider)`, and set minimum and - maximum values. - -===== float/double - -There are two different floating point argument types: - -- float -- double - -All floating point types are created the same way, the only difference is the class. These examples will use `FloatArgument`, but the same -methods are available in `DoubleArgument`. - -Floating point arguments can be constructed using: - -* `FloatArgument.of(name)`: Required float argument without a range - -* `FloatArgument.optional(name)`: Optional float argument without a range - -* `FloatArgument.optional(name, default)`: Optional float argument without a range, with a default value - -Furthermore, a floating-point argument builder can be constructed using `FloatArgument.builder(name)`. This allows you to -provide a custom suggestion generator, using `FloatArgument.Builder#withSuggestionProvider(SuggestionProvider)`, and set -minimum and maximum values. - -===== enums - -The enum argument type allows you to create a command argument using any enum type. They can be created using `EnumArgument.of` -and `EnumArgument.optional`. The parser accepts case independent values and suggestions will be created for you. - -===== boolean - -The boolean argument type is very simple. It parses boolean-like values from the input. There are two different modes: - -liberal:: Accepts truthy values ("true", "yes", "on") and falsy values ("false", "no", off") -non-liberal:: Accepts only "true" and "false" - -===== compound arguments - -Compound arguments are a special type of arguments that consists of multiple other arguments. -By default, 2 or 3 arguments may be used in a compound argument. - -The methods for creating compounds arguments can be found in CommandManager, or in the -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/arguments/compound/ArgumentPair.html[ArgumentPair] -or -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/arguments/compound/ArgumentTriplet.html[ArgumentTriplet] -classes. - -In general, they need a tuple of names, and a tuple of argument types. They can also -take in a mapping function which maps the value to a more user-friendly type. - -[title=Argument triplet mapping to a vector] -==== -[source,java] ----- -commandBuilder.argumentTriplet( - "coords", - TypeToken.get(Vector.class), - Triplet.of("x", "y", "z"), - Triplet.of(Integer.class, Integer.class, Integer.class), - (sender, triplet) -> new Vector(triplet.getFirst(), triplet.getSecond(), - triplet.getThird() - ), - Description.of("Coordinates") -) ----- -==== - -==== Custom - -Cloud allows you to create custom argument parsers. The easiest way to achieve this -is by extending `CommandArgument`. This is recommended if you are creating -arguments that will be exposed in some kind of library. For inspiration on how -to achieve this, it is recommended to check out the standard Cloud arguments. - -If you don't need to expose your parser as a part of an API, you may simply -implement `ArgumentParser`. The method you will be working with -looks like: - -[source,java] ----- -public @NonNull ArgumentParseResult parse( - @NonNull CommandContext<@NonNull C> commandContext, - @NonNull Queue<@NonNull String> inputQueue <1> -) { - // ... -} ----- -<1> Queue containing (remaining) user input. - -When reading an argument you should do the following: - -1. Peek the queue. -2. Attempt to parse your object. - * If the object could not be parsed, return `ArgumentParseResult.failure(exception)` -3. If the object was parsed successfully, pop a string from the queue. -4. Return `ArgumentParseResult.success(object)`. - -WARNING: If the read string(s) isn't popped from the queue, then the command engine will assume that the syntax is wrong and -send an error message to the command sender. - -It is highly recommended to make use of -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/exceptions/parsing/ParserException.html[ParserException] -when returning a failed result. This allows for integration with the Cloud caption system (refer to the section on Exception -Handling for more information). - -You should - in most cases - register your parser to the -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/arguments/parser/ParserRegistry.html[ParserRegistry] -which you can access using -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/CommandManager.html#getParserRegistry()[CommandManager#getParserRegistry()]. -If you are registering a parser that shouldn't be the default for the -argument type, then it is recommended to register a named parser. -If your parser is not registered to the parser registry, it will -not be usable in annotated command methods. - -When registering a command parser, you're actually registering a -function that will generate a parser based on parser parameters. -These parameters can be used together with the annotation system -to differentiate between different parsers and also change parser -settings. In order to create these parameters you can create -an annotation mapper using -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/arguments/parser/ParserRegistry.html#registerAnnotationMapper(java.lang.Class,java.util.function.BiFunction)[ParserRegistry#registerAnnotationMapper]. - -Here's an example of how a UUID parser can be created and registered: - -[title=Example UUID parser] -==== -This example is taken from -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/arguments/standard/UUIDArgument.html[UUIDArgument.java] -, which also includes a custom exception and argument builder. -It's a good reference class for custom arguments, as it does -not contain any complicated logic. - -[source,java] ----- -public final class UUIDParser implements ArgumentParser { - - @Override - public @NonNull ArgumentParseResult parse( - final String input = inputQueue.peek(); - if (input == null) { - return ArgumentParseResult.failure(new NoInputProvidedException( - UUIDParser.class, - commandContext - )); - } - - try { - UUID uuid = UUID.fromString(input); - inputQueue.remove(); - return ArgumentParseResult.success(uuid); - } catch(final IllegalArgumentException e) { - return ArgumentParseResult.failure(new UUIDParseException(input, commandContext)); - } - ) - -} ----- - -It is then registered to the parser registry using -[source,java] ----- -parserRegistry.registerParserSupplier( - TypeToken.get(UUID.class), - options -> new UUIDParser<>() -); ----- -in -https://github.com/Incendo/cloud/blob/master/cloud-core/src/main/java/cloud/commandframework/arguments/parser/StandardParserRegistry.java[StandardParserRegistry.java]. - -==== - -==== Flags - -Flags are named optional values that can either have an associated argument (value flag) or have the value evaluated by whether the flag is present (presence flag). These flags are registered much the same way as normal arguments, only that you use `.flag` methods in the command builder instead. - -Flags are always optional. You cannot have required flags. If you need required values, then they should be part of a deterministic command chain. Flags must also necessarily be placed at the tail of a command chain, and you cannot put any arguments (required, or optional) after the flags. This is enforced by the command builder. - -Flags can have aliases alongside their full names. When referring to the full name of a flag, you use `--name` whereas an alias -uses syntax similar to `-a`. You can chain the aliases of multiple presence flags together, such that `-a -b -c` is equivalent -to `-abc`. - -[title=Example of a presence flag] -==== -[source,java] ----- -manager.command( - manager.commandBuilder("cp") - .argument(StringArgument.of("source"), ArgumentDescription.of("Source path")) - .argument(StringArgument.of("destination"), ArgumentDescription.of("Destination path")) - .flag( - manager.flagBuilder("recursive") - .withAliases("r") - .withDescription(ArgumentDescription.of("Recursive copy")) - ).handler(context -> { - boolean recursive = context.flags().isPresent("recursive"); - // ... - }) -); ----- -==== - -[title=Example of a value flag] -==== -In this example the flag is constructed outside the command builder, -and referenced using the flag object itself. Flag objects are also -reusable across multiple commands (unlike command arguments). - -[source,java] ----- -final CommandFlag yawFlag = CommandFlag - .builder("yaw") - .withArgument(FloatArgument.of("yaw")) - .build(); -manager.command( - manager.commandBuilder("teleport") - .argumentTriplet( - "vector", - Triplet.of("x", "y", "z"), - Triplet.of(Double.class, Double.class, Double.class), - ArgumentDescription.of("The position to teleport to") - ) - .flag(yawFlag) - .handler(context -> { - // ... - final float yaw = context.flags().getValue(yawFlag, 0f); - // ... - }) -); ----- -==== - -==== Argument Preprocessing - -An argument preprocessor is a function that gets to act on command -input before it's given to a command. This allows you to inject -custom verification behaviour into existing parsers, or register -annotations that add extra verification to your custom annotations. - -https://github.com/Incendo/cloud/blob/master/cloud-core/src/main/java/cloud/commandframework/arguments/preprocessor/RegexPreprocessor.java[RegexPreprocessor.java] -is a good example of a preprocessor that allows you to add regular -expression checking to your arguments. - -Argument preprocessors can be applied to created arguments using -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/arguments/CommandArgument.html#addPreprocessor(java.util.function.BiFunction)(java.util.function.BiFunction)[CommandArgument#addPreprocessor]. - -=== Suggestions - -Many platforms support command suggestions. You can add command suggestions to your command parser, by overriding the suggestion -method: - -[source,java] ----- -@Override -public @NonNull List<@NonNull String> suggestions( - final @NonNull CommandContext commandContext, - final @NonNull String input -) { - final List completions = new ArrayList<>(); - for (Material value : Material.values()) { - completions.add(value.name().toLowerCase()); - } - return completions; -} ----- - -or by specifying a suggestion function in a command argument builder -using -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/arguments/CommandArgument.Builder.html#withSuggestionProvider(java.util.function.BiFunction)[CommandArgument.Builder#withSuggestionProvider]. - -You also register a standalone suggestions to the parser registry, -using -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/arguments/parser/ParserRegistry.html#registerSuggestionProvider(java.lang.String,java.util.function.BiFunction)[ParserRegistry#registerSuggestionProvider]. -Registering a named suggestion provider allows it to be used in -annotated command methods, or retrieved using `ParserRegistry#getSuggestionProvider`. - -=== Injection Points - -image::image-2021-01-18-16-23-02-480.png[Execution Pipeline] - -When a command is entered by a command sender, it goes through -the following stages: - -1. It is turned into string tokens. This is used to create the input queue. -2. A command context is created for the input queue combined with the command sender. -3. The command is passed to the preprocessors, which may alter the input queue or write to the context. - * If a preprocessor causes an interrupt using `ConsumerService.interrupt()` then the context will be filtered out and the -command will not be parsed. - * If no preprocessor filters out the context, the context and input will be ready to be parsed into an executable command. -4. The input is parsed into a command chain and components are written -to the context. - * If the command does not fit any existing command chains, the sender is notified and the parsing is cancelled. - * If the command is valid, it will be sent to the postprocessors. -5. The command postprocessors get to act on the command can alter the command context. they may now postpone command execution, -such is the case with the command confirmation postprocessor. - * If a postprocessor causes an interrupt using `ConsumerService.interrupt()` the command will not be executed. - * If no postprocessor interrupts during the post-processing stage, the command will be sent to the executor. -6. The command is executed using the command executor. - -==== Preprocessing - -Command preprocessing happens before the input has been pasted to the command tree for parsing. To register a preprocessor, implement `cloud.commandframework.execution.preprocessor.CommandPreProcessor`: - -[source,java] ----- -public class YourPreProcessor implements CommandPreprocessor { - - @Override - public void accept(final CommandPreprocessingContext context) { - /* Act on the context */ - if (yourCondition) { - /* Filter out the context so that it is never passed to the parser */ - ConsumerService.interrupt(); - } - } - -} ----- - -Then register the preprocessor using `CommandManager#registerCommandPreProcessor(CommandPreprocessor)`. - -==== Postprocessing - -Command postprocessing happen after the input has been parsed into a command chain, but before the command is executed. To register a postprocessor, implement `cloud.commandframework.execution.postprocessor.CommandPostProcessor`: - -[source,java] ----- -public class YourPostprocessor implements CommandPostprocessor { - - @Override - public void accept(final CommandPostprocessingContext context) { - /* Act on the context */ - if (yourCondition) { - /* Filter out the context so that it is never passed to the executor */ - ConsumerService.interrupt(); - } - } - -} ----- - -Then register the postprocessor using `CommandManager#registerCommandPostProcessor(CommandPostprocessor)`. - -=== Execution Coordinators -TODO - -=== Command Proxies - -Command proxying is a feature that allows you to forward a command chain -to another command chain. More specifically, a "proxy" of a command is a command -which has all the same required arguments in the same order as in the -original command. Essentially, they can be thought of as more powerful -command aliases. - -It is easier understood by an example. Imagine you have a warp command in a game, -let's call it `/game warp me `, but you feel like it's a little too verbose for common use. You may then choose to introduce -a `/warpme ` command proxy that gets forwarded to the original command. - -To create a command proxy you can use -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/Command.Builder.html#proxies(cloud.commandframework.Command)[Command.Builder#proxies(Command)]. -Please note the documentation of the method, which reads: - -> 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. - -=== Permissions -TODO - -=== Exception Handling - -In general, it is up to each platform manager to handle command exceptions. -Command exceptions are thrown whenever a command cannot be executed normally. - -This can be for several reasons, such as: - -- The command sender does not have the required permission (NoPermissionException) -- The command sender is of the wrong type (InvalidCommandSenderException) -- The requested command does not exist (NoSuchCommandException) -- The provided command input is invalid (InvalidSyntaxException) -- The input provided to a command argument cannot be parsed (ArgumentParseException) - -Generally, the command managers are highly encouraged to make use of -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/CommandManager.html#handleException(C,java.lang.Class,E,java.util.function.BiConsumer)[CommandManager#handleException], -in which case you may override the exception handling by using -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/CommandManager.html#registerExceptionHandler(java.lang.Class,java.util.function.BiConsumer)[CommandManager#registerExceptionHandler]. - -ArgumentParseException is a special case which makes use of the internal caption -system. (Nearly) all argument parsers in cloud will throw -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/exceptions/parsing/ParserException.html[ParserException] -on -invalid input, in which case you are able to override the exception message by -configuring the manager's -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/captions/CaptionRegistry.html[CaptionRegistry]. -By default, cloud uses a -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/captions/FactoryDelegatingCaptionRegistry.html[FactoryDelegatingCaptionRegistry], -which allows you -to override the exception handling per caption key. All standard caption keys can -be found in -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/captions/StandardCaptionKeys.html[StandardCaptionKeys]. -Some platform adapters have their own caption key classes as well. - -The caption keys have JavaDoc that list their replacement variables. The message -registered for the caption will have those variables replaced with values -specific to the parsing instance. `{input}` is accepted by all parser captions, -and will be replaced with the argument input that caused the exception to be thrown. - -[title=Example caption registry usage] -==== -[source,java] ----- -final CaptionRegistry registry = manager.getCaptionRegistry(); -if (registry instanceof FactoryDelegatingCaptionRegistry) { - final FactoryDelegatingCaptionRegistry factoryRegistry = (FactoryDelegatingCaptionRegistry) registry; - factoryRegistry.registerMessageFactory( - StandardCaptionKeys.ARGUMENT_PARSE_FAILURE_BOOLEAN, - (context, key) -> "'{input}' är inte ett tillåtet booelskt värde" - ); -} ----- -==== - -=== Extra - -==== Confirmations - -Cloud has built in support for commands that require confirmation by the sender. It essentially postpones command execution -until an additional command has been dispatched. - -You first have to create a command confirmation manager: -[source,java] ----- -CommandConfirmationManager confirmationManager = new CommandConfirmationManager<>( - 30L, <1> - TimeUnit.SECONDS, - context -> context.getCommandContext().sender().sendMessage("Confirmation required!"), <2> - sender -> sender.sendMessage("You don't have any pending commands") <3> -); ----- -<1> The amount (in the selected time unit) before the pending command expires. -<2> Action to run when the confirmation manager requires action from the sender. -<3> Action to run when the confirmation command is ran by a sender without any pending commands. - -The confirmation manager needs to be registered to the command manager. This is as easy as -`confirmationManager.registerConfirmationProcessor(manager)`. - -You also need a confirmation command. The recommended way to create this is by doing: -[source,java] ----- -manager.command( - builder.literal("confirm")) - .meta(CommandMeta.DESCRIPTION, "Confirm a pending command") - .handler(confirmationManager.createConfirmationExecutionHandler()) -); ----- - -The important part is that the generated execution handler is used in your command. All commands -that require confirmation needs `.meta(CommandConfirmationManager.META_CONFIRMATION_REQUIRED, true)` -or a `@Confirmation` annotation. - -==== Help Generation -TODO - -== Annotations - -Annotations allow for an alternative way of declaring commands in cloud. Instead of constructing commands -using builders, commands consist of annotated instance methods. Command arguments will be bound to the -method parameters, instead of being retrieved through the command context. - -NOTE: Since version 1.7.0, `cloud-annotations` will now also perform -annotation processing, verifying that `@CommandMethod` annotated methods -have valid signatures, etc. - -=== Install - -In order to use the annotation parser & annotation processor, you need to -add `cloud-annotations` as a dependency: - -*Maven* -[source,xml,subs="attributes,verbatim"] ----- - - cloud.commandframework - cloud-annotations - {cloud-version} - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - - cloud.commandframework - cloud-annotations - {cloud-version} - - - - - - ----- - -*Gradle (Groovy)* -[source,groovy,subs="attributes,verbatim"] ----- -implementation 'cloud.commandframework:cloud-annotations:{cloud-version}' -annotationProcessor 'cloud.commandframework:cloud-annotations:{cloud-version}' ----- - -*Gradle (Kotlin)* -[source,kotlin,subs="attributes,verbatim"] ----- -implementation("cloud.commandframework:cloud-annotations:{cloud-version}") -annotationProcessor("cloud.commandframework:cloud-annotations:{cloud-version}") ----- - - -=== Annotation Parser - -In order to work with annotated command methods you need to construct an annotation parser. -Fortunately this is very easy: - -[source,java] ----- -AnnotationParser annotationParser = new AnnotationParser<>( - manager, <1> - parameters -> SimpleCommandMeta.empty() <2> -); ----- -<1> Your command manager instance. Commands parsed by the parser will be automatically registered to this manager. -<2> A mapping function that maps parser parameters to a command meta instance. - -In order to parse commands in a class, simply call `annotationParser.parse(yourInstance)` where `yourInstance` is -an instance of the class you wish to parse. - -=== @CommandMethod - -All command methods must be annotated with `@CommandMethod`. The value of the annotation is the command -structure, using the following syntax: - -- literal: `name` -- required argument: `` -- optional argument: `[name]` - -[title=Example command syntax] -==== -`@CommandMethod("command [bar]")` would be equivalent to -[source,java] ----- -builder.literal("command") - .argument(SomeArgument.of("foo")) - .argument(SomeArgument.optional("bar")); ----- -==== - -`@CommandMethod` cannot be put on static methods. - -=== @Argument - -In order to map command arguments to command parameters you need to annotate your parameters with -`@Argument`. The value of the annotation is the name of the argument, and should correspond to -the name used in the command syntax in `@CommandMethod`. - -Ordering of the methods arguments does not matter, -instead Cloud will match arguments based on the names supplied to the annotation. This also means that -Cloud doesn't care about the names of the method parameters. - -You may also specify a named argument parser, named suggestion provider, default value -and description using the `@Argument` annotation. - -=== @Flag - -Flags can be used in annotated command methods by decorating the method parameter with -`@Flag`. Similarly to `@Argument`, this annotation can be used to specify suggestion -providers, parsers, etc. - -If a boolean is annotated with `@Flag`, the flag will become a presence flag. Otherwise -it will become a value flag, with the parameter type as the type of the flag value. - -WARNING: `@Flag` should NOT be used together with `@Argument`. Nor should flags be included -in the `@CommandMethod` syntax string. - -=== @CommandDescription - -`@CommandDescription` can be put on command methods to specify the description of the command. - -=== @CommandPermission - -`@CommandPermission` can be put on either a command method or a class containing command methods -in order to specify the permission required to use the command. - -=== @ProxiedBy - -`@ProxiedBy` lets you define command proxies on top of command methods. Unlike -the builder method, this annotation creates a proxy of the annotated method. -rather than making the target a proxy. - -[title=Example usage of @ProxiedBy] -==== -[source,java] ----- -@ProxiedBy("warpme") -@CommandMethod("game warp me ") -public void warpMe(final @NonNull GamePlayer player, final @NonNull @Argument("warp") Warp warp) { - player.teleport(warp); -} ----- - -This method will generate two commands: `/game warp me ` and `/warpme`, with identical -functionality. -==== - -=== @Regex - -`@Regex` can be used on command arguments to apply a regex argument -pre-processor. - -[title=Example usage of @Regex] -==== -[source,java] ----- -@Argument("money") @Regex( - value = "(?=.*?\\d)^\\$?(([1-9]\\d{0,2}(,\\d{3})*)|\\d+)?(\\.\\d{1,2})?$", - failureCaption = "regex.money" -) String money ----- -==== - -=== @Parser - -`@Parser` can be used to create argument parsers from instance methods. -The annotation value is the name of the parser. If no name is supplied, -the parser will be registered as the default parser for the method's -return type. - -The signature of the method should be: -[source,java] ----- -@Parser("name") -public ParsedType methodName(CommandContext sender, Queue input) { -} ----- - -The method can throw exceptions, and the thrown exceptions will automatically -be wrapped in an argument parse result. - -It is also possibly to specify the suggestion provider that should be used by -default by the generated parser. This is done by specifying a name in the annotation, -such as `@Parser(suggestions="yourSuggestionProvider")`. For this to work -the suggestion provider must be registered in the parser registry. - -=== @Suggestions - -`@Suggestions` can be used to create suggestion provider from instance methods. -The annotation value is the name of the suggestion provider. - -The signature of the method should be: -[source,java] ----- -@Suggestions("name") -public List methodName(CommandContext sender, String input) { -} ----- - -`@Suggestions` -generated suggestion providers will be automatically registered to the parser registry. - -=== Injections - -Command methods may have parameters that are not arguments. A very common example -would be the command sender object, or the command object. Command method -parameters that aren't arguments are referred to as _injected values_. - -Injected values can be registered in the -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/annotations/injection/ParameterInjectorRegistry.html[ParameterInjectorRegistry], -which is available in the command manager. You register a parameter injector for a specific -type (class), which is essentially a function mapping the command context and an annotation accessor to an injectable value. - -[title=Example injector] -==== -The following is an example from `cloud-annotations` that injects the raw command input -into string arrays annotated with `@RawArgs`. -[source,java] ----- -this.getParameterInjectorRegistry().registerInjector( - String[].class, <1> - (context, annotations) -> annotations.annotation(RawArgs.class) == null - ? null <2> - : context.getRawInput().toArray(new String[0]) -); ----- -<1> Type to inject. -<2> If no value can be injected, it is fine to return `null`. -==== - -By default, the `CommandContext`, `@RawArgs String[]` and the command sender are injectable. - -==== Injection services - -It is possible to register injection services that delegate injections to a custom, or existing -dependency injection system. In version 1.4.0, a `GuiceInjectionService` was added which can be -used to delegate injection requests to a Guice injector. - -All you need is to create an injection service: -[source,java] ----- -public class YourInjectionService implements InjectionService { - - @Override - public Object handle(CommandContext context, Class clazz) { - return yourInjectionSystem.injectInstance(clazz); - } - -} ----- -and then register it to the parameter injection registry using -`manager.parameterInjectionRegistry().registerInjectionService(new YourInjectionService<>())`. - -=== Builder Modifiers - -Builder modifiers allow you to register annotations that can effect how a -`@CommandMethod` based command is generated. - -Builder modifiers are allowed to -act on command builders after all arguments have been added to the builder. -This allows for modifications to the builder instance before the command is -registered to the command manager. - -Builder modifiers are registered to the annotation parser: -[source,java] ----- -annotationParser.registerBuilderModifier( - YourAnnotation.class, <1> - (yourAnnotation, builder) -> builder.meta("key", "value") <2> -); ----- -<1> The modifier receives the instance of the method annotation. -<2> The modifier method must necessarily return the modified builder. Command -builders immutable, so the modifier should return the instance of the command -builder that is returned as the result of any operations on the builder. - -=== Annotation Mappers - -Annotation mappers allow you to register custom annotations that will -modify the parser parameters for a command argument. This allows you to -modify how the command parser is generated for a command based on the -annotation. - -Annotation mappers are registered to the annotation parser: -[source,java] ----- -annotationParser.registerAnnotationMapper( - YourAnnotation.class, - (yourAnnotation) -> ParserParameters.single(StandardParameters.RANGE_MIN, 10) -); ----- - -=== Pre-processor Mappers - -It is possible to register annotations that will bind a given argument pre-processor -to the annotated argument. - -Pre-processor mappers are registered to the annotation parser: -[source,java] ----- -annotationParser.registerPreprocessorMapper( - YourAnnotation.class, - annotation -> yourPreProcessor -); ----- - -=== @CommandContainer -TODO - -== Kotlin DSL -TODO - -== Platforms - -=== Minecraft - -==== Bukkit - -Bukkit mappings for cloud. If commodore is present on the classpath and the server is running at least version 1.13+, Brigadier mappings will be available. - -To setup a Bukkit command manager, simply do: - -[source,java] ----- -final BukkitCommandManager bukkitCommandManager = new BukkitCommandManager<>( - yourPlugin, - yourExecutionCoordinator, - forwardMapper, <1> - backwardsMapper <2> -); ----- -<1> The `forwardMapper` is a function that maps your chosen sender type to Bukkit's -https://jd.bukkit.org/org/bukkit/command/CommandSender.html[CommandSender]. -<2> The `backwardMapper` does the opposite of the `forwardMapper`. - -NOTE: In the case that you don't need a custom sender type, you can simply use `CommandSender` as the generic type and pass -`Function.identity()` as the forward and backward mappers. - -===== Commodore - -To use commodore, include it as a dependency: - -**maven**: -[source,xml] ----- - - me.lucko - commodore - 1.9 - ----- - -**gradle (groovy)** -[source,groovy] ----- -dependencies { - implementation 'me.lucko:commodore:1.9' -} ----- - -Then initialise the commodore mappings using: - -[source,java] ----- -try { - bukkitCommandManager.registerBrigadier(); -} catch (final Exception e) { - plugin.getLogger().warning("Failed to initialize Brigadier support: " + e.getMessage()); -} ----- - -The mappings will then be created and registered automatically whenever a new command is registered. - -NOTE: The mapper must be initialized *before* any commands are registered. - -You can check whether the running server supports Brigadier, by using `bukkitCommandManager.queryCapability(...)`. When shading Commodore into your plugin, remember to relocate it's classes. - -===== Parser - -`cloud-bukkit` has plenty of Bukkit-specific parsers. These are easiest found -via the JavaDocs: - -- https://javadoc.io/doc/cloud.commandframework/cloud-bukkit/latest/cloud/commandframework/bukkit/parsers/package-summary.html -- https://javadoc.io/doc/cloud.commandframework/cloud-bukkit/latest/cloud/commandframework/bukkit/parsers/location/package-summary.html -- https://javadoc.io/doc/cloud.commandframework/cloud-bukkit/latest/cloud/commandframework/bukkit/parsers/selector/package-summary.html - -Many of these are pre-mapped to serializable Brigadier argument types. - -==== Paper - -`cloud-paper` works on all Bukkit derivatives and has graceful fallbacks for cases where Paper specific features are missing. -It is initialized the same way as `cloud-bukkit`, except `PaperCommandManager` is used in place of `BukkitCommandManager`. -When using Paper 1.15+ Brigadier mappings are available even without commodore present. - -An example plugin using the `cloud-paper` API can be found -https://github.com/Sauilitired/cloud/tree/master/examples/example-bukkit[here]. - -===== Asynchronous completions -`cloud-paper` supports asynchronous completions when running on Paper. -First check if the capability is present, by using `paperCommandManager.queryCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)` -and then initialize the asynchronous completion listener by using `paperCommandManager.registerAsynchronousCompletions()`. - -==== Sponge - -TODO - -==== Fabric - -Documentation for the Fabric implementation is still a work in progress. - -==== minecraft-extras - -The `cloud-minecraft-extras` module contains additional opinionated features for the cloud minecraft platforms, taking advantage of the Kyori https://github.com/KyoriPowered/adventure[adventure] api for sending text components to minecraft users. On platforms like Sponge and Velocity which include `adventure-api` as the standard text and user interface library, minecraft-extras can be used with no additional dependencies. On platforms that do not natively support `adventure`, like Bukkit and BungeeCord for example, a platform adapter must be used. Learn more about adventure platform adapters at the https://docs.adventure.kyori.net/platform/index.html[adventure docs]. - -===== Pre-built exception handlers - -Included in minecraft-extras are prebuilt handlers for `ArgumentParseException`, `InvalidCommandSenderException`, `InvalidSyntaxException`, and `NoPermissionException`. These handlers provide improved aesthetics on exception messages, and allow for custom decoration of the messages, for example with a prefix. - -Use these exception handlers by creating a new instance of -https://javadoc.io/doc/cloud.commandframework/cloud-minecraft-extras/latest/cloud/commandframework/minecraft/extras/MinecraftExceptionHandler.html[`MinecraftExceptionHandler`], -applying the handlers and decorator you wish to use, and then applying the handlers to the manager. - -[title=Usage of the MinecraftExceptionHandler class] -==== -[source,java] ----- -new MinecraftExceptionHandler() - .withArgumentParsingHandler() - .withInvalidSenderHandler() - .withInvalidSyntaxHandler() - .withNoPermissionHandler() - .withCommandExecutionHandler() - .withDecorator(message -> myPrefixComponent.append(Component.space()).append(message)) - .apply(commandManager, bukkitAudiences::sender); <1> ----- -<1> `bukkitAudiences::sender` is simply a method mapping the CommandSender to an Audience -==== - -===== Minecraft-specific help menu generation -minecraft-extras includes a utility for generating attractive help menus for your minecraft projects. These help menus include hover and click elements, pagination of results, and customization of colors and text. - -To use the minecraft-extras help menu, first create an instance of -https://javadoc.io/doc/cloud.commandframework/cloud-minecraft-extras/latest/cloud/commandframework/minecraft/extras/MinecraftHelp.html[`MinecraftHelp`], -like so: - -[source,java] ----- -new MinecraftHelp( - "/myplugin help", <1> - bukkitAudiences::sender, <2> - commandManager -); ----- -<1> The command which this help menu will be bound to -<2> Function mapping your CommandSender type to an adventure Audience - -To query help and display the results to a user, use the `MinecraftHelp#queryCommands(String, C)` method in the handler for -your help command. Continuing with the above example, our help command might look something like this: - -[source,java] ----- -manager.command( - manager.commandBuilder("myplugin") - .literal("help") - .argument(StringArgument.optional("query", StringArgument.StringMode.GREEDY)) - .handler(context -> { - minecraftHelp.queryCommands(context.getOrDefault("query", ""), context.sender()); - }) -); ----- - -Something developers may find desirable as well is to use a custom suggestion provider for the query argument, and to suggest syntax strings gotten from a blank query to `CommandHelpHandler#queryHelp` -(see -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/CommandManager.html#getCommandHelpHandler()[CommandManager#getCommandHelpHandler] -and -https://javadoc.io/doc/cloud.commandframework/cloud-core/latest/cloud/commandframework/CommandHelpHandler.html#queryHelp(C,java.lang.String)[CommandHelpHandler#queryHelp] -). - -==== Brigadier - -https://github.com/Mojang/Brigadier[Brigadier] -is Mojang's command parser and dispatcher for Minecraft: Java Edition. -It was released in version 1.13, and is available in Notchian -servers and clients released since. The most notable feature of Brigadier -is the real-time argument parsing and feedback system, which allows you -to see whether your argument is valid, while writing it. This feature -works for the primitive Java types, and some serializable types in the -Minecraft: Java Edition client. - -Cloud has Brigadier hooks for: Velocity 1.10+, Paper 1.15+ (1.13+ using -https://github.com/lucko/commodore[commodore]), -Spigot 1.13 using -https://github.com/lucko/commodore[commodore], -and Sponge v8+. -When using Paper/Spigot, this feature is opt-in (refer to the platform documentation for more information). - -Cloud will try to hook into the Mojang (`net.minecraft.server`) serializable -types. In most cases this works when using the platform specific argument types, -such as Location. You can also create your own mappings. See the platform adapter -JavaDoc for more information. - -=== Discord -TODO - -==== JDA -TODO - -==== Javacord -TODO - -=== IRC -TODO - -[glossary] -== Glossary - -[glossary] -sender:: A thing that is able to produce input that gets parsed into commands. - -argument:: An argument is something that can be parsed from a string. - -required argument:: A required argument is an argument that must be supplied by the sender. - -optional argument:: An optional argument is an argument that can be omitted by the sender. It -may have a default value. - -literal:: A fixed string. - -command:: A command is a chain of arguments combined with a handler that acts -on the parsed arguments. - -command tree:: A structure that contains all recognized commands, and that is used -when parsing command sender input. diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index 2f7efbeab..000000000 --- a/docs/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-minimal \ No newline at end of file diff --git a/docs/image-2021-01-18-16-23-02-480.png b/docs/image-2021-01-18-16-23-02-480.png deleted file mode 100644 index 1cd8e2157bb5525fa5eb6e3868e7bd853bd3cf95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9765 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 p;j