|
| 1 | +--- |
| 2 | +slug: /dev/command-api/arguments/adventure-arguments |
| 3 | +description: Documentation for all arguments returning Adventure API objects |
| 4 | +--- |
| 5 | + |
| 6 | +import ComponentMp4 from "./assets/vanilla-arguments/component.mp4" |
| 7 | +import KeyMp4 from "./assets/vanilla-arguments/key.mp4" |
| 8 | +import NamedColorMp4 from "./assets/vanilla-arguments/namedcolor.mp4" |
| 9 | +import StyleMp4 from "./assets/vanilla-arguments/style.mp4" |
| 10 | +import SignedMessageMp4 from "./assets/vanilla-arguments/signedmessage.mp4" |
| 11 | + |
| 12 | +# Adventure Library Arguments |
| 13 | +These arguments return a class from the `net.kyori` package. They are *technically* not native to Minecraft or Bukkit, but as Paper includes the Adventure library, they are |
| 14 | +usually widely used in the Paper ecosystem. |
| 15 | + |
| 16 | + |
| 17 | +## Component Argument |
| 18 | +The component argument is a very complicated command for the user, which is why it should not be used for usual user input. It follows the same format as the `/tellraw <player> <msg>` |
| 19 | +command for its second argument. It accepts a text component as its json representation, returning it as an Adventure component to work with. |
| 20 | + |
| 21 | +### Example usage |
| 22 | +```java |
| 23 | +public static LiteralCommandNode<CommandSourceStack> componentArgument() { |
| 24 | + return Commands.literal("componentargument") |
| 25 | + .then(Commands.argument("arg", ArgumentTypes.component()) |
| 26 | + .executes(ctx -> { |
| 27 | + final Component component = ctx.getArgument("arg", Component.class); |
| 28 | + |
| 29 | + ctx.getSource().getSender().sendRichMessage( |
| 30 | + "Your message: <input>", |
| 31 | + Placeholder.component("input", component) |
| 32 | + ); |
| 33 | + return Command.SINGLE_SUCCESS; |
| 34 | + })) |
| 35 | + .build(); |
| 36 | +} |
| 37 | +``` |
| 38 | + |
| 39 | +### In-game preview |
| 40 | +<FullWidthVideo src={ComponentMp4}/> |
| 41 | + |
| 42 | + |
| 43 | + |
| 44 | +## Key Argument |
| 45 | +The key argument allows a user to put in any artificial (namespaced) key, ensuring its validity. This returns a `net.kyori.adventure.key.Key` from the adventure library, |
| 46 | +which can be used at various other places in the Bukkit/Paper API. |
| 47 | + |
| 48 | +### Example usage |
| 49 | +```java |
| 50 | +public static LiteralCommandNode<CommandSourceStack> keyArgument() { |
| 51 | + return Commands.literal("key") |
| 52 | + .then(Commands.argument("key_input", ArgumentTypes.key()) |
| 53 | + .executes(ctx -> { |
| 54 | + final Key key = ctx.getArgument("key_input", Key.class); |
| 55 | + |
| 56 | + ctx.getSource().getSender().sendRichMessage("You put in <aqua><key></aqua>!", |
| 57 | + Placeholder.unparsed("key", key.asString()) |
| 58 | + ); |
| 59 | + |
| 60 | + return Command.SINGLE_SUCCESS; |
| 61 | + })) |
| 62 | + .build(); |
| 63 | +} |
| 64 | +``` |
| 65 | + |
| 66 | +### In-game preview |
| 67 | +<FullWidthVideo src={KeyMp4}/> |
| 68 | + |
| 69 | + |
| 70 | + |
| 71 | +## Named Color Argument |
| 72 | +This argument provides the user with the ability to select between the 16 build-in "named" text colors. This argument returns a `net.kyori.adventure.text.format.NamedtextColor` that |
| 73 | +you can use for styling components. |
| 74 | + |
| 75 | +### Example usage |
| 76 | +```java |
| 77 | +public static LiteralCommandNode<CommandSourceStack> namedColorArgument() { |
| 78 | + return Commands.literal("namedcolor") |
| 79 | + .then(Commands.argument("color", ArgumentTypes.namedColor()) |
| 80 | + .then(Commands.argument("message", StringArgumentType.greedyString()) |
| 81 | + .executes(ctx -> { |
| 82 | + final NamedTextColor color = ctx.getArgument("color", NamedTextColor.class); |
| 83 | + final String msg = ctx.getArgument("message", String.class); |
| 84 | + |
| 85 | + ctx.getSource().getSender().sendMessage( |
| 86 | + Component.text(msg).color(color) |
| 87 | + ); |
| 88 | + return Command.SINGLE_SUCCESS; |
| 89 | + }))) |
| 90 | + .build(); |
| 91 | +} |
| 92 | +``` |
| 93 | + |
| 94 | +### In-game preview |
| 95 | +<FullWidthVideo src={NamedColorMp4}/> |
| 96 | + |
| 97 | + |
| 98 | + |
| 99 | +## Adventure Style Argument |
| 100 | +:::note |
| 101 | + |
| 102 | +Similar to the component argument, this argument is not really appropriate for general user input, as it also follows the json format for displaying components. Most users |
| 103 | +do not know how to use that format and thus its public usage is not advised. |
| 104 | + |
| 105 | +::: |
| 106 | + |
| 107 | +The style argument returns its value in form of an `net.kyori.adventure.text.format.Style` object. This can be applied to any component using `Component#style(Style)`. |
| 108 | + |
| 109 | +Whilst the json input allows for the `text` field, it does not actually do anything. |
| 110 | + |
| 111 | +### Example usage |
| 112 | +```java |
| 113 | +public static LiteralCommandNode<CommandSourceStack> styleArgument() { |
| 114 | + return Commands.literal("style") |
| 115 | + .then(Commands.argument("style", ArgumentTypes.style()) |
| 116 | + .then(Commands.argument("message", StringArgumentType.greedyString()) |
| 117 | + .executes(ctx -> { |
| 118 | + final Style style = ctx.getArgument("style", Style.class); |
| 119 | + final String message = ctx.getArgument("message", String.class); |
| 120 | + |
| 121 | + ctx.getSource().getSender().sendRichMessage("Your input: <input>", |
| 122 | + Placeholder.component("input", Component.text(message).style(style)) |
| 123 | + ); |
| 124 | + return Command.SINGLE_SUCCESS; |
| 125 | + }))) |
| 126 | + .build(); |
| 127 | +} |
| 128 | +``` |
| 129 | + |
| 130 | +### In-game preview |
| 131 | +<FullWidthVideo src={StyleMp4}/> |
| 132 | + |
| 133 | + |
| 134 | + |
| 135 | +## Signed Message Argument |
| 136 | +The signed message argument allows a player (not a console!!) to send an argument in form of a **signed message** to the server. This signed message is a special type - it |
| 137 | +allows the server to send that message, without the ability to directly modify it, to any player. The visible difference is that unsigned messages have a white bar at the left, |
| 138 | +whilst signed messages don't. |
| 139 | + |
| 140 | +A signed message argument returns a `SignedMessageResolver`. In order to call its `#resolve` method, you have to pass in two parameters: |
| 141 | +* The argument name |
| 142 | +* The `CommandContext<CommandSourceStack>` object |
| 143 | + |
| 144 | +You then get returned with a `CompletableFuture<SignedMessage>`. In order to work with the resulting `SignedMessage`, you can call `CompletableFuture<T>#thenAccept(Consumer<T>)` |
| 145 | +on that resulting completable future. Inside of that, you can send the signed message to players or work with it in other ways. |
| 146 | + |
| 147 | +:::warning |
| 148 | + |
| 149 | +The use of thread unsafe Bukkit API inside the `.thenAccept` method is not supported, as this is an asynchronous method, which does not run on the main thread. |
| 150 | +If you need to use Bukkit API, you can schedule a task to be run on the next available tick. You can read up on that **here** (WIP). |
| 151 | + |
| 152 | +::: |
| 153 | + |
| 154 | +:::note |
| 155 | + |
| 156 | +A non-player sender is not capable of sending a signed message, which means that the method block inside the `#thenAccept` method of the `SignedMessageResolver#resolve` method |
| 157 | +will never be called. You should make sure to put a `.requires(ctx -> ctx.getSender() instanceof Player)` on your SignedArgument to only allow Players to run it. You may |
| 158 | +add a fallback greedy string argument for non-player senders if you want the argument to execute regardless of signing or not. |
| 159 | + |
| 160 | +::: |
| 161 | + |
| 162 | +### Example usage |
| 163 | +```java title="MinecraftArguments.java" |
| 164 | +public static LiteralCommandNode<CommandSourceStack> signedMessageArgument() { |
| 165 | + return Commands.literal("signedmessage") |
| 166 | + .then(Commands.argument("target", ArgumentTypes.player()) |
| 167 | + .then(Commands.argument("message", ArgumentTypes.signedMessage()) |
| 168 | + .executes(MinecraftArguments::executeSignedMessageCommand))) |
| 169 | + .build(); |
| 170 | +} |
| 171 | + |
| 172 | +private static int executeSignedMessageCommand(final CommandContext<CommandSourceStack> ctx) throws CommandSyntaxException { |
| 173 | + final Player target = ctx.getArgument("target", PlayerSelectorArgumentResolver.class).resolve(ctx.getSource()).getFirst(); |
| 174 | + final SignedMessageResolver messageResolver = ctx.getArgument("message", SignedMessageResolver.class); |
| 175 | + |
| 176 | + messageResolver.resolveSignedMessage("message", ctx).thenAccept(msg -> { |
| 177 | + target.sendMessage(msg, ChatType.CHAT.bind(ctx.getSource().getSender().name())); |
| 178 | + }); |
| 179 | + |
| 180 | + |
| 181 | + return Command.SINGLE_SUCCESS; |
| 182 | +} |
| 183 | +``` |
| 184 | + |
| 185 | +### In-game preview |
| 186 | +<FullWidthVideo src={SignedMessageMp4}/> |
0 commit comments