-
Notifications
You must be signed in to change notification settings - Fork 0
v5 Text and Components
Available in spigot-utils and its inheritors (spigot-jar).
v5 replaced coloured Strings with VersionedComponent, a component type that works identically on
every supported server from 1.8.8 to 26.2. Most of KamiCommon now takes and returns it, and the String
overloads on ItemBuilder are deprecated as of 5.0.0-alpha.26.
You never name an Adventure type, and you never write a version check.
VersionedComponentSerializer s = NmsAPI.getVersionedComponentSerializer();It is a factory, not a holder. Six ways in:
s.fromMiniMessage("<gold>Hello"); // MiniMessage
s.fromMiniMessage("<gold>Hi <player>", placeholders); // MiniMessage + TextPlaceholder...
s.fromLegacyAmpersand("&6Hello"); // &6 codes
s.fromLegacySection("§6Hello"); // §6 codes
s.fromPlainText("Hello"); // no formatting at all
s.fromJson(json); // Minecraft component JSONEvery builder method returns a new instance. Nothing mutates.
VersionedComponent msg = s.fromMiniMessage("<yellow>[Claim]")
.click(ClickAction.RUN_COMMAND, "claim daily") // no leading slash
.hover(s.fromMiniMessage("<green>Click to claim"))
.decorate(TextDecoration.ITALIC, false)
.append(s.fromPlainText(" today"));
msg.sendTo(player); // also sendTo(CommandSender...) and sendTo(Collection<CommandSender>)Five ways out:
msg.serializeMiniMessage();
msg.serializeLegacyAmpersand();
msg.serializeLegacySection();
msg.serializePlainText();
msg.serializeJson(); // use this to store or transport a componentserializeJson() and fromJson(String) are the pair to use for persistence or for sending a component
between services. plainText() is deprecated in favour of serializePlainText().
hoverItem(ItemStack) is the item form of hover(VersionedComponent). The hover shows the item with
its name, lore and enchantments as a player would see them in an inventory. A component carries one
hover, so the two methods replace each other.
VersionedComponent line = s.fromMiniMessage("<yellow>[Kit icon]").hoverItem(icon);Air throws IllegalArgumentException, because there is no item to show.
⚠️ On 1.8 through 1.12 the hover loses the item'sDamagevalue. An item hover carries an id, a count and atagcompound, and on those versions a variant or a durability lives in a top-levelDamagefield, outsidetag, with nowhere to go. Red wool therefore hovers as white wool and a worn pickaxe as an undamaged one. Name, lore and enchantments are insidetagand survive. From 1.13 the variant is part of the id and durability moved intotag, so nothing is lost. This is the shape of an item hover itself, not a limit of this library.
TextPlaceholder fills a <tag> in a MiniMessage string. There are three kinds and the difference
matters:
TextPlaceholder.literal("player", player.getName()); // inserted verbatim, MiniMessage NOT parsed
TextPlaceholder.miniMessage("rank", "<red><bold>ADMIN"); // value is parsed as MiniMessage
TextPlaceholder.component("item", someComponent); // value is an existing componentThe key is the tag name without angle brackets, so literal("player", ...) fills <player>.
⚠️ Useliteral(...)for anything a user controls, such as names, nicknames, chat input and faction names. The other two parse their value, so a player called<red>x</red>could inject formatting. This is the only escape-safe route.
VersionedComponent msg = s.fromMiniMessage(
"<gray>Welcome back, <gold><player></gold>!",
TextPlaceholder.literal("player", player.getName()));ClickAction: RUN_COMMAND, SUGGEST_COMMAND, OPEN_URL, COPY_TO_CLIPBOARD. Command values carry
no leading slash.
COPY_TO_CLIPBOARDrequires 1.16 or newer. Below that it throwsUnsupportedOperationExceptionnaming the server version, rather than silently dropping the click.
Hovers and clicks reach the client on every supported version. Below 1.18.2 a component is serialized
and handed to the bungee-chat the server itself ships, which reads the hoverEvent and clickEvent key
names, so those are the names KamiCommon emits on those tiers.
TextDecoration: BOLD, ITALIC, UNDERLINED, STRIKETHROUGH, OBFUSCATED.
Minecraft italicises custom item names and lore by default. KamiCommon suppresses that for you, so
an item name written through VersionedComponentUtil renders upright on every supported version
without any decoration call. Ask for italics explicitly if you want them:
s.fromMiniMessage("<light_purple>Daily Crate").decorate(TextDecoration.ITALIC, true);Only the unset case is suppressed, so an explicit true is honoured and an explicit false is
harmless.
VersionedComponentUtil writes components onto an ItemMeta on any version:
ItemMeta meta = stack.getItemMeta();
VersionedComponentUtil.setDisplayName(meta, s.fromMiniMessage("<gold>Excavator"));
VersionedComponentUtil.setLore(meta, List.of(
s.fromMiniMessage("<gray>Right-click to dig")));
VersionedComponentUtil.addLoreLine(meta, s.fromMiniMessage("<dark_gray>Legendary"));
stack.setItemMeta(meta);getDisplayName(meta) and getLore(meta) read them back, returning null when unset.
ItemBuilder takes components directly, which is usually easier:
new ItemBuilder(XMaterial.DIAMOND_PICKAXE)
.displayName(s.fromMiniMessage("<gold>Excavator"))
.lore(s.fromMiniMessage("<gray>Right-click to dig"))
.build();For chat messages, especially ones read from config, MiniMessageBuilder handles multiple lines,
replacements and PlaceholderAPI in one object.
MiniMessageBuilder.fromMiniMessage(config, "messages.welcome")
.replace("{player}", player.getName())
.send(player);Four factory families, each with five overloads (a single String, a Collection<String>, a
String..., and a Bukkit or KamiCommon ConfigurationSection plus a key):
fromMiniMessage(...)fromLegacyAmpersand(...)fromLegacySection(...)-
fromStringParser(...), which detects the format, see below
A config key may hold a String or a List<String>; a list becomes one line per entry. Anything else
throws IllegalArgumentException.
PlaceholderAPI translation is on by default; turn it off with setTranslatePAPI(false).
⚠️ replace(String, String)serializes to MiniMessage, replaces, and re-parses, so a replacement containing MiniMessage syntax will be parsed. PAPI translation works the same way. For user-controlled values useTextPlaceholder.literal(...)on the serializer instead.
MessageBuilder still exists and is not deprecated. It is the String-based sibling. Use
MiniMessageBuilder for new code.
Menu titles, icon names, every lore line and subsystem message prefixes are read through
ColoredStringParser.parse(String), which picks a format from the content, in this order:
- contains a
§section symbol → legacy section codes - contains a legacy colour code, meaning
&followed by a code character → legacy ampersand codes - contains a
<tag>→ MiniMessage - otherwise → plain text
So &7Usage: &f/kit <name> is read as legacy and keeps its colours, while <gray>Tips & Tricks is read
as MiniMessage, because a bare & in prose is not a colour code. You cannot mix the two formats in one
string; pick one per line.
ComponentLogger writes components to console. KamiPlugin already builds one:
getColorComponentLogger().info(s.fromMiniMessage("<green>Loaded <count> arenas",
TextPlaceholder.literal("count", String.valueOf(arenas.size()))));info, warn, warning, severe and error each take a component, or a Throwable and a component.
debug takes a component only. setMessagePrefix(VersionedComponent) prefixes every line. The String-taking overrides are
deprecated in favour of the component forms, as is KamiPlugin's old string logger getter.
- Adventure and Server Versions, covering which Adventure your server uses and how to use Adventure directly
Setup
Spigot
Text
Data
Migration
Other versions