Content generated with AI — it may contain mistakes.

Chat module

Formats

One file per format under chat/formats/: components, hovers, clicks, the token list, and how a format is chosen.

A format is a whole chat line, described by a file under chat/formats/. The file name is the format name: vip.yml is the format vip. Two ship — default.yml and msg.yml — and both are rewritten on the first start if they are missing.

A file is one format, or several

A file with components: at its root is one format, named after the file.

A file without one is read block by block: each top-level block that has a components: section becomes a format named file.block. That is how msg.yml produces msg.sender and msg.receiver. A block format never takes part in the weight contest below — it is asked for by name, by the feature that needs it.

plugins/ExyliaChatCosmetics/chat/formats/vip.yml
permission: exyliachatcosmetics.chat.format.vip   # empty = everybody
weight: 10                                        # heaviest qualifying format wins
per-viewer: false                                 # true renders the line once per reader
components:
  '1':
    text: '{tag}{nick} {letters_black}» '
    hover:
      - '{secondary}Player'
      - ' {letters_black}▎ {letters}Name {letters_black}» {info}{name}'
    click: 'SUGGEST_COMMAND:/msg {name} '
  '2':
    text: '{message}'
KeyDefaultMeaning
permissionemptyWho may be given this format. Empty means everybody
weight0When a player qualifies for several, the heaviest wins
per-viewerfalseRender the line once per reader even when nothing in it asks for it
components—The pieces of the line, in the order they are written

The component keys are names, not indices; '1', '2' is a convention, not a requirement. A component with no text is skipped and reported. A format that ends up with no usable component is dropped, and if default is the one that failed the console says so and messages are sent bare.

Inside a component

KeyHolds
textWhat is drawn. Palette tokens, & codes and MiniMessage all work
hoverOne line or a list, shown while the mouse is over this piece
clickRUN_COMMAND:/x, SUGGEST_COMMAND:/x, OPEN_URL:https://x or COPY:text

A click that is not one of those four is reported when the file is read, rather than silently dropped on every message afterwards.

Tokens work in all three. A click carries its tokens as plain text, so SUGGEST_COMMAND:/msg {name} puts the player's actual name into the chat box rather than the literal {name}.

Which format a message wears

The channel's own

If the channel names a format and that file loaded, it is used, whoever is talking.

The heaviest one the sender qualifies for

Every top-level format whose permission the sender holds, or that has none. The highest weight wins. Block formats such as msg.sender never enter this contest.

`default`

When none qualified.

Tokens

Tokens are components, placed into the line directly — no placeholder round-trip, and a tag or a coloured name keeps its own colours instead of being flattened into a string.

TokenIs
{message}The styled message body
{name}The plain name
{nick}The name in the player's nick colour
{tag}The equipped tag, with its format
{prefix}The rank prefix, in the player's rank colour
{suffix}The rank suffix, in that same colour
{channel}The channel's name, parsed, so its own colour survives

Private-message formats get their own set instead: {message}, {sender}, {sender_nick}, {sender_tag}, {receiver}, {receiver_nick}, {receiver_tag}.

Braces rather than percent signs, so a token can never collide with a placeholder. A brace pair nobody claims — {primary}, {letters_black} — is left for the text engine, which reads it as a palette colour.

The colour a line was written in carries across a token: the piece before {nick} opens a colour, the token is drawn under it as a fallback, and the piece after it continues the same sentence. Anything that names its own colour, an item's name for one, still wins.

Placeholders and per-viewer

Any %placeholder% ExyliaLib or PlaceholderAPI knows works in text, hover and click. By default it resolves for the sender, because the line is about them.

Turn per-viewer: true on and the line is rendered once for each reader: %player_…% is then the reader and %target_…% stays the sender. That is the switch for a line that says something about whoever is looking at it.

A %rel_…% placeholder makes a format viewer-aware on its own, in text, hover or click, without per-viewer being set — a relational placeholder has no meaning without a reader.

Per-viewer costs a render per reader

A viewer-unaware format is rendered once per message and handed to everybody. A viewer-aware one is rendered once per reader. On a busy server that is the difference between one render and a hundred, so turn it on only for a format that needs it.

Padding falls outside the hover and the click

The blanks a component is padded with are taken off both of its ends before the hover and the click go on, and put back afterwards. A gap belongs to neither of the pieces it separates.

Without that, the space in '{nick} ➞ ' sat inside the hover, and hovering the arrow answered "Player" right where the message began. The peeling happens on the rendered piece rather than on the written text, so a blank that a placeholder left behind — an empty rank prefix in '{prefix} {nick}' — falls outside the hover just the same.

This is also why msg.yml has a component that is nothing but a space between the heading and the message: a deliberate gap that answers to neither.

To check where a hover actually stops, use /cca chat line [message]. It renders your own line, sends it to you, and writes to the console the same line broken into the stretches that share a hover and a click.

What ships

default.yml

Three components, and it is a worked example of everything above.

ComponentDrawsHoverClick
'1'{prefix} {nick}{suffix}An INFORMATION box: ping through %player_ping%, the rank through {prefix}, and a line inviting a private messageSUGGEST_COMMAND:/msg {name}
'2'➠——
'3'{message}A WARNING box offering to report the messageRUN_COMMAND:/report {name} offensive_language

The separator is its own component precisely so that neither the name's hover nor the message's report click reaches the arrow between them. weight: 0, no permission: everybody gets it unless a heavier format applies.

The report click assumes a report command

/report is not shipped by this plugin. If your server has no such command, change or remove the click on the third component.

msg.yml

Two blocks, sender and receiver, giving the formats msg.sender and msg.receiver. Each has three components: a heading — [You ➜ them] on one screen, [them ➜ You] on the other — that hovers with who the message is with and clicks to SUGGEST_COMMAND:/reply , then a bare space, then {message} hovering "Click to copy it" with COPY:{message}.

Each screen is rendered with its own reader as the viewer and the other person as the placeholder target, so a hover about "them" is about the right person on both.

The format permission node is on Permissions, and /cca chat line on Commands.

Something missing on this page? Tell us on Discord