Scoreboard sidebar now supports Component (with RGB and stuff) + little improvement of Chat API

This commit is contained in:
Marc Baloup 2021-09-05 20:06:07 +02:00
parent ea1cf90119
commit 9391dcafbc
Signed by: marcbal
GPG Key ID: BBC0FE3ABC30B893
4 changed files with 144 additions and 142 deletions

View File

@ -268,16 +268,7 @@ public class ChatColorUtil {
public static class ChatValueGradient {
//private record GradientValueColor(float value, ChatColor color) { } // Java 16
private static class GradientValueColor {
private final float value;
private final TextColor color;
public GradientValueColor(float value, TextColor color) {
this.value = value; this.color = color;
}
public float value() { return value; }
public TextColor color() { return color; }
}
private record GradientValueColor(float value, TextColor color) { } // Java 16
List<GradientValueColor> colors = new ArrayList<>();

View File

@ -5,6 +5,7 @@ import java.util.Objects;
import fr.pandacube.lib.core.chat.Chat.FormatableChat;
import fr.pandacube.lib.core.util.Log;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.md_5.bungee.api.chat.BaseComponent;
@ -77,13 +78,14 @@ public abstract class ChatStatic {
}
public static FormatableChat playerNameText(String legacyText) {
return legacyText(legacyText).white();
FormatableChat fc = legacyText(legacyText);
fc.builder.colorIfAbsent(NamedTextColor.WHITE);
return fc;
}
public static FormatableChat playerNameComponent(Component c) {
FormatableChat fc = chatComponent(c);
if (c.color() == null)
fc.white();
fc.builder.colorIfAbsent(NamedTextColor.WHITE);
return fc;
}

View File

@ -1,129 +0,0 @@
package fr.pandacube.lib.paper.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.Score;
import org.bukkit.scoreboard.Scoreboard;
import fr.pandacube.lib.core.chat.Chat;
import fr.pandacube.lib.core.chat.ChatUtil;
import net.md_5.bungee.api.ChatColor;
public class ScoreBoardUtil {
/**
* Update the sidebar of the provided scoreboard, with the given title and lines.
*
* @param scBrd the scoreboard
* @param title the title of the sidebar
* @param lines the lines that have to be displayed. Null values are treated as empty lines.
* The lines support legacy formatting only, and will be truncated to 40 characters.
* Lines present multiple times will have hidden characters appended to make them different.
* Vanilla Java Edition clients only display the 15 first lines.
* @implNote The implementation makes sure that the minimum amount of data is transmitted to the client,
* to reduce bandwith usage and avoid the sidebar flickering.
* <ul>
* <li>If a provided line is already present in the sidebar, and at the same line number, it will not be updated.
* <li>If a provided line is already present but at another position, only the score (i.e. the line number) is updated.
* <li>If a provided line was not present before, it is added as a new score entry in the scoreboard.
* <li>If a line that was already present is not in the provided lines, it is removed from the scoreboard.
* <li>The title is only updated if it has actually changed.
*/
public static void updateScoreboardSidebar(Scoreboard scBrd, Chat title, String[] lines) {
if (scBrd == null) throw new IllegalArgumentException("scBrd doit être non null");
if (lines == null) lines = new String[0];
Objective obj = scBrd.getObjective("sidebar_autogen");
if (obj != null && !obj.getCriteria().equalsIgnoreCase("dummy")) {
// objective present but with wrong criteria, removing it
obj.unregister();
obj = null;
}
if (obj == null) {
obj = scBrd.registerNewObjective("sidebar_autogen", "dummy", title.getAdv());
obj.setDisplaySlot(DisplaySlot.SIDEBAR);
}
else {
// only update title if needed
if (!title.getAdv().equals(obj.displayName()))
obj.displayName(title.getAdv());
// fix display slot if someone else changed it
if (DisplaySlot.SIDEBAR != obj.getDisplaySlot())
obj.setDisplaySlot(DisplaySlot.SIDEBAR);
}
filterLines(lines);
List<String> listLines = Arrays.asList(lines);
// remove lines from the scoreboard that are not in the provided array
Objective fObj = obj;
scBrd.getEntries().stream()
.filter(e -> !listLines.contains(e))
.filter(e -> fObj.getScore(e).isScoreSet())
.forEach(scBrd::resetScores);
// add and update others lines
int boardPos = lines.length;
for (String line : lines) {
Score score = obj.getScore(line);
if (score.getScore() != boardPos)
score.setScore(boardPos);
boardPos--;
}
}
/**
* Update the sidebar of the provided scoreboard, with the given title and lines.
*
* @param scBrd the scoreboard
* @param title the title of the sidebar
* @param lines the lines that have to be displayed. Null values are treated as empty lines.
* The lines support legacy formatting only, and will be truncated to 40 characters.
* Lines present multiple times will have hidden characters appended to make them different.
* Vanilla Java Edition clients only display the 15 first lines.
* @implNote The implementation makes sure that the minimum amount of data is transmitted to the client,
* to reduce bandwith usage and avoid the sidebar flickering.
* <ul>
* <li>If a provided line is already present in the sidebar, and at the same line number, it will not be updated.
* <li>If a provided line is already present but at another position, only the score (i.e. the line number) is updated.
* <li>If a provided line was not present before, it is added as a new score entry in the scoreboard.
* <li>If a line that was already present is not in the provided lines, it is removed from the scoreboard.
* <li>The title is only updated if it has actually changed.
*/
public static void updateScoreboardSidebar(Scoreboard scBrd, Chat title, List<String> lines) {
updateScoreboardSidebar(scBrd, title, lines.toArray(new String[lines.size()]));
}
@SuppressWarnings("deprecation")
private static void filterLines(String[] lines) {
List<String> previous = new ArrayList<>();
for (int i = 0; i < lines.length; i++) {
String line = lines[i] == null ? "" : ChatUtil.truncateAtLengthWithoutReset(lines[i], 40);
if (previous.contains(line)) {
for (ChatColor c : ChatColor.values()) {
line = ChatUtil.truncateAtLengthWithoutReset(lines[i], 38) + c;
if (!previous.contains(line)) {
break;
}
}
}
lines[i] = line;
previous.add(lines[i]);
}
}
}

View File

@ -0,0 +1,138 @@
package fr.pandacube.lib.paper.util;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.Score;
import org.bukkit.scoreboard.Scoreboard;
import org.bukkit.scoreboard.Team;
import fr.pandacube.lib.core.chat.Chat;
import net.kyori.adventure.text.Component;
public class ScoreboardUtil {
/**
* Update the sidebar of the provided scoreboard, with the given title and lines.
*
* @param scBrd the scoreboard
* @param title the title of the sidebar
* @param lines the lines that have to be displayed. Null values are treated as empty lines.
* The lines support legacy formatting only, and will be truncated to 40 characters.
* Lines present multiple times will have hidden characters appended to make them different.
* Vanilla Java Edition clients only display the 15 first lines.
*/
public static void updateScoreboardSidebar(Scoreboard scBrd, Component title, Component[] lines) {
Objective obj = scBrd.getObjective("sidebar_autogen");
if (obj != null && !obj.getCriteria().equalsIgnoreCase("dummy")) {
// objective present but with wrong criteria, removing it
obj.unregister();
obj = null;
}
if (obj == null) {
obj = scBrd.registerNewObjective("sidebar_autogen", "dummy", title);
obj.setDisplaySlot(DisplaySlot.SIDEBAR);
}
else {
// only update title if needed
if (!title.equals(obj.displayName())) {
obj.displayName(title);
}
// fix display slot if someone else changed it
if (DisplaySlot.SIDEBAR != obj.getDisplaySlot()) {
obj.setDisplaySlot(DisplaySlot.SIDEBAR);
}
}
ChatColor[] colors = ChatColor.values();
/*
* Scanning lines from last to first, keeping only the 15 first lines
*/
int score = 1, i = 0;
for (int lineIndex = Math.min(lines.length, 15) - 1; lineIndex >= 0; i++, score++, lineIndex--) {
String teamId = "sidebar_team" + score;
String sbEntry = colors[i].toString();
Team tLine = scBrd.getTeam(teamId);
if (tLine == null) {
tLine = scBrd.registerNewTeam(teamId);
}
if (!tLine.hasEntry(sbEntry)) {
tLine.addEntry(sbEntry);
}
if (!tLine.prefix().equals(lines[lineIndex])) {
tLine.prefix(lines[lineIndex]);
}
Score scoreEntry = obj.getScore(sbEntry);
if (scoreEntry.getScore() != score) {
scoreEntry.setScore(score);
}
}
// clean older data when we are reducing the number of line displayed
for (; i < colors.length; i++, score++) {
String teamId = "sidebar_team" + score;
String sbEntry = colors[i].toString();
if (obj.getScore(sbEntry).isScoreSet()) {
scBrd.resetScores(sbEntry);
}
Team tLine = scBrd.getTeam(teamId);
if (tLine != null && !tLine.prefix().equals(Component.empty())) {
tLine.prefix(Component.empty());
}
}
}
/**
* Update the sidebar of the provided scoreboard, with the given title and lines.
*
* @param scBrd the scoreboard
* @param title the title of the sidebar
* @param lines the lines that have to be displayed. Null values are treated as empty lines.
* The lines support legacy formatting only, and will be truncated to 40 characters.
* Lines present multiple times will have hidden characters appended to make them different.
* Vanilla Java Edition clients only display the 15 first lines.
*/
public static void updateScoreboardSidebar(Scoreboard scBrd, Chat title, Chat[] lines) {
Component[] cmpLines = new Component[lines.length];
for (int i = 0; i < lines.length; i++) {
cmpLines[i] = lines[i].getAdv();
}
updateScoreboardSidebar(scBrd, title.getAdv(), cmpLines);
}
/**
* Update the sidebar of the provided scoreboard, with the given title and lines.
*
* @param scBrd the scoreboard
* @param title the title of the sidebar
* @param lines the lines that have to be displayed. Null values are treated as empty lines.
* The lines support legacy formatting only, and will be truncated to 40 characters.
* Lines present multiple times will have hidden characters appended to make them different.
* Vanilla Java Edition clients only display the 15 first lines.
*/
public static void updateScoreboardSidebar(Scoreboard scBrd, Chat title, List<Chat> lines) {
Component[] cmpLines = new Component[lines.size()];
for (int i = 0; i < cmpLines.length; i++) {
cmpLines[i] = lines.get(i).getAdv();
}
updateScoreboardSidebar(scBrd, title.getAdv(), cmpLines);
}
}