Content generated with AI — it may contain mistakes.

Gameplay

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.

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
KeyWhat it does
enabledShow it at all — a section can stay written but off.
titleA list. Several entries animate: each refresh shows the next.
linesTop first. At most 15; extra lines are dropped.
update.intervalTicks between refreshes. 20 ticks is one second.
update.smartSend 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 line that expands

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());
KeyWhat it does
enabledShow it at all.
kindTEXT, ITEM or BLOCK.
linesThe text, for TEXT.
item / blockWhat floats, for the other two.
offset-x/y/zWhere it sits relative to the location given.
view-distancePast this, nothing is sent.
refreshHow 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