From d0a57e76f4cea7af40b392beb13cf7608d1897cb Mon Sep 17 00:00:00 2001 From: Muhammad Tamir Date: Sun, 16 Nov 2025 21:20:46 +0700 Subject: [PATCH] Create papermc-dev-docs.md --- .../server/papermc/papermc-dev-docs.md | 10547 ++++++++++++++++ 1 file changed, 10547 insertions(+) create mode 100644 games/minecraft/develoment/server/papermc/papermc-dev-docs.md diff --git a/games/minecraft/develoment/server/papermc/papermc-dev-docs.md b/games/minecraft/develoment/server/papermc/papermc-dev-docs.md new file mode 100644 index 0000000..78ab287 --- /dev/null +++ b/games/minecraft/develoment/server/papermc/papermc-dev-docs.md @@ -0,0 +1,10547 @@ +```markdown +# PaperMC Knowledge Base + +## General + +### Contributing +* [Contributing](Contributing) - Information on how to contribute to the PaperMC project. + +### Miscellaneous + +* [Using databases](Using databases) - Recommended way to store a large amount of data. +* [Debugging your plugin](Debugging your plugin) - Common ways to debug your plugin. +* [Minecraft internals](Minecraft internals) - Overview of how to use internals in your plugin. +* [Reading stacktraces](Reading stacktraces) - Basics of how to read stacktraces produced by the JVM when an exception occurs. + +## API + +### Command API +* [Command API](Command API) - Guide to Paper's Brigadier command API. + + * **Basics** + * [Introduction](Command%20API) - A guide to Paper's Brigadier command API. + * [Command trees](Command%20trees) - An extensive guide to building up a command tree. + * [Arguments and literals](Arguments%20and%20literals) - An extensive guide to command arguments and literals. + * [Executors](Executors) - A guide to execution logic for Brigadier commands. + * [Registration](Registration) - A guide to registering Brigadier commands. + * [Requirements](Requirements) - A guide to setting requirements for commands. + * [Suggestions](Suggestions) - Documentation about defining custom argument suggestions. + * [Custom arguments](Custom%20arguments) - Guide on custom arguments. + * **Arguments** + * [Minecraft-specific](Minecraft-specific) - Everything regarding the essential Brigadier arguments. + * [Location](Location) - BlockPosition, FinePosition and World argument documentation. + * [Entities and players](Entities%20and%20players) - Player and Entity arguments documentation. + * [Registry](Registry) - Documentation for arguments retrieving registry values. + * [Paper-specific](Paper-specific) - Documentation for arguments handling miscellaneous Paper API values. + * [Enums](Enums) - Documentation for EntityAnchor, GameMode and similar enum value arguments. + * [Predicates](Predicates) - Documentation for arguments that allow value validation. + * [Adventure](Adventure) - Documentation for all arguments returning Adventure API objects. + * **Miscellaneous** + * [Basic commands](Basic%20commands) - An overview of a Bukkit-style command declaration using Brigadier. + * [Comparison](Comparison) - A comparison between Brigadier and Bukkit commands. + +### Component API +* [Component API](Component%20API) - Guide to Adventure components. + * [Introduction](Component%20API) - An introduction to how components work. + * [Internationalization](Internationalization) - How to use Adventure's internationalization. + * [Audiences](Audiences) - How to use Adventure's Audiences. + * [Signed messages](Signed%20messages) - A guide to working with SignedMessage objects. + +### Event API +* [Event API](Event%20API) - Guide to Paper's event system. + * [Listeners](Listeners) - Developer guide for how to listen to the broadcasted events. + * [Custom events](Custom%20events) - A guide to show you how to add custom events to your plugin. + * [Handler lists](Handler%20lists) - An explanation to what an event's HandlerList is. + * [Chat events](Chat%20events) - An outline on AsyncChatEvent and how to handle it. + +### Entity API +* [Entity API](Entity%20API) - Documentation for working with entities. + * [Teleportation](Teleportation) - Guide on entity teleportation. + * [Display entities](Display%20entities) - Guide on display entities. + +### Inventories +* [Inventories](Inventories) - Documentation for working with inventories. + * [Menu Type API](Menu%20Type%20API) - A guide to the Menu Type API. + * [Custom InventoryHolders](Custom%20InventoryHolders) - How to use a custom InventoryHolder to identify custom inventories. + +### Lifecycle API +* [Lifecycle API](Lifecycle%20API) - Documentation for Paper's Lifecycle API. + * [Introduction](Lifecycle%20API) - An introduction to Paper's Lifecycle API. + * [Datapack discovery](Datapack%20discovery) - A guide to including datapacks in your plugin and registering them with the lifecycle API. + +### Experimental +* [Data components](Data%20components) - A guide to the ItemStack data component API. +* [Persistent data container (PDC)](Persistent%20data%20container%20(PDC)) - A guide to the PDC API for storing data. +* [Scheduling](Scheduling) - A guide on how to use BukkitScheduler to run code at specific times. +* [Plugin messaging](Plugin%20messaging) - How to communicate with clients or proxies. +* [Plugin configuration](Plugin%20configuration) - How to create configuration files for your plugins to customize behavior. +* [Registries](Registries) - A guide to registries and their modification on Paper. +* [Dialog API](Dialog%20API) - A guide to the dialog API introduced in 1.21.7. +* [Recipes](Recipes) - How to create and manage recipes. +* [Particles](Particles) - A comprehensive guide to particle spawning. + +## Development + +* [Development](Development) - Welcome to the Paper development guide! + * [Getting started](Development#getting-started) + * [Paper plugins](Paper%20plugins) - A development guide for how to write Paper-specific plugins. + * [Project setup](Project%20setup) - Step-by-step instructions on how to set up a plugin development environment. + * [How plugins work](How%20plugins%20work) - How plugins work in Paper. + * [plugin.yml](plugin.yml) - A guide to Bukkit's plugin.yml file. + * [paperweight-userdev](paperweight-userdev) - A guide on how to use the paperweight-userdev Gradle plugin to access internal code. + +## Command API - Arguments + +### Minecraft-specific Arguments + +#### Location Argument + +* **Block position argument** + * Used for retrieving the position of a block. Works the same way as the first argument of the `/setblock ` Vanilla command. + * Returns a `BlockPosition` variable from the `BlockPositionResolver`. + * Example Usage: + + ```java + public static LiteralCommandNode blockPositionArgument() { + return Commands.literal("blockpositionargument") + .then(Commands.argument("arg", ArgumentTypes.blockPosition()) + .executes(ctx -> { + final BlockPositionResolver blockPositionResolver = ctx.getArgument("arg", BlockPositionResolver.class); + final BlockPosition blockPosition = blockPositionResolver.resolve(ctx.getSource()); + ctx.getSource().getSender().sendPlainMessage( + "Put in " + blockPosition.x() + " " + blockPosition.y() + " " + blockPosition.z()); + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +* **Fine position argument** + * Works similarly to the block position argument, with the difference being that it can accept decimal (precise) location input. + * The optional overload (`ArgumentTypes.finePosition(boolean centerIntegers)`), which defaults to false if not set, will center whole input, meaning 5 becomes 5.5 (5.0 would stay as 5.0 though), as that is the “middle” of a block. This only applies to X/Z. The y coordinate is untouched by this operation. + * Returns a `FinePositionResolver`. You can resolve that by running `FinePositionResolver#resolve(CommandSourceStack)` to get the resulting `FinePosition`. + * Example Usage: + + ```java + public static LiteralCommandNode finePositionArgument() { + return Commands.literal("fineposition") + .then(Commands.argument("arg", ArgumentTypes.finePosition(true)) + .executes(ctx -> { + final FinePositionResolver resolver = ctx.getArgument("arg", FinePositionResolver.class); + final FinePosition finePosition = resolver.resolve(ctx.getSource()); + ctx.getSource().getSender().sendRichMessage( + "Position: ", + Placeholder.unparsed("x", Double.toString(finePosition.x())), + Placeholder.unparsed("y", Double.toString(finePosition.y())), + Placeholder.unparsed("z", Double.toString(finePosition.z())) + ); + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +* **World argument** + * Allows the user to select one of the currently loaded worlds. + * Returns a generic Bukkit `World` object. + * Example Usage: + + ```java + public static LiteralCommandNode worldArgument() { + return Commands.literal("teleport-to-world") + .then(Commands.argument("world", ArgumentTypes.world()) + .executes(ctx -> { + final World world = ctx.getArgument("world", World.class); + if (ctx.getSource().getExecutor() instanceof Player player) { + player.teleport(world.getSpawnLocation(), PlayerTeleportEvent.TeleportCause.COMMAND); + ctx.getSource().getSender().sendRichMessage( + "Successfully teleported to ", + Placeholder.component("player", player.name()), + Placeholder.unparsed("world", world.getName()) + ); + return Command.SINGLE_SUCCESS; + } + ctx.getSource().getSender().sendRichMessage("This command requires a player!"); + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +#### Entities and players Argument + +* The arguments described in this section relate to arguments which you can use to retrieve entities. Their main usage is the selection of command targets. +* All of these have entity selectors (`@a`, `@e`, `@n`, etc.) as valid inputs, though they require the `minecraft.command.selector` permission in order to be able to be used. The specific arguments may allow or disallow certain selectors. +* Due to the permission requirement for selectors it is advised to add a `requires` statement to your command: + `.requires(ctx -> ctx.getSender().hasPermission("minecraft.command.selector"))` + +* **Entity argument** + * Returns a list of exactly one entity. + * Returns an `EntitySelectorArgumentResolver`. + * Safe to call `List#getFirst()` to retrieve that entity. + * You can resolve it using `ArgumentResolver#resolve(CommandSourceStack)` + * Example usage: + + ```java + public static LiteralCommandNode entityArgument() { + return Commands.literal("entityarg") + .then(Commands.argument("arg", ArgumentTypes.entity()) + .executes(ctx -> { + final EntitySelectorArgumentResolver entitySelectorArgumentResolver = ctx.getArgument("arg", EntitySelectorArgumentResolver.class); + final List entities = entitySelectorArgumentResolver.resolve(ctx.getSource()); + ctx.getSource().getSender().sendRichMessage( + "Found ", + Placeholder.component("entityname", entities.getFirst().name()) + ); + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +* **Entities argument** + * Accepts any amount of entities, with the minimum amount of entities being 1. + * Returns an `EntitySelectorArgumentResolver`. + * Can be resolved using `ArgumentResolver#resolve(CommandSourceStack)`, which returns a `List`. + * Example usage: + + ```java + public static LiteralCommandNode entitiesArgument() { + return Commands.literal("entitiesarg") + .then(Commands.argument("arg", ArgumentTypes.entities()) + .executes(ctx -> { + final EntitySelectorArgumentResolver entitySelectorArgumentResolver = ctx.getArgument("arg", EntitySelectorArgumentResolver.class); + final List entities = entitySelectorArgumentResolver.resolve(ctx.getSource()); + final Component foundEntities = Component.join(JoinConfiguration.commas(true), + entities.stream().map(Entity::name).toList()); + ctx.getSource().getSender().sendRichMessage( + "Found ", + Placeholder.component("entitynames", foundEntities) + ); + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +* **Player argument** + * Allows to retrieve a `PlayerSelectorArgumentResolver` for player arguments. + * For this “single player” argument, you can safely get the target player by running `PlayerSelectorArgumentResolver.resolve(ctx.getSource()).getFirst()`, which returns a `Player` object. + * Example usage: + + ```java + public static LiteralCommandNode playerArgument() { + return Commands.literal("player") + .then(Commands.argument("target", ArgumentTypes.player()) + .executes(ctx -> { + final PlayerSelectorArgumentResolver targetResolver = ctx.getArgument("target", PlayerSelectorArgumentResolver.class); + final Player target = targetResolver.resolve(ctx.getSource()).getFirst(); + target.setVelocity(new Vector(0, 100, 0)); + target.sendRichMessage("Yeeeeeeeeeet"); + ctx.getSource().getSender().sendRichMessage( + "Yeeted !", + Placeholder.component("target", target.name()) + ); + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +* **Players argument** + * The “multiple players” argument works similarly to the “single player” argument, also returning a `PlayerSelectorArgumentResolver`. + * Instead of just resolving to exactly one `Player`, this one can resolve to more than just one player - which you should account for in case of using this argument. + * `PlayerSelectorArgumentResolver.resolve(ctx.getSource())` returns a `List`, which you can just iterate through. + * Example usage: + + ```java + public static LiteralCommandNode playersArgument() { + return Commands.literal("players") + .then(Commands.argument("targets", ArgumentTypes.players()) + .executes(ctx -> { + final PlayerSelectorArgumentResolver targetResolver = ctx.getArgument("targets", PlayerSelectorArgumentResolver.class); + final List targets = targetResolver.resolve(ctx.getSource()); + final CommandSender sender = ctx.getSource().getSender(); + for (final Player target : targets) { + target.setVelocity(new Vector(0, 100, 0)); + target.sendRichMessage("Yeeeeeeeeeet"); + sender.sendRichMessage( + "Yeeted !", + Placeholder.component("target", target.name()) + ); + } + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +* **Player profiles argument** + * Can retrieve both offline and online players. + * Returns the result of the argument as a `PlayerProfileListResolver`, which resolves to a `Collection`. + * This collection can be iterated to get the resulting profile(s). Usually, it only returns a single `PlayerProfile` if retrieving a player by name, but it can return multiple if using the entity selectors (like `@a` on online players). Thus it always makes sense to run whatever operation you want to run on all entries in the collection instead of just the first one. + * This argument will run API calls to Mojang servers in order to retrieve player information for players which have never joined the server before. + * It is suggested to resolve this argument in an asynchronous context in order to not cause any server lag. + * Example usage: + + ```java + public static LiteralCommandNode playerProfilesArgument() { + return Commands.literal("lookup") + .then(Commands.argument("profile", ArgumentTypes.playerProfiles()) + .executes(ctx -> { + final PlayerProfileListResolver profilesResolver = ctx.getArgument("profile", PlayerProfileListResolver.class); + final Collection foundProfiles = profilesResolver.resolve(ctx.getSource()); + for (final PlayerProfile profile : foundProfiles) { + ctx.getSource().getSender().sendPlainMessage("Found " + profile.getName()); + } + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +#### Enum Argument + +* **Entity anchor argument** + * Has two valid inputs: `feet` and `eyes`. + * The resulting `LookAnchor` is mainly used for methods like `Entity#lookAt(Position, LookAnchor)` or `Player#lookAt(Entity, LookAnchor, LookAnchor)`. + * Example usage: + + ```java + public static LiteralCommandNode entityAnchorArgument() { + return Commands.literal("entityanchor") + .then(Commands.argument("arg", ArgumentTypes.entityAnchor()) + .executes(ctx -> { + final LookAnchor lookAnchor = ctx.getArgument("arg", LookAnchor.class); + ctx.getSource().getSender().sendRichMessage( + "You chose !", + Placeholder.unparsed("anchor", lookAnchor.name()) + ); + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +* **GameMode argument** + * Works the same way as the first argument of the Vanilla `/gamemode ` command. + * Accepts any of the 4 valid game modes, returning a `GameMode` enum to use in code. + * Example usage: + + ```java + public static LiteralCommandNode gameModeArgument() { + return Commands.literal("gamemodearg") + .then(Commands.argument("arg", ArgumentTypes.gameMode()) + .executes(ctx -> { + final GameMode gamemode = ctx.getArgument("arg", GameMode.class); + if (ctx.getSource().getExecutor() instanceof Player player) { + player.setGameMode(gamemode); + player.sendRichMessage( + "Your gamemode has been set to !", + Placeholder.component("gamemode", Component.translatable(gamemode)) + ); + return Command.SINGLE_SUCCESS; + } + ctx.getSource().getSender().sendPlainMessage("This command requires a player!"); + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +* **HeightMap argument** + * Consists of the following, valid inputs: `motion_blocking`, `motion_blocking_no_leaves`, `ocean_floor`, and `world_surface`. + * It is often used for declaring relative positioning for data packs or the `/execute positioned over ` command. + * Example usage: + + ```java + public static LiteralCommandNode heightMapArgument() { + return Commands.literal("heightmap") + .then(Commands.argument("arg", ArgumentTypes.heightMap()) + .executes(ctx -> { + final HeightMap heightMap = ctx.getArgument("arg", HeightMap.class); + ctx.getSource().getSender().sendRichMessage( + "You selected ", + Placeholder.unparsed("selection", heightMap.name()) + ); + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +* **Scoreboard display slot argument** + * Allows you to retrieve a `DisplaySlot` enum value from the user. + * Example usage: + + ```java + public static LiteralCommandNode scoreboardDisplaySlotArgument() { + return Commands.literal("scoreboarddisplayslot") + .then(Commands.argument("slot", ArgumentTypes.scoreboardDisplaySlot()) + .executes(ctx -> { + final DisplaySlot slot = ctx.getArgument("slot", DisplaySlot.class); + ctx.getSource().getSender().sendPlainMessage("You selected: " + slot.getId()); + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +* **Template mirror argument** + * The user has 3 valid input possibilities: `front_back`, `left_right`, and `none`. + * You can retrieve the result of the argument as a `Mirror` enum value. + * Example usage: + + ```java + public static LiteralCommandNode templateMirrorArgument() { + return Commands.literal("templatemirror") + .then(Commands.argument("mirror", ArgumentTypes.templateMirror()) + .executes(ctx -> { + final Mirror mirror = ctx.getArgument("mirror", Mirror.class); + ctx.getSource().getSender().sendPlainMessage("You selected: " + mirror.name()); + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +* **Template rotation argument** + * The user has 4 valid input possibilities: `180`, `clockwise_90`, `counterclockwise_90`, and `none`. + * You can retrieve the result of the argument as a `StructureRotation` enum value. + * Example usage: + + ```java + public static LiteralCommandNode templateRotationArgument() { + return Commands.literal("templaterotation") + .then(Commands.argument("rotation", ArgumentTypes.templateRotation()) + .executes(ctx -> { + final StructureRotation rotation = ctx.getArgument("rotation", StructureRotation.class); + ctx.getSource().getSender().sendPlainMessage("You selected: " + rotation.name()); + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +#### Adventure Argument + +* **Component argument** + * Expects the JSON representation of a text component, making it inappropriate for general user input. + * The result is returned as an Adventure component to work with. + * Example usage: + + ```java + public static LiteralCommandNode 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: ", + Placeholder.component("input", component) + ); + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +* **Key argument** + * Allows a user to put in any artificial (namespaced) key, ensuring its validity. + * Returns a `Key`, which can be used at various other places in the Paper API. + * Example usage: + + ```java + public static LiteralCommandNode 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 !", + Placeholder.unparsed("key", key.asString()) + ); + return Command.SINGLE_SUCCESS; + })) + .build(); + } + ``` + +* **Named color argument** + * Provides the user with the ability to select between the 16 built-in “named” text colors. + * Returns a `NamedTextColor`, which you can use for applying a color to components. + * Example usage: + + ```java + public static LiteralCommandNode 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 = StringArgumentType.getString(ctx, "message"); + ctx.getSource().getSender().sendMessage(Component.text(msg).color(color)); + return Command.SINGLE_SUCCESS; + }))) + .build(); + } + ``` + +* **Adventure style argument** + * 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. + * Returns its value in the form of a `Style` object. + * This can be applied to any component using `Component#style(Style)`. + * Example usage: + + ```java + public static LiteralCommandNode 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 msg = StringArgumentType.getString(ctx, "message"); + ctx.getSource().getSender().sendRichMessage( + "Your input: ", + Placeholder.component("input", Component.text(message).style(style)) + ); + return Command.SINGLE_SUCCESS; + }))) + .build(); + } + ``` + +* **Signed message argument** + * Allows a player to send an argument in the form of a signed message to the server. + * Returns a `SignedMessageResolver`. + * In order to call its `#resolve` method, you have to pass in two parameters: + * The argument name + * The `CommandContext` object + * The resolved value is a `CompletableFuture`, whose `SignedMessage` value you can handle using `thenAccept(Consumer)`. + * Example usage: + + ```java + public static LiteralCommandNode 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 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; + } + ``` + +## Event API - Chat Events + +### Chat Events +* The chat event has evolved a few times over the years. +* This guide will explain how to properly use the new `AsyncChatEvent` and its `ChatRenderer`. +* The `AsyncChatEvent` is an improved version of the old `AsyncPlayerChatEvent` that allows you to render chat messages individually for each player. + +#### AsyncChatEvent vs ChatEvent +* The key difference between `AsyncChatEvent` and `ChatEvent` is that `AsyncChatEvent` is fired asynchronously. +* This means that it does not block the main thread and sends the chat message when the listener has completed. +* Be aware that using the Bukkit API in an asynchronous context (i.e. the event handler) is unsafe and exceptions may be thrown. +* If you need to use the Bukkit API, you can use `ChatEvent`. +* However, we recommend using `BukkitScheduler`. + +#### Understanding the renderer +* The renderer is Paper’s way of allowing plugins to modify the chat message before it is sent to the player. +* This is done by using the `ChatRenderer` interface with its `ChatRenderer#render(Player, Component, Component, Audience)` method. +* Previously, this was done by using the `AsyncPlayerChatEvent` with its `AsyncPlayerChatEvent#setFormat(String)` method. + +```java +ChatRenderer#render +public Component render(Player source, Component sourceDisplayName, Component message, Audience viewer) { + // ... +} +``` + +* The `render` method is called when a chat message is sent to the player. + * `source`: The player that sent the message. + * `sourceDisplayName`: The display name of the player that sent the message. + * `message`: The message that was sent. + * `viewer`: The player that is receiving the message. + +* **ChatRenderer.ViewerUnaware** + * If your renderer does not need to know about the viewer, you can use the `ChatRenderer.ViewerUnaware` interface instead of the `ChatRenderer` interface. + * This will benefit performance as the message will only be rendered once instead of each individual player. + +#### Using the renderer +* There are two ways to use the renderer: + 1. Implementing the `ChatRenderer` interface in a class. + 2. Using a lambda expression. +* Depending on the complexity of your renderer, you may want to use one or the other. + +#### Implementing the ChatRenderer interface +* Tell the event to use the renderer by using the `AbstractChatEvent#renderer()` method. + +```java +ChatListener.java +public class ChatListener implements Listener, ChatRenderer { + // Implement the ChatRenderer and Listener interface + // Listen for the AsyncChatEvent + @EventHandler + public void onChat(AsyncChatEvent event) { + event.renderer(this); + // Tell the event to use our renderer + } + + // Override the render method + @Override + public Component render(Player source, Component sourceDisplayName, Component message, Audience viewer) { + // ... + } +} +``` + +* **Note:** If you decide to create a separate class for your renderer, it is important to know that you don’t need to instantiate the class every time the event is called. In this case, you can use the singleton pattern to create a single instance of the class. + +#### Using a lambda expression + +```java +ChatListener.java +public class ChatListener implements Listener { + @EventHandler + public void onChat(AsyncChatEvent event) { + event.renderer((source, sourceDisplayName, message, viewer) -> { + // ... + }); + } +} +``` + +#### Rendering the message +* Return a new `Component` that contains the message you want to send. + +```java +ChatListener.java +public class ChatListener implements Listener, ChatRenderer { + // Listener logic + @Override + public Component render(Player source, Component sourceDisplayName, Component message, Audience viewer) { + return sourceDisplayName.append(Component.text(": ")).append(message); + } +} +``` + +# Command API Arguments + +This knowledge base covers the various arguments available in the PaperMC Command API. + +## Minecraft-specific Arguments + +The `ArgumentTypes` class provides access to Minecraft-specific arguments. + +### Quick Overview + +| Method Name | Return Value | Quick Link | +| -------------------------- | ------------------------------ | --------------------------------------------- | +| `blockPosition()` | `BlockPositionResolver` | [Block Position Argument](#block-position-argument) | +| `blockState()` | `BlockState` | [Block State Argument](#block-state-argument) | +| `component()` | `Component (Kyori)` | [Component Argument](#component-argument) | +| `doubleRange()` | `DoubleRangeProvider` | [Double Range argument](#double-range-argument) | +| `entity()` | `EntitySelectorArgumentResolver`| [Entity Argument](#entity-argument) | +| `entities()` | `EntitySelectorArgumentResolver`| [Entities Argument](#entities-argument) | +| `entityAnchor()` | `LookAnchor` | Entity Anchor Argument | +| `finePosition(boolean centerIntegers)` | `FinePositionResolver` | [Fine Position Argument](#fine-position-argument) | +| `gameMode()` | `GameMode` | GameMode Argument | +| `heightMap()` | `HeightMap` | HeightMap Argument | +| `integerRange()` | `IntegerRangeProvider` | [Integer Range Argument](#integer-range-argument) | +| `itemPredicate()` | `ItemStackPredicate` | [Item Predicate Argument](#item-predicate-argument) | +| `itemStack()` | `ItemStack` | [ItemStack Argument](#itemstack-argument) | +| `key()` | `Key (Kyori)` | [Key Argument](#key-argument) | +| `namedColor()` | `NamedTextColor (Kyori)` | [Named Color Argument](#named-color-argument) | +| `namespacedKey()` | `NamespacedKey` | [Bukkit NamespacedKey Argument](#namespacedkey-argument) | +| `objectiveCriteria()` | `Criteria` | [Objective Criteria Argument](#objective-criteria-argument) | +| `player()` | `PlayerSelectorArgumentResolver`| [Player Argument](#player-argument) | +| `players()` | `PlayerSelectorArgumentResolver`| [Players Argument](#players-argument) | +| `playerProfiles()` | `PlayerProfileListResolver` | [Player Profiles Argument](#player-profiles-argument) | +| `resource(RegistryKey)` | `(Depends on RegistryKey)` | [Resource Argument](#resource-argument) | +| `resourceKey(RegistryKey)` | `(Depends on RegistryKey)` | [Resource Key Argument](#resource-key-argument) | +| `style()` | `Style (Kyori)` | [Style Argument](#adventure-style-argument) | +| `signedMessage()` | `SignedMessageResolver` | [Signed Message Argument](#signed-message-argument) | +| `scoreboardDisplaySlot()` | `DisplaySlot` | Scoreboard Display Slot Argument | +| `time(int mintime)` | `Integer` | [Time Argument](#time-argument) | +| `templateMirror()` | `Mirror` | Template Mirror Argument | +| `templateRotation()` | `StructureRotation` | Template Rotation Argument | +| `uuid()` | `UUID` | [UUID Argument](#uuid-argument) | +| `world()` | `World` | [World Argument](#world-argument) | + +## Location Arguments + +These arguments are used for retrieving location-based data. + +### Block position argument + +The block position argument is used for retrieving the position of a block. +It works the same way as the first argument of the `/setblock ` Vanilla command. + +* To retrieve the `BlockPosition` variable from the `BlockPositionResolver`, it must be resolved using the command source. + +#### Example usage + +```java +public static LiteralCommandNode blockPositionArgument() { + return Commands + .literal("blockpositionargument") + .then(Commands.argument("arg", ArgumentTypes.blockPosition()) + .executes(ctx -> { + final BlockPositionResolver blockPositionResolver = ctx.getArgument("arg", BlockPositionResolver.class); + final BlockPosition blockPosition = blockPositionResolver.resolve(ctx.getSource()); + ctx.getSource().getSender().sendPlainMessage( + "Put in " + blockPosition.x() + " " + blockPosition.y() + " " + blockPosition.z()); + return Command.SINGLE_SUCCESS; + })) + .build(); +} +``` + +#### In-game preview + +Your device does not support video playback. + +### Fine position argument + +The fine position argument works similarly to the block position argument, with the only difference being that it can accept decimal (precise) location input. +The optional overload `ArgumentTypes.finePosition(boolean centerIntegers)`, which defaults to false if not set, will center whole input, meaning 5 becomes 5.5 (5.0 would stay as 5.0 though), as that is the “middle” of a block. This only applies to X/Z. The y coordinate is untouched by this operation. + +* This argument returns a `FinePositionResolver`. +* Resolve by running `FinePositionResolver#resolve(CommandSourceStack)` to get the resulting `FinePosition`. + +#### Example usage + +```java +public static LiteralCommandNode finePositionArgument() { + return Commands + .literal("fineposition") + .then(Commands.argument("arg", ArgumentTypes.finePosition(true)) + .executes(ctx -> { + final FinePositionResolver resolver = ctx.getArgument("arg", FinePositionResolver.class); + final FinePosition finePosition = resolver.resolve(ctx.getSource()); + ctx.getSource().getSender().sendRichMessage("Position: ", + Placeholder.unparsed("x", Double.toString(finePosition.x())), + Placeholder.unparsed("y", Double.toString(finePosition.y())), + Placeholder.unparsed("z", Double.toString(finePosition.z()))); + return Command.SINGLE_SUCCESS; + })) + .build(); +} +``` + +#### In-game preview + +Your device does not support video playback. + +### World argument + +This argument allows the user to select one of the currently loaded world. + +* You can retrieve the result as a generic Bukkit `World` object. + +#### Example usage + +```java +public static LiteralCommandNode worldArgument() { + return Commands + .literal("teleport-to-world") + .then(Commands.argument("world", ArgumentTypes.world()) + .executes(ctx -> { + final World world = ctx.getArgument("world", World.class); + if (ctx.getSource().getExecutor() instanceof Player player) { + player.teleport(world.getSpawnLocation(), PlayerTeleportEvent.TeleportCause.COMMAND); + ctx.getSource().getSender().sendRichMessage("Successfully teleported to ", + Placeholder.component("player", player.name()), + Placeholder.unparsed("world", world.getName())); + return Command.SINGLE_SUCCESS; + } + ctx.getSource().getSender().sendRichMessage("This command requires a player!"); + return Command.SINGLE_SUCCESS; + })) + .build(); +} +``` + +#### In-game preview + +Your device does not support video playback. + +## Entities and Players Arguments + +These arguments are used for retrieving entities and players. + +### Entity argument + +* This argument returns an `EntitySelectorArgumentResolver`. +* Use `ArgumentResolver#resolve(CommandSourceStack)` to resolve the entity. +* The `getFirst()` method returns a single `Entity` object. + +#### Example usage + +```java +public static LiteralCommandNode entityArgument() { + return Commands + .literal("entity") + .then(Commands.argument("target", ArgumentTypes.entity()) + .executes(ctx -> { + final EntitySelectorArgumentResolver targetResolver = ctx.getArgument("target", EntitySelectorArgumentResolver.class); + final Entity entity = targetResolver.resolve(ctx.getSource()).getFirst(); + ctx.getSource().getSender().sendRichMessage("Found ", + Placeholder.component("entityname", entity.name())); + return Command.SINGLE_SUCCESS; + })) + .build(); +} +``` + +#### In-game preview + +Your device does not support video playback. + +If the executing player doesn’t have the `minecraft.command.selector` permission: + +Your device does not support video playback. + +If the executing player has the `minecraft.command.selector` permission: + +Your device does not support video playback. + +### Entities argument + +In contrast to the single entity argument, this multiple-entities argument accepts any amount of entities, with the minimum amount of entities being 1. + +* They can be resolved using `ArgumentResolver#resolve(CommandSourceStack)`, which returns a `List`. + +#### Example usage + +```java +public static LiteralCommandNode entitiesArgument() { + return Commands + .literal("entitiesarg") + .then(Commands.argument("arg", ArgumentTypes.entities()) + .executes(ctx -> { + final EntitySelectorArgumentResolver entitySelectorArgumentResolver = ctx.getArgument("arg", EntitySelectorArgumentResolver.class); + final List entities = entitySelectorArgumentResolver.resolve(ctx.getSource()); + final Component foundEntities = Component.join(JoinConfiguration.commas(true), entities.stream().map(Entity::name).toList()); + ctx.getSource().getSender().sendRichMessage("Found ", + Placeholder.component("entitynames", foundEntities)); + return Command.SINGLE_SUCCESS; + })) + .build(); +} +``` + +#### In-game preview + +Your device does not support video playback. + +### Player argument + +The player argument allows to retrieve a `PlayerSelectorArgumentResolver` for player arguments. + +* For this “single player” argument, you can safely get the target player by running `PlayerSelectorArgumentResolver.resolve(ctx.getSource()).getFirst()`, which returns a `Player` object. + +#### Example usage + +This command yeets the targeted player into the air! + +```java +public static LiteralCommandNode playerArgument() { + return Commands + .literal("player") + .then(Commands.argument("target", ArgumentTypes.player()) + .executes(ctx -> { + final PlayerSelectorArgumentResolver targetResolver = ctx.getArgument("target", PlayerSelectorArgumentResolver.class); + final Player target = targetResolver.resolve(ctx.getSource()).getFirst(); + target.setVelocity(new Vector(0, 100, 0)); + target.sendRichMessage("Yeeeeeeeeeet"); + ctx.getSource().getSender().sendRichMessage("Yeeted !", + Placeholder.component("target", target.name())); + return Command.SINGLE_SUCCESS; + })) + .build(); +} +``` + +#### In-game preview + +Your device does not support video playback. + +### Players argument + +The “multiple players” argument works similarly to the “single player” argument, also returning a `PlayerSelectorArgumentResolver`. + +* Instead of just resolving to exactly one `Player`, this one can resolve to more than just one player - which you should account for in case of using this argument. +* `PlayerSelectorArgumentResolver.resolve(ctx.getSource())` returns a `List`, which you can just iterate through. + +#### Example usage + +Extending the “single player” yeet command to support multiple targets can look like this: + +```java +public static LiteralCommandNode playersArgument() { + return Commands + .literal("players") + .then(Commands.argument("targets", ArgumentTypes.players()) + .executes(ctx -> { + final PlayerSelectorArgumentResolver targetResolver = ctx.getArgument("targets", PlayerSelectorArgumentResolver.class); + final List targets = targetResolver.resolve(ctx.getSource()); + final CommandSender sender = ctx.getSource().getSender(); + for (final Player target : targets) { + target.setVelocity(new Vector(0, 100, 0)); + target.sendRichMessage("Yeeeeeeeeeet"); + sender.sendRichMessage("Yeeted !", + Placeholder.component("target", target.name())); + } + return Command.SINGLE_SUCCESS; + })) + .build(); +} +``` + +#### In-game preview + +Your device does not support video playback. + +### Player profiles argument + +The player profiles argument is a very powerful argument which can retrieve both offline and online players. + +* It returns the result of the argument as a `PlayerProfileListResolver`, which resolves to a `Collection`. +* This collection can be iterated to get the resulting profile(s). +* Usually, it only returns a single `PlayerProfile` if retrieving a player by name, but it can return multiple if using the entity selectors (like `@a` on online players). +* It always makes sense to run whatever operation you want to run on all entries in the collection instead of just the first one. +* This argument will run API calls to Mojang servers in order to retrieve player information for players which have never joined the server before. +* It is suggested to resolve this argument in an asynchronous context in order to not cause any server lag. +* Sometimes, these API calls may fail. + +#### Example usage - player lookup command + +```java +public static LiteralCommandNode playerProfilesArgument() { + return Commands + .literal("lookup") + .then(Commands.argument("profile", ArgumentTypes.playerProfiles()) + .executes(ctx -> { + final PlayerProfileListResolver profilesResolver = ctx.getArgument("profile", PlayerProfileListResolver.class); + final Collection foundProfiles = profilesResolver.resolve(ctx.getSource()); + for (final PlayerProfile profile : foundProfiles) { + ctx.getSource().getSender().sendPlainMessage("Found " + profile.getName()); + } + return Command.SINGLE_SUCCESS; + })) + .build(); +} +``` + +#### In-game preview + +Your device does not support video playback. + +## Registry Arguments + +Registries in Minecraft hold information about item or block types, enchantments, potion effects, and more. + +There are two types of registry arguments: `resource` and `resourceKey`. + +* `resource` argument returns the parsed value. +* `resourceKey` only returns a `TypedKey`, which you can use to retrieve the value yourself. + +### Resource argument + +* You can get a `ArgumentType` reference to it using `ArgumentTypes.resource(RegistryKey)`. +* A selection of possible registry keys can be found below. +* They are accessed in a static context using the `RegistryKey` interface. +* Each entry in `RegistryKey` returns a `RegistryKey`. +* The `` generic parameter describes the return type. + +#### Example + +```java +public static LiteralCommandNode enchantmentRegistry() { + return Commands + .literal("enchants-registry") + .then(Commands.argument("enchantment", ArgumentTypes.resource(RegistryKey.ENCHANTMENT)) + .executes(ctx -> { + final Enchantment enchantment = ctx.getArgument("enchantment", Enchantment.class); + if (ctx.getSource().getExecutor() instanceof Player player) { + final ItemStack stack = player.getInventory().getItemInMainHand(); + stack.addUnsafeEnchantment(enchantment, 10); + ctx.getSource().getSender().sendRichMessage( + "Enchanted 's with !", + Placeholder.component("player", player.name()), + Placeholder.component("item", Component.translatable(stack)), + Placeholder.component("enchantment", enchantment.displayName(10)) + ); + return Command.SINGLE_SUCCESS; + } + ctx.getSource().getSender().sendRichMessage("This command requires a player!"); + return Command.SINGLE_SUCCESS; + })) + .build(); +} +``` + +#### In-game preview + +Your device does not support video playback. + +#### Caution + +There are certain edge-cases, where this argument, due to missing registries on the client, will cause a `Network Protocol Error`. + +Basically, the only argument where this is the case right now is with the `STRUCTURE` registry key. + +```java +// Registering this command will cause clients to not be able to connect to the server. +final LiteralCommandNode invalidRegistryArgument = Commands + .literal("registry-structure") + .then(Commands.argument("value", ArgumentTypes.resource(RegistryKey.STRUCTURE))) + .build(); +``` + +Due to this fact, it is advised to only use the `STRUCTURE` registry key argument with a `resourceKey(...)` argument type and parse the values yourself. + +### Resource key argument + +For the client, there is barely any difference between the using `ArgumentTypes.resource` or `ArgumentTypes.resourceKey`. The only difference is that using `ArgumentTypes.resourceKey` does not provide error checking. + +The resource argument provides a much cleaner user experience, whilst the `resourceKey` argument has one very important use case: You get the raw `TypedKey` returned as an argument result. +This object is particularly useful, as it provides all information required to be able to retrieve a value from a registry yourself. + +Unless you have a specific reason for using the `resourceKey` argument over the `resource` one, the `resource` argument is preferred due to the client-side error checking and simple usability. + +#### Direct code comparison + +Here is a simple code snipped on how one could use the `RegistryKey.ITEM` registry with a `resource` argument type: + +```java +Commands + .argument("item", ArgumentTypes.resource(RegistryKey.ITEM)) + .executes(ctx -> { + final ItemType item = ctx.getArgument("item", ItemType.class); + if (ctx.getSource().getExecutor() instanceof Player player) { + player.getInventory().addItem(item.createItemStack()); + } + return Command.SINGLE_SUCCESS; + }); +``` + +Here is the same code, using a `resourceKey` argument type. Instead of directly retrieving the argument using `ctx.getArgument("item", TypedKey.class)`, we instead use the `RegistryArgumentExtractor` to retrieve our `TypedKey`. + +```java +Commands + .argument("item", ArgumentTypes.resourceKey(RegistryKey.ITEM)) + .executes(ctx -> { + final TypedKey itemKey = RegistryArgumentExtractor.getTypedKey(ctx, RegistryKey.ITEM, "item"); + ItemType item = RegistryAccess.registryAccess().getRegistry(itemKey.registryKey()).get(itemKey.key()); + if (item == null) { + ctx.getSource().getSender().sendRichMessage("Please provide a valid item!"); + return Command.SINGLE_SUCCESS; + } + if (ctx.getSource().getExecutor() instanceof Player player) { + player.getInventory().addItem(item.createItemStack()); + } + return Command.SINGLE_SUCCESS; + }); +``` + +#### Using a TypedKey + +1. In order to get the correct registry, you can run `RegistryAccess#getRegistry(RegistryKey)`. +2. In order to get a `RegistryAccess`, you can just use the static `RegistryAccess.registryAccess()` method. +3. The `RegistryKey` is retrieved using `TypedKey#registryKey()`. +4. Now, in order to get the final value `T`, you can run `Registry#get(Key)`, where the key can be retrieved using `TypedKey#key()`. +5. This will return the backing instance from that resource key or null, if no value has been found. + +#### Use case over resource argument + +The main use case for this argument type is the ability to store the key (the value returned to you by `TypedKey#key`). +If you want to be able to store the exact user input and be able to retrieve the backed instance without much trouble, that is the way to do it. + +### Registry key previews + +The following `RegistryKeys` exist: + +| RegistryKeys Field | Return Value | Preview Video | +| ---------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ATTRIBUTE` | `Attribute` | [Attribute](#attribute) | +| `BANNER_PATTERN` | `PatternType` | [Banner Pattern](#banner-pattern) | +| `BIOME` | `Biome` | [Biome](#biome) | +| `BLOCK` | `BlockType` | [Block](#block) | +| `CAT_VARIANT` | `Cat.Type` | [Cat Variant](#cat-variant) | +| `CHICKEN_VARIANT` | `Chicken.Variant` | [Chicken Variant](#chicken-variant) | +| `COW_VARIANT` | `Cow.Variant` | [Cow Variant](#cow-variant) | +| `DAMAGE_TYPE` | `DamageType` | [Damage Type](#damage-type) | +| `DATA_COMPONENT_TYPE` | `DataComponentType` | [Data Component Type](#data-component-type) | +| `DIALOG` | `Dialog` | [Dialog](#dialog) | +| `ENCHANTMENT` | `Enchantment` | [Enchantment](#enchantment) | +| `ENTITY_TYPE` | `EntityType` | [Entity Type](#entity-type) | +| `FLUID` | `Fluid` | [Fluid](#fluid) | +| `FROG_VARIANT` | `Frog.Variant` | [Frog Variant](#frog-variant) | +| `GAME_EVENT` | `GameEvent` | [Game Event](#game-event) | +| `INSTRUMENT` | `MusicInstrument` | [Instrument](#instrument) | +| `ITEM` | `ItemType` | [Item](#item) | +| `JUKEBOX_SONG` | `JukeboxSong` | [Jukebox Song](#jukebox-song) | +| `MAP_DECORATION_TYPE` | `MapCursor.Type` | [Map Decoration Type](#map-decoration-type) | +| `MEMORY_MODULE_TYPE` | `MemoryKey` | [Memory Module Type](#memory-module-type) | +| `MENU` | `MenuType` | [Menu](#menu) | +| `MOB_EFFECT` | `PotionEffectType` | [Mob effect](#mob-effect) | +| `PAINTING_VARIANT` | `Art` | [Painting variant](#painting-variant) | +| `PARTICLE_TYPE` | `Particle` | [Particle](#particle) | +| `PIG_VARIANT` | `Pig.Variant` | [Pig Variant](#pig-variant) | +| `POTION` | `PotionType` | [Potion](#potion) | +| `SOUND_EVENT` | `Sound` | [Sound](#sound) | +| `STRUCTURE` | `Structure` | [Structure](#structure) | +| `STRUCTURE_TYPE` | `StructureType` | [Structure type](#structure-type) | +| `TRIM_MATERIAL` | `TrimMaterial` | [Trim material](#trim-material) | +| `TRIM_PATTERN` | `TrimPattern` | [Trim pattern](#trim-pattern) | +| `VILLAGER_PROFESSION` | `Villager.Profession` | [Villager Profession](#villager-profession) | +| `VILLAGER_TYPE` | `Villager.Type` | [Villager Type](#villager-type) | +| `WOLF_SOUND_VARIANT` | `Wolf.SoundVariant` | [Wolf Sound Variant](#wolf-sound-variant) | +| `WOLF_VARIANT` | `Wolf.Variant` | [Wolf Variant](#wolf-variant) | + +#### Attribute + +Your device does not support video playback. + +#### Banner pattern + +Your device does not support video playback. + +#### Biome + +Your device does not support video playback. + +#### Block + +Your device does not support video playback. + +#### Cat variant + +Your device does not support video playback. + +#### Chicken variant + +Your device does not support video playback. + +#### Cow variant + +Your device does not support video playback. + +#### Damage type + +Your device does not support video playback. + +#### Data component type + +Your device does not support video playback. + +#### Dialog + +Your device does not support video playback. + +#### Enchantment + +Your device does not support video playback. + +#### Entity type + +Your device does not support video playback. + +#### Fluid + +Your device does not support video playback. + +#### Frog variant + +Your device does not support video playback. + +#### Game event + +Your device does not support video playback. + +#### Instrument + +Your device does not support video playback. + +#### Item + +Your device does not support video playback. + +#### Jukebox Song + +Your device does not support video playback. + +#### Map decoration type + +Your device does not support video playback. + +#### Memory module type + +Your device does not support video playback. + +#### Menu + +Your device does not support video playback. + +#### Mob effect + +Your device does not support video playback. + +#### Painting variant + +Your device does not support video playback. + +#### Particle + +Your device does not support video playback. + +#### Pig variant + +Your device does not support video playback. + +#### Potion + +Your device does not support video playback. + +#### Sound + +Your device does not support video playback. + +#### Structure + +This argument kicks the client, so no preview for this one ¯\_(ツ)_/¯ + +#### Structure type + +Your device does not support video playback. + +#### Trim material + +Your device does not support video playback. + +#### Trim pattern + +Your device does not support video playback. + +#### Villager profession + +Your device does not support video playback. + +#### Villager type + +Your device does not support video playback. + +#### Wolf sound variant + +Your device does not support video playback. + +#### Wolf variant + +Your device does not support video playback. + +## Paper-specific Arguments + +These arguments return objects frequently used in Paper API. + +### Block state argument + +The block state argument can be used for getting a block type and explicit, associated data. + +#### Example usage + +```java +public static LiteralCommandNode blockStateArgument() { + return Commands + .literal("blockstateargument") + .then(Commands.argument("arg", ArgumentTypes.blockState()) + .executes(ctx -> { + final BlockState blockState = ctx.getArgument("arg", BlockState.class); + ctx.getSource().getSender().sendPlainMessage("You specified a " + blockState.getType() + "!"); + return Command.SINGLE_SUCCESS; + })) + .build(); +} +``` + +#### In-game preview + +Your device does not support video playback. + +### ItemStack argument + +The item stack argument is the way to retrieve an `ItemStack` following the same argument format as the Vanilla `/give []` command as its second argument. + +* The user may also define components to further customize the `ItemStack`. +* If you only require a `Material`, you should instead check out the [registry arguments](#registry-arguments). + +#### Example usage + +```java +public static LiteralCommandNode itemStackArgument() { + return Commands + .literal("itemstack") + .then(Commands.argument("stack", ArgumentTypes.itemStack()) + .executes(ctx -> { + final ItemStack itemStack = ctx.getArgument("stack", ItemStack.class); + if (ctx.getSource().getExecutor() instanceof Player player) { + player.getInventory().addItem(itemStack); + ctx.getSource().getSender().sendRichMessage("Successfully gave a ", + Placeholder.component("player", player.name()), + Placeholder.component("item", Component.translatable(itemStack))); + return Command.SINGLE_SUCCESS; + } + ctx.getSource().getSender().sendRichMessage("This argument requires a player!"); + return Command.SINGLE_SUCCESS; + })) + .build(); +} +``` + +#### In-game preview + +Your device does not support video playback. + +### NamespacedKey argument + +This argument allows the user to provide any artificial (namespaced) key. + +* The return value of this argument is a `NamespacedKey`, which makes it useful when dealing with Bukkit API. + +#### Example usage + +```java +public static LiteralCommandNode namespacedKeyArgument() { + return Commands + .literal("namespacedkey") + .then(Commands.argument("key", ArgumentTypes.namespacedKey()) + .executes(ctx -> { + final NamespacedKey key = ctx.getArgument("key", NamespacedKey.class); + ctx.getSource().getSender().sendRichMessage("You put in !", + Placeholder.unparsed("key", key.toString())); + return Command.SINGLE_SUCCESS; + })) + .build(); +} +``` + +#### In-game preview + +Your device does not support video playback. + +### Time argument + +The time argument allows the user to define a time frame, similar to the Vanilla `/time