oblak/docs
2021-01-14 11:28:48 +01:00
..
_config.yml Set theme jekyll-theme-minimal 2020-12-30 22:52:49 +01:00
README.adoc 📚 Document compound arguments 2021-01-14 11:28:48 +01:00

= 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

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.commandframework.cloud/cloud/commandframework/arguments/compound/ArgumentPair.html[ArgumentPair]
or
https://javadoc.commandframework.cloud/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

==== 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.