v1.2.0 release
This commit is contained in:
1 parent
1a61dbc537
commit
da395ca2e0
7 files changed
+254
-2
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ public class Listeners implements Listener {
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
|
||||
ScoreboardOG.getInstance().closeBoard(event.getPlayer());
|
||||
ScoreboardOG.getInstance().forgetClaims(event.getPlayer());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user