Skip to content

Adventure Series: Tag Resolvers

TagResolvers are a way to declare custom tags for your MiniMessage string. Most places which take in TagResolvers usually take in a varargs one. That means that you can just put in however many you need. In case you do require to have them all condensed in just one, Adventure provides the TagResolver.resolver(TagResolver...) method for convenience.

The simplest form of TagResolvers are Placeholders. These allow the direct insertion of Components or strings into serialized component. Each placeholder takes in the tag name as its first parameter and a value as their second parameter. Tags should always follow the snake_case_naming_scheme and only contain alphabetical characters and underscores.

There are three inserting placeholder, and one styling placeholder. The styling one will, instead of adding text content, modify the style of text.

The most common use of placeholders are the inserting ones. You can use these whenever you have a Component and want to embed it into your MiniMessage string. This might look like this:

final Component msg = miniMessage().deserialize("I am currently holding a <aqua><item></aqua>!",
Placeholder.component("item", Component.text("Diamond Pickaxe"))
);
In-game preview

Styling placeholders can be used like this:

miniMessage().deserialize("<red><custom_style>Hey</custom_style> o/",
Placeholder.styling("custom_style", TextDecoration.BOLD)
);

The code above would essentially be equal to just writing

miniMessage().deserialize("<red><bold>Hey</bold> o/");

But text decorations aren’t the only thing you can apply! Hover and click events also count as styling. The following code makes the <custom_style> tag style with an acacia boat hover:

final ItemStack stack = ItemType.ACACIA_BOAT.createItemStack();
final Component component = miniMessage().deserialize("<red><custom_style>Hey o/",
Placeholder.styling("custom_style", stack.asHoverEvent())
);
In-game preview

These resolvers work similarly to the Placeholder ones. The first parameter of the resolver(String, Tag) method is, once again, the name of the tag. The second parameter is the Tag itself.

The first pair of methods are the inserting ones. These will just insert a Component into the serialized component. Any content which is inside of the tag will be added as a child Component, meaning that any style of the inserted component will also be used on the child component, unless it specifies its own style.

Unstyled text, <inserted_component> now the text shares the inserted component's style</inserted_component> and now it doesn't.

The second pair of methods are the selfClosingInserting ones. These work similarly to the inserting ones, but do not need closing. That also means that no styling will be applied to other components.


The styling tag works the same way as Placeholder.styling(...).

One of the more complex ways to retrieve a TagResolver, but also one of the most versatile ones, is using a BiFunction<ArgumentQueue, Context, Tag>. This allows for argument input and a lot more control flow. A very good example of its use, made by @mbaxter, is the following papi tag resolver for PlaceholderAPI. This allows parsing placeholder api placeholders in MiniMessage (%player_name% turns into <papi:player_name>).

/**
* Creates a tag resolver capable of resolving PlaceholderAPI tags for a given player.
*
* @param player the player
* @return the tag resolver
*/
public @NotNull TagResolver papiTag(final @NotNull Player player) {
return TagResolver.resolver("papi", (argumentQueue, context) -> {
// Get the string placeholder that they want to use.
final String papiPlaceholder = argumentQueue.popOr("papi tag requires an argument").value();
// Then get PAPI to parse the placeholder for the given player.
final String parsedPlaceholder = PlaceholderAPI.setPlaceholders(player, '%' + papiPlaceholder + '%');
// We need to turn this ugly legacy string into a nice component.
final Component componentPlaceholder = LegacyComponentSerializer.legacySection().deserialize(parsedPlaceholder);
// Finally, return the tag instance to insert the placeholder!
return Tag.selfClosingInserting(componentPlaceholder);
});
}

Learn Paper Dev is licensed under CC BY-NC-SA 4.0