v1.2.0 release

This commit is contained in:
NotAlexNoyle committed 2026-09-12 09:41:36 -04:00
1 parent 1a61dbc537
commit da395ca2e0
7 files changed
+254 -2

No files matched your search

+10
View File
@@ -2,6 +2,16 @@
All notable changes to Scoreboard-OG are documented here.
## 1.2.0 - 2026-09-12
### Changes
- Add a sidebar API for other plugins: `ScoreboardOGAPI.claim`, `release`,
`releaseAll` and `getOwner`, with a `SidebarProvider` supplying a title and up
to 15 lines. A claim replaces the network board with the provider's content,
survives `/togglescoreboard` and world changes, and hands the sidebar back on
release, quit, or when the provider throws.
## 1.1.0 - 2026-07-29
### Changes
+23 -1
View File
@@ -2,7 +2,7 @@
TrueOG Network's custom Scoreboard plugin supporting dynamic MiniPlaceholders. Based on [scoreboard-library by MegavexNetwork](https://github.com/MegavexNetwork/scoreboard-library).
Current version: `1.1.0` ([changelog](CHANGELOG.md)).
Current version: `1.2.0` ([changelog](CHANGELOG.md)).
Gradle Version: 8.14.3
@@ -12,4 +12,26 @@ Minecraft API: 1.19
API Jar: 1.19.4 Purpur
## API for other plugins
A minigame can take over a player's sidebar for the length of a match and hand it back afterwards. Compile against the jar, soft-depend on `Scoreboard-OG`, and only touch the API after checking the plugin is enabled.
```java
import plugin.api.ScoreboardOGAPI;
import plugin.api.SidebarProvider;
ScoreboardOGAPI.claim(player, "MyGame-OG", new SidebarProvider() {
public Component title(Player player) { return Component.text("My Game"); }
public List<Component> lines(Player player) { return List.of(Component.text("Players: 4")); }
});
// later
ScoreboardOGAPI.release(player, "MyGame-OG");
// on disable
ScoreboardOGAPI.releaseAll("MyGame-OG");
```
`claim` replaces the network board with the provider's content, polled on the main thread every ten ticks; up to 15 lines, fewer lines shrink the board. `release` hands the sidebar back only when the named owner still holds it, and the network board returns on its own. A player who hid the sidebar with `/togglescoreboard` sees neither board. A provider that throws loses its claim.
TheHerobrine-OG, BuildBattle-OG and Splegg-OG use this API and fall back to their own scoreboards when Scoreboard-OG is absent.
Scoreboard-OG is public domain software released under the terms of [The Unlicense](https://github.com/true-og/Template-OG/blob/main/LICENSE).
+1 -1
View File
@@ -30,7 +30,7 @@ kotlin { jvmToolchain(17) }
/* ----------------------------- Metadata ------------------------------ */
group = "net.trueog.scoreboard-og" // Declare bundle identifier.
version = "1.1.0" // Declare plugin version (will be in .jar).
version = "1.2.0" // Declare plugin version (will be in .jar).
val apiVersion = "1.19" // Declare minecraft server target version.
+1
View File
@@ -25,6 +25,7 @@ public class Listeners implements Listener {
public void onPlayerQuit(PlayerQuitEvent event) {
ScoreboardOG.getInstance().closeBoard(event.getPlayer());
ScoreboardOG.getInstance().forgetClaims(event.getPlayer());
}
+132
View File
@@ -24,6 +24,7 @@ import net.luckperms.api.model.user.User;
import net.megavex.scoreboardlibrary.api.ScoreboardLibrary;
import net.megavex.scoreboardlibrary.api.sidebar.Sidebar;
import net.trueog.utilitiesog.UtilitiesOG;
import plugin.api.SidebarProvider;
public class ScoreboardOG extends JavaPlugin {
@@ -31,11 +32,19 @@ public class ScoreboardOG extends JavaPlugin {
private static final Component EMPTY_LINE = Component.empty();
private static final Component SIDEBAR_TITLE = legacyText("&4♥ &a&lTrue&c&lOG&r&e Network &4♥");
private static final Component FOOTER_LINE = legacyText("&etrue-og.net");
private static final int NETWORK_LINE_COUNT = 14;
private static ScoreboardOG instance;
private FileConfiguration config;
private final Map<UUID, PlayerSidebar> sidebars = new HashMap<>();
// Sidebars other plugins currently own, kept apart from the boards so a toggle
// or a world change never drops a running match's content.
private final Map<UUID, SidebarClaim> claims = new HashMap<>();
private record SidebarClaim(String owner, SidebarProvider provider) {
}
private LuckPerms luckPerms;
private ScoreboardLibrary scoreboardLibrary;
@@ -136,6 +145,7 @@ public class ScoreboardOG extends JavaPlugin {
sidebars.values().forEach(PlayerSidebar::close);
sidebars.clear();
claims.clear();
if (scoreboardLibrary != null) {
@@ -151,6 +161,70 @@ public class ScoreboardOG extends JavaPlugin {
}
public boolean isSidebarReady() {
return scoreboardLibrary != null;
}
public void claimSidebar(Player player, String owner, SidebarProvider provider) {
claims.put(player.getUniqueId(), new SidebarClaim(owner, provider));
final PlayerSidebar sidebar = sidebars.get(player.getUniqueId());
if (sidebar != null) {
sidebar.tick();
}
}
public boolean releaseSidebar(Player player, String owner) {
final SidebarClaim claim = claims.get(player.getUniqueId());
if (claim == null || !claim.owner().equals(owner)) {
return false;
}
claims.remove(player.getUniqueId());
final PlayerSidebar sidebar = sidebars.get(player.getUniqueId());
if (sidebar != null) {
sidebar.tick();
}
return true;
}
public void releaseAllSidebars(String owner) {
for (Player online : Bukkit.getOnlinePlayers()) {
releaseSidebar(online, owner);
}
claims.values().removeIf(claim -> claim.owner().equals(owner));
}
public String getSidebarOwner(Player player) {
final SidebarClaim claim = claims.get(player.getUniqueId());
return claim == null ? null : claim.owner();
}
public void forgetClaims(Player player) {
claims.remove(player.getUniqueId());
}
public YamlConfiguration getScoreboardPreferences() {
return scoreboardPreferences;
@@ -355,6 +429,7 @@ public class ScoreboardOG extends JavaPlugin {
private final Player player;
private final Sidebar sidebar;
private int renderedLines = 0;
private PlayerSidebar(Player player) {
@@ -366,7 +441,16 @@ public class ScoreboardOG extends JavaPlugin {
private void tick() {
final SidebarClaim claim = claims.get(player.getUniqueId());
if (claim != null) {
tickClaim(claim);
return;
}
sidebar.title(SIDEBAR_TITLE);
shrinkTo(NETWORK_LINE_COUNT);
setLine(0, EMPTY_LINE);
setLine(1, createRankLine(player));
@@ -382,6 +466,54 @@ public class ScoreboardOG extends JavaPlugin {
setLine(11, createDeathsLine(player));
setLine(12, EMPTY_LINE);
setLine(13, FOOTER_LINE);
renderedLines = NETWORK_LINE_COUNT;
}
// A provider that throws loses its claim, so one bad plugin cannot blank the
// board every ten ticks.
private void tickClaim(SidebarClaim claim) {
final Component title;
final java.util.List<Component> lines;
try {
title = claim.provider().title(player);
lines = claim.provider().lines(player);
} catch (Throwable error) {
getLogger().warning("Sidebar provider from " + claim.owner() + " failed for " + player.getName()
+ ", handing the sidebar back: " + error.getMessage());
claims.remove(player.getUniqueId());
return;
}
sidebar.title(title == null ? Component.empty() : title);
final int count = lines == null ? 0 : Math.min(lines.size(), sidebar.maxLines());
shrinkTo(count);
for (int index = 0; index < count; index++) {
final Component line = lines.get(index);
setLine(index, line == null ? EMPTY_LINE : line);
}
renderedLines = count;
}
// The library keeps lines until they are cleared, so a shorter board has to
// drop the surplus before it is redrawn.
private void shrinkTo(int count) {
if (count < renderedLines) {
sidebar.clearLines();
}
}
@@ -0,0 +1,67 @@
// This is free and unencumbered software released into the public domain.
// Author: NotAlexNoyle.
package plugin.api;
import org.bukkit.entity.Player;
import plugin.ScoreboardOG;
// Lets a minigame take over a player's sidebar for the length of a match and hand
// it back afterwards. The network board returns on its own once the claim is released.
public final class ScoreboardOGAPI {
private ScoreboardOGAPI() {
}
// True once Scoreboard-OG is enabled and its packet sidebar is usable.
public static boolean isAvailable() {
final ScoreboardOG plugin = ScoreboardOG.getInstance();
return plugin != null && plugin.isEnabled() && plugin.isSidebarReady();
}
// Replaces the network board with the provider's content. A later claim by
// any owner wins; the owner name is what release checks.
public static void claim(Player player, String owner, SidebarProvider provider) {
if (!isAvailable() || player == null || owner == null || provider == null)
return;
ScoreboardOG.getInstance().claimSidebar(player, owner, provider);
}
// Hands the sidebar back if this owner still holds it. Returns whether it did.
public static boolean release(Player player, String owner) {
if (!isAvailable() || player == null || owner == null)
return false;
return ScoreboardOG.getInstance().releaseSidebar(player, owner);
}
// Hands back every sidebar this owner holds; for a plugin's onDisable.
public static void releaseAll(String owner) {
if (!isAvailable() || owner == null)
return;
ScoreboardOG.getInstance().releaseAllSidebars(owner);
}
// The owner currently holding the player's sidebar, or null for the network
// board.
public static String getOwner(Player player) {
if (!isAvailable() || player == null)
return null;
return ScoreboardOG.getInstance().getSidebarOwner(player);
}
}
@@ -0,0 +1,20 @@
// This is free and unencumbered software released into the public domain.
// Author: NotAlexNoyle.
package plugin.api;
import java.util.List;
import org.bukkit.entity.Player;
import net.kyori.adventure.text.Component;
// Content another plugin wants on a player's sidebar instead of the network board.
// Both methods are polled on the main thread every ten ticks while the claim holds.
public interface SidebarProvider {
Component title(Player player);
// Top to bottom, at most 15 entries. Fewer entries shrink the sidebar.
List<Component> lines(Player player);
}