First steps
The first ten minutes: the menu, what a player already owns, granting a tag, and getting the identity into your chat format.
The plugin is installed and the server is up. Nothing about your chat has changed, no player has been given anything, and the catalogue is sitting there with 180 tags and about 350 colours in it. This is the shortest route from that to a player wearing something and everybody seeing it.
Open the menu
/cc in game. The permission it wants, exyliachatcosmetics.command.cosmetics, is declared
default: true in plugin.yml, so every player already has it — an undeclared node is
operator-only in Bukkit, which is exactly why the ones a player needs to use the plugin are
declared and the ones that decide what they own are not.
The main screen has seven things on it: YOUR CHAT, a live preview of the line the player would send right now; IDENTITY for tags, nick colours and rank colours; MESSAGE for chat colours, shadow colours, fonts and modifiers; FAVORITES; LOADOUTS; YOUR COLLECTION, which counts what they own; and TAKE IT ALL OFF, drawn only when there is something to take off. There is no close button anywhere — a player closes a window the way they close every other one.
Four top-level shortcuts open a browser directly, on the same permission: /tags, /nickcolors,
/rankcolors and /chatcolors.
See what a player already owns
Open /cc as somebody with no permissions at all and most rows read Not yours yet. That is
the deliberate default: a catalogue entry is owned through the node
exyliachatcosmetics.<type>.<id> or through a grant, and nothing else.
Rank colours are the exception, and it is worth understanding before you write a single node. They
ship with permission: false — the type's own default, the other way round from every other file
— which means the permission node does not decide who owns one. What decides is the entry's
groups list, read from LuckPerms.
| Tab | Entries | Who owns them |
|---|---|---|
solid | 15 | Everyone. They name no groups and set no node, so every rank may wear them. |
metal, gems, gradient, animated | 54 | Whoever holds exyliachatcosmetics.rank_color.<id>. These entries set permission: true back on, one by one. |
staff | 8 | Whoever is in one of the groups the entry names — owner, admin, mod and so on. |
So on a server with LuckPerms and nothing else configured, a brand-new player can already open
/rankcolors and repaint their rank prefix in any of fifteen flat colours. Everything else waits
for you.
The eight staff entries list groups such as owner, admin, mod and helper. If LuckPerms
on your server calls them something else, the tab is empty for everybody until you edit the
groups lists in cosmetics/rank-colors.yml.
One catalogue tag, event, also ships permission: false. There is no node that grants it — it
exists to be handed out and cannot be bought.
Give somebody a tag
/cca give Notch tag:heart
/cca give Notch tag:heart 14d --source PURCHASE --note "October sale"A cosmetic is always named type:id, and it is tab-completed. No duration means permanent;
14d is fourteen days, in ExyliaLib's duration format (30m, 2h, 14d, 1w, decimals
allowed). Without --source the grant is recorded as ADMIN; --source takes PURCHASE,
REWARD, EVENT, ACHIEVEMENT or EXTERNAL, and --ref and --note are yours to fill with an
order id or a reason.
The target may be offline as long as they have played before. Check what stuck with
/cca list Notch for every grant with its row id, source and time left, or /cca check Notch tag:heart for the one answer.
A player may hold several grants for the same cosmetic at once — a permanent one from a rank, a 14-day admin grant, a 30-day purchase — and removing one never touches the others.
Open a whole tab at once
Granting 180 tags one at a time is not the intention. Four shapes of node, from narrowest to widest:
| Node | Owns |
|---|---|
exyliachatcosmetics.tag.heart | that one cosmetic |
exyliachatcosmetics.tag.category.symbols | every tag in the symbols tab |
exyliachatcosmetics.tag.* | every tag |
exyliachatcosmetics.* | everything in the catalogue |
The type ids are tag, nick_color, rank_color, chat_color, shadow_color, font and
modifier, and the category is the tab id as it is written in the file — so a VIP rank that
should get the premium colours and every font is:
/lp group vip permission set exyliachatcosmetics.chat_color.category.premium
/lp group vip permission set exyliachatcosmetics.nick_color.category.premium
/lp group vip permission set exyliachatcosmetics.font.*Ownership by node is never stored. It is asked live and memoised for the session, so taking the node away takes the cosmetic off without anything having to be cleaned up — and what the player had equipped stays on their row, ready to be drawn again the day the node comes back.
Put the identity into your chat format
The plugin never cancels a chat event and never owns your format. The tag and the coloured name are yours to place, as placeholders, in whatever chat plugin you already run:
%exyliachatcosmetics_tag%%exyliachatcosmetics_nick%<gray>: <white>%message%%exyliachatcosmetics_tag% is the worn tag with its trailing space already attached, and a
custom tag the player made wins over a catalogue one. %exyliachatcosmetics_nick% is their name
in their nick colour. %exyliachatcosmetics_identity% is the two together.
Three notations, because chat plugins do not agree on one — pick the suffix your plugin parses:
| Placeholder | Output |
|---|---|
%exyliachatcosmetics_tag% | MiniMessage, <#ffd700>[MVP]</#ffd700> — the default |
%exyliachatcosmetics_tag_legacy% | & codes, with &#rrggbb for hex |
%exyliachatcosmetics_tag_section% | § codes, with §x§r§r… for hex |
The name carries the same three: %exyliachatcosmetics_nick%,
%exyliachatcosmetics_nick_legacy% and %exyliachatcosmetics_nick_section%. So the same format
for a legacy-string chat plugin reads:
%exyliachatcosmetics_tag_section%%exyliachatcosmetics_nick_section%§7: §f%message%Getting the wrong one is the single most common mistake here, and it looks like raw <#ffd700>
text in chat. Outside ExyliaLib's own text these need PlaceholderAPI installed to resolve.
A player wearing nothing yields an empty string, so a format with %exyliachatcosmetics_tag%
in it is safe for everybody from the first day.
Pick the right hook for your chat plugin
That covers the identity. The message body — the chat colour, the shadow, the font, the
modifiers — is styled by the hook, and the right mode depends on how your chat plugin reads a
message. chat.hook in config.yml:
| You run | hook | Why |
|---|---|---|
Paper's own chat, or any plugin that renders through AsyncChatEvent / a ChatRenderer | decorate | The styled body replaces the decorated message before any chat plugin sees it, and nothing is cancelled. The default, and the right answer for most servers. |
A plugin that reads AsyncChatEvent.message() but ignores decoration | chat_event, with chat.priority below its own (LOW) | The rewrite lands before it reads. |
A plugin still on AsyncPlayerChatEvent | legacy_event, at a priority below it | The string it reads already carries § colours. |
| Spigot, with no Paper events at all | anything | decorate and chat_event fall back to legacy_event with a warning at startup. |
| Your own code, composing the line yourself | off | Nothing is touched; use ChatCosmeticsAPI.styleMessage so nothing is styled twice. |
Any change to a message body — a colour included — marks it "modified" for a vanilla client. It
still shows, but a client with Only Show Secure Chat enabled hides it. Every chat-colour
plugin has this property; servers that care set enforce-secure-profile=false.
Look at it before anybody else does
/cc preview
/cc preview whatever you likeDraws the line the player's chat would produce right now, into their own chat and nobody else's.
Its shape is preview.format in config.yml, %tag%%prefix% %name%%suffix%{letters_black}: %message%
by default, so it shows the rank prefix in the rank colour being looked at as well as the tag and
the name.
From the console or as an admin, /cca preview <player> [message] sends the target their own line,
and /cca render <player> sends the pieces one at a time — the tag, the coloured name, a styled
sample — which is what tells you which of the three is wrong when something looks off.
After the first ten minutes
Everything above is the cosmetics half working through the chat you already run. Two directions from here: put more of the catalogue in players' hands, or hand your chat to the plugin as well.
Available, owned, equipped — three separate questions, grants that expire, and why nothing is ever deleted for saying no.
PermissionsEvery node, and which ones a fresh install already grants.
PlaceholdersAll of them, the three notations, and the fallback syntax.
The chat moduleChannels, formats, filter, mentions, whispers and the announcer, if you want this plugin to run the chat too.
Something missing on this page? Tell us on Discord