Skip to main content

Adventure Library Arguments

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 usually widely used in the Paper ecosystem.

Component Argument

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> command for its second argument. It accepts a text component as its json representation, returning it as an Adventure component to work with.

Example usage

public static LiteralCommandNode<CommandSourceStack> componentArgument() {
return Commands.literal("componentargument")
.then(Commands.argument("arg", ArgumentTypes.component())
.executes(ctx -> {
final Component component = ctx.getArgument("arg", Component.class);

ctx.getSource().getSender().sendRichMessage(
"Your message: <input>",
Placeholder.component("input", component)
);
return Command.SINGLE_SUCCESS;
}))
.build();
}

In-game preview

Key Argument

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, which can be used at various other places in the Bukkit/Paper API.

Example usage

public static LiteralCommandNode<CommandSourceStack> keyArgument() {
return Commands.literal("key")
.then(Commands.argument("key_input", ArgumentTypes.key())
.executes(ctx -> {
final Key key = ctx.getArgument("key_input", Key.class);

ctx.getSource().getSender().sendRichMessage("You put in <aqua><key></aqua>!",
Placeholder.unparsed("key", key.asString())
);

return Command.SINGLE_SUCCESS;
}))
.build();
}

In-game preview

Named Color Argument

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 you can use for styling components.

Example usage

public static LiteralCommandNode<CommandSourceStack> namedColorArgument() {
return Commands.literal("namedcolor")
.then(Commands.argument("color", ArgumentTypes.namedColor())
.then(Commands.argument("message", StringArgumentType.greedyString())
.executes(ctx -> {
final NamedTextColor color = ctx.getArgument("color", NamedTextColor.class);
final String msg = ctx.getArgument("message", String.class);

ctx.getSource().getSender().sendMessage(
Component.text(msg).color(color)
);
return Command.SINGLE_SUCCESS;
})))
.build();
}

In-game preview

Adventure Style Argument

note

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 do not know how to use that format and thus its public usage is not advised.

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).

Whilst the json input allows for the text field, it does not actually do anything.

Example usage

public static LiteralCommandNode<CommandSourceStack> styleArgument() {
return Commands.literal("style")
.then(Commands.argument("style", ArgumentTypes.style())
.then(Commands.argument("message", StringArgumentType.greedyString())
.executes(ctx -> {
final Style style = ctx.getArgument("style", Style.class);
final String message = ctx.getArgument("message", String.class);

ctx.getSource().getSender().sendRichMessage("Your input: <input>",
Placeholder.component("input", Component.text(message).style(style))
);
return Command.SINGLE_SUCCESS;
})))
.build();
}

In-game preview

Signed Message Argument

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 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, whilst signed messages don't.

A signed message argument returns a SignedMessageResolver. In order to call its #resolve method, you have to pass in two parameters:

  • The argument name
  • The CommandContext<CommandSourceStack> object

You then get returned with a CompletableFuture<SignedMessage>. In order to work with the resulting SignedMessage, you can call CompletableFuture<T>#thenAccept(Consumer<T>) on that resulting completable future. Inside of that, you can send the signed message to players or work with it in other ways.

warning

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. 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).

note

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 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 add a fallback greedy string argument for non-player senders if you want the argument to execute regardless of signing or not.

Example usage

MinecraftArguments.java
public static LiteralCommandNode<CommandSourceStack> signedMessageArgument() {
return Commands.literal("signedmessage")
.then(Commands.argument("target", ArgumentTypes.player())
.then(Commands.argument("message", ArgumentTypes.signedMessage())
.executes(MinecraftArguments::executeSignedMessageCommand)))
.build();
}

private static int executeSignedMessageCommand(final CommandContext<CommandSourceStack> ctx) throws CommandSyntaxException {
final Player target = ctx.getArgument("target", PlayerSelectorArgumentResolver.class).resolve(ctx.getSource()).getFirst();
final SignedMessageResolver messageResolver = ctx.getArgument("message", SignedMessageResolver.class);

messageResolver.resolveSignedMessage("message", ctx).thenAccept(msg -> {
target.sendMessage(msg, ChatType.CHAT.bind(ctx.getSource().getSender().name()));
});


return Command.SINGLE_SUCCESS;
}

In-game preview