|
| 1 | +--- |
| 2 | +order: 1 |
| 3 | +authors: |
| 4 | + - JorelAli |
| 5 | +--- |
| 6 | + |
| 7 | +# Annotation-based commands |
| 8 | + |
| 9 | +The CommandAPI also includes a very small lightweight annotation-based command framework. This works very differently compared to previous commands shown in this documentation and **it is less feature-rich than registering commands using the other methods.** |
| 10 | + |
| 11 | +In short, the CommandAPI's annotation-based system: |
| 12 | + |
| 13 | +- Has no runtime overhead compared to using the regular command registration system (unlike other annotation-based frameworks such as [ACF](https://github.com/aikar/commands)). |
| 14 | +- Reduces code bloat (to an extent). |
| 15 | +- Improves readability since commands are declared declaratively instead of imperatively. |
| 16 | +- Is not as powerful as the regular command registration system. |
| 17 | + |
| 18 | +:::info |
| 19 | + |
| 20 | +Currently, the annotation framework is in its infancy, so any suggestions or improvements are heavily appreciated! |
| 21 | + |
| 22 | +::: |
| 23 | + |
| 24 | +:::danger Developer's Note: |
| 25 | + |
| 26 | +As of the time of writing, annotation-based commands are **not** compatible with the Kotlin programming language! The CommandAPI does have the [Kotlin DSL](../kotlin-dsl/intro.md) instead, which is leaner, cleaner and provides a much more Kotliny experience! |
| 27 | + |
| 28 | +::: |
| 29 | + |
| 30 | +Before we go into too much detail, let's take a look at an example of what this annotation framework looks like, and compare this to the existing method. |
| 31 | + |
| 32 | +## Example: A warp command |
| 33 | + |
| 34 | +Let's say we're writing a plugin with the capability to create warps to places on the server. To do this, we'll make a simple command `/warp`, defined as follows: |
| 35 | + |
| 36 | +```mccmd |
| 37 | +/warp - Shows help |
| 38 | +/warp <warp> - Teleports a player to <warp> |
| 39 | +/warp create <name> - Creates a new warp <name> at the player's location |
| 40 | +``` |
| 41 | + |
| 42 | +### Warp command (without annotations) |
| 43 | + |
| 44 | +Using the regular CommandAPI, this is one way we can create this command. In the code below, we use StringArguments to represent the warp names. To teleport to a warp, we also populate it with suggestions (deferred so it updates), and also use a subcommand to represent `/warp create`: |
| 45 | + |
| 46 | +<<< @/../reference-code/src/main/java/annotations/Intro.java#legacyExample |
| 47 | + |
| 48 | +Seems fairly straightforward, given everything else covered in this documentation. Now let's compare it to using annotations! |
| 49 | + |
| 50 | +### Warp command (with annotations) |
| 51 | + |
| 52 | +I think it's best to show the example and the explain it afterwards: |
| 53 | + |
| 54 | +<<< @/../reference-code/src/main/java/annotations/Intro.java#annotationsExample |
| 55 | + |
| 56 | +<<< @/../reference-code/src/main/java/annotations/Intro.java#annotationsRegisterExample |
| 57 | + |
| 58 | +As we can see, the code certainly _looks_ very different to the normal registration method. Let's take it apart piece by piece to see what exactly is going on here. |
| 59 | + |
| 60 | +#### Command declaration |
| 61 | + |
| 62 | +<<< @/../reference-code/src/main/java/annotations/Intro.java#declareCommand |
| 63 | + |
| 64 | +Firstly, we declare our command `warp`. To do this, we use the `@Command` annotation and simply state the name of the command in the annotation. This annotation is attached to the class `WarpCommand`, which indicates that the whole class `WarpCommand` will be housing our command. |
| 65 | + |
| 66 | +The annotation framework is designed in such a way that an entire command is represented by a single class. This provides a more modular approach to command declaration that allows you to easily contain the methods of a command in one location. |
| 67 | + |
| 68 | +#### Default command |
| 69 | +<<< @/../reference-code/src/main/java/annotations/Intro.java#defaultExample |
| 70 | + |
| 71 | +Here, declare the main command implementation using the `@Default` annotation. The `@Default` annotation informs the CommandAPI that the method it is attached to does not have any subcommands. This is effectively the same as registering a regular command without using `.withSubcommand()`. |
| 72 | + |
| 73 | +Here, we simply write what happens when no arguments are run (i.e. the user just runs `/warp` on its own). As such, we don't include any parameters to our method. |
| 74 | + |
| 75 | +#### Default command (again!) |
| 76 | + |
| 77 | +<<< @/../reference-code/src/main/java/annotations/Intro.java#anotherDefaultExample |
| 78 | + |
| 79 | +We also have a second `@Default` annotated method, which handles our `/warp <warp>` command. Because this isn't a subcommand (the warp to teleport to is not a subcommand, it's an argument), we still using the `@Default` annotation. In this method, we include an argument with this command by using the `@AStringArgument` annotation. This argument uses the `StringArgument` class, and the name of this argument is "warpName", which is extracted from the name of the variable. Simply put, **the Annotation for an argument is A** followed by the name of the argument. This is synonymous with using the following: |
| 80 | + |
| 81 | +```java |
| 82 | +new StringArgument("warp") |
| 83 | +``` |
| 84 | + |
| 85 | +It's also very important to note the parameters for this method. The first parameter is a `Player` object, which represents our command sender. The CommandAPI's annotation system uses the fact that the command sender is a `Player` object and automatically ensures that anyone using the command must be a `Player`. In other words, non-players (such as the console or command blocks), would be unable to execute this command. |
| 86 | + |
| 87 | +The second argument is a `String` object, which represents the result of our argument "warp". The CommandAPI's annotation system can also infer the return type of the argument that is provided to it (in this case, a `StringArgument` will produce a `String`) and will automatically cast and provide the result to that parameter. |
| 88 | + |
| 89 | +#### Subcommand |
| 90 | + |
| 91 | +<<< @/../reference-code/src/main/java/annotations/Intro.java#subcommandExample |
| 92 | + |
| 93 | +Lastly, we declare a subcommand to allow us to run `/warp create <name>`. To do this, we simply use the `@Subcommand` annotation. In this example, we also apply a permission node that is required to run the command by using the `@Permission` annotation. The rest is fairly straight forward - we declare an argument, in this case it's another `StringArgument` , so we use `@AStringArgument` and then declare everything else in a similar fashion to the default command executor. |
| 94 | + |
| 95 | +#### Registering the command |
| 96 | + |
| 97 | +Registering the command is fairly simple and is a one liner: |
| 98 | + |
| 99 | +<<< @/../reference-code/src/main/java/annotations/Intro.java#annotationsRegisterExample |
| 100 | + |
| 101 | +This line can be placed in your `onEnable()` or `onLoad()` method like you were registering a normal command. |
0 commit comments