Skip to main content
The TablistListener intercepts and formats the header and footer of the player list (tab list). This allows servers to display formatted information above and below the player list with MiniMessage formatting and placeholder support.

Packet Type

Intercepts: PacketType.Play.Server.PLAYER_LIST_HEADER_AND_FOOTER This packet is sent when the server updates the tab list header or footer.

Configuration

listeners:
  tablist: true
When disabled, tab list headers and footers are sent unmodified to the client.

Class Structure

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

    @Override
    public void onPacketPlaySend(PacketPlaySendEvent e) {
        // Implementation
    }
}
Source: TablistListener.java:10-25

Implementation Details

1. Packet Type Validation

if (!config.getOrDefault("listeners.tablist", true) ||
    e.getPacketType() != PacketType.Play.Server.PLAYER_LIST_HEADER_AND_FOOTER) return;
Source: TablistListener.java:17-18 The listener exits early if:
  • The listener is disabled in the configuration
  • The packet type doesn’t match PLAYER_LIST_HEADER_AND_FOOTER
Player player = e.getPlayer();
WrapperPlayServerPlayerListHeaderAndFooter packet = new WrapperPlayServerPlayerListHeaderAndFooter(e);
packet.setFooter(handler.processComponent(packet.getFooter(), player));
packet.setHeader(handler.processComponent(packet.getHeader(), player));
Source: TablistListener.java:20-23 Both the header and footer are processed through ProcessHandler.processComponent(), which:
  • Resolves PlaceholderAPI placeholders
  • Resolves MiniPlaceholders
  • Parses MiniMessage formatting
  • Returns formatted Adventure Component objects

Usage Example

When a plugin sets the tab list:
player.setPlayerListHeader(Component.text("<gradient:gold:yellow>Server Name</gradient>"));
player.setPlayerListFooter(Component.text("Players: %server_online%/%server_max%"));
The listener will:
  1. Intercept the header and footer packets
  2. Process MiniMessage formatting for the gradient
  3. Resolve %server_online% and %server_max% placeholders
  4. Send the formatted components to the client
Result:
  • Header: Displays “Server Name” with a gold-to-yellow gradient
  • Footer: Shows current player count like “Players: 15/100”

Processing Order

The footer is processed before the header in the implementation, but this order doesn’t affect the visual result since both are sent in the same packet.
packet.setFooter(handler.processComponent(packet.getFooter(), player));
packet.setHeader(handler.processComponent(packet.getHeader(), player));

Per-Player Formatting

Since the processing includes the player parameter, each player can see personalized tab list content:
header: "<rainbow>Welcome, %player_name%!</rainbow>"
footer: "Rank: %player_rank% | Balance: $%player_balance%"
Each player will see their own name, rank, and balance in the tab list.

Dependencies

  • PacketEvents: For packet interception
  • WrapperPlayServerPlayerListHeaderAndFooter: Packet wrapper for reading/modifying tab list
  • ProcessHandler: For placeholder resolution and formatting

Common Use Cases

  1. Server Information Display
    • Show server name, website, Discord link
    • Display current game mode or event information
  2. Player Statistics
    • Show player count, ping, TPS
    • Display player-specific stats like rank, balance, playtime
  3. Dynamic Updates
    • Real-time event countdowns
    • Rotating tips or announcements
    • Live server status indicators

Build docs developers (and LLMs) love