424 lines
13 KiB
Text
424 lines
13 KiB
Text
= Cloud documentation
|
|
Alexander Söderberg <contact@alexander-soderberg.com>
|
|
v0.1.0, 2020-12-30
|
|
:sectnums:
|
|
:cloud-version: 1.3.0
|
|
:toc: left
|
|
:toclevels: 3
|
|
:icons: font
|
|
:hide-uri-scheme:
|
|
|
|
== 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.
|
|
|
|
== Getting Started
|
|
|
|
Cloud is available through https://search.maven.org/search?q=cloud.commandframework[Maven Central].
|
|
|
|
[source,xml,subs="attributes,verbatim"]
|
|
----
|
|
<dependency>
|
|
<groupId>cloud.commandframework</groupId>
|
|
<artifactId>cloud-core</artifactId>
|
|
<version>{cloud-version}</version>
|
|
</dependency>
|
|
----
|
|
|
|
If you want to use snapshot builds, then they are available via the Sonatype OSS Snapshot repository:
|
|
|
|
[source,xml]
|
|
----
|
|
<repository>
|
|
<id>sonatype-snapshots</id>
|
|
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
|
</repository>
|
|
----
|
|
|
|
=== 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-jda:: Cloud implementation for the JDA API.
|
|
|
|
cloud-javacord:: Cloud implementation for the Javacord API.
|
|
|
|
cloud-pircbotx:: Cloud implementation for the PircBotX framework.
|
|
|
|
== 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<CommandSender> manager = new BukkitCommandManager<>(
|
|
/* Owning plugin */ this,
|
|
AsynchronousCommandExecutionCoordinator.newBuilder().build(), <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.commandframework.cloud/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 <arg>
|
|
/foo <arg> <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.commandframework.cloud/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.newBuilder(name)`.
|
|
This allows you to provide a custom suggestion generator, using `StringArgument.Builder#withSuggestionsProvider(BiFunction<CommandContext<C>, List<String>>)`.
|
|
|
|
===== 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.newBuilder(name)`. This allows you to provide a custom suggestion generator, using `IntegerArgument.Builder#withSuggestionsProvider(BiFunction<CommandContext<C>, List<String>>)`, 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.newBuilder(name)`. This allows you to provide a custom suggestion generator, using `FloatArgument.Builder#withSuggestionsProvider(BiFunction<CommandContext<C>, List<String>>)`, 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
|
|
|
|
==== Custom
|
|
|
|
==== Flags
|
|
|
|
=== Suggestions
|
|
|
|
=== Injection Points
|
|
|
|
==== Preprocessing
|
|
|
|
==== Postprocessing
|
|
|
|
=== Execution Coordinators
|
|
|
|
=== Command Proxies
|
|
|
|
=== Permissions
|
|
|
|
=== Exception Handling
|
|
|
|
=== Command Context
|
|
|
|
=== Command Handler
|
|
|
|
=== Extra
|
|
|
|
==== Translations
|
|
|
|
==== 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<YourSender> confirmationManager = new CommandConfirmationManager<>(
|
|
30L, <1>
|
|
TimeUnit.SECONDS,
|
|
context -> context.getCommandContext().getSender().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
|
|
|
|
== Annotations
|
|
|
|
=== 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.commandframework.cloud/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<C> implements InjectionService<C> {
|
|
|
|
@Override
|
|
public Object handle(CommandContext<C> context, Class<?> clazz) {
|
|
return yourInjectionSystem.injectInstance(clazz);
|
|
}
|
|
|
|
}
|
|
----
|
|
and then register it to the parameter injection registry using
|
|
`manager.parameterInjectionRegistry().registerInjectionService(new YourInjectionService<>())`.
|
|
|
|
== Kotlin DSL
|
|
|
|
== Platforms
|
|
|
|
=== Minecraft
|
|
|
|
==== Bukkit
|
|
|
|
===== Paper
|
|
|
|
===== Brigadier
|
|
|
|
==== Sponge
|
|
|
|
The Sponge implementation is still a work in progress.
|
|
|
|
==== Fabric
|
|
|
|
The Fabric implementation is still a work in progress.
|
|
|
|
=== Discord
|
|
|
|
==== JDA
|
|
|
|
==== Javacord
|
|
|
|
=== IRC
|
|
|
|
[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.
|