8000 Merge pull request #1 from Bram1903/feat/AsyncOfflinePlayerArgument · CommandAPI/docs@e28728d · GitHub
[go: up one dir, main page]

Skip to content

Commit e28728d

Browse files
authored
Merge pull request #1 from Bram1903/feat/AsyncOfflinePlayerArgument
[Feat] AsyncOfflinePlayerArgument Documentation CommandAPI/CommandAPI#633
2 parents 008f2ec + 3651187 commit e28728d

File tree

3 files changed

+120
-1
lines changed

3 files changed

+120
-1
lines changed

docs/en/create-commands/arguments/types/entities-arguments.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,41 @@ And there we have it! One thing to note is that entity selectors are still a val
103103

104104
## OfflinePlayer argument
105105

106-
The `OfflinePlayerArgument` class is identical to the `PlayerArgument` class, but instead of returning a `Player` object, it returns an `OfflinePlayer` object. Internally, this argument makes calls to Mojang servers (via Mojang's authlib), meaning it can be slightly slower than alternative methods (such as using a `StringArgument` and suggesting a list of existing offline players).
106+
The `OfflinePlayerArgument` class is identical to the `PlayerArgument` class, but instead of returning a `Player` object, it returns an `OfflinePlayer` object. Internally, this argument makes calls to Mojang servers (via Mojang's authlib), meaning it can be slightly slower than alternative methods such as using a `AsyncOfflinePlayerArgument`, which runs the API call asynchronously, or using a `StringArgument` and suggesting a list of existing offline players.
107107

108108
The `OfflinePlayerArgument` _should_ be able to retrieve players that have never joined the server before.
109109

110+
## AsyncOfflinePlayer argument
111+
112+
The `AsyncOfflinePlayerArgument` class is identical to the `OfflinePlayerArgument` class, but instead of making the API call synchronously, it makes the API call asynchronously. This means that the command will not block the main thread while waiting for the API call to complete.
113+
114+
:::info
115+
The `AsyncOfflinePlayerArgument` returns a `CompletableFuture<OfflinePlayer>` object, which can be used to retrieve the `OfflinePlayer` object when the API call is complete.
116+
:::
117+
118+
::::tip Example - Checking if a player has joined before
119+
120+
Say we want to create a command that tells us if a player has joined the server before. We can use the `AsyncOfflinePlayerArgument` to fetch the `OfflinePlayer` object asynchronously. That way we simply wait for the request to complete, and once it does, we can check if the player has joined the server before. We want to create a command of the following form:
121+
122+
```mccmd
123+
/playedbefore <player>
124+
```
125+
126+
We now want to get the `CompletableFuture<OfflinePlayer>` object from the `AsyncOfflinePlayerArgument` and then use it to get the `OfflinePlayer` object. We can define it like this:
127+
128+
:::tabs
129+
===Java
130+
<<< @/../reference-code/src/main/java/createcommands/arguments/types/EntitiesArguments.java#playedBeforeArgumentExample
131+
===Kotlin
132+
<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/EntitiesArguments.kt#playedBeforeArgumentExample
133+
===Kotlin DSL
134+
<<< @/../reference-code/src/main/kotlin/createcommands/arguments/types/EntitiesArguments.kt#playedBeforeArgumentExampleDSL
135+
:::
136+
137+
We now successfully ran a command that asynchronously checks if a player has joined the server before without blocking the main thread despite making an API call.
138+
139+
::::
140+
110141
## Entity type argument
111142

112143
![An image of an entity argument displaying a list of entity type suggestions](/images/arguments/entitytype.png)

reference-code/src/main/java/createcommands/arguments/types/EntitiesArguments.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@
22

33
import dev.jorel.commandapi.CommandAPICommand;
44
import dev.jorel.commandapi.arguments.Argument;
5+
import dev.jorel.commandapi.arguments.AsyncOfflinePlayerArgument;
56
import dev.jorel.commandapi.arguments.EntitySelectorArgument;
67
import dev.jorel.commandapi.arguments.EntityTypeArgument;
78
import dev.jorel.commandapi.arguments.IntegerArgument;
89
import dev.jorel.commandapi.arguments.PlayerArgument;
910
import dev.jorel.commandapi.arguments.SafeSuggestions;
1011
import dev.jorel.commandapi.executors.CommandArguments;
1112
import org.bukkit.Bukkit;
13+
import org.bukkit.OfflinePlayer;
1214
import org.bukkit.entity.Entity;
1315
import org.bukkit.entity.EntityType;
1416
import org.bukkit.entity.Player;
1517

1618
import java.util.Collection;
19+
import java.util.concurrent.CompletableFuture;
1720

1821
class EntitiesArguments {
1922
static {
@@ -51,6 +54,33 @@ class EntitiesArguments {
5154
.register();
5255
// #endregion noSelectorSuggestionsExample
5356

57+
// #region playedBeforeArgumentExample
58+
new CommandAPICommand("playedbefore")
59+
.withArguments(new AsyncOfflinePlayerArgument("player"))
60+
.executes((sender, args) -> {
61+
CompletableFuture<OfflinePlayer> player = (CompletableFuture<OfflinePlayer>) args.get("player");
62+
63+
// Directly sends a message to the sender, indicating that the command is running to prevent confusion
64+
sender.sendMessage("Checking if the player has played before...");
65+
66+
player.thenAccept(offlinePlayer -> {
67+
if (offlinePlayer.hasPlayedBefore()) {
68+
sender.sendMessage("Player has played before");
69+
} else {
70+
sender.sendMessage("Player has never played before");
71+
}
72+
}).exceptionally(throwable -> {
73+
// We have to partly handle exceptions ourselves, since we are using a CompletableFuture
74+
Throwable cause = throwable.getCause();
75+
Throwable rootCause = cause instanceof RuntimeException ? cause.getCause() : cause;
76+
77+
sender.sendMessage(rootCause.getMessage());
78+
return null;
79+
});
80+
})
81+
.register();
82+
// #endregion playedBeforeArgumentExample
83+
5484
// #region entityTypeArgumentExample
5585
new CommandAPICommand("spawnmob")
5686
.withArguments(new EntityTypeArgument("entity"))
9E88

reference-code/src/main/kotlin/createcommands/arguments/types/EntitiesArguments.kt

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package createcommands.arguments.types
22

33
import dev.jorel.commandapi.CommandAPICommand
4+
import dev.jorel.commandapi.arguments.AsyncOfflinePlayerArgument
45
import dev.jorel.commandapi.arguments.EntitySelectorArgument
56
import dev.jorel.commandapi.arguments.EntityTypeArgument
67
import dev.jorel.commandapi.arguments.IntegerArgument
@@ -10,14 +11,17 @@ import dev.jorel.commandapi.executors.CommandExecutor
1011
import dev.jorel.commandapi.executors.PlayerCommandExecutor
1112
import dev.jorel.commandapi.kotlindsl.anyExecutor
1213
import dev.jorel.commandapi.kotlindsl.commandAPICommand
14+
import dev.jorel.commandapi.kotlindsl.asyncOfflinePlayerArgument
1315
import dev.jorel.commandapi.kotlindsl.entitySelectorArgumentManyEntities
1416
import dev.jorel.commandapi.kotlindsl.entityTypeArgument
1517
import dev.jorel.commandapi.kotlindsl.integerArgument
1618
import dev.jorel.commandapi.kotlindsl.playerExecutor
1719
import org.bukkit.Bukkit
20+
import org.bukkit.OfflinePlayer
1821
import org.bukkit.entity.Entity
1922
import org.bukkit.entity.EntityType
2023
import org.bukkit.entity.Player
24+
import java.util.concurrent.CompletableFuture
2125

2226
fun entitiesArguments() {
2327
// #region entitySelectorArgumentExample
@@ -53,6 +57,33 @@ fun entitiesArguments() {
5357
.register()
5458
// #endregion noSelectorSuggestionsExample
5559

60+
// #region playedBeforeArgumentExample
61+
CommandAPICommand("playedbefore")
62+
.withArguments(AsyncOfflinePlayerArgument("player"))
63+
.executes(CommandExecutor { sender, args ->
64+
val player = args["player"] as CompletableFuture<OfflinePlayer>
65+
66+
// Directly sends a message to the sender, indicating that the command is running to prevent confusion
67+
sender.sendMessage("Checking if the player has played before...")
68+
69+
player.thenAccept { offlinePlayer ->
70+
if (offlinePlayer.hasPlayedBefore()) {
71+
sender.sendMessage("Player has played before")
72+
} else {
73+
sender.sendMessage("Player has never played before")
74+
}
75+
}.exceptionally { throwable ->
76+
// We have to partly handle exceptions ourselves, since we are using a CompletableFuture
77+
val cause = throwable.cause
78+
val rootCause = if (cause is RuntimeException) cause.cause else cause
79+
80+
sender.sendMessage(rootCause?.message ?: "An error occurred")
81+
null
82+
}
83+
})
84+
.register()
85+
// #endregion playedBeforeArgumentExample
86+
5687
// #region entityTypeArgumentExample
5788
CommandAPICommand("spawnmob")
5889
.withArguments(EntityTypeArgument("entity"))
@@ -83,6 +114,33 @@ fun entitiesArgumentsDSL() {
83114
}
84115
// #endregion entitySelectorArgumentExampleDSL
85116

117+
// #region playedBeforeArgumentExampleDSL
118+
commandAPICommand("playedbefore") {
119+
asyncOfflinePlayerArgument("player")
120+
anyExecutor { sender, args ->
121+
val player = args["player"] as CompletableFuture<OfflinePlayer>
122+
123+
// Directly sends a message to the sender, indicating that the command is running to prevent confusion
124+
sender.sendMessage("Checking if the player has played before...")
125+
126+
player.thenAccept { offlinePlayer ->
127+
if (offlinePlayer.hasPlayedBefore()) {
128+
sender.sendMessage("Player has played before")
129+
} else {
130+
sender.sendMessage("Player has never played before")
131+
}
132+
}.exceptionally { throwable ->
133+
// We have to partly handle exceptions ourselves, since we are using a CompletableFuture
134+
val cause = throwable.cause
135+
val rootCause = if (cause is RuntimeException) cause.cause else cause
136+
137+
sender.sendMessage(rootCause?.message ?: "An error occurred")
138+
null
139+
}
140+
}
141+
}
142+
// #endregion playedBeforeArgumentExampleDSL
143+
86144
// #region entityTypeArgumentExampleDSL
87145
commandAPICommand("spawnmob") {
88146
entityTypeArgument("entity")

0 commit comments

Comments
 (0)
0