Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fe6200cda | ||
|
|
fb4863a9e3 | ||
|
|
a298842bce | ||
|
|
16314a7d14 | ||
|
|
c1286520d3 | ||
|
|
bc8e3c2d2e | ||
|
|
032349b190 | ||
|
|
d0d5eaa706 | ||
|
|
ac334838ee | ||
|
|
162de14e0e | ||
|
|
5f5b3efc5f | ||
|
|
41c0a4b3c9 | ||
|
|
a276708162 | ||
|
|
793e78284f | ||
|
|
38de97ba01 | ||
|
|
a535f37214 | ||
|
|
48351b6c81 | ||
|
|
7dcf1e30eb | ||
|
|
2ca874346d | ||
|
|
cb08e5d3d9 | ||
|
|
eecde934a8 | ||
|
|
2a070cdc3d | ||
|
|
589ab095b2 | ||
|
|
41fb8aa4aa | ||
|
|
da69391930 | ||
|
|
47ef9a8143 | ||
|
|
ccf9aad96d | ||
|
|
facb3a4d1c | ||
|
|
f41c1ce0b1 | ||
|
|
e72d442f9b |
No files matched your search
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
+12
@@ -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
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -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
@@ -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 {
|
||||
|
||||
@@ -4,4 +4,5 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
api(project(":scoreboard-library-api"))
|
||||
compileOnly(libs.spigotApi)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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" ]
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -5,4 +5,5 @@ plugins {
|
||||
dependencies {
|
||||
api(project(":scoreboard-library-api"))
|
||||
implementation(project(":scoreboard-library-packet-adapter-base"))
|
||||
compileOnly(libs.spigotApi)
|
||||
}
|
||||
+5
@@ -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
|
||||
|
||||
+3
-3
@@ -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);
|
||||
|
||||
+22
-4
@@ -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);
|
||||
}
|
||||
|
||||
+34
-12
@@ -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;
|
||||
}
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+2
-2
@@ -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);
|
||||
|
||||
+5
@@ -210,6 +210,11 @@ public class TeamDisplayImpl implements TeamDisplay, ImmutableTeamProperties<Com
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
scheduleUpdate();
|
||||
}
|
||||
|
||||
public @NotNull TeamDisplayPacketAdapter packetAdapter() {
|
||||
return packetAdapter;
|
||||
}
|
||||
|
||||
@@ -4,4 +4,5 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
compileOnly(project(":scoreboard-library-packet-adapter-base"))
|
||||
compileOnly(libs.spigotApi)
|
||||
}
|
||||
+5
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+31
-19
@@ -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};
|
||||
|
||||
+47
-7
@@ -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 =
|
||||
|
||||
+7
-3
@@ -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
-8
@@ -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));
|
||||
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
+2
@@ -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(
|
||||
|
||||
+20
-13
@@ -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) {
|
||||
|
||||
@@ -9,4 +9,5 @@ repositories {
|
||||
dependencies {
|
||||
compileOnly(project(":scoreboard-library-packet-adapter-base"))
|
||||
compileOnly(libs.packetEvents)
|
||||
compileOnly(libs.spigotApi)
|
||||
}
|
||||
+5
-1
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user