### Full Sidebar Example with Custom Components and Animations Source: https://github.com/vytskalt/scoreboard-library/blob/main/README.md This example demonstrates a complete sidebar setup using a custom `KeyValueSidebarComponent`, dynamic lines for time, and an animated title. The `tick()` method should be called regularly to update the sidebar. ```java public class ExampleComponentSidebar { private final Sidebar sidebar; private final ComponentSidebarLayout componentSidebar; private final SidebarAnimation titleAnimation; public ExampleComponentSidebar(@NotNull Plugin plugin, @NotNull Sidebar sidebar) { this.sidebar = sidebar; this.titleAnimation = createGradientAnimation(Component.text("Sidebar Example", Style.style(TextDecoration.BOLD))); var title = SidebarComponent.animatedLine(titleAnimation); SimpleDateFormat dtf = new SimpleDateFormat("HH:mm:ss"); // Custom SidebarComponent, see below for how an implementation might look like SidebarComponent onlinePlayers = new KeyValueSidebarComponent( Component.text("Online players"), () -> Component.text(plugin.getServer().getOnlinePlayers().size()) ); SidebarComponent lines = SidebarComponent.builder() .addDynamicLine(() -> { var time = dtf.format(new Date()); return Component.text(time, NamedTextColor.GRAY); }) .addBlankLine() .addStaticLine(Component.text("A static line")) .addComponent(onlinePlayers) .addBlankLine() .addStaticLine(Component.text("epicserver.net", NamedTextColor.AQUA)) .build(); this.componentSidebar = new ComponentSidebarLayout(title, lines); } // Called every tick public void tick() { // Advance title animation to the next frame titleAnimation.nextFrame(); // Update sidebar title & lines componentSidebar.apply(sidebar); } private @NotNull SidebarAnimation createGradientAnimation(@NotNull Component text) { float step = 1f / 8f; TagResolver.Single textPlaceholder = Placeholder.component("text", text); List frames = new ArrayList<>((int) (2f / step)); float phase = -1f; while (phase < 1) { ``` -------------------------------- ### Setup Faction System with TeamDisplay Source: https://context7.com/vytskalt/scoreboard-library/llms.txt Demonstrates how to set up a faction system where players see different prefixes and colors for allies and enemies. Requires a TeamManager instance. ```java import net.megavex.scoreboardlibrary.api.team.TeamManager; import net.megavex.scoreboardlibrary.api.team.ScoreboardTeam; import net.megavex.scoreboardlibrary.api.team.TeamDisplay; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; public class PerPlayerTeamExample { private final TeamManager teamManager; public PerPlayerTeamExample(ScoreboardLibrary library) { this.teamManager = library.createTeamManager(); } public void setupFactionSystem(Player viewer, Player target, boolean isFriendly) { // Add viewer to team manager teamManager.addPlayer(viewer); // Create team for target player ScoreboardTeam targetTeam = teamManager.createIfAbsent("player_" + target.getUniqueId()); targetTeam.defaultDisplay().addEntry(target.getName()); // Create custom display for this viewer TeamDisplay customDisplay = targetTeam.createDisplay(); if (isFriendly) { // Show green for friendly players customDisplay.prefix(Component.text("[Ally] ", NamedTextColor.GREEN)); customDisplay.playerColor(NamedTextColor.GREEN); } else { // Show red for enemies customDisplay.prefix(Component.text("[Enemy] ", NamedTextColor.RED)); customDisplay.playerColor(NamedTextColor.RED); } // Apply custom display only to this viewer targetTeam.display(viewer, customDisplay); } public void updateRelationship(Player viewer, Player target, boolean nowFriendly) { ScoreboardTeam targetTeam = teamManager.team("player_" + target.getUniqueId()); if (targetTeam == null) return; TeamDisplay display = targetTeam.display(viewer); if (nowFriendly) { display.prefix(Component.text("[Ally] ", NamedTextColor.GREEN)); display.playerColor(NamedTextColor.GREEN); } else { display.prefix(Component.text("[Enemy] ", NamedTextColor.RED)); display.playerColor(NamedTextColor.RED); } } public void destroy() { teamManager.close(); } } ``` -------------------------------- ### Low-Level Sidebar API Example Source: https://context7.com/vytskalt/scoreboard-library/llms.txt Create, update, and manage a sidebar with direct control over lines and player assignments. Ensure the sidebar is closed when no longer needed. ```java import net.megavex.scoreboardlibrary.api.sidebar.Sidebar; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; public class SimpleSidebarExample { private final ScoreboardLibrary scoreboardLibrary; private Sidebar sidebar; public SimpleSidebarExample(ScoreboardLibrary scoreboardLibrary) { this.scoreboardLibrary = scoreboardLibrary; } public void createSidebar() { // Create a sidebar with default max lines (15) sidebar = scoreboardLibrary.createSidebar(); // Set the sidebar title sidebar.title(Component.text("My Server", NamedTextColor.GOLD)); // Set lines (index 0 = bottom, higher index = higher position) sidebar.line(0, Component.text("play.myserver.com", NamedTextColor.AQUA)); sidebar.line(1, Component.empty()); // Blank line sidebar.line(2, Component.text("Players: 100", NamedTextColor.WHITE)); sidebar.line(3, Component.text("TPS: 20.0", NamedTextColor.GREEN)); sidebar.line(4, Component.empty()); sidebar.line(5, Component.text("Welcome!", NamedTextColor.YELLOW)); } public void addPlayer(Player player) { // Add player to see the sidebar sidebar.addPlayer(player); } public void removePlayer(Player player) { sidebar.removePlayer(player); } public void updateLine(int index, Component content) { // Update a specific line dynamically sidebar.line(index, content); } public void destroy() { // Always close sidebar when done to prevent memory leaks if (sidebar != null && !sidebar.closed()) { sidebar.close(); } } } ``` -------------------------------- ### Implement a Custom KeyValueSidebarComponent Source: https://github.com/vytskalt/scoreboard-library/blob/main/README.md Create a custom `SidebarComponent` by implementing the `SidebarComponent` interface. This example shows how to display a key-value pair where the value is dynamically generated. ```java public class KeyValueSidebarComponent implements SidebarComponent { private final Component key; private final Supplier valueSupplier; public KeyValueSidebarComponent(@NotNull Component key, @NotNull Supplier 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); } } ``` -------------------------------- ### Create Animated Sidebar Content Source: https://context7.com/vytskalt/scoreboard-library/llms.txt This example shows how to create a sidebar with animated titles and lines using `SidebarAnimation` and `ComponentSidebarLayout`. It includes setting up color cycling animations and a scheduled task to update the sidebar frames. ```java import net.megavex.scoreboardlibrary.api.sidebar.Sidebar; import net.megavex.scoreboardlibrary.api.sidebar.component.ComponentSidebarLayout; import net.megavex.scoreboardlibrary.api.sidebar.component.SidebarComponent; import net.megavex.scoreboardlibrary.api.sidebar.component.animation.CollectionSidebarAnimation; import net.megavex.scoreboardlibrary.api.sidebar.component.animation.SidebarAnimation; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitRunnable; import java.util.ArrayList; import java.util.List; import java.util.Set; public class AnimatedSidebarExample { private final Sidebar sidebar; private final ComponentSidebarLayout layout; private final SidebarAnimation titleAnimation; public AnimatedSidebarExample(Plugin plugin, ScoreboardLibrary library) { this.sidebar = library.createSidebar(); // Create color cycling animation for title this.titleAnimation = createColorAnimation( Component.text("My Server", Style.style(TextDecoration.BOLD)) ); SidebarComponent title = SidebarComponent.animatedLine(titleAnimation); // Create animated line that cycles through colors List rainbowFrames = new ArrayList<>(); for (NamedTextColor color : NamedTextColor.NAMES.values()) { rainbowFrames.add(Component.text("Rainbow Text!", color)); } SidebarAnimation rainbowAnimation = new CollectionSidebarAnimation<>(rainbowFrames); SidebarComponent lines = SidebarComponent.builder() .addAnimatedLine(rainbowAnimation) .addBlankLine() .addStaticLine(Component.text("Static content", NamedTextColor.WHITE)) .build(); this.layout = new ComponentSidebarLayout(title, lines); // Start animation task (runs every 5 ticks = 250ms) new BukkitRunnable() { @Override public void run() { if (sidebar.closed()) { cancel(); return; } titleAnimation.nextFrame(); rainbowAnimation.nextFrame(); layout.apply(sidebar); } }.runTaskTimer(plugin, 0L, 5L); } private SidebarAnimation createColorAnimation(Component text) { List frames = new ArrayList<>(); NamedTextColor[] colors = { NamedTextColor.YELLOW, NamedTextColor.GOLD, NamedTextColor.RED, NamedTextColor.LIGHT_PURPLE, NamedTextColor.AQUA, NamedTextColor.GREEN }; for (NamedTextColor color : colors) { frames.add(text.color(color)); } return new CollectionSidebarAnimation<>(frames); } public Sidebar getSidebar() { return sidebar; } } ``` -------------------------------- ### Create a Dynamic Sidebar with ComponentSidebarLayout Source: https://context7.com/vytskalt/scoreboard-library/llms.txt Demonstrates building a sidebar with static and dynamic components, including player stats and current time. Requires ScoreboardLibrary and Adventure API. ```java import net.megavex.scoreboardlibrary.api.sidebar.Sidebar; import net.megavex.scoreboardlibrary.api.sidebar.component.ComponentSidebarLayout; import net.megavex.scoreboardlibrary.api.sidebar.component.SidebarComponent; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; import java.text.SimpleDateFormat; import java.util.Date; public class ComponentSidebarExample { private final Player player; private final Sidebar sidebar; private final ComponentSidebarLayout layout; public ComponentSidebarExample(ScoreboardLibrary library, Player player) { this.player = player; this.sidebar = library.createSidebar(); // Build the title component SidebarComponent title = SidebarComponent.staticLine( Component.text("Player Info", NamedTextColor.GOLD) ); // Build the lines component using the builder SidebarComponent lines = SidebarComponent.builder() // Dynamic line that updates each tick .addDynamicLine(() -> { SimpleDateFormat dtf = new SimpleDateFormat("HH:mm:ss"); return Component.text(dtf.format(new Date()), NamedTextColor.GRAY); }) .addBlankLine() // Static line that never changes .addStaticLine(Component.text("Stats:", NamedTextColor.YELLOW)) // Dynamic lines showing player stats .addDynamicLine(() -> Component.text("Health: " + (int) player.getHealth() + "/" + (int) player.getMaxHealth(), NamedTextColor.RED)) .addDynamicLine(() -> Component.text("Level: " + player.getLevel(), NamedTextColor.GREEN)) .addDynamicLine(() -> Component.text("Food: " + player.getFoodLevel() + "/20", NamedTextColor.GOLD)) .addBlankLine() .addStaticLine(Component.text("play.myserver.com", NamedTextColor.AQUA)) .build(); // Create the layout this.layout = new ComponentSidebarLayout(title, lines); // Add player to sidebar sidebar.addPlayer(player); } // Call this every tick to update dynamic content public void tick() { layout.apply(sidebar); } public void destroy() { sidebar.close(); } } ``` -------------------------------- ### Demonstrate Objective Display Slots Source: https://context7.com/vytskalt/scoreboard-library/llms.txt Shows how to create and display objectives in different slots like player list, sidebar, below name, and team sidebars. Requires ScoreboardLibrary. ```java import net.megavex.scoreboardlibrary.api.objective.ObjectiveDisplaySlot; import net.megavex.scoreboardlibrary.api.objective.ObjectiveManager; import net.megavex.scoreboardlibrary.api.objective.ScoreboardObjective; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; public class DisplaySlotExample { private final ObjectiveManager manager; public DisplaySlotExample(ScoreboardLibrary library) { this.manager = library.createObjectiveManager(); } public void demonstrateDisplaySlots() { // Player list (tab menu) - shows scores next to player names ScoreboardObjective tabObjective = manager.create("tab_score"); tabObjective.value(Component.text("Score")); manager.display(ObjectiveDisplaySlot.playerList(), tabObjective); // Sidebar - standard right-side scoreboard ScoreboardObjective sidebarObjective = manager.create("sidebar_score"); sidebarObjective.value(Component.text("Stats")); manager.display(ObjectiveDisplaySlot.sidebar(), sidebarObjective); // Below name - shows under player name tags in world ScoreboardObjective belowNameObjective = manager.create("health_display"); belowNameObjective.value(Component.text("HP", NamedTextColor.RED)); manager.display(ObjectiveDisplaySlot.belowName(), belowNameObjective); // Team sidebar - shows sidebar only to specific team color (1.8+) ScoreboardObjective redTeamObjective = manager.create("red_team_sidebar"); redTeamObjective.value(Component.text("Red Team Stats", NamedTextColor.RED)); manager.display(ObjectiveDisplaySlot.teamSidebar(NamedTextColor.RED), redTeamObjective); ScoreboardObjective blueTeamObjective = manager.create("blue_team_sidebar"); blueTeamObjective.value(Component.text("Blue Team Stats", NamedTextColor.BLUE)); manager.display(ObjectiveDisplaySlot.teamSidebar(NamedTextColor.BLUE), blueTeamObjective); } } ``` -------------------------------- ### Create and Manage Sidebar Source: https://github.com/vytskalt/scoreboard-library/blob/main/README.md Creates a new sidebar instance, sets its title and lines, and adds a player to it. Remember to close the sidebar when it's no longer needed. ```java 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.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! ``` -------------------------------- ### Create Paginated Sidebar Components Source: https://github.com/vytskalt/scoreboard-library/blob/main/README.md Use `SidebarComponent.builder()` with dynamic lines to create different pages for pagination. Each dynamic line can display changing player data. ```java Player player = ...; SidebarComponent firstPage = SidebarComponent.builder() .addStaticLine(Component.text("First page")) .addDynamicLine(() -> Component.text("Level: " + player.getLevel())) .build(); SidebarComponent secondPage = SidebarComponent.builder() .addStaticLine(Component.text("Second page")) .addDynamicLine(() -> Component.text("Health: " + player.getHealth())) .build(); List pages = Arrays.asList(firstPage, secondPage); SidebarAnimation pageAnimation = new CollectionSidebarAnimation<>(pages); SidebarComponent paginatedComponent = SidebarComponent.animatedComponent(pageAnimation); // ... ``` -------------------------------- ### Initialize ScoreboardLibrary Source: https://context7.com/vytskalt/scoreboard-library/llms.txt Load the ScoreboardLibrary instance on plugin enable and close it on disable to prevent memory leaks. Includes fallback for unsupported server versions. ```java import net.megavex.scoreboardlibrary.api.ScoreboardLibrary; import net.megavex.scoreboardlibrary.api.exception.NoPacketAdapterAvailableException; import net.megavex.scoreboardlibrary.api.noop.NoopScoreboardLibrary; import org.bukkit.plugin.java.JavaPlugin; public class MyPlugin extends JavaPlugin { private ScoreboardLibrary scoreboardLibrary; @Override public void onEnable() { try { // Load the scoreboard library with packet adapter support scoreboardLibrary = ScoreboardLibrary.loadScoreboardLibrary(this); } catch (NoPacketAdapterAvailableException e) { // Fallback to no-op implementation for unsupported server versions scoreboardLibrary = new NoopScoreboardLibrary(); getLogger().warning("Server version unsupported, scoreboard functionality will not be visible!"); } } @Override public void onDisable() { // Always close the library when plugin disables to prevent memory leaks if (scoreboardLibrary != null) { scoreboardLibrary.close(); } } public ScoreboardLibrary getScoreboardLibrary() { return scoreboardLibrary; } } ``` -------------------------------- ### ViaVersion Awareness Configuration Source: https://github.com/vytskalt/scoreboard-library/blob/main/INSTALLATION.md To enable ViaVersion awareness, add 'ViaVersion' to the 'softdepend' or 'depend' section of your plugin.yml file. ```yaml softdepend: ["ViaVersion"] # or depend: ["ViaVersion"] ``` -------------------------------- ### Build a Sidebar with Multiple Components Source: https://github.com/vytskalt/scoreboard-library/blob/main/README.md Utilize `SidebarComponent.builder()` to chain multiple sidebar components, including static lines and shorthand additions. This allows for complex sidebar structures. ```java SidebarComponent lines = SidebarComponent.builder() .addComponent(SidebarComponent.staticLine(Component.text("A static line"))) .addStaticLine(Component.text("Another static line")) // Shorthand for line above .build(); ``` -------------------------------- ### Create and Apply a Component Sidebar Layout Source: https://github.com/vytskalt/scoreboard-library/blob/main/README.md Instantiate `ComponentSidebarLayout` with a title and content components, then apply it to a `Sidebar` object. Remember to re-apply the layout whenever the title or lines need updating. ```java ComponentSidebarLayout layout = new ComponentSidebarLayout( SidebarComponent.staticLine(Component.text("Sidebar Title")), lines ); Sidebar sidebar = scoreboardLibrary.createSidebar(); // Apply the title & lines components to the Sidebar // Do this every time the title or any line needs to be updated layout.apply(sidebar); ``` -------------------------------- ### Load Scoreboard Library Source: https://github.com/vytskalt/scoreboard-library/blob/main/README.md Loads the scoreboard library instance. If the server version is unsupported, it falls back to a no-op implementation. Ensure to close the library on plugin shutdown. ```java ScoreboardLibrary scoreboardLibrary; try { scoreboardLibrary = ScoreboardLibrary.loadScoreboardLibrary(plugin); } catch (NoPacketAdapterAvailableException e) { // If server version is not yet supported, you can fallback to the no-op implementation: scoreboardLibrary = new NoopScoreboardLibrary(); plugin.getLogger().warning("Server version unsupported, scoreboard functionality will not be visible!"); } // On plugin shutdown: scoreboardLibrary.close(); ``` -------------------------------- ### Gradle Dependencies for Scoreboard Library Source: https://context7.com/vytskalt/scoreboard-library/llms.txt Configures Gradle build file to include scoreboard-library API and implementation, and Adventure platform for older Minecraft versions. Requires the shadow plugin for dependency relocation. ```kotlin // build.gradle.kts plugins { id("com.gradleup.shadow") version "9.3.1" } repositories { mavenCentral() } dependencies { implementation("net.megavex:scoreboard-library-api:2.7.4") runtimeOnly("net.megavex:scoreboard-library-implementation:2.7.4") // Only needed for servers without native Adventure support (pre-1.16.5 Paper, all Spigot) implementation("net.kyori:adventure-platform-bukkit:4.4.1") } // Configure shadow plugin to relocate dependencies tasks.shadowJar { relocate("net.megavex.scoreboardlibrary", "com.yourplugin.libs.scoreboardlibrary") relocate("net.kyori", "com.yourplugin.libs.kyori") } ``` -------------------------------- ### Create and Manage Objectives Source: https://github.com/vytskalt/scoreboard-library/blob/main/README.md Use ObjectiveManager to create objectives, set their display name and score for players, and assign them to specific display slots. Remember to close the manager when done. ```java ObjectiveManager objectiveManager = scoreboardLibrary.createObjectiveManager(); ScoreboardObjective objective = objectiveManager.create("coolobjective"); objective.value(Component.text("Display name")); objective.score(player.getName(), 69420); objectiveManager.display(ObjectiveDisplaySlot.belowName(), objective); objectiveManager.addPlayer(player); // Make a player see the objectives // Don't forget to call objectiveManager.close() once you don't need it anymore! ``` -------------------------------- ### Create and Manage Teams Source: https://github.com/vytskalt/scoreboard-library/blob/main/README.md Use TeamManager to create teams and customize their display properties like prefix, suffix, and color. Players can be assigned to default or custom team displays. ```java TeamManager teamManager = scoreboardLibrary.createTeamManager(); ScoreboardTeam team = teamManager.createIfAbsent("team_name"); // A TeamDisplay holds all the display properties that a team can have (prefix, suffix etc.). // You can apply different TeamDisplays for each player so different players can see // different properties on a single ScoreboardTeam. However if you don't need that you can // use the default TeamDisplay that is created in every ScoreboardTeam. 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); // Player will be added to the default TeamDisplay of each ScoreboardTeam // Create a new TeamDisplay like this: TeamDisplay newTeamDisplay = team.createDisplay(); newTeamDisplay.displayName(Component.text("Other Team Display Name")); // Change the TeamDisplay a player sees like this: team.display(player, newTeamDisplay); // Don't forget to call teamManager.close() once you don't need it anymore! ``` -------------------------------- ### Manage Scoreboard Teams with Per-Player Display Source: https://context7.com/vytskalt/scoreboard-library/llms.txt Utilize `TeamManager` to create and configure scoreboard teams, including custom prefixes, suffixes, and colors for individual players via `TeamDisplay`. ```java import net.megavex.scoreboardlibrary.api.team.TeamManager; import net.megavex.scoreboardlibrary.api.team.ScoreboardTeam; import net.megavex.scoreboardlibrary.api.team.TeamDisplay; import net.megavex.scoreboardlibrary.api.team.enums.CollisionRule; import net.megavex.scoreboardlibrary.api.team.enums.NameTagVisibility; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; public class TeamExample { private final TeamManager teamManager; public TeamExample(ScoreboardLibrary library) { this.teamManager = library.createTeamManager(); } public void setupTeams() { // Create admin team with red prefix ScoreboardTeam adminTeam = teamManager.createIfAbsent("admin"); TeamDisplay adminDisplay = adminTeam.defaultDisplay(); adminDisplay.displayName(Component.text("Admins")); adminDisplay.prefix(Component.text("[Admin] ", NamedTextColor.RED)); adminDisplay.playerColor(NamedTextColor.RED); adminDisplay.nameTagVisibility(NameTagVisibility.ALWAYS); // Create VIP team with gold prefix ScoreboardTeam vipTeam = teamManager.createIfAbsent("vip"); TeamDisplay vipDisplay = vipTeam.defaultDisplay(); vipDisplay.displayName(Component.text("VIPs")); vipDisplay.prefix(Component.text("[VIP] ", NamedTextColor.GOLD)); vipDisplay.suffix(Component.text(" *", NamedTextColor.YELLOW)); vipDisplay.playerColor(NamedTextColor.GOLD); // Create default team ScoreboardTeam defaultTeam = teamManager.createIfAbsent("default"); TeamDisplay defaultDisplay = defaultTeam.defaultDisplay(); defaultDisplay.prefix(Component.text("[Player] ", NamedTextColor.GRAY)); defaultDisplay.collisionRule(CollisionRule.PUSH_OWN_TEAM); } public void addPlayerToTeam(Player player, String teamName) { // Add player as a viewer of the team manager teamManager.addPlayer(player); // Get the team and add player's name as an entry ScoreboardTeam team = teamManager.team(teamName); if (team != null) { team.defaultDisplay().addEntry(player.getName()); } } public void removePlayerFromTeam(Player player, String teamName) { ScoreboardTeam team = teamManager.team(teamName); if (team != null) { team.defaultDisplay().removeEntry(player.getName()); } } public void destroy() { teamManager.close(); } } ``` -------------------------------- ### Paginated Sidebar with Animation Source: https://context7.com/vytskalt/scoreboard-library/llms.txt Implements a paginated sidebar using SidebarAnimation and SidebarComponent. Each page displays different information, and dynamic lines update in real-time. Requires ScoreboardLibrary and Adventure API. ```java import net.megavex.scoreboardlibrary.api.sidebar.Sidebar; import net.megavex.scoreboardlibrary.api.sidebar.component.ComponentSidebarLayout; import net.megavex.scoreboardlibrary.api.sidebar.component.SidebarComponent; import net.megavex.scoreboardlibrary.api.sidebar.component.animation.CollectionSidebarAnimation; import net.megavex.scoreboardlibrary.api.sidebar.component.animation.SidebarAnimation; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; import java.util.Arrays; import java.util.List; public class PaginatedSidebarExample { private final Sidebar sidebar; private final ComponentSidebarLayout layout; private final SidebarAnimation pageAnimation; public PaginatedSidebarExample(ScoreboardLibrary library, Player player) { this.sidebar = library.createSidebar(); // Page 1: Player stats SidebarComponent statsPage = SidebarComponent.builder() .addStaticLine(Component.text("=== Stats ===", NamedTextColor.GOLD)) .addBlankLine() .addDynamicLine(() -> Component.text("Level: " + player.getLevel(), NamedTextColor.GREEN)) .addDynamicLine(() -> Component.text("Health: " + (int) player.getHealth(), NamedTextColor.RED)) .addDynamicLine(() -> Component.text("Food: " + player.getFoodLevel(), NamedTextColor.YELLOW)) .addBlankLine() .addStaticLine(Component.text("Page 1/3", NamedTextColor.GRAY)) .build(); // Page 2: Location info SidebarComponent locationPage = SidebarComponent.builder() .addStaticLine(Component.text("=== Location ===", NamedTextColor.AQUA)) .addBlankLine() .addDynamicLine(() -> Component.text("World: " + player.getWorld().getName(), NamedTextColor.WHITE)) .addDynamicLine(() -> Component.text("X: " + player.getLocation().getBlockX(), NamedTextColor.WHITE)) .addDynamicLine(() -> Component.text("Y: " + player.getLocation().getBlockY(), NamedTextColor.WHITE)) .addDynamicLine(() -> Component.text("Z: " + player.getLocation().getBlockZ(), NamedTextColor.WHITE)) .addBlankLine() .addStaticLine(Component.text("Page 2/3", NamedTextColor.GRAY)) .build(); // Page 3: Server info SidebarComponent serverPage = SidebarComponent.builder() .addStaticLine(Component.text("=== Server ===", NamedTextColor.LIGHT_PURPLE)) .addBlankLine() .addStaticLine(Component.text("play.myserver.com", NamedTextColor.AQUA)) .addStaticLine(Component.text("Discord: discord.gg/xxx", NamedTextColor.BLUE)) .addBlankLine() .addStaticLine(Component.text("Page 3/3", NamedTextColor.GRAY)) .build(); // Create page animation List pages = Arrays.asList(statsPage, locationPage, serverPage); this.pageAnimation = new CollectionSidebarAnimation<>(pages); // Use animatedComponent for page switching SidebarComponent paginatedContent = SidebarComponent.animatedComponent(pageAnimation); SidebarComponent title = SidebarComponent.staticLine( Component.text("My Server", NamedTextColor.GOLD) ); this.layout = new ComponentSidebarLayout(title, paginatedContent); sidebar.addPlayer(player); } // Call to switch to next page public void nextPage() { pageAnimation.nextFrame(); layout.apply(sidebar); } // Call every tick to update dynamic content on current page public void tick() { layout.apply(sidebar); } public void destroy() { sidebar.close(); } } ``` -------------------------------- ### Create Custom Key-Value Sidebar Component Source: https://context7.com/vytskalt/scoreboard-library/llms.txt Implement `SidebarComponent` to create reusable key-value pairs for sidebars. Requires `LineDrawable` for rendering and `Supplier` for dynamic values. ```java import net.megavex.scoreboardlibrary.api.sidebar.component.LineDrawable; import net.megavex.scoreboardlibrary.api.sidebar.component.SidebarComponent; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.jetbrains.annotations.NotNull; import java.util.function.Supplier; // Custom reusable component for key-value pairs public class KeyValueComponent implements SidebarComponent { private final Component key; private final Supplier valueSupplier; public KeyValueComponent(@NotNull Component key, @NotNull Supplier valueSupplier) { this.key = key; this.valueSupplier = valueSupplier; } @Override public void draw(@NotNull LineDrawable drawable) { Component line = Component.text() .append(key) .append(Component.text(": ", NamedTextColor.GRAY)) .append(valueSupplier.get().colorIfAbsent(NamedTextColor.WHITE)) .build(); drawable.drawLine(line); } } ``` -------------------------------- ### Create and Display Scoreboard Objectives Source: https://context7.com/vytskalt/scoreboard-library/llms.txt Demonstrates creating a health objective displayed below player names and a kills objective in the player list. Requires ObjectiveManager and ScoreboardObjective instances. ```java import net.megavex.scoreboardlibrary.api.objective.ObjectiveManager; import net.megavex.scoreboardlibrary.api.objective.ObjectiveDisplaySlot; import net.megavex.scoreboardlibrary.api.objective.ObjectiveRenderType; import net.megavex.scoreboardlibrary.api.objective.ScoreboardObjective; import net.megavex.scoreboardlibrary.api.objective.ScoreFormat; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; public class ObjectiveExample { private final ObjectiveManager objectiveManager; private ScoreboardObjective healthObjective; private ScoreboardObjective killsObjective; public ObjectiveExample(ScoreboardLibrary library) { this.objectiveManager = library.createObjectiveManager(); } public void setupObjectives() { // Create health display below player names healthObjective = objectiveManager.create("health"); healthObjective.value(Component.text("Health", NamedTextColor.RED)); healthObjective.renderType(ObjectiveRenderType.HEARTS); objectiveManager.display(ObjectiveDisplaySlot.belowName(), healthObjective); // Create kills display in player list killsObjective = objectiveManager.create("kills"); killsObjective.value(Component.text("Kills", NamedTextColor.GOLD)); killsObjective.renderType(ObjectiveRenderType.INTEGER); objectiveManager.display(ObjectiveDisplaySlot.playerList(), killsObjective); } public void addPlayer(Player player) { objectiveManager.addPlayer(player); // Set initial scores healthObjective.score(player.getName(), (int) player.getHealth()); killsObjective.score(player.getName(), 0); } public void updateHealth(Player player) { healthObjective.score(player.getName(), (int) player.getHealth()); } public void addKill(Player player) { Integer currentKills = killsObjective.score(player.getName()); int newKills = (currentKills != null ? currentKills : 0) + 1; killsObjective.score(player.getName(), newKills); } // 1.20.3+ feature: custom score formats public void setFormattedScore(Player player, int kills) { killsObjective.score( player.getName(), kills, Component.text(player.getName(), NamedTextColor.YELLOW), // Custom display name ScoreFormat.fixed(Component.text(kills + " kills", NamedTextColor.GOLD)) // Custom format ); } public void removePlayer(Player player) { healthObjective.removeScore(player.getName()); killsObjective.removeScore(player.getName()); objectiveManager.removePlayer(player); } public void destroy() { objectiveManager.close(); } } ``` -------------------------------- ### Maven Dependencies and Shade Plugin Configuration Source: https://context7.com/vytskalt/scoreboard-library/llms.txt Add these dependencies to your pom.xml for the scoreboard-library. Configure the maven-shade-plugin to relocate its packages to avoid conflicts. ```xml net.megavex scoreboard-library-api 2.7.4 net.megavex scoreboard-library-implementation 2.7.4 runtime net.kyori adventure-platform-bukkit 4.4.1 org.apache.maven.plugins maven-shade-plugin 3.5.1 package shade net.megavex.scoreboardlibrary com.yourplugin.libs.scoreboardlibrary ``` -------------------------------- ### Gradle Dependencies for Scoreboard Library Source: https://github.com/vytskalt/scoreboard-library/blob/main/INSTALLATION.md Add these dependencies to your Gradle build file for the scoreboard library API and implementation. Include Adventure platform if targeting older server versions. ```kotlin repositories { mavenCentral() } dependencies { implementation("net.megavex:scoreboard-library-api:2.7.4") runtimeOnly("net.megavex:scoreboard-library-implementation:2.7.4") // If targeting a server version without native Adventure support, add it as well: implementation("net.kyori:adventure-platform-bukkit:4.4.1") } ``` -------------------------------- ### Maven Dependencies for Scoreboard Library Source: https://github.com/vytskalt/scoreboard-library/blob/main/INSTALLATION.md Include these dependencies in your Maven pom.xml for the scoreboard library. Add the Adventure platform dependency if your server version lacks native support. ```xml net.megavex scoreboard-library-api 2.7.4 net.megavex scoreboard-library-implementation 2.7.4 runtime net.kyori adventure-platform-bukkit 4.4.1 ``` -------------------------------- ### Create a Static Sidebar Line Source: https://github.com/vytskalt/scoreboard-library/blob/main/README.md Use `SidebarComponent.staticLine` to create a sidebar component with a single, static line of text. This is useful for fixed elements in your sidebar. ```java SidebarComponent staticLine = SidebarComponent.staticLine(Component.text("A static line")); ``` -------------------------------- ### Create a Sidebar Animation with a Collection Source: https://github.com/vytskalt/scoreboard-library/blob/main/README.md Generate a `SidebarAnimation` using `CollectionSidebarAnimation` to cycle through a list of `Component`s. This is suitable for creating animated text effects. ```java Component lineComponent = Component.text("Line that changes colors"); Set colors = NamedTextColor.NAMES.values(); List frames = new ArrayList<>(colors.size()); for (NamedTextColor color : colors) { frames.add(lineComponent.color(color)); } SidebarAnimation animation = new CollectionSidebarAnimation<>(frames); // You can also implement SidebarAnimation yourself SidebarComponent line = SidebarComponent.animatedLine(animation); // Advance to the next frame of the animation animation.nextFrame(); ``` -------------------------------- ### ViaVersion Soft Dependency in plugin.yml Source: https://context7.com/vytskalt/scoreboard-library/llms.txt Declare ViaVersion as a soft dependency in your plugin.yml to enable compatibility features for older client versions. ```yaml # plugin.yml name: MyPlugin version: 1.0.0 main: com.example.myplugin.MyPlugin api-version: "1.21" # Add ViaVersion as a soft dependency for version detection softdepend: ["ViaVersion"] # Or as a hard dependency: # depend: ["ViaVersion"] ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.