Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/xMrAfonso/Runway/llms.txt

Use this file to discover all available pages before exploring further.

The ScoreboardListener intercepts scoreboard-related packets to format objective titles and score entry text. This enables sidebar scoreboards to use MiniMessage formatting and placeholders for dynamic, per-player content.

Packet Types

Intercepts three packet types:
  • PacketType.Play.Server.SCOREBOARD_OBJECTIVE - Scoreboard objective creation/update
  • PacketType.Play.Server.UPDATE_SCORE - Individual score entry updates
  • PacketType.Play.Server.DISPLAY_SCOREBOARD - Scoreboard display position changes

Configuration

listeners:
  scoreboards: true
When disabled, scoreboard packets are sent unmodified to the client.

Class Structure

public class ScoreboardListener extends AbstractListener {
    public ScoreboardListener(ProcessHandler processHandler, ConfigManager configManager) {
        super(processHandler, configManager);
    }

    @Override
    public void onPacketPlaySend(PacketPlaySendEvent e) {
        // Implementation
    }
}
Source: ScoreboardListener.java:13-44

Implementation Details

1. Packet Type Validation

PacketTypeCommon type = e.getPacketType();
if (!config.getOrDefault("listeners.scoreboards", true) || (
    type != PacketType.Play.Server.SCOREBOARD_OBJECTIVE &&
    type != PacketType.Play.Server.UPDATE_SCORE) &&
    type != PacketType.Play.Server.DISPLAY_SCOREBOARD) {
    
    return;
}
Source: ScoreboardListener.java:20-27 The listener exits early if:
  • The listener is disabled in the configuration
  • The packet type doesn’t match any of the three scoreboard packet types

2. Objective Title Processing

Player player = e.getPlayer();

if (type == PacketType.Play.Server.SCOREBOARD_OBJECTIVE) {
    WrapperPlayServerScoreboardObjective packet = new WrapperPlayServerScoreboardObjective(e);
    packet.setDisplayName(handler.processComponent(packet.getDisplayName(), player));
}
Source: ScoreboardListener.java:29-34 When a scoreboard objective is created or updated:
  1. Wraps the packet in WrapperPlayServerScoreboardObjective
  2. Extracts the display name (objective title)
  3. Processes it through ProcessHandler
  4. Sets the formatted display name back to the packet

3. Display Scoreboard Handling

else if (type == PacketType.Play.Server.DISPLAY_SCOREBOARD) {
    WrapperPlayServerDisplayScoreboard packet = new WrapperPlayServerDisplayScoreboard(e);
    packet.setScoreName("testing");
}
Source: ScoreboardListener.java:35-38
This implementation sets a hardcoded score name “testing”. This appears to be debug code and may need refinement for production use.

4. Score Entry Processing

else {
    WrapperPlayServerUpdateScore packet = new WrapperPlayServerUpdateScore(e);
    packet.setEntityDisplayName(handler.processComponent(packet.getEntityDisplayName(), player));
}
Source: ScoreboardListener.java:39-42 When a score entry is updated:
  1. Wraps the packet in WrapperPlayServerUpdateScore
  2. Extracts the entity display name (score line text)
  3. Processes it through ProcessHandler
  4. Sets the formatted display name back to the packet

Usage Example

When creating a scoreboard:
Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
Objective objective = scoreboard.registerNewObjective(
    "sidebar",
    "dummy",
    Component.text("<gradient:gold:yellow>Server Stats</gradient>")
);

Score playerScore = objective.getScore("<green>Players: %server_online%");
playerScore.setScore(1);

Score balanceScore = objective.getScore("<yellow>Balance: $%player_balance%");
balanceScore.setScore(2);

player.setScoreboard(scoreboard);
The listener will:
  1. Objective Title: Process the gradient formatting for “Server Stats”
  2. Score Entries:
    • Resolve %server_online% placeholder
    • Resolve per-player %player_balance% placeholder
    • Apply color codes (<green>, <yellow>)
Result:
  • Title displays with a gold-to-yellow gradient
  • Each player sees personalized balance
  • Player count is shared across all players

Processing Flow

1

Objective Registered

Server sends SCOREBOARD_OBJECTIVE packet
2

Interception

ScoreboardListener intercepts the packet
3

Title Extraction

Extracts the objective display name
4

Processing

Resolves placeholders and MiniMessage formatting
5

Update

Sets formatted title back to the packet
6

Display

Scoreboard title appears on player’s screen

Per-Player Scoreboards

Since processing includes the player parameter, each player can see personalized scoreboards:
Objective objective = scoreboard.registerNewObjective(
    "stats",
    "dummy",
    Component.text("<rainbow>%player_name%'s Stats</rainbow>")
);

Score rank = objective.getScore("Rank: <gold>%player_rank%</gold>");
Score kills = objective.getScore("Kills: <red>%player_kills%</red>");
Score deaths = objective.getScore("Deaths: <gray>%player_deaths%</gray>");
Each player sees their own:
  • Name in the title
  • Rank, kills, and death count
  • Personalized statistics

Team-Based Scoreboards

The listener processes display names for score entries, which are often used with team-based scoreboard implementations where teams control line text formatting.
Many scoreboard libraries use teams to create dynamic scoreboards. This listener ensures that team-based score entries are properly formatted with placeholders and MiniMessage syntax.

Dependencies

  • PacketEvents: For packet interception
  • WrapperPlayServerScoreboardObjective: Packet wrapper for objective packets
  • WrapperPlayServerUpdateScore: Packet wrapper for score update packets
  • WrapperPlayServerDisplayScoreboard: Packet wrapper for display position packets
  • ProcessHandler: For placeholder resolution and formatting

Common Use Cases

  1. Server Information Boards
    • Display player count, TPS, server stats
    • Show server IP or website
    • Real-time status indicators
  2. Player Statistics
    • Personal stats like kills, deaths, playtime
    • Economy balance and rank
    • Level and experience progress
  3. Game Information
    • Match timers and scores
    • Team information
    • Objective progress
  4. Dynamic Content
    • Rotating tips or announcements
    • Event countdowns
    • Leaderboards