Scoreboard Library

repository·main·Indexed 42 days ago

https://github.com/vytskalt/scoreboard-library

A packet-level Minecraft scoreboard library for Paper/Spigot servers using the Adventure component library. It supports custom score formats, async operations, and Folia compatibility. Features include high-level Component sidebars with animations, a TeamManager for per-player team displays, and an ObjectiveManager for managing scores and display slots (sidebar, playerList, belowName). Tested across Minecraft versions 1.7.10 to 1.21.11.

Tokens
4.8K
Snippets
14
Records
19
Agent score
54%

What's inside Scoreboard Library

  1. How Component sidebars work

    main

    Component sidebars are a high-level abstraction that allows for cleaner, more modular sidebar design. Instead of managing indices manually, you compose a sidebar using SidebarComponents (static lines, dynamic lines, or animated lines) and wrap them in a ComponentSidebarLayout.

    To update the sidebar (e.g., when a dynamic value changes or an animation advances), you must call layout.apply(sidebar) on your Sidebar instance. This should typically be done inside a tick loop.

    // 1. Create components
    SidebarComponent staticLine = SidebarComponent.staticLine(Component.text("A static line"));
    
    SidebarComponent lines = SidebarComponent.builder()
      .addComponent(staticLine)
      .addStaticLine(Component.text("Another static line"))
      .build();
    
    // 2. Create the layout
    ComponentSidebarLayout layout = new ComponentSidebarLayout(
      SidebarComponent.staticLine(Component.text("Sidebar Title")),
      lines
    );
    
    // 3. Apply to a sidebar
    Sidebar sidebar = scoreboardLibrary.createSidebar();
    layout.apply(sidebar);
  2. Install scoreboard-library via Maven

    main

    To use scoreboard-library in a Maven project, add the scoreboard-library-api and scoreboard-library-implementation dependencies. The implementation should be scoped as runtime.

    Important: You must shade and relocate these dependencies using the maven-shade-plugin.

    If you are targeting server versions that do not have native Adventure support (such as Spigot or Paper versions older than 1.16.5), you must also include adventure-platform-bukkit.

    <dependencies>
      <dependency>
        <groupId>net.megavex</groupId>
        <artifactId>scoreboard-library-api</artifactId>
        <version>2.8.2</version>
      </dependency>
      <dependency>
        <groupId>net.megavex</groupId>
        <artifactId>scoreboard-library-implementation</artifactId>
        <version>2.8.2</version>
        <scope>runtime</scope>
      </dependency>
    
      <!-- If targeting a server version without native Adventure support (Spigot or older than 1.16.5 Paper), add it as well: -->
      <dependency>
        <groupId>net.kyori</groupId>
        <artifactId>adventure-platform-bukkit</artifactId>
        <version>4.4.1</version>
      </dependency>
    </dependencies>
  3. Install and initialize ScoreboardLibrary

    main

    To use the library, load it using ScoreboardLibrary.loadScoreboardLibrary(plugin). If the server version is not supported, the library throws a NoPacketAdapterAvailableException. In this case, you should fallback to a NoopScoreboardLibrary to prevent your plugin from crashing, though scoreboard functionality will not be visible. Always call scoreboardLibrary.close() during your plugin's shutdown to clean up resources.

    ScoreboardLibrary scoreboardLibrary;
    try {
      scoreboardLibrary = ScoreboardLibrary.loadScoreboardLibrary(plugin);
    } catch (NoPacketAdapterAvailableException e) {
      // Fallback to no-op implementation if version is unsupported
      scoreboardLibrary = new NoopScoreboardLibrary();
      plugin.getLogger().warning("Server version unsupported, scoreboard functionality will not be visible!");
    }
    
    // On plugin shutdown:
    scoreboardLibrary.close();
  4. Install scoreboard-library via Gradle

    main

    To use scoreboard-library in a Gradle project, add mavenCentral() to your repositories. You must include both the api (for compilation) and the implementation (for runtime).

    Important: You must shade and relocate these dependencies (using a tool like Shadow) to avoid classpath conflicts.

    If you are targeting server versions that do not have native Adventure support (such as Spigot or Paper versions older than 1.16.5), you must also include adventure-platform-bukkit.

    repositories {
      mavenCentral()
    }
    
    dependencies {
      implementation("net.megavex:scoreboard-library-api:2.8.2")
      runtimeOnly("net.megavex:scoreboard-library-implementation:2.8.2")
    
      // If targeting a server version without native Adventure support (Spigot or older than 1.16.5 Paper), add it as well:
      implementation("net.kyori:adventure-platform-bukkit:4.4.1")
    }
  5. Manage Teams with TeamManager

    main

    The TeamManager allows you to create and manage Minecraft teams. A key feature is that you can show different properties (like prefixes or display names) of the same team to different players using TeamDisplay.

    1. Create a TeamManager via scoreboardLibrary.createTeamManager().
    2. Create a team with createIfAbsent(String name).
    3. Use team.defaultDisplay() for standard behavior, or team.createDisplay() to create custom views.
    4. Assign a specific display to a player using team.display(player, newTeamDisplay).
    5. Always call teamManager.close() when finished.
    TeamManager teamManager = scoreboardLibrary.createTeamManager();
    ScoreboardTeam team = teamManager.createIfAbsent("team_name");
    
    // Configure default display
    TeamDisplay teamDisplay = team.defaultDisplay();
    teamDisplay.displayName(Component.text("Team Display Name"));
    teamDisplay.prefix(Component.text("[Prefix] "));
    teamDisplay.suffix(Component.text(" [Suffix]"));
    teamDisplay.playerColor(NamedTextColor.RED);
    teamDisplay.addEntry(player.getName());
    
    teamManager.addPlayer(player); // Adds player to default TeamDisplay of all teams
    
    // Use a custom display for a specific player
    TeamDisplay newTeamDisplay = team.createDisplay();
    newTeamDisplay.displayName(Component.text("Other Team Display Name"));
    team.display(player, newTeamDisplay);
    
    // Cleanup
    teamManager.close();
  6. Manage Objectives with ObjectiveManager

    main

    Use ObjectiveManager to create and display scoreboard objectives (e.g., below the player's name).

    1. Create an ObjectiveManager via scoreboardLibrary.createObjectiveManager().
    2. Create an objective with create(String name) and set its display name with .value(Component).
    3. Set scores for players using .score(playerName, int).
    4. Display the objective in a specific slot using .display(ObjectiveDisplaySlot slot, ScoreboardObjective objective).
    5. Call objectiveManager.addPlayer(player) to make the objective visible to them.
    6. Always call objectiveManager.close() when finished.
    ObjectiveManager objectiveManager = scoreboardLibrary.createObjectiveManager();
    ScoreboardObjective objective = objectiveManager.create("coolobjective");
    objective.value(Component.text("Display name"));
    objective.score(player.getName(), 69420);
    
    // Display below the player's name
    objectiveManager.display(ObjectiveDisplaySlot.belowName(), objective);
    
    objectiveManager.addPlayer(player);
    
    // Cleanup
    objectiveManager.close();
  7. Create animations for sidebars

    main

    You can create visual effects in sidebars using SidebarAnimation<T>. The library provides CollectionSidebarAnimation which can cycle through a list of frames. This can be used for color shifting (using NamedTextColor) or even paginating between different SidebarComponent layouts.

    // Color animation example
    Component lineComponent = Component.text("Line that changes colors");
    Set<NamedTextColor> colors = NamedTextColor.NAMES.values();
    List<Component> frames = new ArrayList<>(colors.size());
    for (NamedTextColor color : colors) {
      frames.add(lineComponent.color(color));
    }
    
    SidebarAnimation<Component> animation = new CollectionSidebarAnimation<>(frames);
    SidebarComponent line = SidebarComponent.animatedLine(animation);
    
    // Advance the animation
    animation.nextFrame();
  8. Implement custom SidebarComponents

    main

    If the built-in static, dynamic, or animated components are insufficient, you can implement the SidebarComponent interface. You must override the draw(@NotNull LineDrawable drawable) method, where you use the drawable object to write your component's content to a specific line.

    public class KeyValueSidebarComponent implements SidebarComponent {
      private final Component key;
      private final Supplier<Component> valueSupplier;
    
      public KeyValueSidebarComponent(@NotNull Component key, @NotNull Supplier<Component> valueSupplier) {
        this.key = key;
        this.valueSupplier = valueSupplier;
      }
    
      @Override
      public void draw(@NotNull LineDrawable drawable) {
        var value = valueSupplier.get();
        var line = Component.text()
          .append(key)
          .append(Component.text(": "))
          .append(value.colorIfAbsent(NamedTextColor.AQUA))
          .build();
    
        drawable.drawLine(line);
      }
    }
  9. How low-level Sidebars work

    main

    A low-level Sidebar allows you to manually control lines and titles. You can set a title using .title(Component) and define lines at specific indices using .line(int index, Component component). After configuring the lines, you must call .addPlayer(player) to make the sidebar visible to a specific player. Remember to call sidebar.close() when the sidebar is no longer needed.

    Sidebar sidebar = scoreboardLibrary.createSidebar();
    
    sidebar.title(Component.text("Sidebar Title"));
    sidebar.line(0, Component.empty());
    sidebar.line(1, Component.text("Line 1"));
    sidebar.line(2, Component.text("Line 2"));
    sidebar.line(2, Component.empty());
    sidebar.line(3, Component.text("epicserver.net"));
    
    sidebar.addPlayer(player); // Add the player to the sidebar
    
    // Don't forget to call sidebar.close() once you don't need it anymore!
  10. Check supported and tested server versions

    main

    Before integrating scoreboard-library, verify that your server version is listed under the tested versions to ensure compatibility. The library has been explicitly tested against a wide range of Minecraft versions from 1.7.10 up to 1.21.11, as well as specific Spigot and Paper builds (26.1, 26.1.1, 26.1.2, and 26.2).

    ### Tested server versions
    
    - [x] 1.7.10
    - [x] 1.8.8
    - [x] 1.9.4
    - [x] 1.10.2
    - [x] 1.11.2
    - [x] 1.12.2
    - [x] 1.13
    - [x] 1.14.4
    - [x] 1.15.2
    - [x] 1.16.5
    - [x] 1.17
    - [x] 1.18.2
    - [x] 1.19.4
    - [x] 1.20.2
    - [x] 1.20.4
    - [x] 1.20.5
    - [x] 1.21.3
    - [x] 1.21.5
    - [x] 1.21.6
    - [x] 1.21.9
    - [x] 1.21.11
    - [x] 26.1 (Spigot)
    - [x] 26.1.1 (Paper)
    - [x] 26.1.2 (Spigot)
    - [x] 26.2