Skip to content

Commit 1c2cf26

Browse files
feat: Improve basic commands page (#634)
Co-authored-by: Malfrador <[email protected]>
1 parent c339963 commit 1c2cf26

File tree

2 files changed

+79
-31
lines changed

2 files changed

+79
-31
lines changed

src/content/docs/paper/dev/api/command-api/basics/introduction.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ To see a comparison between the new Brigadier system and the old Bukkit system,
1818
:::
1919

2020
## Guide
21+
22+
:::tip
23+
24+
If the Brigadier API seems too complicated, you can start with
25+
[basic commands](/paper/dev/command-api/misc/basic-command). They
26+
provide a simple way of creating commands, with only a small learning curve.
27+
28+
:::
29+
2130
The following sites are worth-while to look through first when learning about Brigadier:
2231
- [The Command Tree](/paper/dev/command-api/basics/command-tree)
2332
- [Arguments and Literals](/paper/dev/command-api/basics/arguments-and-literals)

src/content/docs/paper/dev/api/command-api/misc/basic-command.md

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
title: Basic commands
33
description: An overview of a Bukkit-style command declaration using Brigadier.
44
slug: paper/dev/command-api/misc/basic-command
5+
version: 1.21.1
56
---
67

78
For very simple commands Paper has a way to declare Bukkit-style commands by implementing the [`BasicCommand`](jd:paper:io.papermc.paper.command.brigadier.BasicCommand) interface.
89

910
This interface has one method you have to override:
10-
- `void execute(CommandSourceStack commandSourceStack, String[] args)`
11+
- `void execute(CommandSourceStack source, String[] args)`
1112

1213
And three more, optional methods which you can, but don't have to override:
13-
- `Collection<String> suggest(CommandSourceStack commandSourceStack, String[] args)`
14+
- `Collection<String> suggest(CommandSourceStack source, String[] args)`
1415
- `boolean canUse(CommandSender sender)`
1516
- `@Nullable String permission()`
1617

@@ -27,20 +28,17 @@ import org.jspecify.annotations.NullMarked;
2728
public class YourCommand implements BasicCommand {
2829

2930
@Override
30-
public void execute(CommandSourceStack commandSourceStack, String[] args) {
31+
public void execute(CommandSourceStack source, String[] args) {
3132

3233
}
3334
}
3435
```
3536

36-
If you have seen the `CommandContext<CommandSourceStack>` class before, you might recognize the first parameter of the execute method as the generic
37-
parameter `S` from our `CommandContext<S>`, which is also used in the `executes` method from the `ArgumentBuilder`.
38-
39-
With a `CommandSourceStack`, we can retrieve basic information about the sender of the command, the location the command was send from, and the executing entity.
40-
For more information, check out [basics/command-executors](/paper/dev/command-api/basics/executors).
37+
With a `CommandSourceStack` you can retrieve basic information about the sender of the command, the location the command was send from,
38+
and the entity for which the command was executed for. You can find more information on [our page on command executors](/paper/dev/command-api/basics/executors).
4139

4240
## The optional methods
43-
You can freely choose whether to implement either of the at the top mentioned, optional methods. Here is a quick overview on what which one does:
41+
You can freely choose whether to implement either of the mentioned, optional methods. Here is a quick overview on what which one does:
4442

4543
### `suggest(CommandSourceStack, String[])`
4644
This method returns some sort of `Collection<String>` and takes in a `CommandSourceStack` and a `String[] args` as parameters. This is similar to the
@@ -52,9 +50,52 @@ Each entry in the collection that you return will be send to the client to be sh
5250
With this method, you can set up a basic `requires` structure from Brigadier commands. [You can read more on that here](/paper/dev/command-api/basics/requirements).
5351
This method returns a `boolean`, which is required to return `true` in order for a command sender to be able to execute that command.
5452

53+
:::note
54+
55+
If you override this method, overriding `permission()` does nothing. This is because the default implementation
56+
uses the return value of `permission()`, which wouldn't be used anymore if you were to override it.
57+
58+
```java title="BasicCommand.java"
59+
default boolean canUse(final CommandSender sender) {
60+
final String permission = this.permission();
61+
return permission == null || sender.hasPermission(permission);
62+
}
63+
```
64+
65+
:::
66+
5567
### `permission()`
5668
With the permission method you can, similar to the `canUse` method, set the permission required to be able to execute and view this command.
5769

70+
## Registering basic commands
71+
Registering a `BasicCommand` is very simple: In your plugin's main class, you can simply call one of the
72+
[`registerCommand(...)`](jd:paper:org.bukkit.plugin.java.JavaPlugin#registerCommand(java.lang.String,io.papermc.paper.command.brigadier.BasicCommand))
73+
methods inside the `onEnable` method.
74+
75+
```java title="YourPlugin.java"
76+
public class YourPlugin extends JavaPlugin {
77+
78+
@Override
79+
public void onEnable() {
80+
BasicCommand yourCommand = ...;
81+
registerCommand("mycommand", yourCommand);
82+
}
83+
}
84+
```
85+
86+
### Basic commands are functional interfaces
87+
Because you only have to override one method, you can directly pass in a lambda statement. This is not recommended for styling
88+
reasons, as it makes the code harder to read.
89+
90+
```java
91+
@Override
92+
public void onEnable() {
93+
registerCommand(
94+
"quickcmd",
95+
(source, args) -> source.getSender().sendRichMessage("<yellow>Hello!")
96+
);
97+
}
98+
```
5899

59100
## Example: Broadcast command
60101
As an example, we can create a simple broadcast command. We start by declaring creating a class which implements `BasicCommand` and overrides `execute` and `permission`:
@@ -71,7 +112,7 @@ import org.jspecify.annotations.Nullable;
71112
public class BroadcastCommand implements BasicCommand {
72113

73114
@Override
74-
public void execute(CommandSourceStack commandSourceStack, String[] args) {
115+
public void execute(CommandSourceStack source, String[] args) {
75116

76117
}
77118

@@ -88,9 +129,9 @@ operator permissions. You can also set this permission to be `true` by default.
88129
Now, in our `execute` method, we can retrieve the name of the executor of that command. If we do not find one, we can just get the name of the command sender, like this:
89130

90131
```java
91-
final Component name = commandSourceStack.getExecutor() != null
92-
? commandSourceStack.getExecutor().name()
93-
: commandSourceStack.getSender().name();
132+
final Component name = source.getExecutor() != null
133+
? source.getExecutor().name()
134+
: source.getSender().name();
94135
```
95136

96137
This makes sure that we cover all cases and even allow the command to work correctly with `/execute as`.
@@ -99,7 +140,7 @@ Next, we retrieve all arguments and join them to a string or tell the sender tha
99140
arguments (meaning that `args` has a length of 0):
100141
```java
101142
if (args.length == 0) {
102-
commandSourceStack.getSender().sendRichMessage("<red>You cannot send an empty broadcast!");
143+
source.getSender().sendRichMessage("<red>You cannot send an empty broadcast!");
103144
return;
104145
}
105146

@@ -136,13 +177,13 @@ import org.jspecify.annotations.Nullable;
136177
public class BroadcastCommand implements BasicCommand {
137178

138179
@Override
139-
public void execute(CommandSourceStack commandSourceStack, String[] args) {
140-
final Component name = commandSourceStack.getExecutor() != null
141-
? commandSourceStack.getExecutor().name()
142-
: commandSourceStack.getSender().name();
180+
public void execute(CommandSourceStack source, String[] args) {
181+
final Component name = source.getExecutor() != null
182+
? source.getExecutor().name()
183+
: source.getSender().name();
143184

144185
if (args.length == 0) {
145-
commandSourceStack.getSender().sendRichMessage("<red>You cannot send an empty broadcast!");
186+
source.getSender().sendRichMessage("<red>You cannot send an empty broadcast!");
146187
return;
147188
}
148189

@@ -163,28 +204,26 @@ public class BroadcastCommand implements BasicCommand {
163204
}
164205
```
165206

166-
Registering our command looks like this:
207+
Registering the command looks like this:
167208

168209
```java title="PluginMainClass.java"
169210
@Override
170211
public void onEnable() {
171-
this.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS,
172-
event -> event.registrar().register("broadcast", new BroadcastCommand())
173-
);
212+
registerCommand("broadcast", new BroadcastCommand());
174213
}
175214
```
176215

177216
And this is how it looks like in-game:
178217
![](./assets/broadcast-command.png)
179218

180219

181-
## Example: Adding suggestions
220+
### Adding suggestions
182221
Our broadcast command works pretty well, but it is lacking on suggestions. A very common kind of suggestion for text based commands are player names.
183222
In order to suggest player names, we can just map all online players to their name, like this:
184223

185224
```java
186225
@Override
187-
public Collection<String> suggest(CommandSourceStack commandSourceStack, String[] args) {
226+
public Collection<String> suggest(CommandSourceStack source, String[] args) {
188227
return Bukkit.getOnlinePlayers().stream().map(Player::getName).toList();
189228
}
190229
```
@@ -239,13 +278,13 @@ import java.util.Collection;
239278
public class BroadcastCommand implements BasicCommand {
240279

241280
@Override
242-
public void execute(CommandSourceStack commandSourceStack, String[] args) {
243-
final Component name = commandSourceStack.getExecutor() != null
244-
? commandSourceStack.getExecutor().name()
245-
: commandSourceStack.getSender().name();
281+
public void execute(CommandSourceStack source, String[] args) {
282+
final Component name = source.getExecutor() != null
283+
? source.getExecutor().name()
284+
: source.getSender().name();
246285

247286
if (args.length == 0) {
248-
commandSourceStack.getSender().sendRichMessage("<red>You cannot send an empty broadcast!");
287+
source.getSender().sendRichMessage("<red>You cannot send an empty broadcast!");
249288
return;
250289
}
251290

@@ -265,7 +304,7 @@ public class BroadcastCommand implements BasicCommand {
265304
}
266305

267306
@Override
268-
public Collection<String> suggest(CommandSourceStack commandSourceStack, String[] args) {
307+
public Collection<String> suggest(CommandSourceStack source, String[] args) {
269308
if (args.length == 0) {
270309
return Bukkit.getOnlinePlayers().stream().map(Player::getName).toList();
271310
}

0 commit comments

Comments
 (0)