Sidebars, holograms and nametags
Everything drawn on a player's screen, sent as packets and declared in configuration.
Four modules with one thing in common: none of them creates real server state. No scoreboard team, no armour stand, no entity to leak.
Sidebars
Scoreboards.show(this, player, config.ffa());SidebarConfig nests in your own config record, so the sidebar lives in the owner's file:
scoreboard:
enabled: true
title:
- "{primary}&lFFA"
lines:
- " {muted}❙ {letters}Kills: {success}%kills%"
- " {muted}❙ {letters}KDR: {highlight}%kdr%"
update:
interval: 15
smart: true| Key | What it does |
|---|---|
enabled | Show it at all — a section can stay written but off. |
title | A list. Several entries animate: each refresh shows the next. |
lines | Top first. At most 15; extra lines are dropped. |
update.interval | Ticks between refreshes. 20 ticks is one second. |
update.smart | Send only the lines that changed instead of the whole board. |
Scoreboards.show returns a Board: refresh(), updateData(map), hide(). Boards stack per
player — showing one pauses the previous, and closing it brings the previous back. That is what lets
an event's sidebar cover a hub's without either plugin knowing about the other.
A placeholder returning text with line breaks becomes several lines. It is how one %objectives%
value can draw three rows without the file knowing how many there will be.
Holograms
Holograms.show(this, "trophy", location, config.trophy());| Key | What it does |
|---|---|
enabled | Show it at all. |
kind | TEXT, ITEM or BLOCK. |
lines | The text, for TEXT. |
item / block | What floats, for the other two. |
offset-x/y/z | Where it sits relative to the location given. |
view-distance | Past this, nothing is sent. |
refresh | How often the text is re-rendered. |
They are display-entity packets: per-player when the text differs per viewer, shared when it does not. Nothing exists server-side, so a hologram cannot be pushed by a piston, killed by a mob, or left behind when the plugin crashes.
Holograms.get(plugin, id), all(plugin), remove(plugin, id) and removeAll(plugin) manage them by
id. isSupported() answers honestly when PacketEvents is absent.
Nametags
PluginNametags tags = Nametags.of(this);
tags.paint(viewer, target, style); // how one player sees another
tags.paintEachOther(team, style); // a whole team, mutually
tags.reset(viewer, target);
tags.resetEverywhere(target);The whole point is per viewer, not per player: the same player can be red to one person and blue to another, which is what a team game needs and what a scoreboard team cannot do without fighting every other plugin for the same team name.
Name colour, glow colour and collision travel together as a style. Vanilla clients are included — this is not a client mod feature.
Without PacketEvents, Nametags.isSupported() is false and every call does nothing rather than
throwing.
Client waypoints and cooldowns
For players on Lunar (through Apollo) or Feather:
Clients.of(this).waypoints().show(player,
Waypoint.at("koth", location).colour("#ff5555"));
Clients.of(this).waypoints().remove(player, "koth");
Clients.of(this).waypoints().clear(player);The waypoint is keyed by name, and the name is the key — two waypoints called spawn are one
waypoint. Keying them per plugin is what stops a lobby plugin's marker and an event's marker from
deleting each other.
Client cooldowns and teammate markers work the same way. A player whose client supports none of it simply receives nothing; the caller never branches on which client somebody is using.
Something missing on this page? Tell us on Discord