Adventure chat arguments

Developer's Note:

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

From Paper 1.16.5 build #473 onwards, Paper now includes Kyori's Adventure API. This library is a replacement of the BungeeCord chat API and has all of the same functionality as the BungeeCord chat API (and more!). The documentation for this API can be found here.

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.


Adventure chat color argument

Chatcolor argument in-game, displaying a list of Minecraft chat colors

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.

Example - Username color changing plugin

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:

/namecolor <chatcolor>

We then use the ChatColorArgument to change the player's name color:

new CommandAPICommand("namecolor")
    .withArguments(new AdventureChatColorArgument("chatcolor"))
    .executesPlayer((player, args) -> {
        NamedTextColor color = (NamedTextColor) args.get("chatcolor");
        player.displayName(Component.text().color(color).append(Component.text(player.getName())).build());
    })
    .register();
CommandAPICommand("namecolor")
    .withArguments(AdventureChatColorArgument("chatcolor"))
    .executesPlayer(PlayerCommandExecutor { player, args ->
        val color = args["chatcolor"] as NamedTextColor
        player.displayName(Component.text().color(color).append(Component.text(player.name)).build())
    })
    .register()
commandAPICommand("namecolor") {
    chatColorArgument("chatcolor")
    playerExecutor { player, args ->
        val color = args["chatcolor"] as NamedTextColor
        player.displayName(Component.text().color(color).append(Component.text(player.name)).build())
    }
}

Adventure chat component argument

The AdventureChatComponentArgument class accepts raw chat-based JSON as valid input, as declared here. This is converted into Adventure's Component class.

Example - Opening a book with raw JSON content

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:

/showbook <target> <title> <author> <contents>

We can construct a book using the Adventure API's Book.book(Component, Component, Component...) method. In order 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:

new CommandAPICommand("showbook")
    .withArguments(new PlayerArgument("target"))
    .withArguments(new TextArgument("title"))
    .withArguments(new StringArgument("author"))
    .withArguments(new AdventureChatComponentArgument("contents"))
    .executes((sender, args) -> {
        Player target = (Player) args.get("target");
        String title = (String) args.get("title");
        String author = (String) args.get("author");
        Component content = (Component) args.get("contents");
        
        // Create a book and show it to the user (Requires Paper)
        Book mybook = Book.book(Component.text(title), Component.text(author), content);
        target.openBook(mybook);
    })
    .register();
CommandAPICommand("showbook")
    .withArguments(PlayerArgument("target"))
    .withArguments(TextArgument("title"))
    .withArguments(StringArgument("author"))
    .withArguments(AdventureChatComponentArgument("contents"))
    .executes(CommandExecutor { _, args ->
        val target = args["target"] as Player
        val title = args["title"] as String
        val author = args["author"] as String
        val content = args["contents"] as Component

        // Create a book and show it to the user (Requires Paper)
        val mybook = Book.book(Component.text(title), Component.text(author), content)
        target.openBook(mybook)
    })
    .register()
commandAPICommand("showbook") {
    playerArgument("target")
    textArgument("title")
    stringArgument("author")
    adventureChatComponentArgument("contents")
    anyExecutor { _, args ->
        val target = args["target"] as Player
        val title = args["title"] as String
        val author = args["author"] as String
        val content = args["contents"] as Component

        // Create a book and show it to the user (Requires Paper)
        val mybook = Book.book(Component.text(title), Component.text(author), content)
        target.openBook(mybook)
    }
}

Adventure chat argument

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.

Example - Sending personalized messages to players

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:

/pbroadcast <message>

In order 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 in order to receive the broadcasted message. By default, Bukkit-based servers (Spigot and Paper) use the bukkit.broadcast.user permission, which is described here:

new CommandAPICommand("pbroadcast")
    .withArguments(new AdventureChatArgument("message"))
    .executes((sender, args) -> {
        Component message = (Component) args.get("message");
        
        // Broadcast the message to everyone with broadcast permissions.
        Bukkit.getServer().broadcast(message, Server.BROADCAST_CHANNEL_USERS);
        Bukkit.getServer().broadcast(message);
    })
    .register();
CommandAPICommand("pbroadcast")
    .withArguments(AdventureChatArgument("message"))
    .executes(CommandExecutor { _, args ->
        val message = args["message"] as Component

        // Broadcast the message to everyone with broadcast permissions.
        Bukkit.getServer().broadcast(message, Server.BROADCAST_CHANNEL_USERS)
        Bukkit.getServer().broadcast(message)
    })
    .register()
commandAPICommand("pbroadcast") {
    adventureChatArgument("message")
    anyExecutor { _, args ->
        val message = args["message"] as Component

        // Broadcast the message to everyone with broadcast permissions.
        Bukkit.getServer().broadcast(message, Server.BROADCAST_CHANNEL_USERS)
        Bukkit.getServer().broadcast(message)
    }
}