Simple Scoreboard

A Plugin wich adds a new Scoreboard desing, wich can also be configured ingame with a nice GUI.

20

Simple Scoreboard

SimpleScoreboard

A configurable scoreboard plugin for Paper. Author your sidebar, tab-list, and below-name displays in YAML or edit them in-game from a chest GUI. Multi-board priority selection by world, permission, or gamemode. Frame rotation, horizontal scrolling, and full Adventure MiniMessage formatting.

Features

- Diff-based render: sidebar, tab-list (header + footer), below-name objective - Diff-based render with conditions on world, permission, gamemode (combinable, AND-evaluated, first match wins) - Diff-based render: frame rotation and horizontal text scrolling, configurable per line and tick-precise - Diff-based render for all text — colors, gradients, rainbows, click and hover events - Diff-based render for player, world, ping, coords, gamemode, health, online count, max players, TPS - Diff-based render integration when present — every `%papi_*%` token just works - Diff-based render (`/sb gui`) for the impatient: edit boards, conditions, lines, and animations from a chest menu with live preview - Diff-based render on every `/sb` subcommand including dynamic board names - Diff-based render with persistence (`/sb toggle`) - Diff-based render without server restart (`/sb reload`) - Diff-based render: per-player last-sent cache means packets only fire when output actually changes — static lines never re-send

Quick Example

```yaml defaults: tick-interval: 1 scroll-width: 24

boards: - name: pvp-arena conditions: worlds: [pvp_arena] permission: server.staff sidebar: title: type: rotate interval: 10 frames: - "<gradient:gold:red>STAFF</gradient>" - "<gradient:red:gold>STAFF</gradient>" lines: - "<dark_gray>───────────────" - "<gray>Player: <white>%player%" - "<gray>Kills: <red>%vault_kills%" - "" - type: scroll width: 24 interval: 2 text: "Welcome to the staff PvP arena" - "<dark_gray>───────────────"

- name: default sidebar: title: "<aqua>My Server" lines: - "<gray>Online: <white>%online%/%max-players%" - "<gray>TPS: <green>%tps%" tablist: header: "<gold>My Server" footer: "<gray>%online%/%max-players% online" ```

Commands

| Command | Permission | Description | |---|---|---| | `/sb gui [board]` | `simplescoreboard.admin` | Open the in-game editor (optionally jumping to a specific board) | | `/sb reload` | `simplescoreboard.admin` | Reload `scoreboard.yml`. On parse error the old config keeps running. | | `/sb list` | `simplescoreboard.admin` | List boards in priority order | | `/sb show <board>` | `simplescoreboard.admin` | Force-preview a specific board for yourself | | `/sb show none` | `simplescoreboard.admin` | Clear preview, return to normal selection | | `/sb toggle` | `simplescoreboard.toggle` | Hide/show your own scoreboard. Preference persists across reconnects. |

Aliases: `/scoreboard`, `/simplescoreboard`.

Requirements

- PlaceholderAPI (built against API `26.1.2`) - PlaceholderAPI - PlaceholderAPI — optional, only needed for `%papi_*%` tokens

Installation

1. Drop `SimpleScoreboard.jar` into your `plugins/` folder. 2. Start the server. A default `scoreboard.yml` is created in `plugins/SimpleScoreboard/`. 3. Edit the YAML or run `/sb gui` to customize. 4. `/sb reload` applies YAML changes without restart.

Configuration

`plugins/SimpleScoreboard/scoreboard.yml`. Top-level structure:

```yaml defaults: tick-interval: 1 # ticks between renders. 1 = full animation resolution. scroll-width: 24 # default character window for scrolling lines

boards: - name: <unique-name> conditions: # optional. omit = catch-all (matches everyone) worlds: [...] # optional, any of these worlds permission: ... # optional, player must have this permission gamemodes: [...] # optional, any of these gamemodes sidebar: # optional, omit to leave sidebar untouched title: <line> lines: - <line> tablist: # optional header: <line> footer: <line> below-name: # optional title: <line> score: "%health%" # any placeholder that resolves to an integer ```

Line types

A `<line>` is either a plain string (Static) or a typed object:

```yaml

Static — plain MiniMessage string

"<gold>Hello %player%"

Rotate — cycle through frames

type: rotate interval: 10 # ticks per frame frames: ["Frame A", "Frame B", "Frame C"]

Scroll — horizontal scroll within a fixed width

type: scroll interval: 2 # ticks per character shift width: 24 # visible characters text: "Long welcome text that scrolls" ```

In-Game Editor

`/sb gui` opens a chest-based editor. Navigation:

``` MainMenu (board list + add) └── BoardMenu (rename, delete, conditions, slots) ├── ConditionsMenu (worlds, permission, gamemodes) ├── SidebarMenu (title + lines, reorder, add, remove) │ └── LineEditMenu (Static / Rotate / Scroll switcher) │ └── RotateFramesMenu (for Rotate type) ├── TablistMenu (header, footer, enable/disable) └── BelowNameMenu (title, score expression, enable/disable) ```

Text content (titles, frame text, scroll text, score expressions) is entered through chat — when you click "Edit text" the menu closes, you type the new MiniMessage value, and the menu reopens. Type `!cancel` to abort. Inputs time out after 60 seconds.

While editing, your own scoreboard updates live with the unsaved draft so you can see how it looks before committing.

Saving regenerates `scoreboard.yml` (a one-time `.backup` is created first), atomically replaces the file, and re-renders for all players. Cancel discards the draft without touching the file.

> Note: GUI saves rewrite the YAML through SnakeYAML's standard dumper. Hand-written comments are not preserved. Keep that in mind if you maintain `scoreboard.yml` by hand and use the GUI on the same file.

Built-in Placeholders

| Token | Resolves to | |---|---| | `%player%` | Player name | | `%displayname%` | Adventure-Component display name (string form) | | `%world%` | Current world name | | `%gamemode%` | `SURVIVAL` / `CREATIVE` / `ADVENTURE` / `SPECTATOR` | | `%ping%` | Player ping in ms | | `%x%`, `%y%`, `%z%` | Integer block coordinates | | `%health%` | Health rounded to integer | | `%online%` | Online player count | | `%max-players%` | Server slot count | | `%tps%` | Server TPS (1 decimal) |

Anything else is forwarded to PlaceholderAPI when installed. Unknown tokens (no built-in, no PAPI) stay as raw text — useful for spotting typos visually.

Permissions

| Node | Default | Grants | |---|---|---| | `simplescoreboard.admin` | op | `/sb reload`, `/sb list`, `/sb show`, `/sb gui` | | `simplescoreboard.toggle` | true | `/sb toggle` |

Performance

Each player has a per-tick render cycle. The renderer compares the freshly-built component list against a cached last-sent snapshot and only sends an update packet when a line actually differs. Static lines without dynamic placeholders never re-send. Frame-rotation and scrolling lines re-send only when the frame index or scroll offset changes.

`scoreboard.yml` is parsed once at startup (and on `/sb reload`). The `BoardRegistry` uses an atomic reference, so reloads are wait-free for the render loop.

Compatibility Notes

- The Sidebar slot is rendered through the FastBoard library (shaded and relocated). Plays nicely alongside any other scoreboard plugin that touches Tab-list or Below-Name only. - Two plugins both writing the Sidebar will conflict — disable one or coordinate via permissions. - Tab-list is set per-player via Paper's Adventure API. Tab-list-modifying plugins (e.g. some prefix systems that write the player-list display name) are independent and won't conflict.

ADS