Skip to content

Messages and text

Lesson 6.2

Chat messages, action-bar hints, command replies: mods talk to players a lot. The easy helpers send plain text. For colours, translations and texts built from parts, the API has text components.

Plain messages

You know these already:

player.send_message("Hello!");                                   // chat
player.send_message(std::format("You have {} rubies.", n));      // chat, with formatting
player.send_action_bar("Ready.");                                // above the hotbar
clight::broadcast("The event starts now!");                      // chat, to everyone

They are all server-side. std::format builds a std::string the same way clight::log does: {} is replaced by the next value.

Text components

A text is what Minecraft really sends: a piece of text with a style, which can have more pieces attached. In C++ it is a clight::Text. Make one, style it, send it:

clight::Text t = clight::literal("Hello!");
player.send_message(t);

That is exactly what player.send_message("Hello!") does inside. clight::Text releases itself, like every owned class (see Handles and strings).

Function or method Does
clight::literal("...") A text with exactly these characters.
clight::text::translatable("key") A text looked up in the player’s language file.
t.color(0xRRGGBB) Sets the colour.
t.append(child) Attaches a child text after this one.
t.to_plain() The text without styles, as an Expected<std::string>.

And where texts go:

Method Shows it
player.send_message(t) In the player’s chat.
player.send_action_bar(t) Above the player’s hotbar.
t.server_broadcast() In everybody’s chat.
ctx.send_success(t) / ctx.send_failure(t) As a command reply (both also take a plain string).

None of them take your text away: you can send the same clight::Text again, or change it and send it once more.

Colours

Colours are written 0xRRGGBB: red, green and blue, each from 00 to FF.

clight::Text t = clight::literal("Ruby found!");
t.color(0xE0115F);   // ruby red
player.send_message(t);

A few vanilla chat colours: green 0x55FF55, yellow 0xFFFF55, red 0xFF5555, aqua 0x55FFFF, gold 0xFFAA00, grey 0xAAAAAA.

Texts from parts

append builds a message with several colours. The child inherits the parent’s style unless it sets its own:

void send_score(clight::Entity player, int score) {
    clight::Text msg = clight::literal("Your score: ");
    msg.color(0xAAAAAA);

    clight::Text value = clight::literal(std::to_string(score));
    value.color(0xFFAA00);
    msg.append(value);   // msg keeps its own reference to value

    player.send_message(msg);
}

append takes its own reference to the child, so value can go out of scope without breaking msg. When the last owner is gone, the game frees the text.

Translations

Mods are played in many languages. Instead of writing English into your code, write a translation key, and put the texts into language files:

player.send_message(clight::text::translatable("my_mod.welcome"));

assets/my_mod/lang/en_us.json:

{
  "my_mod.welcome": "Welcome to the server!"
}

assets/my_mod/lang/de_de.json:

{
  "my_mod.welcome": "Willkommen auf dem Server!"
}

Each player sees the text in their own language, and falls back to English when their language is missing. The key is sent as it is, so players without your mod see my_mod.welcome. For messages from a server-side mod that players may not have, use literal text.

Values in translations

For “You have 3 rubies”, the language file marks the value with %s, and add_arg adds it:

{ "my_mod.rubies": "You have %s rubies." }
clight::Text t = clight::text::translatable("my_mod.rubies");
t.add_arg(clight::literal(std::to_string(3)));
player.send_message(t);

Several add_arg calls fill %s in order; a language may also write %2$s and %1$s.

Styles, clicks and hovers

clight::Text link = clight::literal("[Open the wiki]");
link.set_style(CL_STYLE_BOLD | CL_STYLE_UNDERLINED, true);   // false switches a style off on purpose
link.click(CL_TEXT_CLICK_OPEN_URL, "https://example.com/ruby-wiki");
link.hover(clight::literal("Opens the wiki in your browser"));
player.send_message(link);

The styles are CL_STYLE_BOLD, CL_STYLE_ITALIC, CL_STYLE_UNDERLINED, CL_STYLE_STRIKETHROUGH and CL_STYLE_OBFUSCATED. The click actions:

Action A click
CL_TEXT_CLICK_OPEN_URL asks, then opens the address (https:// or http:// only)
CL_TEXT_CLICK_RUN_COMMAND runs the command as the player ("/spawn")
CL_TEXT_CLICK_SUGGEST_COMMAND puts the text into the chat box
CL_TEXT_CLICK_COPY_TO_CLIPBOARD copies the value

Titles

player.send_title("Round 2", "Get ready!");          // vanilla's times
player.send_title("Go!", {}, 5, 20, 10);             // fade in, stay, fade out in ticks
player.clear_title();

An empty subtitle keeps the current one, and -1 keeps a time.

Messages only this player sees

On the client, clight::text::client_show_message(text, overlay) shows a chat line (overlay = true: above the hotbar) without sending anything to the server, and clight::text::client_show_title(...) a title. They work on any server, even one without your mod.

Reading a text

to_plain() turns a text back into a string, without colours:

if (auto plain = msg.to_plain()) clight::log::info("sent: {}", *plain);

Try it

Write void announce(std::string_view who, std::string_view what) that sends everyone a message like Alex found a diamond!, where the name is gold, the thing is aqua and the rest is white.

Show a solution
void add_part(clight::Text& parent, std::string_view s, cl_color color) {
    clight::Text part = clight::literal(s);
    part.color(color);
    parent.append(part);
}

void announce(std::string_view who, std::string_view what) {
    clight::Text msg = clight::literal("");
    msg.color(0xFFFFFF);
    add_part(msg, who, 0xFFAA00);
    add_part(msg, " found ", 0xFFFFFF);
    add_part(msg, what, 0x55FFFF);
    add_part(msg, "!", 0xFFFFFF);
    msg.server_broadcast();
}

The parent is an empty text that only holds the parts. add_part takes the parent by reference (clight::Text&), so it adds to the real message instead of a copy. Each part is released at the end of add_part, while msg keeps its own reference to it.

Recap: the easy helpers send plain strings (build them with + or std::format); clight::literal and clight::text::translatable make a clight::Text you colour with color, combine with append, and send with send_message or server_broadcast, and it releases itself.