Compare commits

...
30 Commits
Author SHA1 Message Date
vytskalt 6fe6200cda ci fix 2025-09-30 19:29:00 +03:00
vytskalt fb4863a9e3 release 2.4.2 2025-09-30 19:16:48 +03:00
vytskalt a298842bce 1.21.9 2025-09-30 19:15:53 +03:00
vytskalt 16314a7d14 fix build 2025-09-30 18:39:29 +03:00
vytskalt c1286520d3 draw up to sidebar#maxLines() 2025-09-30 18:38:58 +03:00
vytskalt bc8e3c2d2e release: 2.4.1 2025-07-17 18:37:46 +03:00
vytskalt 032349b190 mark 1.21.8 as supported 2025-07-17 18:37:08 +03:00
vytskalt d0d5eaa706 release: 2.4.0 2025-07-08 17:24:34 +03:00
vytskalt ac334838ee bump dependencies 2025-07-08 16:57:44 +03:00
vytskalt 162de14e0e Merge pull request #100 from huanmeng-qwq/feat/refresh
Add refresh-related methods
2025-07-08 16:53:38 +03:00
vytskalt 5f5b3efc5f improve docs 2025-07-08 13:55:05 +03:00
vytskalt 41c0a4b3c9 improve objective api 2025-07-08 13:52:12 +03:00
vytskalt a276708162 make sure to update the sidebar score format as well 2025-07-08 13:37:39 +03:00
huanmeng-qwq 793e78284f feat(api): Add refresh-related methods to ScoreboardObjective, Sidebar, and TeamDisplay. 2025-07-08 17:11:47 +08:00
vytskalt 38de97ba01 release: 2.3.3 2025-07-02 15:34:32 +03:00
vytskalt a535f37214 1.21.7 2025-07-02 15:34:04 +03:00
vytskalt 48351b6c81 release: 2.3.2 2025-06-23 01:11:13 +03:00
vytskalt 7dcf1e30eb add 1.21.6 support 2025-06-23 01:06:20 +03:00
vytskalt 2ca874346d release: 2.3.1 2025-05-04 19:29:04 +03:00
vytskalt cb08e5d3d9 Merge remote-tracking branch 'origin/main' 2025-04-26 23:53:16 +03:00
vytskalt eecde934a8 setup snapshot 2025-04-26 23:52:50 +03:00
vytskalt 2a070cdc3d remove transitive dependency on spigot-api 2025-04-26 23:52:11 +03:00
vytskalt 589ab095b2 [ci skip] Update INSTALLATION.md 2025-04-21 19:52:18 +03:00
vytskalt 41fb8aa4aa Update INSTALLATION.md 2025-04-21 19:43:22 +03:00
vytskalt da69391930 release: 2.3.0 2025-04-12 19:31:35 +03:00
vytskalt 47ef9a8143 update junit platform launcher 2025-04-12 19:27:25 +03:00
vytskalt ccf9aad96d update dependencies 2025-04-12 19:23:17 +03:00
vytskalt facb3a4d1c allow getting/setting sidebar objective name 2025-04-03 21:42:29 +03:00
vytskalt f41c1ce0b1 1.21.5 2025-03-27 19:59:49 +02:00
vytskalt e72d442f9b upgrade to gradle 8.13 2025-03-27 18:44:23 +02:00
43 changed files with 355 additions and 123 deletions

No files matched your search

+2 -2
View File
@@ -9,8 +9,8 @@ jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
- uses: actions/checkout@v5
- uses: cachix/install-nix-action@v31
- name: Cache Gradle
uses: actions/cache@v4
with:
+3 -3
View File
@@ -1,6 +1,6 @@
# Installation
Latest version: `2.2.2`
Latest version: `2.4.2`
## Gradle
@@ -29,12 +29,12 @@ dependencies {
// https://github.com/retrooper/packetevents-example/blob/24f0c842d47362aef122b794dea29b8fee113fa3/thread-safe-listener/src/main/java/main/Main.java
// If targeting a Minecraft version without native Adventure support, add it as well:
implementation("net.kyori:adventure-platform-bukkit:4.0.1")
implementation("net.kyori:adventure-platform-bukkit:4.3.4")
}
```
You will need to shade these dependencies and relocate them with something
like [Shadow](https://imperceptiblethoughts.com/shadow/).
like [Shadow](https://gradleup.com/shadow/).
## Maven
+1 -1
View File
@@ -23,7 +23,7 @@ Join the [Discord](https://discord.gg/v7nmTDTW8W) or create an issue for support
## Available Packet Adapters
- **modern.** Supports 1.17-1.21.4. Can take advantage of [Paper](https://papermc.io)'s native adventure support to be more efficient.
- **modern.** Supports 1.17-1.21.9. Can take advantage of [Paper](https://papermc.io)'s native adventure support to be more efficient.
- **legacy.** Supports 1.7.10-1.12.2.
- **PacketEvents.** Supports 1.8+. Requires [PacketEvents 2.0](https://github.com/retrooper/packetevents/tree/2.0) to be shaded or installed as a plugin.
+5
View File
@@ -1,3 +1,8 @@
plugins {
id("net.megavex.scoreboardlibrary.base-conventions")
}
dependencies {
compileOnlyApi(libs.bundles.adventure)
compileOnly(libs.spigotApi)
}
@@ -5,6 +5,7 @@ import net.megavex.scoreboardlibrary.api.noop.NoopScoreboardLibrary;
import net.megavex.scoreboardlibrary.api.objective.ObjectiveManager;
import net.megavex.scoreboardlibrary.api.sidebar.Sidebar;
import net.megavex.scoreboardlibrary.api.team.TeamManager;
import org.apache.commons.lang.RandomStringUtils;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.ApiStatus;
@@ -56,7 +57,7 @@ public interface ScoreboardLibrary {
* @return newly created sidebar
*/
default @NotNull Sidebar createSidebar() {
return createSidebar(Sidebar.MAX_LINES, null);
return createSidebar(Sidebar.MAX_LINES);
}
/**
@@ -79,7 +80,21 @@ public interface ScoreboardLibrary {
* or null if the locale should depend on the player
* @return newly created sidebar
*/
@NotNull Sidebar createSidebar(@Range(from = 1, to = Integer.MAX_VALUE) int maxLines, @Nullable Locale locale);
default @NotNull Sidebar createSidebar(@Range(from = 1, to = Integer.MAX_VALUE) int maxLines, @Nullable Locale locale) {
return createSidebar(maxLines, locale, RandomStringUtils.randomAlphanumeric(16));
}
/**
* Creates a new {@link Sidebar}.
*
* @param maxLines max amount of lines the sidebar will have.
* Note that vanilla clients can only display at most {@value Sidebar#MAX_LINES}
* @param locale locale which will be used for translating {@link net.kyori.adventure.text.TranslatableComponent}s,
* or null if the locale should depend on the player
* @param objectiveName objective name the sidebar should use
* @return newly created sidebar
*/
@NotNull Sidebar createSidebar(@Range(from = 1, to = Integer.MAX_VALUE) int maxLines, @Nullable Locale locale, @NotNull String objectiveName);
/**
* Creates a new {@link TeamManager}.
@@ -19,9 +19,9 @@ public final class NoopScoreboardLibrary implements ScoreboardLibrary {
private boolean closed = false;
@Override
public @NotNull Sidebar createSidebar(@Range(from = 1, to = Sidebar.MAX_LINES) int maxLines, @Nullable Locale locale) {
public @NotNull Sidebar createSidebar(@Range(from = 1, to = Integer.MAX_VALUE) int maxLines, @Nullable Locale locale, @NotNull String objectiveName) {
checkClosed();
return new NoopSidebar(maxLines, locale);
return new NoopSidebar(maxLines, objectiveName, locale);
}
@Override
@@ -52,6 +52,10 @@ public class NoopScoreboardObjective implements ScoreboardObjective {
this.defaultScoreFormat = defaultScoreFormat;
}
@Override
public void refreshProperties() {
}
@Override
public @Nullable ObjectiveScore scoreInfo(@NotNull String entry) {
return scores.get(entry);
@@ -68,4 +72,8 @@ public class NoopScoreboardObjective implements ScoreboardObjective {
scores.remove(entry);
return this;
}
@Override
public void refreshScore(@NotNull String entry) {
}
}
@@ -17,14 +17,16 @@ import static net.kyori.adventure.text.Component.empty;
class NoopSidebar implements Sidebar {
private final Set<Player> players = new HashSet<>();
private final int maxLines;
private final String objectiveName;
private final Locale locale;
private final Component[] lines;
private Component title = empty();
private boolean closed;
NoopSidebar(int maxLines, @Nullable Locale locale) {
NoopSidebar(int maxLines, String objectiveName, @Nullable Locale locale) {
this.maxLines = maxLines;
this.locale = locale;
this.objectiveName = objectiveName;
this.lines = new Component[maxLines];
}
@@ -62,6 +64,11 @@ class NoopSidebar implements Sidebar {
return maxLines;
}
@Override
public @NotNull String objectiveName() {
return objectiveName;
}
@Override
public @Nullable Locale locale() {
return locale;
@@ -74,6 +81,10 @@ class NoopSidebar implements Sidebar {
lines[index] = value == null ? null : value.asComponent();
}
@Override
public void refreshLine(@Range(from = 0, to = Integer.MAX_VALUE - 1) final int index) {
}
@Override
public @Nullable Component line(int line) {
checkLineBounds(line);
@@ -93,6 +104,11 @@ class NoopSidebar implements Sidebar {
this.title = title.asComponent();
}
@Override
public void refreshTitle() {
}
private void checkClosed() {
if (closed) {
throw new IllegalStateException("NoopSidebar is closed");
@@ -140,4 +140,8 @@ class NoopTeamDisplay implements TeamDisplay {
this.playerColor = playerColor;
return this;
}
@Override
public void refresh() {
}
}
@@ -49,6 +49,11 @@ public interface ScoreboardObjective {
*/
void defaultScoreFormat(@Nullable ScoreFormat defaultScoreFormat);
/**
* Refreshes the objective's {@link #value()} and {@link #defaultScoreFormat()}, re-rendering any {@link net.kyori.adventure.text.TranslatableComponent}s.
*/
void refreshProperties();
/**
* Get the score for an entry, or null if the entry has no score.
*
@@ -141,4 +146,11 @@ public interface ScoreboardObjective {
* @param entry entry to remove score of
*/
@NotNull ScoreboardObjective removeScore(@NotNull String entry);
/**
* Refreshes a score, re-rendering any {@link net.kyori.adventure.text.TranslatableComponent}s inside its format.
*
* @param entry entry to refresh score of
*/
void refreshScore(@NotNull String entry);
}
@@ -1,18 +1,17 @@
package net.megavex.scoreboardlibrary.api.sidebar;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import net.megavex.scoreboardlibrary.api.ScoreboardLibrary;
import net.megavex.scoreboardlibrary.api.objective.ScoreFormat;
import java.util.Collection;
import java.util.Locale;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Range;
import java.util.Collection;
import java.util.Locale;
/**
* Represents a sidebar.
* To get an instance of this interface, use {@link ScoreboardLibrary#createSidebar()}.
@@ -31,7 +30,13 @@ public interface Sidebar {
/**
* @return max amount of lines this sidebar can have
*/
@Range(from = 1, to = Integer.MAX_VALUE) int maxLines();
@Range(from = 1, to = Integer.MAX_VALUE)
int maxLines();
/**
* @return objective name used by this sidebar
*/
@NotNull String objectiveName();
/**
* @return locale which is used for translating {@link net.kyori.adventure.text.TranslatableComponent}s,
@@ -85,6 +90,22 @@ public interface Sidebar {
}
}
/**
* Refreshes a specific line, re-rendering any {@link net.kyori.adventure.text.TranslatableComponent}s.
*
* @param index line index
*/
void refreshLine(@Range(from = 0, to = Integer.MAX_VALUE - 1) int index);
/**
* Refreshes all lines in this sidebar, re-rendering any {@link net.kyori.adventure.text.TranslatableComponent}s.
*/
default void refreshLines() {
for (int i = 0; i < maxLines(); i++) {
refreshLine(i);
}
}
// Title
/**
@@ -99,6 +120,11 @@ public interface Sidebar {
*/
void title(@NotNull ComponentLike title);
/**
* Refresh the title of the sidebar, re-rendering any {@link net.kyori.adventure.text.TranslatableComponent}s.
*/
void refreshTitle();
// Players
/**
@@ -78,7 +78,7 @@ public final class ComponentSidebarLayout {
public void drawLine(@NotNull ComponentLike line, @Nullable ScoreFormat scoreFormat) {
Preconditions.checkNotNull(line);
if (index < Sidebar.MAX_LINES) {
if (index < sidebar.maxLines()) {
sidebar.line(index++, line, scoreFormat);
}
}
@@ -170,4 +170,9 @@ public interface TeamDisplay {
* @since Minecraft 1.8
*/
@NotNull TeamDisplay playerColor(@Nullable NamedTextColor playerColor);
/**
* Refreshes the team display, re-rendering any {@link net.kyori.adventure.text.TranslatableComponent}s.
*/
void refresh();
}
+1 -1
View File
@@ -1,5 +1,5 @@
allprojects {
version = "2.2.2"
version = "2.4.2"
group = "net.megavex"
description = "Powerful packet-level scoreboard library for Paper/Spigot servers"
}
@@ -16,16 +16,18 @@ repositories {
mavenCentral()
maven("https://oss.sonatype.org/content/repositories/snapshots")
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
maven("https://hub.spigotmc.org/nexus/content/repositories/sonatype-nexus-snapshots/") {
content {
includeGroup("net.md-5")
}
}
}
dependencies {
compileOnly(libs.spigotApi)
compileOnly(libs.bundles.adventure)
testImplementation(libs.spigotApi)
testImplementation(libs.bundles.adventure)
testImplementation(libs.junitJupiterApi)
testRuntimeOnly(libs.junitJupiterEngine)
testImplementation(libs.junitJupiter)
testRuntimeOnly(libs.junitPlatformLauncher)
}
indra {
+1
View File
@@ -4,4 +4,5 @@ plugins {
dependencies {
api(project(":scoreboard-library-api"))
compileOnly(libs.spigotApi)
}
+6 -3
View File
@@ -1,4 +1,6 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
plugins {
id("net.megavex.scoreboardlibrary.base-conventions")
@@ -12,10 +14,11 @@ kotlin {
dependencies {
api(project(":scoreboard-library-api"))
testImplementation(kotlin("test"))
compileOnly(libs.spigotApi)
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = "1.8"
tasks.withType<KotlinJvmCompile>().configureEach {
compilerOptions {
jvmTarget = JvmTarget.JVM_1_8
}
}
+9 -9
View File
@@ -1,24 +1,24 @@
[versions]
adventure = "4.17.0"
junitJupiter = "5.11.3"
devBundle = "1.21.4-R0.1-20241208.061653-9" # find latest here: https://repo.papermc.io/repository/maven-snapshots/io/papermc/paper/dev-bundle/1.21.4-R0.1-SNAPSHOT/maven-metadata.xml
adventure = "4.24.0"
#devBundle = "1.21.9-R0.1-20250930.152416-1" # find latest here: https://repo.papermc.io/repository/maven-snapshots/io/papermc/paper/dev-bundle/1.21.9-R0.1-SNAPSHOT/maven-metadata.xml
devBundle = "1.21.7-R0.1-20250701.225444-12" # find latest here: https://repo.papermc.io/repository/maven-snapshots/io/papermc/paper/dev-bundle/1.21.7-R0.1-SNAPSHOT/maven-metadata.xml
[libraries]
spigotApi = "org.spigotmc:spigot-api:1.12.2-R0.1-SNAPSHOT" # do not update
packetEvents = "com.github.retrooper:packetevents-spigot:2.6.0"
buildIndra = { module = "net.kyori:indra-common", version = "3.1.3" }
packetEvents = "com.github.retrooper:packetevents-spigot:2.9.5"
buildIndra = { module = "net.kyori:indra-common", version = "3.2.0" }
buildNmcp = "com.gradleup.nmcp:com.gradleup.nmcp.gradle.plugin:0.0.9"
adventureApi = { module = "net.kyori:adventure-api", version.ref = "adventure" }
adventureTextSerializerGson = { module = "net.kyori:adventure-text-serializer-gson", version.ref = "adventure" }
adventureTextSerializerLegacy = { module = "net.kyori:adventure-text-serializer-legacy", version.ref = "adventure" }
junitJupiterApi = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junitJupiter" }
junitJupiterEngine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junitJupiter" }
junitJupiter = "org.junit.jupiter:junit-jupiter:5.13.3"
junitPlatformLauncher = "org.junit.platform:junit-platform-launcher:1.13.3"
[plugins]
kotlin = "org.jetbrains.kotlin.jvm:2.1.0"
paperweight = "io.papermc.paperweight.userdev:1.7.7"
kotlin = "org.jetbrains.kotlin.jvm:2.2.20"
paperweight = "io.papermc.paperweight.userdev:2.0.0-beta.19"
[bundles]
adventure = [ "adventureApi", "adventureTextSerializerGson", "adventureTextSerializerLegacy" ]
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+4 -8
View File
@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -86,8 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -115,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -173,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -206,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
Vendored
+1 -2
View File
@@ -70,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
+1
View File
@@ -5,4 +5,5 @@ plugins {
dependencies {
api(project(":scoreboard-library-api"))
implementation(project(":scoreboard-library-packet-adapter-base"))
compileOnly(libs.spigotApi)
}
@@ -90,6 +90,11 @@ public final class PacketAdapterLoader {
case "1.21.2":
case "1.21.3":
case "1.21.4":
case "1.21.5":
case "1.21.6":
case "1.21.7":
case "1.21.8":
case "1.21.9":
return tryLoadImplementationClass(MODERN);
default:
// Hide from relocation checkers
@@ -90,7 +90,7 @@ public class ScoreboardLibraryImpl implements ScoreboardLibrary {
}
@Override
public @NotNull Sidebar createSidebar(int maxLines, @Nullable Locale locale) {
public @NotNull Sidebar createSidebar(int maxLines, @Nullable Locale locale, @NotNull String objectiveName) {
checkClosed();
if (maxLines <= 0) {
@@ -99,9 +99,9 @@ public class ScoreboardLibraryImpl implements ScoreboardLibrary {
AbstractSidebar sidebar;
if (locale == null) {
sidebar = new PlayerDependantLocaleSidebar(this, maxLines);
sidebar = new PlayerDependantLocaleSidebar(this, maxLines, objectiveName);
} else {
sidebar = new SingleLocaleSidebar(this, maxLines, locale);
sidebar = new SingleLocaleSidebar(this, maxLines, objectiveName, locale);
}
sidebars().add(sidebar);
@@ -1,19 +1,22 @@
package net.megavex.scoreboardlibrary.implementation.objective;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import net.megavex.scoreboardlibrary.api.objective.ObjectiveRenderType;
import net.megavex.scoreboardlibrary.api.objective.ObjectiveScore;
import net.megavex.scoreboardlibrary.api.objective.ScoreFormat;
import net.megavex.scoreboardlibrary.api.objective.ScoreboardObjective;
import net.megavex.scoreboardlibrary.implementation.packetAdapter.PropertiesPacketType;
import net.megavex.scoreboardlibrary.implementation.packetAdapter.objective.ObjectivePacketAdapter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Queue;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import static net.kyori.adventure.text.Component.empty;
public class ScoreboardObjectiveImpl implements ScoreboardObjective {
@@ -95,6 +98,13 @@ public class ScoreboardObjectiveImpl implements ScoreboardObjective {
}
}
@Override
public void refreshProperties() {
if (!closed) {
taskQueue.add(new ObjectiveManagerTask.UpdateObjective(this));
}
}
@Override
public @Nullable ObjectiveScore scoreInfo(@NotNull String entry) {
return scores.get(entry);
@@ -117,6 +127,14 @@ public class ScoreboardObjectiveImpl implements ScoreboardObjective {
return this;
}
@Override
public void refreshScore(@NotNull String entry) {
ObjectiveScore score = scores.get(entry);
if (score != null) {
taskQueue.add(new ObjectiveManagerTask.UpdateScore(this, entry, score));
}
}
public void sendProperties(@NotNull Collection<Player> players, @NotNull PropertiesPacketType packetType) {
packetAdapter.sendProperties(players, packetType, value, renderType, defaultScoreFormat);
}
@@ -1,10 +1,6 @@
package net.megavex.scoreboardlibrary.implementation.sidebar;
import com.google.common.base.Preconditions;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.adventure.translation.GlobalTranslator;
import net.megavex.scoreboardlibrary.api.objective.ObjectiveDisplaySlot;
import net.megavex.scoreboardlibrary.api.objective.ObjectiveRenderType;
import net.megavex.scoreboardlibrary.api.objective.ScoreFormat;
@@ -17,16 +13,22 @@ import net.megavex.scoreboardlibrary.implementation.player.PlayerDisplayable;
import net.megavex.scoreboardlibrary.implementation.player.ScoreboardLibraryPlayer;
import net.megavex.scoreboardlibrary.implementation.sidebar.line.GlobalLineInfo;
import net.megavex.scoreboardlibrary.implementation.sidebar.line.LocaleLineHandler;
import org.apache.commons.lang.RandomStringUtils;
import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.Consumer;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.adventure.translation.GlobalTranslator;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Range;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.Consumer;
import static net.kyori.adventure.text.Component.empty;
public abstract class AbstractSidebar implements Sidebar, PlayerDisplayable {
@@ -42,10 +44,8 @@ public abstract class AbstractSidebar implements Sidebar, PlayerDisplayable {
private final Queue<SidebarTask> taskQueue = new ConcurrentLinkedQueue<>();
public AbstractSidebar(@NotNull ScoreboardLibraryImpl scoreboardLibrary, int maxLines) {
public AbstractSidebar(@NotNull ScoreboardLibraryImpl scoreboardLibrary, int maxLines, @NotNull String objectiveName) {
this.scoreboardLibrary = scoreboardLibrary;
String objectiveName = RandomStringUtils.randomAlphanumeric(16);
this.packetAdapter = scoreboardLibrary.packetAdapter().createObjectiveAdapter(objectiveName);
this.lines = new GlobalLineInfo[maxLines];
}
@@ -107,6 +107,11 @@ public abstract class AbstractSidebar implements Sidebar, PlayerDisplayable {
return lines.length;
}
@Override
public @NotNull String objectiveName() {
return packetAdapter.objectiveName();
}
@Override
public final void line(@Range(from = 0, to = MAX_LINES - 1) int index, @Nullable ComponentLike value, @Nullable ScoreFormat scoreFormat) {
checkClosed();
@@ -124,6 +129,17 @@ public abstract class AbstractSidebar implements Sidebar, PlayerDisplayable {
}
}
@Override
public void refreshLine(@Range(from = 0, to = Integer.MAX_VALUE - 1) final int index) {
checkClosed();
GlobalLineInfo line = lines[index];
if (line != null) {
boolean updateValue = line.value() != null;
boolean updateScore = line.scoreFormat() != null;
taskQueue.add(new SidebarTask.UpdateLine(index, updateValue, updateScore));
}
}
@Override
public final @Nullable Component line(@Range(from = 0, to = MAX_LINES - 1) int line) {
checkClosed();
@@ -149,6 +165,12 @@ public abstract class AbstractSidebar implements Sidebar, PlayerDisplayable {
}
}
@Override
public void refreshTitle() {
checkClosed();
taskQueue.add(SidebarTask.UpdateTitle.INSTANCE);
}
public final @NotNull ScoreboardLibraryImpl scoreboardLibrary() {
return scoreboardLibrary;
}
@@ -17,8 +17,8 @@ public class PlayerDependantLocaleSidebar extends AbstractSidebar {
private final Map<Player, LocaleLineHandler> playerMap = new HashMap<>();
private final Map<Locale, LocaleLineHandler> localeMap = new HashMap<>();
public PlayerDependantLocaleSidebar(@NotNull ScoreboardLibraryImpl scoreboardLibrary, int maxLines) {
super(scoreboardLibrary, maxLines);
public PlayerDependantLocaleSidebar(@NotNull ScoreboardLibraryImpl scoreboardLibrary, int maxLines, @NotNull String objectiveName) {
super(scoreboardLibrary, maxLines, objectiveName);
}
@Override
@@ -16,8 +16,8 @@ public class SingleLocaleSidebar extends AbstractSidebar {
private final LocaleLineHandler sidebar;
private final Set<Player> internalPlayers;
public SingleLocaleSidebar(@NotNull ScoreboardLibraryImpl scoreboardLibrary, int size, @NotNull Locale locale) {
super(scoreboardLibrary, size);
public SingleLocaleSidebar(@NotNull ScoreboardLibraryImpl scoreboardLibrary, int size, @NotNull String objectiveName, @NotNull Locale locale) {
super(scoreboardLibrary, size, objectiveName);
this.locale = locale;
this.sidebar = new LocaleLineHandler(this, locale);
this.internalPlayers = CollectionProvider.set(8);
@@ -210,6 +210,11 @@ public class TeamDisplayImpl implements TeamDisplay, ImmutableTeamProperties<Com
return this;
}
@Override
public void refresh() {
scheduleUpdate();
}
public @NotNull TeamDisplayPacketAdapter packetAdapter() {
return packetAdapter;
}
+1
View File
@@ -4,4 +4,5 @@ plugins {
dependencies {
compileOnly(project(":scoreboard-library-packet-adapter-base"))
compileOnly(libs.spigotApi)
}
@@ -26,6 +26,11 @@ public class ObjectivePacketAdapterImpl implements ObjectivePacketAdapter {
this.objectiveName = objectiveName;
}
@Override
public @NotNull String objectiveName() {
return objectiveName;
}
@Override
public void display(@NotNull Collection<Player> players, @NotNull ObjectiveDisplaySlot slot) {
Object packet = PacketAccessors.DISPLAY_OBJECTIVE_CONSTRUCTOR.invoke();
+7 -1
View File
@@ -4,7 +4,9 @@ plugins {
}
dependencies {
compileOnly(project(":scoreboard-library-packet-adapter-base"))
compileOnly(project(":scoreboard-library-packet-adapter-base")) {
exclude(group = "org.spigotmc", module = "spigot-api")
}
paperweight.paperDevBundle(libs.versions.devBundle.get())
}
@@ -23,6 +25,10 @@ tasks {
assemble {
dependsOn(reobfJar)
}
javadoc {
exclude("**")
}
}
java {
@@ -1,11 +1,13 @@
package net.megavex.scoreboardlibrary.implementation.packetAdapter.modern;
import com.google.gson.JsonElement;
import com.mojang.serialization.JsonOps;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.translation.GlobalTranslator;
import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.NativeAdventureUtil;
import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.RegistryUtil;
import net.minecraft.network.chat.Component.Serializer;
import net.megavex.scoreboardlibrary.implementation.packetAdapter.util.reflect.ReflectUtil;
import net.minecraft.network.chat.ComponentSerialization;
import net.minecraft.network.chat.MutableComponent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -21,27 +23,32 @@ public class ComponentProviderImpl implements ComponentProvider {
private static final MethodHandle FROM_JSON_METHOD;
static {
MethodHandle handle = null;
for (Method method : Serializer.class.getMethods()) {
if (method.getReturnType() == MutableComponent.class &&
method.getParameterCount() >= 1 &&
method.getParameterCount() <= 2 &&
method.getParameterTypes()[0] == JsonElement.class
) {
try {
handle = MethodHandles.lookup().unreflect(method);
break;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
if (!PacketAccessors.IS_1_21_6_OR_ABOVE) {
Class<?> serializerClass = ReflectUtil.getClassOrThrow("net.minecraft.network.chat.Component$Serializer", "net.minecraft.network.chat.IChatBaseComponent$ChatSerializer");
MethodHandle handle = null;
for (Method method : serializerClass.getMethods()) {
if (method.getReturnType() == MutableComponent.class &&
method.getParameterCount() >= 1 &&
method.getParameterCount() <= 2 &&
method.getParameterTypes()[0] == JsonElement.class
) {
try {
handle = MethodHandles.lookup().unreflect(method);
break;
} catch (IllegalAccessException e) {
throw new ExceptionInInitializerError(e);
}
}
}
}
if (handle == null) {
throw new ExceptionInInitializerError("failed to find chat component fromJson method");
}
if (handle == null) {
throw new ExceptionInInitializerError("failed to find chat component fromJson method");
}
FROM_JSON_METHOD = handle;
FROM_JSON_METHOD = handle;
} else {
FROM_JSON_METHOD = null;
}
}
private final boolean isNativeAdventure;
@@ -60,8 +67,13 @@ public class ComponentProviderImpl implements ComponentProvider {
if (locale != null) {
translated = GlobalTranslator.render(adventure, locale);
}
JsonElement json = gson().serializeToTree(translated);
if (FROM_JSON_METHOD == null) {
// 1.21.6+
return ComponentSerialization.CODEC.parse(JsonOps.INSTANCE, json).getOrThrow();
}
Object[] args;
if (PacketAccessors.IS_1_20_5_OR_ABOVE) {
args = new Object[]{json, RegistryUtil.MINECRAFT_REGISTRY};
@@ -11,8 +11,8 @@ import net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket;
import net.minecraft.network.protocol.game.ClientboundSetObjectivePacket;
import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket;
import net.minecraft.network.protocol.game.ClientboundSetScorePacket;
import net.minecraft.server.ServerScoreboard;
import net.minecraft.world.scores.Objective;
import net.minecraft.world.scores.Team;
import net.minecraft.world.scores.criteria.ObjectiveCriteria;
import java.util.Collection;
@@ -44,22 +44,58 @@ public final class PacketAccessors {
}
IS_1_20_5_OR_ABOVE = is1_20_5OrAbove;
boolean is1_21_5OrAbove = false;
try {
Class.forName("net.minecraft.world.item.component.BlocksAttacks"); // Random 1.21.5 class
is1_21_5OrAbove = true;
} catch (ClassNotFoundException ignored) {
}
IS_1_21_5_OR_ABOVE = is1_21_5OrAbove;
boolean is1_21_6OrAbove = false;
try {
Class.forName("net.minecraft.server.dialog.Dialog"); // Random 1.21.6 class
is1_21_6OrAbove = true;
} catch (ClassNotFoundException ignored) {
}
IS_1_21_6_OR_ABOVE = is1_21_6OrAbove;
if (is1_21_5OrAbove) {
NAME_TAG_VISIBILITY_FIELD_1_21_5 = ReflectUtil.findField(ClientboundSetPlayerTeamPacket.Parameters.class, 0, Team.Visibility.class);
COLLISION_RULE_FIELD_1_21_5 = ReflectUtil.findField(ClientboundSetPlayerTeamPacket.Parameters.class, 0, Team.CollisionRule.class);
NAME_TAG_VISIBILITY_FIELD_1_21_4 = null;
COLLISION_RULE_FIELD_1_21_4 = null;
} else {
NAME_TAG_VISIBILITY_FIELD_1_21_4 = ReflectUtil.findField(ClientboundSetPlayerTeamPacket.Parameters.class, 0, String.class);
COLLISION_RULE_FIELD_1_21_4 = ReflectUtil.findField(ClientboundSetPlayerTeamPacket.Parameters.class, 1, String.class);
NAME_TAG_VISIBILITY_FIELD_1_21_5 = null;
COLLISION_RULE_FIELD_1_21_5 = null;
}
if (is1_20_5OrAbove) {
OBJECTIVE_NUMBER_FORMAT_FIELD = ReflectUtil.findFieldUnchecked(ClientboundSetObjectivePacket.class, 0, Optional.class);
SCORE_1_20_2_CONSTRUCTOR = null;
SCORE_1_20_3_CONSTRUCTOR = null;
SCORE_1_20_2_METHOD_CHANGE = null;
SCORE_1_20_2_METHOD_REMOVE = null;
} else if (is1_20_3OrAbove) {
OBJECTIVE_NUMBER_FORMAT_FIELD = ReflectUtil.findFieldUnchecked(ClientboundSetObjectivePacket.class, 0, NumberFormat.class);
SCORE_1_20_3_CONSTRUCTOR = ReflectUtil.findConstructor(ClientboundSetScorePacket.class, String.class, String.class, int.class, Component.class, NumberFormat.class);
SCORE_1_20_2_METHOD_CHANGE = null;
SCORE_1_20_2_METHOD_REMOVE = null;
SCORE_1_20_2_CONSTRUCTOR = null;
} else {
OBJECTIVE_NUMBER_FORMAT_FIELD = null;
SCORE_1_20_3_CONSTRUCTOR = null;
SCORE_1_20_2_CONSTRUCTOR = ReflectUtil.findConstructor(ClientboundSetScorePacket.class, ServerScoreboard.Method.class, String.class, String.class, int.class);
Class<?> methodClass = ReflectUtil.getClassOrThrow("net.minecraft.server.ServerScoreboard$Method", "net.minecraft.server.ScoreboardServer$Action");
SCORE_1_20_2_METHOD_CHANGE = ReflectUtil.getEnumInstance(methodClass, "CHANGE", "a");
SCORE_1_20_2_METHOD_REMOVE = ReflectUtil.getEnumInstance(methodClass, "REMOVE", "b");
SCORE_1_20_2_CONSTRUCTOR = ReflectUtil.findConstructor(ClientboundSetScorePacket.class, methodClass, String.class, String.class, int.class);
}
}
public static final boolean IS_1_20_2_OR_ABOVE, IS_1_20_3_OR_ABOVE, IS_1_20_5_OR_ABOVE;
public static final boolean IS_1_20_2_OR_ABOVE, IS_1_20_3_OR_ABOVE, IS_1_20_5_OR_ABOVE, IS_1_21_5_OR_ABOVE, IS_1_21_6_OR_ABOVE;
public static final PacketConstructor<ClientboundSetObjectivePacket> OBJECTIVE_PACKET_CONSTRUCTOR =
ReflectUtil.getEmptyConstructor(ClientboundSetObjectivePacket.class);
@@ -80,6 +116,8 @@ public final class PacketAccessors {
ReflectUtil.findField(ClientboundSetDisplayObjectivePacket.class, 0, String.class);
public static final ConstructorAccessor<ClientboundSetScorePacket> SCORE_1_20_3_CONSTRUCTOR;
public static final Object SCORE_1_20_2_METHOD_CHANGE, SCORE_1_20_2_METHOD_REMOVE;
public static final ConstructorAccessor<ClientboundSetScorePacket> SCORE_1_20_2_CONSTRUCTOR;
public static final ConstructorAccessor<ClientboundSetPlayerTeamPacket> TEAM_PACKET_CONSTRUCTOR =
@@ -92,10 +130,12 @@ public final class PacketAccessors {
ReflectUtil.findField(ClientboundSetPlayerTeamPacket.Parameters.class, 1, net.minecraft.network.chat.Component.class);
public static final FieldAccessor<ClientboundSetPlayerTeamPacket.Parameters, net.minecraft.network.chat.Component> SUFFIX_FIELD =
ReflectUtil.findField(ClientboundSetPlayerTeamPacket.Parameters.class, 2, net.minecraft.network.chat.Component.class);
public static final FieldAccessor<ClientboundSetPlayerTeamPacket.Parameters, String> NAME_TAG_VISIBILITY_FIELD =
ReflectUtil.findField(ClientboundSetPlayerTeamPacket.Parameters.class, 0, String.class);
public static final FieldAccessor<ClientboundSetPlayerTeamPacket.Parameters, String> COLLISION_RULE_FIELD =
ReflectUtil.findField(ClientboundSetPlayerTeamPacket.Parameters.class, 1, String.class);
public static final FieldAccessor<ClientboundSetPlayerTeamPacket.Parameters, String> NAME_TAG_VISIBILITY_FIELD_1_21_4;
public static final FieldAccessor<ClientboundSetPlayerTeamPacket.Parameters, String> COLLISION_RULE_FIELD_1_21_4;
public static final FieldAccessor<ClientboundSetPlayerTeamPacket.Parameters, Team.Visibility> NAME_TAG_VISIBILITY_FIELD_1_21_5;
public static final FieldAccessor<ClientboundSetPlayerTeamPacket.Parameters, Team.CollisionRule> COLLISION_RULE_FIELD_1_21_5;
public static final FieldAccessor<ClientboundSetPlayerTeamPacket.Parameters, ChatFormatting> COLOR_FIELD =
ReflectUtil.findField(ClientboundSetPlayerTeamPacket.Parameters.class, 0, ChatFormatting.class);
public static final FieldAccessor<ClientboundSetPlayerTeamPacket.Parameters, Integer> OPTIONS_FIELD =
@@ -15,7 +15,6 @@ import net.minecraft.network.protocol.game.ClientboundResetScorePacket;
import net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket;
import net.minecraft.network.protocol.game.ClientboundSetObjectivePacket;
import net.minecraft.network.protocol.game.ClientboundSetScorePacket;
import net.minecraft.server.ServerScoreboard;
import net.minecraft.world.scores.criteria.ObjectiveCriteria;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@@ -37,6 +36,11 @@ public abstract class AbstractObjectivePacketAdapter implements ObjectivePacketA
this.objectiveName = objectiveName;
}
@Override
public @NotNull String objectiveName() {
return objectiveName;
}
@Override
public void display(@NotNull Collection<Player> players, @NotNull ObjectiveDisplaySlot slot) {
sender.sendPacket(players, createDisplayPacket(slot));
@@ -59,7 +63,7 @@ public abstract class AbstractObjectivePacketAdapter implements ObjectivePacketA
packet = new ClientboundResetScorePacket(entry, objectiveName);
} else {
packet = Objects.requireNonNull(PacketAccessors.SCORE_1_20_2_CONSTRUCTOR)
.invoke(ServerScoreboard.Method.REMOVE, objectiveName, entry, 0);
.invoke(PacketAccessors.SCORE_1_20_2_METHOD_REMOVE, objectiveName, entry, 0);
}
sender.sendPacket(players, packet);
}
@@ -89,7 +93,7 @@ public abstract class AbstractObjectivePacketAdapter implements ObjectivePacketA
.invoke(entry, objectiveName, value, nmsDisplay, numberFormat);
} else {
return Objects.requireNonNull(PacketAccessors.SCORE_1_20_2_CONSTRUCTOR)
.invoke(ServerScoreboard.Method.CHANGE, objectiveName, entry, value);
.invoke(PacketAccessors.SCORE_1_20_2_METHOD_CHANGE, objectiveName, entry, value);
}
}
@@ -14,15 +14,13 @@ import net.minecraft.ChatFormatting;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket;
import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket.Parameters;
import net.minecraft.world.scores.Team;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.Optional;
import java.util.*;
public abstract class AbstractTeamsPacketAdapterImpl implements TeamsPacketAdapter {
protected final PacketSender<Packet<?>> sender;
@@ -71,11 +69,19 @@ public abstract class AbstractTeamsPacketAdapterImpl implements TeamsPacketAdapt
}
protected void fillParameters(@NotNull Parameters parameters, @UnknownNullability Locale locale) {
String nameTagVisibilityKey = properties.nameTagVisibility().key();
PacketAccessors.NAME_TAG_VISIBILITY_FIELD.set(parameters, nameTagVisibilityKey);
if (PacketAccessors.IS_1_21_5_OR_ABOVE) {
Objects.requireNonNull(PacketAccessors.NAME_TAG_VISIBILITY_FIELD_1_21_5)
.set(parameters, Team.Visibility.valueOf(properties.nameTagVisibility().name()));
String collisionRuleKey = properties.collisionRule().key();
PacketAccessors.COLLISION_RULE_FIELD.set(parameters, collisionRuleKey);
Objects.requireNonNull(PacketAccessors.COLLISION_RULE_FIELD_1_21_5)
.set(parameters, Team.CollisionRule.valueOf(properties.collisionRule().name()));
} else {
Objects.requireNonNull(PacketAccessors.NAME_TAG_VISIBILITY_FIELD_1_21_4)
.set(parameters, properties.nameTagVisibility().key());
Objects.requireNonNull(PacketAccessors.COLLISION_RULE_FIELD_1_21_4)
.set(parameters, properties.collisionRule().key());
}
char legacyChar = LegacyFormatUtil.getChar(properties.playerColor());
PacketAccessors.COLOR_FIELD.set(parameters, ChatFormatting.getByCode(legacyChar));
@@ -56,7 +56,7 @@ public final class PacketUtil {
MethodType sendMethodType = MethodType.methodType(void.class, Packet.class);
MethodHandle sendPacket = null;
String[] sendPacketNames = {"a", "sendPacket", "b"};
String[] sendPacketNames = {"a", "sendPacket", "b", "send"};
for (String name : sendPacketNames) {
try {
sendPacket = lookup.findVirtual(ServerGamePacketListenerImpl.class, name, sendMethodType);
@@ -5,4 +5,5 @@ plugins {
dependencies {
api(project(":scoreboard-library-api"))
api(project(":scoreboard-library-commons"))
compileOnly(libs.spigotApi)
}
@@ -12,6 +12,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface ObjectivePacketAdapter {
@NotNull String objectiveName();
void display(@NotNull Collection<Player> players, @NotNull ObjectiveDisplaySlot slot);
void sendProperties(
@@ -8,7 +8,6 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Optional;
public class ReflectUtil {
// Inspired by
@@ -55,25 +54,33 @@ public class ReflectUtil {
private ReflectUtil() {
}
public static @NotNull Class<?> getClassOrThrow(String name) {
Class<?> c = getOptionalClass(name);
if (c == null){
throw new IllegalStateException("Class " + name + " not found");
public static @NotNull Class<?> getClassOrThrow(String... names) {
Class<?> c = getOptionalClass(names);
if (c == null) {
throw new IllegalStateException("Class with names either of " + String.join(", ", names) + " not found");
}
return c;
}
public static @Nullable Class<?> getOptionalClass(String name) {
try {
return Class.forName(name);
} catch (ClassNotFoundException e) {
return null;
public static @Nullable Class<?> getOptionalClass(String... names) {
for (String name : names) {
try {
return Class.forName(name);
} catch (ClassNotFoundException ignored) {
}
}
return null;
}
public static @NotNull Object getEnumInstance(@NotNull Class<?> clazz, @NotNull String name) {
//noinspection unchecked,rawtypes
return Enum.valueOf((Class<? extends Enum>) clazz, name);
public static @NotNull Object getEnumInstance(@NotNull Class<?> clazz, @NotNull String... names) {
for (String name : names) {
try {
//noinspection unchecked,rawtypes
return Enum.valueOf((Class<? extends Enum>) clazz, name);
} catch (IllegalArgumentException ignored){
}
}
throw new IllegalStateException("Enum " + clazz.getName() + " instance with names either of " + String.join(",", names) + " not found");
}
public static <T, V> @NotNull FieldAccessor<T, V> findField(@NotNull Class<T> clazz, int index, @NotNull Class<V> valueClass) {
+1
View File
@@ -9,4 +9,5 @@ repositories {
dependencies {
compileOnly(project(":scoreboard-library-packet-adapter-base"))
compileOnly(libs.packetEvents)
compileOnly(libs.spigotApi)
}
@@ -2,7 +2,6 @@ package net.megavex.scoreboardlibrary.implementation.packetAdapter.packetevents;
import com.github.retrooper.packetevents.PacketEventsAPI;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDisplayScoreboard;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerResetScore;
@@ -38,6 +37,11 @@ public class ObjectivePacketAdapterImpl implements ObjectivePacketAdapter {
this.objectiveName = objectiveName;
}
@Override
public @NotNull String objectiveName() {
return objectiveName;
}
@Override
public void display(@NotNull Collection<Player> players, @NotNull ObjectiveDisplaySlot slot) {
WrapperPlayServerDisplayScoreboard packet = new WrapperPlayServerDisplayScoreboard(ObjectiveConstants.displaySlotIndex(slot), objectiveName);