Skip to content

Commit 523ab72

Browse files
committed
feat: finish chat argument section
1 parent 5795d57 commit 523ab72

File tree

6 files changed

+592
-0
lines changed

6 files changed

+592
-0
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
---
2+
order: 3
3+
authors:
4+
- JorelAli
5+
- misode
6+
- DerEchtePilz
7+
---
8+
9+
# Adventure chat arguments
10+
11+
:::info
12+
13+
The two following classes, `AdventureChatComponentArgument` and `AdventureChatArgument` depend on a Paper-based server which has the Adventure library. If you use this class on a server without the Adventure library, it will throw a `PaperAdventureNotFoundException`
14+
15+
:::
16+
17+
From Paper 1.16.5 build #473 onwards, Paper now includes [Kyori's Adventure API](https://github.com/KyoriPowered/adventure-platform). This library is a replacement of the BungeeCord chat API and has all the same functionality as the BungeeCord chat API (and more!). The documentation for this API can be found [here](https://docs.adventure.kyori.net/index.html).
18+
19+
Since this functions very similar to the Spigot chat arguments, this page won't reiterate everything about how it works, we'll just outline some examples of how to use these arguments instead.
20+
21+
## Adventure chat color argument
22+
23+
![Chatcolor argument in-game, displaying a list of Minecraft chat colors](/images/arguments/chatcolor.png)
24+
25+
The `AdventureChatColorArgument` class is used to represent a given chat color (e.g., red or green). This argument returns the `NamedTextColor` object. If `reset` is passed to this argument, this will return `NamedTextColor.WHITE`.
26+
27+
::::tip Example – Username color changing plugin
28+
29+
Say we want to create a plugin to change the color of a player's username. We want to create a command of the following form:
30+
31+
```mccmd
32+
/namecolor <chatcolor>
33+
```
34+
35+
We then use the `ChatColorArgument` to change the player's name color:
36+
37+
:::tabs
38+
===Java
39+
<<< @/../reference-code/src/main/java/createcommands/arguments/types/chat/AdventureChatArguments.java#namedTextColorExample
40+
===Kotlin
41+
<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/chat/AdventureChatArguments.kt#namedTextColorExample
42+
===Kotlin DSL
43+
<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/chat/AdventureChatArguments.kt#namedTextColorExampleDSL
44+
:::
45+
46+
::::
47+
48+
## Adventure chat component argument
49+
50+
The `AdventureChatComponentArgument` class accepts raw chat-based JSON as valid input, as declared [here](https://minecraft.wiki/w/Raw_JSON_text_format). This is converted into Adventure's `Component` class.
51+
52+
::::tip Example – Opening a book with raw JSON content
53+
54+
In this example, we'll create a simple command which lets you show a book to a user. The syntax for our command is as follows:
55+
56+
```mccmd
57+
/showbook <target> <title> <author> <contents>
58+
```
59+
60+
We can construct a book using the Adventure API's `Book.book(Component, Component, Component...)` method. To convert our strings into `Component` objects, we use the `Component.text(String)` method. Since Paper supports the Adventure API natively, we can then send this book to a player using the `openBook(Book)` method:
61+
62+
:::tabs
63+
===Java
64+
<<< @/../reference-code/src/main/java/createcommands/arguments/types/chat/AdventureChatArguments.java#componentExample
65+
===Kotlin
66+
<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/chat/AdventureChatArguments.kt#componentExample
67+
===KotlinDSL
68+
<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/chat/AdventureChatArguments.kt#componentExampleDSL
69+
:::
70+
71+
::::
72+
73+
## Adventure chat argument
74+
75+
The `AdventureChatArgument` class is the equivalent Adventure API class for the `ChatArgument` - it represents infinitely long strings similar to the `GreedyStringArgument` and allows entity selectors such as `@e`, `@p` and so on. The `AdventureChatArgument` returns a `Component`, similar to the `AdventureChatComponentArgument`.
76+
77+
::::tip Example – Sending personalized messages to players
78+
79+
We'll take the same example from the `ChatArgument` class, but using the `AdventureChatArgument` instead - We want to create a personalized message broadcasted to all users using a chat component that allows entity selectors. For this command, we want the following syntax:
80+
81+
```mccmd
82+
/pbroadcast <message>
83+
```
84+
85+
To broadcast an Adventure `Component` to all players on the server, we have to use Paper's `broadcast(Component, String)` method. This method requires a permission node which all players must have to receive the broadcasted message. By default, Bukkit-based servers (Spigot and Paper) use the `bukkit.broadcast.user` permission, which is described [here](https://bukkit.fandom.com/wiki/CraftBukkit_Commands#Additional_Permissions):
86+
87+
:::tabs
88+
===Java
89+
<<< @/../reference-code/src/main/java/createcommands/arguments/types/chat/AdventureChatArguments.java#chatArgumentExample
90+
===Kotlin
91+
<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/chat/AdventureChatArguments.kt#chatArgumentExample
92+
===Kotlin DSL
93+
<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/chat/AdventureChatArguments.kt#chatArgumentExampleDSL
94+
95+
:::
96+
97+
::::
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
---
2+
order: 4
3+
authors:
4+
- DerEchtePilz
5+
- willkroboth
6+
- JorelAli
7+
---
8+
9+
# Chat preview
10+
11+
![Chat preview](/images/chatpreview.gif)
12+
13+
Chat preview is a feature introduced in Minecraft 1.19 that allows the server to display a preview of a chat message to the client before the client sends their message to the server. This chat preview feature is also compatible with `/say` and `/msg`, as well as the `ChatArgument` and `AdventureChatArgument` classes.
14+
15+
:::danger Minecraft version support
16+
17+
The chat preview feature is only present in Minecraft versions 1.19, 1.19.1 and 1.19.2. [Chat preview was removed in 1.19.3](https://minecraft.wiki/w/Java_Edition_1.19.3#General_2), so this feature is unfortunately no longer usable in Minecraft 1.19.3 and beyond.
18+
19+
:::
20+
21+
## Enabling chat preview
22+
23+
To use chat preview, your server must have `previews-chat` set to `true` in the `server.properties` file:
24+
25+
```properties
26+
...
27+
previews-chat=true // [!code focus]
28+
...
29+
```
30+
31+
For players that want to use chat preview, they must have `Chat Preview` enabled in `Options > Chat Settings...`
32+
33+
## Specifying a chat preview function
34+
35+
The `ChatArgument` and `AdventureChatArgument` classes include a method, `withPreview`:
36+
37+
```java
38+
public T withPreview(PreviewableFunction preview);
39+
```
40+
41+
The method `withPreview(PreviewableFunction preview)` lets you generate a preview to send to the client. This method takes in the `PreviewableFunction` functional interface, which is a function that takes in a `PreviewInfo` and returns either a `BaseComponent[]` (for `ChatArgument`) or a `Component` (for `AdventureChatArgument`):
42+
43+
```java
44+
public T generatePreview(PreviewInfo info) throws WrapperCommandSyntaxException;
45+
```
46+
47+
The `PreviewInfo` class is a record containing the following:
48+
49+
```java
50+
public record PreviewInfo<T> {
51+
Player player();
52+
String input();
53+
String fullInput();
54+
T parsedInput();
55+
}
56+
```
57+
58+
The following methods are as follows:
59+
60+
```java
61+
Player player();
62+
```
63+
64+
`player()` is the player currently typing a chat preview.
65+
66+
```java
67+
String input();
68+
```
69+
70+
`input()` is the current input for the current `ChatArgument` or `AdventureChatArgument`. If a user is typing `/mycommand hellowor¦` and the command syntax is `/mycommand <ChatArgument>`, the result of `input()` would be `"hellowor"`.
71+
72+
```java
73+
String fullInput();
74+
```
75+
76+
`fullInput()` is the full input that the player has typed, including the leading `/` symbol which is required to start a command. If a user is typing `/mycommand hellowor¦`, the result of `fullInput()` would be `"/mycommand hellowor"`.
77+
78+
```java
79+
T parsedInput();
80+
```
81+
82+
`parsedInput()` is similar to `input()`, except it has been parsed by the CommandAPI's argument parser. This is a representation of what the argument in the executor would look like. For a `ChatArgument` the return type is `BaseComponent[]`, and for `AdventureChatArgument` the return type is `Component`.
83+
84+
## Using the chat preview function as the argument's value
85+
86+
The `ChatArgument` and `AdventureChatArgument` classes also include a method, `usePreview`:
87+
88+
```java
89+
public T usePreview(boolean usePreview);
90+
```
91+
92+
The `usePreview(boolean usePreview)` method lets you specify whether you would like the previewing function to be used as the argument's value during execution. If set to `true`, when the command's `.executes()` method is called, the argument value (e.g. `arg[0]`) will be the same as the content generated by the function provided to `withPreview()`.
93+
94+
## Chat preview examples
95+
96+
::::tip Example – Using chat preview
97+
98+
Say we wanted to make our own `/broadcast` command that allowed the user to use `&` chat colors. We can use chat preview to show users what the result of their `/broadcast` command would look like before running the command. We'll use the following command syntax:
99+
100+
```mccmd
101+
/broadcast <message>
102+
```
103+
104+
Because the `ChatArgument` and `AdventureChatArgument` can support entity selectors (such as `@p`), it's best to use the `info.parsedInput()` method to handle parsed entity selectors. In our code, we use the `.withPreview()` method and take the parsed input and convert it to plain text. We then convert the plain text with `&` characters into component text to be displayed to the user.
105+
106+
For execution, we do the same procedure, because the text that the user enters still has `&` characters that need to be converted into a component.
107+
108+
**Using Adventure Chat API**
109+
110+
:::tabs
111+
===Java
112+
<<< @/../reference-code/src/main/java/createcommands/arguments/types/chat/ChatPreview.java#chatPreviewAdventureExample
113+
===Kotlin
114+
<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/chat/ChatPreview.kt#chatPreviewAdventureExample
115+
:::
116+
117+
**Using Legacy Chat API**
118+
119+
:::tabs
120+
===Java
121+
<<< @/../reference-code/src/main/java/createcommands/arguments/types/chat/ChatPreview.java#chatPreviewLegacyExample
122+
===Kotlin
123+
<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/chat/ChatPreview.kt#chatPreviewLegacyExample
124+
:::
125+
126+
::::
127+
128+
::::tip Example – Using chat preview with `usePreview()`
129+
130+
Extending on the example above where we created a `/broadcast` command with chat preview support, we can simplify the code by using `.usePreview(true)` to use the preview function as the value of our argument in our executor function. We'll use the same command syntax as the previous example:
131+
132+
```mccmd
133+
/broadcast <message>
134+
```
135+
136+
By using `.usePreview(true)`, we don't have to re-translate `&` formatting codes into their corresponding components because that has already been done by the preview function specified in `.withPreview()` method.
137+
138+
**Using Adventure Chat API**
139+
140+
:::tabs
141+
===Java
142+
<<< @/../reference-code/src/main/java/createcommands/arguments/types/chat/ChatPreview.java#usePreviewAdventureExample
143+
===Kotlin
144+
<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/chat/ChatPreview.kt#usePreviewAdventureExample
145+
:::
146+
147+
**Using Legacy Chat API**
148+
149+
:::tabs
150+
===Java
151+
<<< @/../reference-code/src/main/java/createcommands/arguments/types/chat/ChatPreview.java#usePreviewLegacyExample
152+
===Kotlin
153+
<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/chat/ChatPreview.kt#usePreviewLegacyExample
154+
:::
155+
156+
::::
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package createcommands.arguments.types.chat;
2+
3+
import dev.jorel.commandapi.CommandAPICommand;
4+
import dev.jorel.commandapi.arguments.AdventureChatArgument;
5+
import dev.jorel.commandapi.arguments.AdventureChatColorArgument;
6+
import dev.jorel.commandapi.arguments.AdventureChatComponentArgument;
7+
import dev.jorel.commandapi.arguments.PlayerArgument;
8+
import dev.jorel.commandapi.arguments.StringArgument;
9+
import dev.jorel.commandapi.arguments.TextArgument;
10+
import net.kyori.adventure.inventory.Book;
11+
import net.kyori.adventure.text.Component;
12+
import net.kyori.adventure.text.format.NamedTextColor;
13+
import org.bukkit.Bukkit;
14+
import org.bukkit.Server;
15+
import org.bukkit.entity.Player;
16+
17+
class AdventureChatArguments {
18+
{
19+
// #region namedTextColorExample
20+
new CommandAPICommand("namecolor")
21+
.withArguments(new AdventureChatColorArgument("chatcolor"))
22+
.executesPlayer((player, args) -> {
23+
NamedTextColor color = (NamedTextColor) args.get("chatcolor");
24+
player.displayName(Component.text().color(color).append(Component.text(player.getName())).build());
25+
})
26+
.register();
27+
// #endregion namedTextColorExample
28+
29+
// #region componentExample
30+
new CommandAPICommand("showbook")
31+
.withArguments(new PlayerArgument("target"))
32+
.withArguments(new TextArgument("title"))
33+
.withArguments(new StringArgument("author"))
34+
.withArguments(new AdventureChatComponentArgument("contents"))
35+
.executes((sender, args) -> {
36+
Player target = (Player) args.get("target");
37+
String title = (String) args.get("title");
38+
String author = (String) args.get("author");
39+
Component content = (Component) args.get("contents");
40+
41+
// Create a book and show it to the user (Requires Paper)
42+
Book mybook = Book.book(Component.text(title), Component.text(author), content);
43+
target.openBook(mybook);
44+
})
45+
.register();
46+
// #endregion componentExample
47+
48+
// #region chatArgumentExample
49+
new CommandAPICommand("pbroadcast")
50+
.withArguments(new AdventureChatArgument("message"))
51+
.executes((sender, args) -> {
52+
Component message = (Component) args.get("message");
53+
54+
// Broadcast the message to everyone with broadcast permissions.
55+
Bukkit.getServer().broadcast(message, Server.BROADCAST_CHANNEL_USERS);
56+
Bukkit.getServer().broadcast(message);
57+
})
58+
.register();
59+
// #endregion chatArgumentExample
60+
}
61+
}

0 commit comments

Comments
 (0)