From 538edffa1af534c5160791a71b4370bcac0a4a47 Mon Sep 17 00:00:00 2001 From: vytskalt Date: Thu, 19 Feb 2026 23:24:40 +0200 Subject: [PATCH 1/7] begin via integration --- build.gradle.kts | 2 +- .../commons/LegacyFormatUtil.java | 17 ++- .../implementation/PacketAdapterLoader.java | 5 +- .../implementation/ScoreboardLibraryImpl.java | 2 +- test-env/init | 8 ++ test-plugin/src/main/resources/plugin.yml | 1 + .../legacy/PacketAdapterProviderImpl.java | 3 + versions/modern/build.gradle.kts | 6 + .../modern/PacketAdapterProviderImpl.java | 37 +++++- .../team/AbstractTeamsPacketAdapterImpl.java | 32 ++---- .../team/LegacyTeamDisplayPacketAdapter.java | 107 ++++++++++++++++++ .../modern/team/ModernTeamPackets.java | 38 +++++++ .../team/PaperTeamsPacketAdapterImpl.java | 6 +- .../modern/team/SpigotTeamsPacketAdapter.java | 5 +- 14 files changed, 230 insertions(+), 39 deletions(-) create mode 100644 versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java create mode 100644 versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/ModernTeamPackets.java diff --git a/build.gradle.kts b/build.gradle.kts index ad6f85a2..2800c9e5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ allprojects { - version = "2.6.0-SNAPSHOT" + version = "2.7.0-SNAPSHOT" group = "net.megavex" description = "Powerful packet-level scoreboard library for Paper/Spigot servers" } diff --git a/commons/src/main/java/net/megavex/scoreboardlibrary/implementation/commons/LegacyFormatUtil.java b/commons/src/main/java/net/megavex/scoreboardlibrary/implementation/commons/LegacyFormatUtil.java index c9be47cc..d43213b8 100644 --- a/commons/src/main/java/net/megavex/scoreboardlibrary/implementation/commons/LegacyFormatUtil.java +++ b/commons/src/main/java/net/megavex/scoreboardlibrary/implementation/commons/LegacyFormatUtil.java @@ -17,17 +17,16 @@ import static net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.parseChar; public final class LegacyFormatUtil { - private static final Map legacyMap; + private static final Map chatColorMap; static { ChatColor[] values = ChatColor.values(); - legacyMap = CollectionProvider.map(values.length); + chatColorMap = CollectionProvider.map(values.length); for (ChatColor value : values) { if (!value.isColor()) continue; - char c = value.getChar(); - LegacyFormat format = Objects.requireNonNull(parseChar(c)); - legacyMap.put((NamedTextColor) format.color(), c); + LegacyFormat format = Objects.requireNonNull(parseChar(value.getChar())); + chatColorMap.put((NamedTextColor) format.color(), value); } } @@ -63,6 +62,12 @@ public static String serialize(@Nullable Component component, @Nullable Locale l public static char getChar(@Nullable NamedTextColor color) { if (color == null) return 'r'; - return legacyMap.getOrDefault(color, '\0'); + ChatColor chatColor = chatColorMap.getOrDefault(color, ChatColor.WHITE); + return chatColor.getChar(); + } + + public static int getIndex(@Nullable NamedTextColor color) { + ChatColor chatColor = chatColorMap.getOrDefault(color == null ? NamedTextColor.WHITE : color, ChatColor.WHITE); + return chatColor.ordinal(); } } diff --git a/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/PacketAdapterLoader.java b/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/PacketAdapterLoader.java index d75a717e..ea242249 100644 --- a/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/PacketAdapterLoader.java +++ b/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/PacketAdapterLoader.java @@ -3,6 +3,7 @@ import net.megavex.scoreboardlibrary.api.exception.NoPacketAdapterAvailableException; import net.megavex.scoreboardlibrary.implementation.packetAdapter.PacketAdapterProvider; import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -16,14 +17,14 @@ public final class PacketAdapterLoader { private PacketAdapterLoader() { } - public static @NotNull PacketAdapterProvider loadPacketAdapter() throws NoPacketAdapterAvailableException { + public static @NotNull PacketAdapterProvider loadPacketAdapter(Plugin plugin) throws NoPacketAdapterAvailableException { Class nmsClass = findAndLoadImplementationClass(); if (nmsClass == null) { throw new NoPacketAdapterAvailableException(); } try { - return (PacketAdapterProvider) nmsClass.getConstructors()[0].newInstance(); + return (PacketAdapterProvider) nmsClass.getConstructors()[0].newInstance(plugin); } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new RuntimeException("couldn't initialize packet adapter", e); } diff --git a/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/ScoreboardLibraryImpl.java b/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/ScoreboardLibraryImpl.java index b9f0f1b9..d41669e9 100644 --- a/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/ScoreboardLibraryImpl.java +++ b/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/ScoreboardLibraryImpl.java @@ -59,7 +59,7 @@ public ScoreboardLibraryImpl(@NotNull Plugin plugin) throws NoPacketAdapterAvail } this.plugin = plugin; - this.packetAdapter = PacketAdapterLoader.loadPacketAdapter(); + this.packetAdapter = PacketAdapterLoader.loadPacketAdapter(plugin); this.taskScheduler = TaskScheduler.create(plugin); boolean localeEventExists = false; diff --git a/test-env/init b/test-env/init index 5dd23252..c10a4e3f 100755 --- a/test-env/init +++ b/test-env/init @@ -97,6 +97,10 @@ download_file() { download_file "buildtools.jar" "https://hub.spigotmc.org/jenkins/job/BuildTools/197/artifact/target/BuildTools.jar" "9a5b059ace22eaef28fb62f96970f0abe1490f06c860229b94627cd72eaf6ea5" +download_file "viaversion.jar" "https://hangarcdn.papermc.io/plugins/ViaVersion/ViaVersion/versions/5.7.1/PAPER/ViaVersion-5.7.1.jar" "0cd2dc443c75b3e4226f029d8b020a3776168da5563239cc96f1acd1ee7ea95a" +download_file "viabackwards.jar" "https://hangarcdn.papermc.io/plugins/ViaVersion/ViaBackwards/versions/5.7.1/PAPER/ViaBackwards-5.7.1.jar" "c2c3aab6d8ac9c132c2f3a18573602a0214af159dfc2981cb4c0d26b1f91b0c8" +download_file "viarewind.jar" "https://hangarcdn.papermc.io/plugins/ViaVersion/ViaRewind/versions/4.0.14/PAPER/ViaRewind-4.0.14.jar" "b0a9a21c022605b5adbd235c3727194dfd101ba4b90934ed51a988ab7db6c0d1" + # --- 1.13 --- download_file "1.13-paper.jar" "https://fill-data.papermc.io/v1/objects/00db82d214242c9345266d44ff8d11a8e857a1a02edf7cb5fcc2d1d973283129/paper-1.13-173.jar" "00db82d214242c9345266d44ff8d11a8e857a1a02edf7cb5fcc2d1d973283129" create_server "1.13-paper" "jdk8" @@ -187,5 +191,9 @@ create_spigot_server "1.21.10" "jdk25" download_file "1.21.11-paper.jar" "https://fill-data.papermc.io/v1/objects/4a558a00005d33dafa4c4d5f9e47b3bd47d92311fceccd9c9754ee6b913f8649/paper-1.21.11-100.jar" "4a558a00005d33dafa4c4d5f9e47b3bd47d92311fceccd9c9754ee6b913f8649" create_server "1.21.11-paper" "jdk25" +ln -sf $PWD/cache/viaversion.jar ./servers/1.21.11-paper/plugins/viaversion.jar +ln -sf $PWD/cache/viabackwards.jar ./servers/1.21.11-paper/plugins/viabackwards.jar +ln -sf $PWD/cache/viarewind.jar ./servers/1.21.11-paper/plugins/viarewind.jar + create_spigot_server "1.21.11" "jdk25" diff --git a/test-plugin/src/main/resources/plugin.yml b/test-plugin/src/main/resources/plugin.yml index 71a7848f..45a336ae 100644 --- a/test-plugin/src/main/resources/plugin.yml +++ b/test-plugin/src/main/resources/plugin.yml @@ -2,3 +2,4 @@ name: scoreboard-library-test version: 0.1.0 main: net.megavex.scoreboardlibrary.testplugin.ScoreboardPlugin api-version: 1.13 +softdepend: ["ViaVersion"] diff --git a/versions/legacy/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/legacy/PacketAdapterProviderImpl.java b/versions/legacy/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/legacy/PacketAdapterProviderImpl.java index 818ce0d6..d10e5eb2 100644 --- a/versions/legacy/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/legacy/PacketAdapterProviderImpl.java +++ b/versions/legacy/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/legacy/PacketAdapterProviderImpl.java @@ -5,10 +5,13 @@ import net.megavex.scoreboardlibrary.implementation.packetAdapter.PacketAdapterProvider; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamsPacketAdapter; import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; @SuppressWarnings("unused") public class PacketAdapterProviderImpl implements PacketAdapterProvider { + public PacketAdapterProviderImpl(Plugin plugin) {} + @Override public @NotNull TeamsPacketAdapter createTeamPacketAdapter(@NotNull String teamName) { return new TeamsPacketAdapterImpl(teamName); diff --git a/versions/modern/build.gradle.kts b/versions/modern/build.gradle.kts index 7a5426e4..63e9aa5b 100644 --- a/versions/modern/build.gradle.kts +++ b/versions/modern/build.gradle.kts @@ -3,11 +3,17 @@ plugins { //id("io.papermc.paperweight.userdev") version "2.0.0-beta.19" } +repositories { + maven("https://repo.viaversion.com") +} + dependencies { compileOnly(project(":scoreboard-library-packet-adapter-base")) { //exclude(group = "org.spigotmc", module = "spigot-api") } compileOnly(libs.spigotApi) + compileOnly("com.viaversion:viaversion-api:5.7.1") + compileOnly("io.netty:netty-buffer:4.2.10.Final") //paperweight.paperDevBundle("1.21.11-R0.1-SNAPSHOT") } diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java index 1f590df8..b76e7f83 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java @@ -1,5 +1,8 @@ package net.megavex.scoreboardlibrary.implementation.packetAdapter.modern; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.ViaAPI; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import net.megavex.scoreboardlibrary.implementation.commons.LineRenderingStrategy; import net.megavex.scoreboardlibrary.implementation.packetAdapter.PacketAdapterProvider; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.objective.PaperObjectivePacketAdapter; @@ -10,11 +13,24 @@ import net.megavex.scoreboardlibrary.implementation.packetAdapter.objective.ObjectivePacketAdapter; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamsPacketAdapter; import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; @SuppressWarnings("unused") public class PacketAdapterProviderImpl implements PacketAdapterProvider { - public PacketAdapterProviderImpl() { + private final ViaAPI via; + + public PacketAdapterProviderImpl(Plugin plugin) { + final String via = "ViaVersion"; + boolean isViaEnabled = plugin.getServer().getPluginManager().isPluginEnabled(via); + boolean isViaAllowed = plugin.getDescription().getSoftDepend().contains(via) || plugin.getDescription().getDepend().contains(via); + if (isViaEnabled && isViaAllowed) { + //noinspection unchecked + this.via = (ViaAPI) Via.getAPI(); + } else { + this.via = null; + } } @Override @@ -27,12 +43,27 @@ public PacketAdapterProviderImpl() { @Override public @NotNull TeamsPacketAdapter createTeamPacketAdapter(@NotNull String teamName) { return ModernComponentProvider.IS_NATIVE_ADVENTURE - ? new PaperTeamsPacketAdapterImpl(teamName) - : new SpigotTeamsPacketAdapter(teamName); + ? new PaperTeamsPacketAdapterImpl(this, teamName) + : new SpigotTeamsPacketAdapter(this, teamName); } @Override public @NotNull LineRenderingStrategy lineRenderingStrategy(@NotNull Player player) { + if (this.via != null) { + final ProtocolVersion ver = this.via.getPlayerProtocolVersion(player); + if (ver.olderThan(ProtocolVersion.v1_13)) { + // didn't test older versions yet + if (ver.newerThanOrEqualTo(ProtocolVersion.v1_7_6)) { + System.out.println("[DEBUG] " + player.getName() + " is legacy player"); + return LineRenderingStrategy.LEGACY; + } + } + } + System.out.println("[DEBUG] is modern player"); return LineRenderingStrategy.MODERN; } + + public @Nullable ViaAPI via() { + return via; + } } diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/AbstractTeamsPacketAdapterImpl.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/AbstractTeamsPacketAdapterImpl.java index 40376a57..98673131 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/AbstractTeamsPacketAdapterImpl.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/AbstractTeamsPacketAdapterImpl.java @@ -4,6 +4,7 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.megavex.scoreboardlibrary.implementation.packetAdapter.ImmutableTeamProperties; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAdapterProviderImpl; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernPacketSender; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.EntriesPacketType; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamConstants; @@ -16,16 +17,23 @@ import java.util.Collection; import java.util.Collections; import java.util.Locale; -import java.util.Optional; +import java.util.Objects; public abstract class AbstractTeamsPacketAdapterImpl implements TeamsPacketAdapter { + private final PacketAdapterProviderImpl provider; protected final String teamName; private Object removePacket; - public AbstractTeamsPacketAdapterImpl(@NotNull String teamName) { + public AbstractTeamsPacketAdapterImpl(@NotNull PacketAdapterProviderImpl provider, @NotNull String teamName) { + this.provider = provider; this.teamName = teamName; } + @Override + public @NotNull TeamDisplayPacketAdapter createLegacyTeamDisplayAdapter(@NotNull ImmutableTeamProperties properties) { + return new LegacyTeamDisplayPacketAdapter(Objects.requireNonNull(provider.via()), teamName, properties); + } + @Override public void removeTeam(@NotNull Iterable players) { if (removePacket == null) { @@ -57,25 +65,7 @@ public TeamDisplayPacketAdapterImpl(ImmutableTeamProperties propertie @Override public void sendEntries(@NotNull EntriesPacketType packetType, @NotNull Collection players, @NotNull Collection entries) { - if (PacketAccessors.IS_1_17_OR_ABOVE) { - Object packet = PacketAccessors.TEAM_PACKET_CONSTRUCTOR.invoke( - teamName, - TeamConstants.mode(packetType), - Optional.empty(), - entries - ); - ModernPacketSender.INSTANCE.sendPacket(players, packet); - } else { - assert PacketAccessors.TEAM_NAME_FIELD != null; - assert PacketAccessors.TEAM_MODE_FIELD != null; - assert PacketAccessors.TEAM_ENTRIES_FIELD != null; - - Object packet = PacketAccessors.TEAM_PACKET_CONSTRUCTOR.invoke(); - PacketAccessors.TEAM_NAME_FIELD.set(packet, teamName); - PacketAccessors.TEAM_MODE_FIELD.set(packet, TeamConstants.mode(packetType)); - PacketAccessors.TEAM_ENTRIES_FIELD.set(packet, entries); - ModernPacketSender.INSTANCE.sendPacket(players, packet); - } + ModernTeamPackets.sendEntries(teamName, packetType, players, entries); } protected void fillParameters(@NotNull Object parameters, @UnknownNullability Locale locale) { diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java new file mode 100644 index 00000000..1eef143f --- /dev/null +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java @@ -0,0 +1,107 @@ +package net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.team; + +import com.viaversion.viaversion.api.ViaAPI; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.api.protocol.packet.PacketType; +import com.viaversion.viaversion.api.protocol.packet.State; +import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypeMap; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +import com.viaversion.viaversion.api.type.Types; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import net.megavex.scoreboardlibrary.api.team.enums.NameTagVisibility; +import net.megavex.scoreboardlibrary.implementation.commons.LegacyFormatUtil; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.ImmutableTeamProperties; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.PropertiesPacketType; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.EntriesPacketType; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamConstants; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamDisplayPacketAdapter; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; + +public final class LegacyTeamDisplayPacketAdapter implements TeamDisplayPacketAdapter { + private final ViaAPI via; + private final String teamName; + private final ImmutableTeamProperties properties; + + public LegacyTeamDisplayPacketAdapter(final ViaAPI via, final String teamName, final ImmutableTeamProperties properties) { + this.via = via; + this.teamName = teamName; + this.properties = properties; + } + + @Override + public void sendEntries(@NotNull EntriesPacketType packetType, @NotNull Collection players, @NotNull Collection entries) { + ModernTeamPackets.sendEntries(this.teamName, packetType, players, entries); + } + + @Override + public void sendProperties(@NotNull PropertiesPacketType packetType, @NotNull Collection players) { + for (final Player player : players) { + final UserConnection conn = via.getConnection(player.getUniqueId()); + if (conn == null) { + throw new IllegalStateException("player conn doesnt exist"); + } + int teamsPacketId = -1; + for (final Protocol proto : conn.getProtocolInfo().getPipeline().pipes()) { + final PacketTypeMap map = proto.getPacketTypesProvider().mappedClientboundPacketTypes().get(State.PLAY); + if (map == null) continue; + final PacketType type = map.typeByName("SET_PLAYER_TEAM"); + if (type == null) continue; + teamsPacketId = type.getId(); + break; + } + if (teamsPacketId == -1) { + throw new IllegalStateException("team packet id for " + conn.getProtocolInfo().protocolVersion() + " not found"); + } + + ByteBuf buf = Unpooled.buffer(128); + Types.VAR_INT.writePrimitive(buf, teamsPacketId); + + Types.STRING.write(buf, teamName); + + Types.BYTE.writePrimitive(buf, (byte) TeamConstants.mode(packetType)); + + Types.STRING.write(buf, properties.displayName()); + Types.STRING.write(buf, properties.prefix()); + Types.STRING.write(buf, properties.suffix()); + + Types.BYTE.writePrimitive(buf, (byte) properties.packOptions()); + + boolean is1_7 = conn.getProtocolInfo().protocolVersion().olderThan(ProtocolVersion.v1_8); + if (is1_7) { + System.out.println("1.7 TODO"); + Types.STRING.write(buf, NameTagVisibility.ALWAYS.key()); + Types.BYTE.writePrimitive(buf, (byte) 15); + } + + Types.STRING.write(buf, properties.nameTagVisibility().key()); + if (conn.getProtocolInfo().protocolVersion().newerThan(ProtocolVersion.v1_9)) { + System.out.println("1.9 shit"); + Types.STRING.write(buf, properties.collisionRule().key()); + } + + Types.BYTE.writePrimitive(buf, (byte) LegacyFormatUtil.getIndex(properties.playerColor())); + + if (packetType == PropertiesPacketType.CREATE) { + if (is1_7) { + Types.SHORT.writePrimitive(buf, (short) properties.syncedEntries().size()); + } else { + Types.VAR_INT.writePrimitive(buf, properties.syncedEntries().size()); + } + + for (final String entry : properties.syncedEntries()) { + Types.STRING.write(buf, entry); + } + } + + conn.scheduleSendRawPacket(buf); + if (packetType == PropertiesPacketType.CREATE) { + System.out.println("sent create packet"); + } + } + } +} diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/ModernTeamPackets.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/ModernTeamPackets.java new file mode 100644 index 00000000..3b67e9f5 --- /dev/null +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/ModernTeamPackets.java @@ -0,0 +1,38 @@ +package net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.team; + +import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernPacketSender; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.EntriesPacketType; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamConstants; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Optional; + +public final class ModernTeamPackets { + private ModernTeamPackets() { + } + + public static void sendEntries(String teamName, @NotNull EntriesPacketType packetType, @NotNull Collection players, @NotNull Collection entries) { + if (PacketAccessors.IS_1_17_OR_ABOVE) { + Object packet = PacketAccessors.TEAM_PACKET_CONSTRUCTOR.invoke( + teamName, + TeamConstants.mode(packetType), + Optional.empty(), + entries + ); + ModernPacketSender.INSTANCE.sendPacket(players, packet); + } else { + assert PacketAccessors.TEAM_NAME_FIELD != null; + assert PacketAccessors.TEAM_MODE_FIELD != null; + assert PacketAccessors.TEAM_ENTRIES_FIELD != null; + + Object packet = PacketAccessors.TEAM_PACKET_CONSTRUCTOR.invoke(); + PacketAccessors.TEAM_NAME_FIELD.set(packet, teamName); + PacketAccessors.TEAM_MODE_FIELD.set(packet, TeamConstants.mode(packetType)); + PacketAccessors.TEAM_ENTRIES_FIELD.set(packet, entries); + ModernPacketSender.INSTANCE.sendPacket(players, packet); + } + } +} diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/PaperTeamsPacketAdapterImpl.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/PaperTeamsPacketAdapterImpl.java index 42c61654..51f2eeb0 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/PaperTeamsPacketAdapterImpl.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/PaperTeamsPacketAdapterImpl.java @@ -1,11 +1,11 @@ package net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.team; import com.google.common.collect.ImmutableList; -import com.google.gson.Gson; import net.kyori.adventure.text.Component; import net.megavex.scoreboardlibrary.implementation.packetAdapter.ImmutableTeamProperties; import net.megavex.scoreboardlibrary.implementation.packetAdapter.PropertiesPacketType; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAdapterProviderImpl; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernPacketSender; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamConstants; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamDisplayPacketAdapter; @@ -18,8 +18,8 @@ import java.util.Optional; public class PaperTeamsPacketAdapterImpl extends AbstractTeamsPacketAdapterImpl { - public PaperTeamsPacketAdapterImpl(@NotNull String teamName) { - super(teamName); + public PaperTeamsPacketAdapterImpl(PacketAdapterProviderImpl provider, @NotNull String teamName) { + super(provider, teamName); } @Override diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/SpigotTeamsPacketAdapter.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/SpigotTeamsPacketAdapter.java index 36d3ec94..9de407be 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/SpigotTeamsPacketAdapter.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/SpigotTeamsPacketAdapter.java @@ -5,6 +5,7 @@ import net.megavex.scoreboardlibrary.implementation.packetAdapter.ImmutableTeamProperties; import net.megavex.scoreboardlibrary.implementation.packetAdapter.PropertiesPacketType; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAdapterProviderImpl; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernComponentProvider; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernPacketSender; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamConstants; @@ -19,8 +20,8 @@ import java.util.Optional; public class SpigotTeamsPacketAdapter extends AbstractTeamsPacketAdapterImpl { - public SpigotTeamsPacketAdapter(@NotNull String teamName) { - super(teamName); + public SpigotTeamsPacketAdapter(PacketAdapterProviderImpl provider, @NotNull String teamName) { + super(provider, teamName); } @Override From d19f9978469a6f36292a38a5f18f726b36202b1b Mon Sep 17 00:00:00 2001 From: vytskalt Date: Fri, 20 Feb 2026 16:33:06 +0200 Subject: [PATCH 2/7] resolve packet ordering --- test-env/init | 6 ++- .../testplugin/module/SidebarModule.java | 14 +++++ versions/modern/build.gradle.kts | 1 + .../modern/PacketAdapterProviderImpl.java | 24 +++++++-- .../AbstractObjectivePacketAdapter.java | 12 +++-- .../PaperObjectivePacketAdapter.java | 10 ++-- .../SpigotObjectivePacketAdapter.java | 10 ++-- .../team/AbstractTeamsPacketAdapterImpl.java | 10 ++-- .../team/LegacyTeamDisplayPacketAdapter.java | 52 ++++++++++--------- .../modern/team/ModernTeamPackets.java | 8 +-- .../team/PaperTeamsPacketAdapterImpl.java | 5 +- .../modern/team/SpigotTeamsPacketAdapter.java | 3 +- .../modern/util/ModernPacketSender.java | 35 ++++++++++--- 13 files changed, 122 insertions(+), 68 deletions(-) diff --git a/test-env/init b/test-env/init index 893c7baf..577c5e7e 100755 --- a/test-env/init +++ b/test-env/init @@ -21,7 +21,7 @@ create_server() { printf "Creating server \033[32m$name\033[0m on port \033[32m$port\033[0m\n" echo "eula=true" > eula.txt - printf "server-port=$port\ndifficulty=peaceful\ngenerate-structures=false\nlevel-type=flat\nallow-nether=false" > server.properties + printf "server-port=$port\ndifficulty=peaceful\ngenerate-structures=false\nlevel-type=flat\nallow-nether=false\nonline-mode=false" > server.properties cp "$root/bukkit.yml" . mkdir -p config @@ -233,3 +233,7 @@ ln -sf $PWD/cache/viarewind.jar ./servers/1.21.11-paper/plugins/viarewind.jar create_spigot_server "1.21.11" "jdk25" +ln -sf $PWD/cache/viaversion.jar ./servers/1.21.11-spigot/plugins/viaversion.jar +ln -sf $PWD/cache/viabackwards.jar ./servers/1.21.11-spigot/plugins/viabackwards.jar +ln -sf $PWD/cache/viarewind.jar ./servers/1.21.11-spigot/plugins/viarewind.jar + diff --git a/test-plugin/src/main/java/net/megavex/scoreboardlibrary/testplugin/module/SidebarModule.java b/test-plugin/src/main/java/net/megavex/scoreboardlibrary/testplugin/module/SidebarModule.java index 6f65cc1e..b188a099 100644 --- a/test-plugin/src/main/java/net/megavex/scoreboardlibrary/testplugin/module/SidebarModule.java +++ b/test-plugin/src/main/java/net/megavex/scoreboardlibrary/testplugin/module/SidebarModule.java @@ -7,13 +7,18 @@ import net.megavex.scoreboardlibrary.api.sidebar.component.ComponentSidebarLayout; import net.megavex.scoreboardlibrary.api.sidebar.component.LineDrawable; import net.megavex.scoreboardlibrary.api.sidebar.component.SidebarComponent; +import net.megavex.scoreboardlibrary.implementation.sidebar.PlayerDependantLocaleSidebar; +import net.megavex.scoreboardlibrary.implementation.sidebar.SidebarTask; import net.megavex.scoreboardlibrary.testplugin.ScoreboardPlugin; import net.megavex.scoreboardlibrary.testplugin.TestTranslator; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerToggleSneakEvent; import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; @@ -73,6 +78,15 @@ public void onQuit(final PlayerQuitEvent event) { sidebar.removePlayer(event.getPlayer()); } + @EventHandler + public void onSneak(PlayerToggleSneakEvent event) { + if (!event.isSneaking()) return; + for (final Player player : Bukkit.getOnlinePlayers()) { + player.sendMessage("Reloading you"); + ((PlayerDependantLocaleSidebar) this.sidebar).taskQueue().add(new SidebarTask.ReloadPlayer(player)); + } + } + @Override public void draw(final @NotNull LineDrawable drawable) { drawable.drawLine(empty(), ScoreFormat.styled(style(this.hueColor()))); diff --git a/versions/modern/build.gradle.kts b/versions/modern/build.gradle.kts index 63e9aa5b..cabcdffb 100644 --- a/versions/modern/build.gradle.kts +++ b/versions/modern/build.gradle.kts @@ -14,6 +14,7 @@ dependencies { compileOnly(libs.spigotApi) compileOnly("com.viaversion:viaversion-api:5.7.1") compileOnly("io.netty:netty-buffer:4.2.10.Final") + compileOnly("io.netty:netty-handler:4.2.10.Final") //paperweight.paperDevBundle("1.21.11-R0.1-SNAPSHOT") } diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java index b76e7f83..609733ad 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java @@ -10,6 +10,7 @@ import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.team.PaperTeamsPacketAdapterImpl; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.team.SpigotTeamsPacketAdapter; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernComponentProvider; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernPacketSender; import net.megavex.scoreboardlibrary.implementation.packetAdapter.objective.ObjectivePacketAdapter; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamsPacketAdapter; import org.bukkit.entity.Player; @@ -17,27 +18,32 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.WeakHashMap; + @SuppressWarnings("unused") public class PacketAdapterProviderImpl implements PacketAdapterProvider { private final ViaAPI via; + private final ModernPacketSender packetSender; + private final WeakHashMap viaTeamPacketIds = new WeakHashMap<>(); public PacketAdapterProviderImpl(Plugin plugin) { - final String via = "ViaVersion"; - boolean isViaEnabled = plugin.getServer().getPluginManager().isPluginEnabled(via); - boolean isViaAllowed = plugin.getDescription().getSoftDepend().contains(via) || plugin.getDescription().getDepend().contains(via); + final String viaPlugin = "ViaVersion"; + boolean isViaEnabled = plugin.getServer().getPluginManager().isPluginEnabled(viaPlugin); + boolean isViaAllowed = plugin.getDescription().getSoftDepend().contains(viaPlugin) || plugin.getDescription().getDepend().contains(viaPlugin); if (isViaEnabled && isViaAllowed) { //noinspection unchecked this.via = (ViaAPI) Via.getAPI(); } else { this.via = null; } + this.packetSender = new ModernPacketSender(this.via); } @Override public @NotNull ObjectivePacketAdapter createObjectiveAdapter(@NotNull String objectiveName) { return ModernComponentProvider.IS_NATIVE_ADVENTURE - ? new PaperObjectivePacketAdapter(objectiveName) - : new SpigotObjectivePacketAdapter(objectiveName); + ? new PaperObjectivePacketAdapter(this, objectiveName) + : new SpigotObjectivePacketAdapter(this, objectiveName); } @Override @@ -66,4 +72,12 @@ public PacketAdapterProviderImpl(Plugin plugin) { public @Nullable ViaAPI via() { return via; } + + public @NotNull ModernPacketSender packetSender() { + return packetSender; + } + + public @NotNull WeakHashMap viaTeamPacketIds() { + return viaTeamPacketIds; + } } diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/AbstractObjectivePacketAdapter.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/AbstractObjectivePacketAdapter.java index 60005fc1..d7e5e377 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/AbstractObjectivePacketAdapter.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/AbstractObjectivePacketAdapter.java @@ -4,7 +4,7 @@ import net.megavex.scoreboardlibrary.api.objective.ObjectiveRenderType; import net.megavex.scoreboardlibrary.implementation.packetAdapter.PropertiesPacketType; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; -import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernPacketSender; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAdapterProviderImpl; import net.megavex.scoreboardlibrary.implementation.packetAdapter.objective.ObjectiveConstants; import net.megavex.scoreboardlibrary.implementation.packetAdapter.objective.ObjectivePacketAdapter; import org.bukkit.entity.Player; @@ -16,10 +16,12 @@ import java.util.Optional; public abstract class AbstractObjectivePacketAdapter implements ObjectivePacketAdapter { + protected final PacketAdapterProviderImpl provider; protected final String objectiveName; private Object removePacket; - public AbstractObjectivePacketAdapter(@NotNull String objectiveName) { + public AbstractObjectivePacketAdapter(@NotNull PacketAdapterProviderImpl provider, @NotNull String objectiveName) { + this.provider = provider; this.objectiveName = objectiveName; } @@ -30,7 +32,7 @@ public AbstractObjectivePacketAdapter(@NotNull String objectiveName) { @Override public void display(@NotNull Collection players, @NotNull ObjectiveDisplaySlot slot) { - ModernPacketSender.INSTANCE.sendPacket(players, createDisplayPacket(slot)); + provider.packetSender().sendPacket(players, createDisplayPacket(slot)); } @Override @@ -40,7 +42,7 @@ public void remove(@NotNull Collection players) { PacketAccessors.OBJECTIVE_NAME_FIELD.set(removePacket, objectiveName); PacketAccessors.OBJECTIVE_MODE_FIELD.set(removePacket, ObjectiveConstants.MODE_REMOVE); } - ModernPacketSender.INSTANCE.sendPacket(players, removePacket); + provider.packetSender().sendPacket(players, removePacket); } @Override @@ -53,7 +55,7 @@ public void removeScore(@NotNull Collection players, @NotNull String ent packet = Objects.requireNonNull(PacketAccessors.SCORE_CONSTRUCTOR) .invoke(PacketAccessors.SCORE_1_20_2_METHOD_REMOVE, objectiveName, entry, 0); } - ModernPacketSender.INSTANCE.sendPacket(players, packet); + provider.packetSender().sendPacket(players, packet); } protected @NotNull Object createDisplayPacket(@NotNull ObjectiveDisplaySlot displaySlot) { diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/PaperObjectivePacketAdapter.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/PaperObjectivePacketAdapter.java index 1e7fbc1a..d4493d73 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/PaperObjectivePacketAdapter.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/PaperObjectivePacketAdapter.java @@ -5,8 +5,8 @@ import net.megavex.scoreboardlibrary.api.objective.ScoreFormat; import net.megavex.scoreboardlibrary.implementation.packetAdapter.PropertiesPacketType; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAdapterProviderImpl; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernComponentProvider; -import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernPacketSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,8 +14,8 @@ import java.util.Collection; public class PaperObjectivePacketAdapter extends AbstractObjectivePacketAdapter { - public PaperObjectivePacketAdapter(@NotNull String objectiveName) { - super(objectiveName); + public PaperObjectivePacketAdapter(@NotNull PacketAdapterProviderImpl provider, @NotNull String objectiveName) { + super(provider, objectiveName); } @Override @@ -23,7 +23,7 @@ public void sendScore(@NotNull Collection players, @NotNull String entry Object nmsDisplay = display == null ? null : ModernComponentProvider.fromAdventure(display, null); Object numberFormat = ScoreFormatConverter.convert(null, scoreFormat); Object packet = createScorePacket(entry, value, nmsDisplay, numberFormat); - ModernPacketSender.INSTANCE.sendPacket(players, packet); + provider.packetSender().sendPacket(players, packet); } @Override @@ -37,6 +37,6 @@ public void sendProperties( Object nmsValue = PacketAccessors.fromAdventureComponent(value); Object numberFormat = ScoreFormatConverter.convert(null, scoreFormat); Object packet = createObjectivePacket(packetType, nmsValue, renderType, numberFormat); - ModernPacketSender.INSTANCE.sendPacket(players, packet); + provider.packetSender().sendPacket(players, packet); } } diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/SpigotObjectivePacketAdapter.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/SpigotObjectivePacketAdapter.java index b88fd1f1..e86bb66f 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/SpigotObjectivePacketAdapter.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/SpigotObjectivePacketAdapter.java @@ -4,8 +4,8 @@ import net.megavex.scoreboardlibrary.api.objective.ObjectiveRenderType; import net.megavex.scoreboardlibrary.api.objective.ScoreFormat; import net.megavex.scoreboardlibrary.implementation.packetAdapter.PropertiesPacketType; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAdapterProviderImpl; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernComponentProvider; -import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernPacketSender; import net.megavex.scoreboardlibrary.implementation.packetAdapter.util.LocalePacketUtil; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -14,13 +14,13 @@ import java.util.Collection; public class SpigotObjectivePacketAdapter extends AbstractObjectivePacketAdapter { - public SpigotObjectivePacketAdapter(@NotNull String objectiveName) { - super(objectiveName); + public SpigotObjectivePacketAdapter(@NotNull PacketAdapterProviderImpl provider, @NotNull String objectiveName) { + super(provider, objectiveName); } @Override public void sendScore(@NotNull Collection players, @NotNull String entry, int value, @Nullable Component display, @Nullable ScoreFormat scoreFormat) { - LocalePacketUtil.sendLocalePackets(ModernPacketSender.INSTANCE, players, locale -> { + LocalePacketUtil.sendLocalePackets(provider.packetSender(), players, locale -> { Object nmsDisplay = display == null ? null : ModernComponentProvider.fromAdventure(display, locale); Object numberFormat = ScoreFormatConverter.convert(locale, scoreFormat); return createScorePacket(entry, value, nmsDisplay, numberFormat); @@ -36,7 +36,7 @@ public void sendProperties( @Nullable ScoreFormat scoreFormat ) { LocalePacketUtil.sendLocalePackets( - ModernPacketSender.INSTANCE, + provider.packetSender(), players, locale -> { Object numberFormat = ScoreFormatConverter.convert(locale, scoreFormat); diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/AbstractTeamsPacketAdapterImpl.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/AbstractTeamsPacketAdapterImpl.java index 98673131..858bc536 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/AbstractTeamsPacketAdapterImpl.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/AbstractTeamsPacketAdapterImpl.java @@ -5,7 +5,6 @@ import net.megavex.scoreboardlibrary.implementation.packetAdapter.ImmutableTeamProperties; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAdapterProviderImpl; -import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernPacketSender; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.EntriesPacketType; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamConstants; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamDisplayPacketAdapter; @@ -17,10 +16,9 @@ import java.util.Collection; import java.util.Collections; import java.util.Locale; -import java.util.Objects; public abstract class AbstractTeamsPacketAdapterImpl implements TeamsPacketAdapter { - private final PacketAdapterProviderImpl provider; + protected final PacketAdapterProviderImpl provider; protected final String teamName; private Object removePacket; @@ -31,7 +29,7 @@ public AbstractTeamsPacketAdapterImpl(@NotNull PacketAdapterProviderImpl provide @Override public @NotNull TeamDisplayPacketAdapter createLegacyTeamDisplayAdapter(@NotNull ImmutableTeamProperties properties) { - return new LegacyTeamDisplayPacketAdapter(Objects.requireNonNull(provider.via()), teamName, properties); + return new LegacyTeamDisplayPacketAdapter(provider, teamName, properties); } @Override @@ -53,7 +51,7 @@ public void removeTeam(@NotNull Iterable players) { PacketAccessors.TEAM_MODE_FIELD.set(removePacket, TeamConstants.MODE_REMOVE); } } - ModernPacketSender.INSTANCE.sendPacket(players, removePacket); + provider.packetSender().sendPacket(players, removePacket); } public abstract class TeamDisplayPacketAdapterImpl implements TeamDisplayPacketAdapter { @@ -65,7 +63,7 @@ public TeamDisplayPacketAdapterImpl(ImmutableTeamProperties propertie @Override public void sendEntries(@NotNull EntriesPacketType packetType, @NotNull Collection players, @NotNull Collection entries) { - ModernTeamPackets.sendEntries(teamName, packetType, players, entries); + ModernTeamPackets.sendEntries(provider.packetSender(), teamName, packetType, players, entries); } protected void fillParameters(@NotNull Object parameters, @UnknownNullability Locale locale) { diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java index 1eef143f..b62d0835 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java @@ -14,6 +14,7 @@ import net.megavex.scoreboardlibrary.implementation.commons.LegacyFormatUtil; import net.megavex.scoreboardlibrary.implementation.packetAdapter.ImmutableTeamProperties; import net.megavex.scoreboardlibrary.implementation.packetAdapter.PropertiesPacketType; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAdapterProviderImpl; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.EntriesPacketType; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamConstants; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamDisplayPacketAdapter; @@ -23,42 +24,46 @@ import java.util.Collection; public final class LegacyTeamDisplayPacketAdapter implements TeamDisplayPacketAdapter { - private final ViaAPI via; + private final PacketAdapterProviderImpl provider; private final String teamName; private final ImmutableTeamProperties properties; - public LegacyTeamDisplayPacketAdapter(final ViaAPI via, final String teamName, final ImmutableTeamProperties properties) { - this.via = via; + public LegacyTeamDisplayPacketAdapter(final PacketAdapterProviderImpl provider, final String teamName, final ImmutableTeamProperties properties) { + this.provider = provider; this.teamName = teamName; this.properties = properties; } @Override public void sendEntries(@NotNull EntriesPacketType packetType, @NotNull Collection players, @NotNull Collection entries) { - ModernTeamPackets.sendEntries(this.teamName, packetType, players, entries); + ModernTeamPackets.sendEntries(provider.packetSender(), this.teamName, packetType, players, entries); } @Override public void sendProperties(@NotNull PropertiesPacketType packetType, @NotNull Collection players) { + ViaAPI via = provider.via(); + assert via != null; for (final Player player : players) { final UserConnection conn = via.getConnection(player.getUniqueId()); - if (conn == null) { - throw new IllegalStateException("player conn doesnt exist"); - } - int teamsPacketId = -1; - for (final Protocol proto : conn.getProtocolInfo().getPipeline().pipes()) { - final PacketTypeMap map = proto.getPacketTypesProvider().mappedClientboundPacketTypes().get(State.PLAY); - if (map == null) continue; - final PacketType type = map.typeByName("SET_PLAYER_TEAM"); - if (type == null) continue; - teamsPacketId = type.getId(); - break; - } - if (teamsPacketId == -1) { - throw new IllegalStateException("team packet id for " + conn.getProtocolInfo().protocolVersion() + " not found"); + if (conn == null) return; + + Integer teamsPacketId = this.provider.viaTeamPacketIds().get(player); + if (teamsPacketId == null) { + for (final Protocol proto : conn.getProtocolInfo().getPipeline().pipes()) { + final PacketTypeMap map = proto.getPacketTypesProvider().mappedClientboundPacketTypes().get(State.PLAY); + if (map == null) continue; + final PacketType type = map.typeByName("SET_PLAYER_TEAM"); + if (type == null) continue; + teamsPacketId = type.getId(); + break; + } + if (teamsPacketId == null) { + throw new IllegalStateException("team packet id for " + conn.getProtocolInfo().protocolVersion() + " not found"); + } + this.provider.viaTeamPacketIds().put(player, teamsPacketId); } - ByteBuf buf = Unpooled.buffer(128); + final ByteBuf buf = Unpooled.buffer(128); Types.VAR_INT.writePrimitive(buf, teamsPacketId); Types.STRING.write(buf, teamName); @@ -71,7 +76,7 @@ public void sendProperties(@NotNull PropertiesPacketType packetType, @NotNull Co Types.BYTE.writePrimitive(buf, (byte) properties.packOptions()); - boolean is1_7 = conn.getProtocolInfo().protocolVersion().olderThan(ProtocolVersion.v1_8); + final boolean is1_7 = conn.getProtocolInfo().protocolVersion().olderThanOrEqualTo(ProtocolVersion.v1_7_6); if (is1_7) { System.out.println("1.7 TODO"); Types.STRING.write(buf, NameTagVisibility.ALWAYS.key()); @@ -79,7 +84,7 @@ public void sendProperties(@NotNull PropertiesPacketType packetType, @NotNull Co } Types.STRING.write(buf, properties.nameTagVisibility().key()); - if (conn.getProtocolInfo().protocolVersion().newerThan(ProtocolVersion.v1_9)) { + if (conn.getProtocolInfo().protocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_9)) { System.out.println("1.9 shit"); Types.STRING.write(buf, properties.collisionRule().key()); } @@ -98,10 +103,7 @@ public void sendProperties(@NotNull PropertiesPacketType packetType, @NotNull Co } } - conn.scheduleSendRawPacket(buf); - if (packetType == PropertiesPacketType.CREATE) { - System.out.println("sent create packet"); - } + via.sendRawPacket(player.getUniqueId(), buf); } } } diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/ModernTeamPackets.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/ModernTeamPackets.java index 3b67e9f5..be00b9d1 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/ModernTeamPackets.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/ModernTeamPackets.java @@ -1,7 +1,7 @@ package net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.team; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.PacketSender; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; -import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernPacketSender; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.EntriesPacketType; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamConstants; import org.bukkit.entity.Player; @@ -14,7 +14,7 @@ public final class ModernTeamPackets { private ModernTeamPackets() { } - public static void sendEntries(String teamName, @NotNull EntriesPacketType packetType, @NotNull Collection players, @NotNull Collection entries) { + public static void sendEntries(PacketSender sender, String teamName, @NotNull EntriesPacketType packetType, @NotNull Collection players, @NotNull Collection entries) { if (PacketAccessors.IS_1_17_OR_ABOVE) { Object packet = PacketAccessors.TEAM_PACKET_CONSTRUCTOR.invoke( teamName, @@ -22,7 +22,7 @@ public static void sendEntries(String teamName, @NotNull EntriesPacketType packe Optional.empty(), entries ); - ModernPacketSender.INSTANCE.sendPacket(players, packet); + sender.sendPacket(players, packet); } else { assert PacketAccessors.TEAM_NAME_FIELD != null; assert PacketAccessors.TEAM_MODE_FIELD != null; @@ -32,7 +32,7 @@ public static void sendEntries(String teamName, @NotNull EntriesPacketType packe PacketAccessors.TEAM_NAME_FIELD.set(packet, teamName); PacketAccessors.TEAM_MODE_FIELD.set(packet, TeamConstants.mode(packetType)); PacketAccessors.TEAM_ENTRIES_FIELD.set(packet, entries); - ModernPacketSender.INSTANCE.sendPacket(players, packet); + sender.sendPacket(players, packet); } } } diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/PaperTeamsPacketAdapterImpl.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/PaperTeamsPacketAdapterImpl.java index 51f2eeb0..8dd0c7e1 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/PaperTeamsPacketAdapterImpl.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/PaperTeamsPacketAdapterImpl.java @@ -6,7 +6,6 @@ import net.megavex.scoreboardlibrary.implementation.packetAdapter.PropertiesPacketType; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAdapterProviderImpl; -import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernPacketSender; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamConstants; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamDisplayPacketAdapter; import org.bukkit.entity.Player; @@ -88,10 +87,10 @@ public void sendProperties(@NotNull PropertiesPacketType packetType, @NotNull Co switch (packetType) { case CREATE: - ModernPacketSender.INSTANCE.sendPacket(players, createPacket); + provider.packetSender().sendPacket(players, createPacket); break; case UPDATE: - ModernPacketSender.INSTANCE.sendPacket(players, updatePacket); + provider.packetSender().sendPacket(players, updatePacket); break; } } diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/SpigotTeamsPacketAdapter.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/SpigotTeamsPacketAdapter.java index 9de407be..369bfdff 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/SpigotTeamsPacketAdapter.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/SpigotTeamsPacketAdapter.java @@ -7,7 +7,6 @@ import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAdapterProviderImpl; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernComponentProvider; -import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernPacketSender; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamConstants; import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamDisplayPacketAdapter; import net.megavex.scoreboardlibrary.implementation.packetAdapter.util.LocalePacketUtil; @@ -38,7 +37,7 @@ public TeamDisplayPacketAdapterImpl(ImmutableTeamProperties propertie public void sendProperties(@NotNull PropertiesPacketType packetType, @NotNull Collection players) { Collection entries = ImmutableList.copyOf(properties.syncedEntries()); LocalePacketUtil.sendLocalePackets( - ModernPacketSender.INSTANCE, + provider.packetSender(), players, locale -> { diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/util/ModernPacketSender.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/util/ModernPacketSender.java index 13200631..c3f1545e 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/util/ModernPacketSender.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/util/ModernPacketSender.java @@ -1,5 +1,8 @@ package net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util; +import com.viaversion.viaversion.api.ViaAPI; +import com.viaversion.viaversion.api.connection.UserConnection; +import io.netty.channel.Channel; import net.megavex.scoreboardlibrary.implementation.packetAdapter.PacketSender; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; import net.megavex.scoreboardlibrary.implementation.packetAdapter.util.reflect.MinecraftClasses; @@ -11,13 +14,14 @@ import java.lang.reflect.Field; public final class ModernPacketSender implements PacketSender { - public static final ModernPacketSender INSTANCE = new ModernPacketSender(); - private static final MethodHandle GET_HANDLE; private static final MethodHandle PLAYER_CONNECTION; private static final MethodHandle SEND_PACKET; - private ModernPacketSender() { + private final ViaAPI via; + + public ModernPacketSender(final ViaAPI via) { + this.via = via; } static { @@ -46,7 +50,7 @@ private ModernPacketSender() { } } } - + if (playerConnection == null) { throw new ExceptionInInitializerError("failed to find player connection field"); } @@ -74,10 +78,27 @@ private ModernPacketSender() { @Override public void sendPacket(Player player, Object packet) { + if (this.via != null) { + final UserConnection conn = this.via.getConnection(player.getUniqueId()); + if (conn != null) { + final Channel channel = conn.getChannel(); + if (channel != null) { + // Paper has some "network optimization" patch that makes the NMS sendPacket method + // not always send the packet immediately to the player's netty channel, + // and this is a problem when we send some packets using ViaVersion API because it always sends + // the packet to the channel immediately, so the packet order between NMS and ViaVersion API can + // get messed up. So for ViaVersion players we send the packet directly to the player's channel + // bypassing Paper logic to work around this. Fortunately ViaVersion provides easy access to the player's channel. + channel.eventLoop().execute(() -> channel.writeAndFlush(packet)); + return; + } + } + } + try { - Object handle = GET_HANDLE.invoke(player); - Object connection = PLAYER_CONNECTION.invoke(handle); - SEND_PACKET.invoke(connection, packet); + Object handle = GET_HANDLE.invoke(player); + Object connection = PLAYER_CONNECTION.invoke(handle); + SEND_PACKET.invoke(connection, packet); } catch (Throwable e) { throw new IllegalStateException("couldn't send packet to player", e); } From 38d006cf6e92f1baa8145e3548db47aa63d11711 Mon Sep 17 00:00:00 2001 From: vytskalt Date: Fri, 20 Feb 2026 17:24:45 +0200 Subject: [PATCH 3/7] almost --- test-env/init | 18 ++++++-------- .../legacy/TeamsPacketAdapterImpl.java | 6 ++--- .../modern/PacketAdapterProviderImpl.java | 7 ++---- .../team/LegacyTeamDisplayPacketAdapter.java | 24 ++++++++++--------- .../packetAdapter/team/TeamConstants.java | 3 ++- 5 files changed, 27 insertions(+), 31 deletions(-) diff --git a/test-env/init b/test-env/init index 577c5e7e..7be4f809 100755 --- a/test-env/init +++ b/test-env/init @@ -30,6 +30,10 @@ create_server() { ln -sf "$plugin_path" plugins/test.jar ln -sf "$jar_path" server.jar + ln -sf $root/cache/viaversion.jar plugins/viaversion.jar + ln -sf $root/cache/viabackwards.jar plugins/viabackwards.jar + ln -sf $root/cache/viarewind.jar plugins/viarewind.jar + local flags="-DPaper.IgnoreJavaVersion=true -Xms512M -Xmx1024M -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 -Dusing.aikars.flags=https://mcflags.emc.gs -Daikars.new.flags=true -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20" printf "#!/bin/sh\nnix develop .#$nixshell -c sh -c 'java $flags -jar server.jar nogui'" > start @@ -97,9 +101,9 @@ download_file() { download_file "buildtools.jar" "https://hub.spigotmc.org/jenkins/job/BuildTools/197/artifact/target/BuildTools.jar" "9a5b059ace22eaef28fb62f96970f0abe1490f06c860229b94627cd72eaf6ea5" -download_file "viaversion.jar" "https://hangarcdn.papermc.io/plugins/ViaVersion/ViaVersion/versions/5.7.1/PAPER/ViaVersion-5.7.1.jar" "0cd2dc443c75b3e4226f029d8b020a3776168da5563239cc96f1acd1ee7ea95a" -download_file "viabackwards.jar" "https://hangarcdn.papermc.io/plugins/ViaVersion/ViaBackwards/versions/5.7.1/PAPER/ViaBackwards-5.7.1.jar" "c2c3aab6d8ac9c132c2f3a18573602a0214af159dfc2981cb4c0d26b1f91b0c8" -download_file "viarewind.jar" "https://hangarcdn.papermc.io/plugins/ViaVersion/ViaRewind/versions/4.0.14/PAPER/ViaRewind-4.0.14.jar" "b0a9a21c022605b5adbd235c3727194dfd101ba4b90934ed51a988ab7db6c0d1" +download_file "viaversion.jar" "https://ci.viaversion.com/job/ViaVersion/1328/artifact/build/libs/ViaVersion-5.7.2-SNAPSHOT.jar" "ddb25eb56ddf1f89388ba654f6da09ba4162f55c291f9b5c2249ef1e8330b260" +download_file "viabackwards.jar" "https://ci.viaversion.com/view/ViaBackwards/job/ViaBackwards/707/artifact/build/libs/ViaBackwards-5.7.2-SNAPSHOT.jar" "f59125c704bc3b2b7d0acd2946b2c35024cce2517a3bbb0b38b439c75d65edb0" +download_file "viarewind.jar" "https://ci.viaversion.com/view/ViaRewind/job/ViaRewind/209/artifact/build/libs/ViaRewind-4.0.15-SNAPSHOT.jar" "dd8b0db2e5469a7d8d9754b9a42bb8b81681bbe8805ddd733f2c4931dd86cbab" # --- 1.7.10 --- download_file "1.7.10-paper.jar" "https://fill-data.papermc.io/v1/objects/33772078d92e9dbb027602da016524ef29af5b4c12eaddac1fe2465b01108185/paper-1.7.10-2025.jar" "33772078d92e9dbb027602da016524ef29af5b4c12eaddac1fe2465b01108185" @@ -227,13 +231,5 @@ create_spigot_server "1.21.10" "jdk25" download_file "1.21.11-paper.jar" "https://fill-data.papermc.io/v1/objects/4a558a00005d33dafa4c4d5f9e47b3bd47d92311fceccd9c9754ee6b913f8649/paper-1.21.11-100.jar" "4a558a00005d33dafa4c4d5f9e47b3bd47d92311fceccd9c9754ee6b913f8649" create_server "1.21.11-paper" "jdk25" -ln -sf $PWD/cache/viaversion.jar ./servers/1.21.11-paper/plugins/viaversion.jar -ln -sf $PWD/cache/viabackwards.jar ./servers/1.21.11-paper/plugins/viabackwards.jar -ln -sf $PWD/cache/viarewind.jar ./servers/1.21.11-paper/plugins/viarewind.jar - create_spigot_server "1.21.11" "jdk25" -ln -sf $PWD/cache/viaversion.jar ./servers/1.21.11-spigot/plugins/viaversion.jar -ln -sf $PWD/cache/viabackwards.jar ./servers/1.21.11-spigot/plugins/viabackwards.jar -ln -sf $PWD/cache/viarewind.jar ./servers/1.21.11-spigot/plugins/viarewind.jar - diff --git a/versions/legacy/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/legacy/TeamsPacketAdapterImpl.java b/versions/legacy/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/legacy/TeamsPacketAdapterImpl.java index b60d2fd6..ebf8ee8b 100644 --- a/versions/legacy/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/legacy/TeamsPacketAdapterImpl.java +++ b/versions/legacy/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/legacy/TeamsPacketAdapterImpl.java @@ -70,9 +70,9 @@ public void sendProperties(@NotNull PropertiesPacketType packetType, @NotNull Co LegacyPacketSender.INSTANCE, players, locale -> { - String displayName = limitLegacyText(toLegacy(properties.displayName(), locale), TeamConstants.LEGACY_CHAR_LIMIT); - String prefix = limitLegacyText(toLegacy(properties.prefix(), locale), TeamConstants.LEGACY_CHAR_LIMIT); - String suffix = limitLegacyText(toLegacy(properties.suffix(), locale), TeamConstants.LEGACY_CHAR_LIMIT); + String displayName = limitLegacyText(toLegacy(properties.displayName(), locale), TeamConstants.DISPLAY_NAME_LEGACY_LIMIT); + String prefix = limitLegacyText(toLegacy(properties.prefix(), locale), TeamConstants.PREFIX_SUFFIX_LEGACY_LIMIT); + String suffix = limitLegacyText(toLegacy(properties.suffix(), locale), TeamConstants.PREFIX_SUFFIX_LEGACY_LIMIT); Object packet = PacketAccessors.TEAM_CONSTRUCTOR.invoke(); PacketAccessors.TEAM_NAME_FIELD.set(packet, teamName); diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java index 609733ad..825b6182 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java @@ -58,11 +58,8 @@ public PacketAdapterProviderImpl(Plugin plugin) { if (this.via != null) { final ProtocolVersion ver = this.via.getPlayerProtocolVersion(player); if (ver.olderThan(ProtocolVersion.v1_13)) { - // didn't test older versions yet - if (ver.newerThanOrEqualTo(ProtocolVersion.v1_7_6)) { - System.out.println("[DEBUG] " + player.getName() + " is legacy player"); - return LineRenderingStrategy.LEGACY; - } + System.out.println("[DEBUG] " + player.getName() + " is legacy player"); + return LineRenderingStrategy.LEGACY; } } System.out.println("[DEBUG] is modern player"); diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java index b62d0835..ff3ae050 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java @@ -10,7 +10,6 @@ import com.viaversion.viaversion.api.type.Types; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import net.megavex.scoreboardlibrary.api.team.enums.NameTagVisibility; import net.megavex.scoreboardlibrary.implementation.commons.LegacyFormatUtil; import net.megavex.scoreboardlibrary.implementation.packetAdapter.ImmutableTeamProperties; import net.megavex.scoreboardlibrary.implementation.packetAdapter.PropertiesPacketType; @@ -23,6 +22,8 @@ import java.util.Collection; +import static net.megavex.scoreboardlibrary.implementation.commons.LegacyFormatUtil.limitLegacyText; + public final class LegacyTeamDisplayPacketAdapter implements TeamDisplayPacketAdapter { private final PacketAdapterProviderImpl provider; private final String teamName; @@ -70,26 +71,27 @@ public void sendProperties(@NotNull PropertiesPacketType packetType, @NotNull Co Types.BYTE.writePrimitive(buf, (byte) TeamConstants.mode(packetType)); - Types.STRING.write(buf, properties.displayName()); - Types.STRING.write(buf, properties.prefix()); - Types.STRING.write(buf, properties.suffix()); + final String displayName = limitLegacyText(properties.displayName(), TeamConstants.DISPLAY_NAME_LEGACY_LIMIT); + final String prefix = limitLegacyText(properties.prefix(), TeamConstants.PREFIX_SUFFIX_LEGACY_LIMIT); + final String suffix = limitLegacyText(properties.suffix(), TeamConstants.PREFIX_SUFFIX_LEGACY_LIMIT); + Types.STRING.write(buf, displayName); + Types.STRING.write(buf, prefix); + Types.STRING.write(buf, suffix); Types.BYTE.writePrimitive(buf, (byte) properties.packOptions()); final boolean is1_7 = conn.getProtocolInfo().protocolVersion().olderThanOrEqualTo(ProtocolVersion.v1_7_6); - if (is1_7) { - System.out.println("1.7 TODO"); - Types.STRING.write(buf, NameTagVisibility.ALWAYS.key()); - Types.BYTE.writePrimitive(buf, (byte) 15); + if (!is1_7) { + Types.STRING.write(buf, properties.nameTagVisibility().key()); } - Types.STRING.write(buf, properties.nameTagVisibility().key()); if (conn.getProtocolInfo().protocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_9)) { - System.out.println("1.9 shit"); Types.STRING.write(buf, properties.collisionRule().key()); } - Types.BYTE.writePrimitive(buf, (byte) LegacyFormatUtil.getIndex(properties.playerColor())); + if (!is1_7) { + Types.BYTE.writePrimitive(buf, (byte) LegacyFormatUtil.getIndex(properties.playerColor())); + } if (packetType == PropertiesPacketType.CREATE) { if (is1_7) { diff --git a/versions/packet-adapter-base/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/team/TeamConstants.java b/versions/packet-adapter-base/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/team/TeamConstants.java index 28c803fb..d4303aea 100644 --- a/versions/packet-adapter-base/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/team/TeamConstants.java +++ b/versions/packet-adapter-base/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/team/TeamConstants.java @@ -4,7 +4,8 @@ import org.jetbrains.annotations.NotNull; public final class TeamConstants { - public static final int LEGACY_CHAR_LIMIT = 16; + public static final int DISPLAY_NAME_LEGACY_LIMIT = 32; + public static final int PREFIX_SUFFIX_LEGACY_LIMIT = 16; public static final int MODE_CREATE = 0, MODE_REMOVE = 1, From ef3998bd3b9c96dafc6a21ea04ef428e756ea855 Mon Sep 17 00:00:00 2001 From: vytskalt Date: Fri, 20 Feb 2026 17:58:48 +0200 Subject: [PATCH 4/7] fix 1.7 --- .../sidebar/line/locale/LegacyLocaleLine.java | 2 +- .../sidebar/line/locale/ModernLocaleLine.java | 2 +- .../team/ScoreboardTeamImpl.java | 2 +- .../implementation/team/TeamManagerImpl.java | 15 +--- .../legacy/TeamsPacketAdapterImpl.java | 22 ++--- .../modern/PacketAdapterProviderImpl.java | 4 +- .../team/AbstractTeamsPacketAdapterImpl.java | 65 +++++++++----- .../team/LegacyTeamDisplayPacketAdapter.java | 89 +++++++++++++++---- .../modern/team/ModernTeamPackets.java | 38 -------- .../team/TeamDisplayPacketAdapter.java | 2 + .../team/TeamsPacketAdapter.java | 2 - 11 files changed, 133 insertions(+), 110 deletions(-) delete mode 100644 versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/ModernTeamPackets.java diff --git a/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/sidebar/line/locale/LegacyLocaleLine.java b/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/sidebar/line/locale/LegacyLocaleLine.java index 49c3ede4..065f43f9 100644 --- a/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/sidebar/line/locale/LegacyLocaleLine.java +++ b/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/sidebar/line/locale/LegacyLocaleLine.java @@ -157,7 +157,7 @@ public void hide(@NotNull Collection players) { } pd.removeScore(players, player); - info.packetAdapter().removeTeam(players); + packetAdapter.removeTeam(players); } } diff --git a/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/sidebar/line/locale/ModernLocaleLine.java b/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/sidebar/line/locale/ModernLocaleLine.java index 8797e13d..49ceff83 100644 --- a/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/sidebar/line/locale/ModernLocaleLine.java +++ b/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/sidebar/line/locale/ModernLocaleLine.java @@ -61,7 +61,7 @@ public void show(@NotNull Collection players) { @Override public void hide(@NotNull Collection players) { handler.localeLineHandler().sidebar().packetAdapter().removeScore(players, info.player()); - info.packetAdapter().removeTeam(players); + packetAdapter.removeTeam(players); } @Override diff --git a/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/team/ScoreboardTeamImpl.java b/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/team/ScoreboardTeamImpl.java index ac4bc73e..cd359e58 100644 --- a/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/team/ScoreboardTeamImpl.java +++ b/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/team/ScoreboardTeamImpl.java @@ -97,7 +97,7 @@ public void addPlayer(@NotNull Player player) { public void removePlayer(@NotNull Player player) { TeamDisplayImpl teamDisplay = Objects.requireNonNull(displayMap.remove(player)); if (teamDisplay.players().remove(player)) { - packetAdapter.removeTeam(Collections.singleton(player)); + teamDisplay.packetAdapter().removeTeam(Collections.singleton(player)); } } diff --git a/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/team/TeamManagerImpl.java b/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/team/TeamManagerImpl.java index 91b09242..2d664ed6 100644 --- a/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/team/TeamManagerImpl.java +++ b/implementation/src/main/java/net/megavex/scoreboardlibrary/implementation/team/TeamManagerImpl.java @@ -173,11 +173,9 @@ public boolean tick() { if (task instanceof TeamManagerTask.Close) { for (ScoreboardTeamImpl team : teams.values()) { - Set removePlayers = CollectionProvider.set(internalPlayers.size()); for (TeamDisplayImpl value : team.displayMap().values()) { - removePlayers.addAll(value.players()); + value.packetAdapter().removeTeam(value.players()); } - team.packetAdapter().removeTeam(removePlayers); } for (Player player : internalPlayers) { @@ -216,16 +214,9 @@ public boolean tick() { } } else if (task instanceof TeamManagerTask.RemoveTeam) { TeamManagerTask.RemoveTeam removeTeamTask = (TeamManagerTask.RemoveTeam) task; - List playersInTeam = CollectionProvider.list(removeTeamTask.team().displayMap().size()); - for (Map.Entry entry : removeTeamTask.team().displayMap().entrySet()) { - Player player = entry.getKey(); - TeamDisplayImpl teamDisplay = entry.getValue(); - if (teamDisplay.players().contains(player)) { - playersInTeam.add(player); - } + for (TeamDisplayImpl value : removeTeamTask.team().displayMap().values()) { + value.packetAdapter().removeTeam(value.players()); } - - removeTeamTask.team().packetAdapter().removeTeam(playersInTeam); } else if (task instanceof TeamManagerTask.UpdateTeamDisplay) { TeamManagerTask.UpdateTeamDisplay updateTeamDisplayTask = (TeamManagerTask.UpdateTeamDisplay) task; @NotNull TeamDisplayImpl teamDisplay = updateTeamDisplayTask.teamDisplay(); diff --git a/versions/legacy/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/legacy/TeamsPacketAdapterImpl.java b/versions/legacy/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/legacy/TeamsPacketAdapterImpl.java index ebf8ee8b..893801f3 100644 --- a/versions/legacy/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/legacy/TeamsPacketAdapterImpl.java +++ b/versions/legacy/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/legacy/TeamsPacketAdapterImpl.java @@ -27,17 +27,6 @@ public TeamsPacketAdapterImpl(@NotNull String teamName) { this.teamName = teamName; } - @Override - public void removeTeam(@NotNull Iterable players) { - if (removePacket == null) { - removePacket = PacketAccessors.TEAM_CONSTRUCTOR.invoke(); - PacketAccessors.TEAM_NAME_FIELD.set(removePacket, teamName); - PacketAccessors.TEAM_MODE_FIELD.set(removePacket, TeamConstants.MODE_REMOVE); - } - - LegacyPacketSender.INSTANCE.sendPacket(players, removePacket); - } - @Override public @NotNull TeamDisplayPacketAdapter createTeamDisplayAdapter(@NotNull ImmutableTeamProperties properties) { return new AdventureTeamDisplayPacketAdapter(properties); @@ -55,6 +44,17 @@ public AbstractTeamDisplayPacketAdapter(@NotNull ImmutableTeamProperties prop this.properties = properties; } + @Override + public void removeTeam(@NotNull Iterable players) { + if (removePacket == null) { + removePacket = PacketAccessors.TEAM_CONSTRUCTOR.invoke(); + PacketAccessors.TEAM_NAME_FIELD.set(removePacket, teamName); + PacketAccessors.TEAM_MODE_FIELD.set(removePacket, TeamConstants.MODE_REMOVE); + } + + LegacyPacketSender.INSTANCE.sendPacket(players, removePacket); + } + @Override public void sendEntries(@NotNull EntriesPacketType packetType, @NotNull Collection players, @NotNull Collection entries) { Object packet = PacketAccessors.TEAM_CONSTRUCTOR.invoke(); diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java index 825b6182..45546ed4 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAdapterProviderImpl.java @@ -58,11 +58,11 @@ public PacketAdapterProviderImpl(Plugin plugin) { if (this.via != null) { final ProtocolVersion ver = this.via.getPlayerProtocolVersion(player); if (ver.olderThan(ProtocolVersion.v1_13)) { - System.out.println("[DEBUG] " + player.getName() + " is legacy player"); + //System.out.println("[DEBUG] " + player.getName() + " is legacy player"); return LineRenderingStrategy.LEGACY; } } - System.out.println("[DEBUG] is modern player"); + //System.out.println("[DEBUG] is modern player"); return LineRenderingStrategy.MODERN; } diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/AbstractTeamsPacketAdapterImpl.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/AbstractTeamsPacketAdapterImpl.java index 858bc536..41e5a943 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/AbstractTeamsPacketAdapterImpl.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/AbstractTeamsPacketAdapterImpl.java @@ -16,6 +16,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Locale; +import java.util.Optional; public abstract class AbstractTeamsPacketAdapterImpl implements TeamsPacketAdapter { protected final PacketAdapterProviderImpl provider; @@ -32,28 +33,6 @@ public AbstractTeamsPacketAdapterImpl(@NotNull PacketAdapterProviderImpl provide return new LegacyTeamDisplayPacketAdapter(provider, teamName, properties); } - @Override - public void removeTeam(@NotNull Iterable players) { - if (removePacket == null) { - if (PacketAccessors.IS_1_17_OR_ABOVE) { - removePacket = PacketAccessors.TEAM_PACKET_CONSTRUCTOR.invoke( - teamName, - TeamConstants.MODE_REMOVE, - null, - Collections.emptyList() - ); - } else { - assert PacketAccessors.TEAM_NAME_FIELD != null; - assert PacketAccessors.TEAM_MODE_FIELD != null; - - removePacket = PacketAccessors.TEAM_PACKET_CONSTRUCTOR.invoke(); - PacketAccessors.TEAM_NAME_FIELD.set(removePacket, teamName); - PacketAccessors.TEAM_MODE_FIELD.set(removePacket, TeamConstants.MODE_REMOVE); - } - } - provider.packetSender().sendPacket(players, removePacket); - } - public abstract class TeamDisplayPacketAdapterImpl implements TeamDisplayPacketAdapter { protected final ImmutableTeamProperties properties; @@ -61,9 +40,49 @@ public TeamDisplayPacketAdapterImpl(ImmutableTeamProperties propertie this.properties = properties; } + @Override + public void removeTeam(@NotNull Iterable players) { + if (removePacket == null) { + if (PacketAccessors.IS_1_17_OR_ABOVE) { + removePacket = PacketAccessors.TEAM_PACKET_CONSTRUCTOR.invoke( + teamName, + TeamConstants.MODE_REMOVE, + null, + Collections.emptyList() + ); + } else { + assert PacketAccessors.TEAM_NAME_FIELD != null; + assert PacketAccessors.TEAM_MODE_FIELD != null; + + removePacket = PacketAccessors.TEAM_PACKET_CONSTRUCTOR.invoke(); + PacketAccessors.TEAM_NAME_FIELD.set(removePacket, teamName); + PacketAccessors.TEAM_MODE_FIELD.set(removePacket, TeamConstants.MODE_REMOVE); + } + } + provider.packetSender().sendPacket(players, removePacket); + } + @Override public void sendEntries(@NotNull EntriesPacketType packetType, @NotNull Collection players, @NotNull Collection entries) { - ModernTeamPackets.sendEntries(provider.packetSender(), teamName, packetType, players, entries); + if (PacketAccessors.IS_1_17_OR_ABOVE) { + Object packet = PacketAccessors.TEAM_PACKET_CONSTRUCTOR.invoke( + teamName, + TeamConstants.mode(packetType), + Optional.empty(), + entries + ); + provider.packetSender().sendPacket(players, packet); + } else { + assert PacketAccessors.TEAM_NAME_FIELD != null; + assert PacketAccessors.TEAM_MODE_FIELD != null; + assert PacketAccessors.TEAM_ENTRIES_FIELD != null; + + Object packet = PacketAccessors.TEAM_PACKET_CONSTRUCTOR.invoke(); + PacketAccessors.TEAM_NAME_FIELD.set(packet, teamName); + PacketAccessors.TEAM_MODE_FIELD.set(packet, TeamConstants.mode(packetType)); + PacketAccessors.TEAM_ENTRIES_FIELD.set(packet, entries); + provider.packetSender().sendPacket(players, packet); + } } protected void fillParameters(@NotNull Object parameters, @UnknownNullability Locale locale) { diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java index ff3ae050..ad6b5ce1 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/LegacyTeamDisplayPacketAdapter.java @@ -35,9 +35,54 @@ public LegacyTeamDisplayPacketAdapter(final PacketAdapterProviderImpl provider, this.properties = properties; } + // have to send every team packet from viaversion otherwise it won't work on 1.7 players + // because ViaRewind's 1.8->1.7 conversion cancels team packets it doesn't recognize and fucks everything up + // https://github.com/ViaVersion/ViaRewind/blob/e0c1f5311521bf062bbdae9f96dc9149d8c13e28/common/src/main/java/com/viaversion/viarewind/protocol/v1_8to1_7_6_10/rewriter/ScoreboardPacketRewriter1_8.java#L179 + + @Override + public void removeTeam(@NotNull Iterable players) { + ViaAPI via = provider.via(); + assert via != null; + for (final Player player : players) { + final UserConnection conn = via.getConnection(player.getUniqueId()); + if (conn == null) continue; + + final ByteBuf buf = Unpooled.buffer(128); + Types.VAR_INT.writePrimitive(buf, teamsPacketId(player, conn)); + Types.STRING.write(buf, teamName); + Types.BYTE.writePrimitive(buf, (byte) TeamConstants.MODE_REMOVE); + + via.sendRawPacket(player.getUniqueId(), buf); + } + } + @Override public void sendEntries(@NotNull EntriesPacketType packetType, @NotNull Collection players, @NotNull Collection entries) { - ModernTeamPackets.sendEntries(provider.packetSender(), this.teamName, packetType, players, entries); + ViaAPI via = provider.via(); + assert via != null; + for (final Player player : players) { + final UserConnection conn = via.getConnection(player.getUniqueId()); + if (conn == null) continue; + + final ByteBuf buf = Unpooled.buffer(128); + Types.VAR_INT.writePrimitive(buf, teamsPacketId(player, conn)); + + Types.STRING.write(buf, teamName); + + Types.BYTE.writePrimitive(buf, (byte) TeamConstants.mode(packetType)); + + if (conn.getProtocolInfo().protocolVersion().olderThanOrEqualTo(ProtocolVersion.v1_7_6)) { + Types.SHORT.writePrimitive(buf, (short) properties.syncedEntries().size()); + } else { + Types.VAR_INT.writePrimitive(buf, properties.syncedEntries().size()); + } + + for (final String entry : entries) { + Types.STRING.write(buf, entry); + } + + via.sendRawPacket(player.getUniqueId(), buf); + } } @Override @@ -46,26 +91,10 @@ public void sendProperties(@NotNull PropertiesPacketType packetType, @NotNull Co assert via != null; for (final Player player : players) { final UserConnection conn = via.getConnection(player.getUniqueId()); - if (conn == null) return; - - Integer teamsPacketId = this.provider.viaTeamPacketIds().get(player); - if (teamsPacketId == null) { - for (final Protocol proto : conn.getProtocolInfo().getPipeline().pipes()) { - final PacketTypeMap map = proto.getPacketTypesProvider().mappedClientboundPacketTypes().get(State.PLAY); - if (map == null) continue; - final PacketType type = map.typeByName("SET_PLAYER_TEAM"); - if (type == null) continue; - teamsPacketId = type.getId(); - break; - } - if (teamsPacketId == null) { - throw new IllegalStateException("team packet id for " + conn.getProtocolInfo().protocolVersion() + " not found"); - } - this.provider.viaTeamPacketIds().put(player, teamsPacketId); - } + if (conn == null) continue; final ByteBuf buf = Unpooled.buffer(128); - Types.VAR_INT.writePrimitive(buf, teamsPacketId); + Types.VAR_INT.writePrimitive(buf, teamsPacketId(player, conn)); Types.STRING.write(buf, teamName); @@ -108,4 +137,26 @@ public void sendProperties(@NotNull PropertiesPacketType packetType, @NotNull Co via.sendRawPacket(player.getUniqueId(), buf); } } + + private @NotNull Integer teamsPacketId(final Player player, final UserConnection conn) { + ViaAPI via = provider.via(); + assert via != null; + + Integer teamsPacketId = this.provider.viaTeamPacketIds().get(player); + if (teamsPacketId != null) return teamsPacketId; + + for (final Protocol proto : conn.getProtocolInfo().getPipeline().pipes()) { + final PacketTypeMap map = proto.getPacketTypesProvider().mappedClientboundPacketTypes().get(State.PLAY); + if (map == null) continue; + final PacketType type = map.typeByName("SET_PLAYER_TEAM"); + if (type == null) continue; + teamsPacketId = type.getId(); + break; + } + if (teamsPacketId == null) { + throw new IllegalStateException("team packet id for " + conn.getProtocolInfo().protocolVersion() + " not found"); + } + this.provider.viaTeamPacketIds().put(player, teamsPacketId); + return teamsPacketId; + } } diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/ModernTeamPackets.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/ModernTeamPackets.java deleted file mode 100644 index be00b9d1..00000000 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/team/ModernTeamPackets.java +++ /dev/null @@ -1,38 +0,0 @@ -package net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.team; - -import net.megavex.scoreboardlibrary.implementation.packetAdapter.PacketSender; -import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; -import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.EntriesPacketType; -import net.megavex.scoreboardlibrary.implementation.packetAdapter.team.TeamConstants; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; -import java.util.Optional; - -public final class ModernTeamPackets { - private ModernTeamPackets() { - } - - public static void sendEntries(PacketSender sender, String teamName, @NotNull EntriesPacketType packetType, @NotNull Collection players, @NotNull Collection entries) { - if (PacketAccessors.IS_1_17_OR_ABOVE) { - Object packet = PacketAccessors.TEAM_PACKET_CONSTRUCTOR.invoke( - teamName, - TeamConstants.mode(packetType), - Optional.empty(), - entries - ); - sender.sendPacket(players, packet); - } else { - assert PacketAccessors.TEAM_NAME_FIELD != null; - assert PacketAccessors.TEAM_MODE_FIELD != null; - assert PacketAccessors.TEAM_ENTRIES_FIELD != null; - - Object packet = PacketAccessors.TEAM_PACKET_CONSTRUCTOR.invoke(); - PacketAccessors.TEAM_NAME_FIELD.set(packet, teamName); - PacketAccessors.TEAM_MODE_FIELD.set(packet, TeamConstants.mode(packetType)); - PacketAccessors.TEAM_ENTRIES_FIELD.set(packet, entries); - sender.sendPacket(players, packet); - } - } -} diff --git a/versions/packet-adapter-base/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/team/TeamDisplayPacketAdapter.java b/versions/packet-adapter-base/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/team/TeamDisplayPacketAdapter.java index 800b08df..73b3bdfc 100644 --- a/versions/packet-adapter-base/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/team/TeamDisplayPacketAdapter.java +++ b/versions/packet-adapter-base/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/team/TeamDisplayPacketAdapter.java @@ -7,6 +7,8 @@ import java.util.Collection; public interface TeamDisplayPacketAdapter { + void removeTeam(@NotNull Iterable players); + default void updateTeamPackets() { } diff --git a/versions/packet-adapter-base/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/team/TeamsPacketAdapter.java b/versions/packet-adapter-base/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/team/TeamsPacketAdapter.java index a7d46c9c..49e0e36a 100644 --- a/versions/packet-adapter-base/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/team/TeamsPacketAdapter.java +++ b/versions/packet-adapter-base/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/team/TeamsPacketAdapter.java @@ -6,8 +6,6 @@ import org.jetbrains.annotations.NotNull; public interface TeamsPacketAdapter { - void removeTeam(@NotNull Iterable players); - @NotNull TeamDisplayPacketAdapter createTeamDisplayAdapter(@NotNull ImmutableTeamProperties properties); default @NotNull TeamDisplayPacketAdapter createLegacyTeamDisplayAdapter(@NotNull ImmutableTeamProperties properties) { From bf01337fcfaa585105bb71446ea6e65cb2e84545 Mon Sep 17 00:00:00 2001 From: vytskalt Date: Sun, 22 Feb 2026 21:49:33 +0200 Subject: [PATCH 5/7] workaround relocated gson --- test-plugin/build.gradle.kts | 9 +++++- .../packetAdapter/modern/PacketAccessors.java | 31 +++++++++++++++++++ .../objective/ScoreFormatConverter.java | 9 ++++-- .../modern/util/ModernComponentProvider.java | 11 +++++-- 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/test-plugin/build.gradle.kts b/test-plugin/build.gradle.kts index acc9ffcc..3786ab55 100644 --- a/test-plugin/build.gradle.kts +++ b/test-plugin/build.gradle.kts @@ -15,6 +15,13 @@ dependencies { // bundled adventure: implementation(libs.adventureApi) - implementation(libs.adventureTextSerializerGson) + implementation(libs.adventureTextSerializerGson) { + //exclude("com.google.code.gson") + } implementation(libs.adventureTextSerializerLegacy) } + +tasks.shadowJar { + relocate("com.google.gson", "net.megavex.scoreboardlibrary.testplugin.lib.gson") + relocate("net.kyori", "net.megavex.scoreboardlibrary.testplugin.lib.kyori") +} diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAccessors.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAccessors.java index c914a987..5ab47630 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAccessors.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAccessors.java @@ -1,5 +1,6 @@ package net.megavex.scoreboardlibrary.implementation.packetAdapter.modern; +import com.google.gson.JsonElement; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.megavex.scoreboardlibrary.api.team.enums.CollisionRule; @@ -11,6 +12,7 @@ import org.jetbrains.annotations.Nullable; import java.lang.invoke.MethodType; +import java.lang.reflect.InvocationTargetException; import java.util.*; public final class PacketAccessors { @@ -76,6 +78,35 @@ private PacketAccessors() { IS_1_21_6_OR_ABOVE = is1_21_6OrAbove; } + public static final String GSON_PKG = "com.go".concat("ogle.gson"); + public static final boolean IS_GSON_RELOCATED; + public static final Object JSON_PARSER; + public static final MethodAccessor PARSE_STRING_METHOD; + + static { + IS_GSON_RELOCATED = !JsonElement.class.getName().equals(GSON_PKG + ".JsonElement"); + + try { + Class jsonElementClass = Class.forName(GSON_PKG + ".JsonElement"); + Class jsonParserClass = Class.forName(GSON_PKG + ".JsonParser"); + JSON_PARSER = jsonParserClass.getConstructors()[0].newInstance(); + MethodAccessor parseStringMethod = ReflectUtil.findOptionalMethod(jsonParserClass, false, MethodType.methodType(jsonElementClass, String.class), "parse"); + if (parseStringMethod == null) { + parseStringMethod = ReflectUtil.findMethod(jsonParserClass, true, MethodType.methodType(jsonElementClass, String.class), "parse"); + //new JsonParser().parse("{}"); + //System.out.println("found via method 1"); + } else { + //System.out.println("found via method 2"); + } + PARSE_STRING_METHOD = parseStringMethod; + //System.out.println(JSON_PARSER); + } catch (ClassNotFoundException | InvocationTargetException | InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + //(new JsonParser()).parse(""); + //System.out.println("GSON RELOCATED = " + IS_GSON_RELOCATED); + } + public static final Class PKT_CLASS, SET_OBJECTIVE_PKT_CLASS, SET_DISPLAY_OBJECTIVE_PKT_CLASS, diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/ScoreFormatConverter.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/ScoreFormatConverter.java index a19327d3..9ad307c6 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/ScoreFormatConverter.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/ScoreFormatConverter.java @@ -1,6 +1,5 @@ package net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.objective; -import com.google.gson.JsonElement; import net.megavex.scoreboardlibrary.api.objective.ScoreFormat; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernComponentProvider; @@ -50,7 +49,13 @@ private ScoreFormatConverter() { if (format == ScoreFormat.blank()) { return BLANK; } else if (format instanceof ScoreFormat.Styled) { - JsonElement json = gson().serializer().toJsonTree(((ScoreFormat.Styled) format).style()); + Object json = gson().serializer().toJsonTree(((ScoreFormat.Styled) format).style()); + if (PacketAccessors.IS_GSON_RELOCATED) { + //System.out.println("working around 2 " + json.getClass().getName()); + json = PacketAccessors.PARSE_STRING_METHOD.invoke(PacketAccessors.JSON_PARSER, json.toString()); + //System.out.println("worked around 2 " + json.getClass().getName()); + } + Object result = PacketAccessors.CODEC_PARSE.invoke(STYLE_CODEC, PacketAccessors.JSON_OPS, json); //noinspection OptionalGetWithoutIsPresent Object style = ((Optional) PacketAccessors.RESULT_UNWRAP_METHOD.invoke(result)).get(); diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/util/ModernComponentProvider.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/util/ModernComponentProvider.java index 9f127520..4aa9df6a 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/util/ModernComponentProvider.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/util/ModernComponentProvider.java @@ -1,6 +1,5 @@ package net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util; -import com.google.gson.JsonElement; import net.kyori.adventure.text.Component; import net.kyori.adventure.translation.GlobalTranslator; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; @@ -62,7 +61,7 @@ private ModernComponentProvider() { for (Method method : PacketAccessors.CHAT_SERIALIZER_CLASS.getMethods()) { if (method.getParameterCount() >= 1 && method.getParameterCount() <= 2 && - method.getParameterTypes()[0] == JsonElement.class + method.getParameterTypes()[0].getName().equals(PacketAccessors.GSON_PKG + ".JsonElement") ) { try { handle = MethodHandles.lookup().unreflect(method); @@ -91,7 +90,13 @@ private ModernComponentProvider() { if (locale != null) { translated = GlobalTranslator.render(adventure, locale); } - JsonElement json = gson().serializeToTree(translated); + Object json = gson().serializeToTree(translated); + + if (PacketAccessors.IS_GSON_RELOCATED) { + //System.out.println("working around " + json.getClass().getName()); + json = PacketAccessors.PARSE_STRING_METHOD.invoke(PacketAccessors.JSON_PARSER, json.toString()); + //System.out.println("worked around " + json.getClass().getName()); + } if (FROM_JSON_METHOD == null) { // 1.21.6+ From cd09080ced4d569b98d3b4d89462edbb41c4cc77 Mon Sep 17 00:00:00 2001 From: vytskalt Date: Sun, 22 Feb 2026 22:00:53 +0200 Subject: [PATCH 6/7] cleaned up --- test-plugin/build.gradle.kts | 4 +- .../packetAdapter/modern/PacketAccessors.java | 36 ++------------- .../packetAdapter/modern/RelocatedGson.java | 46 +++++++++++++++++++ .../objective/ScoreFormatConverter.java | 9 +--- .../modern/util/ModernComponentProvider.java | 10 ++-- 5 files changed, 56 insertions(+), 49 deletions(-) create mode 100644 versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/RelocatedGson.java diff --git a/test-plugin/build.gradle.kts b/test-plugin/build.gradle.kts index 3786ab55..e64f1b12 100644 --- a/test-plugin/build.gradle.kts +++ b/test-plugin/build.gradle.kts @@ -22,6 +22,6 @@ dependencies { } tasks.shadowJar { - relocate("com.google.gson", "net.megavex.scoreboardlibrary.testplugin.lib.gson") - relocate("net.kyori", "net.megavex.scoreboardlibrary.testplugin.lib.kyori") +// relocate("com.google.gson", "net.megavex.scoreboardlibrary.testplugin.lib.gson") +// relocate("net.kyori", "net.megavex.scoreboardlibrary.testplugin.lib.kyori") } diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAccessors.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAccessors.java index 5ab47630..8dc3693d 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAccessors.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/PacketAccessors.java @@ -1,6 +1,5 @@ package net.megavex.scoreboardlibrary.implementation.packetAdapter.modern; -import com.google.gson.JsonElement; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.megavex.scoreboardlibrary.api.team.enums.CollisionRule; @@ -12,7 +11,6 @@ import org.jetbrains.annotations.Nullable; import java.lang.invoke.MethodType; -import java.lang.reflect.InvocationTargetException; import java.util.*; public final class PacketAccessors { @@ -78,35 +76,6 @@ private PacketAccessors() { IS_1_21_6_OR_ABOVE = is1_21_6OrAbove; } - public static final String GSON_PKG = "com.go".concat("ogle.gson"); - public static final boolean IS_GSON_RELOCATED; - public static final Object JSON_PARSER; - public static final MethodAccessor PARSE_STRING_METHOD; - - static { - IS_GSON_RELOCATED = !JsonElement.class.getName().equals(GSON_PKG + ".JsonElement"); - - try { - Class jsonElementClass = Class.forName(GSON_PKG + ".JsonElement"); - Class jsonParserClass = Class.forName(GSON_PKG + ".JsonParser"); - JSON_PARSER = jsonParserClass.getConstructors()[0].newInstance(); - MethodAccessor parseStringMethod = ReflectUtil.findOptionalMethod(jsonParserClass, false, MethodType.methodType(jsonElementClass, String.class), "parse"); - if (parseStringMethod == null) { - parseStringMethod = ReflectUtil.findMethod(jsonParserClass, true, MethodType.methodType(jsonElementClass, String.class), "parse"); - //new JsonParser().parse("{}"); - //System.out.println("found via method 1"); - } else { - //System.out.println("found via method 2"); - } - PARSE_STRING_METHOD = parseStringMethod; - //System.out.println(JSON_PARSER); - } catch (ClassNotFoundException | InvocationTargetException | InstantiationException | IllegalAccessException e) { - throw new RuntimeException(e); - } - //(new JsonParser()).parse(""); - //System.out.println("GSON RELOCATED = " + IS_GSON_RELOCATED); - } - public static final Class PKT_CLASS, SET_OBJECTIVE_PKT_CLASS, SET_DISPLAY_OBJECTIVE_PKT_CLASS, @@ -215,10 +184,11 @@ private PacketAccessors() { Object[] chatFormattings = CHAT_FORMATTING_CLASS.getEnumConstants(); FieldAccessor charField = ReflectUtil.findFieldUnchecked(CHAT_FORMATTING_CLASS, 0, char.class); - outer: for (NamedTextColor color : NamedTextColor.NAMES.values()) { + outer: + for (NamedTextColor color : NamedTextColor.NAMES.values()) { char c = LegacyFormatUtil.getChar(color); for (Object chatFormatting : chatFormattings) { - if (c == (char)charField.get(chatFormatting)) { + if (c == (char) charField.get(chatFormatting)) { NMS_CHAT_FORMATTING_MAP.put(color, chatFormatting); continue outer; } diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/RelocatedGson.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/RelocatedGson.java new file mode 100644 index 00000000..33c38173 --- /dev/null +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/RelocatedGson.java @@ -0,0 +1,46 @@ +package net.megavex.scoreboardlibrary.implementation.packetAdapter.modern; + +import com.google.gson.JsonElement; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.util.reflect.MethodAccessor; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.util.reflect.ReflectUtil; + +import java.lang.invoke.MethodType; +import java.lang.reflect.InvocationTargetException; + +public final class RelocatedGson { + public static final String SERVER_GSON_PKG = "com.go".concat("ogle.gson"); + public static final boolean IS_GSON_RELOCATED; + public static final Object JSON_PARSER; + public static final MethodAccessor PARSE_STRING_METHOD; + + private RelocatedGson() { + } + + static { + IS_GSON_RELOCATED = !JsonElement.class.getName().equals(SERVER_GSON_PKG + ".JsonElement"); + + if (IS_GSON_RELOCATED) { + try { + Class jsonElementClass = Class.forName(SERVER_GSON_PKG + ".JsonElement"); + Class jsonParserClass = Class.forName(SERVER_GSON_PKG + ".JsonParser"); + JSON_PARSER = jsonParserClass.getConstructors()[0].newInstance(); + PARSE_STRING_METHOD = ReflectUtil.findMethod(jsonParserClass, false, MethodType.methodType(jsonElementClass, String.class), "parse"); + } catch (ClassNotFoundException | InvocationTargetException | InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } else { + JSON_PARSER = null; + PARSE_STRING_METHOD = null; + } + //System.out.println("GSON RELOCATED = " + IS_GSON_RELOCATED); + } + + public static Object convertToServerGson(final JsonElement element) { + if (IS_GSON_RELOCATED) { + assert PARSE_STRING_METHOD != null; + //System.out.println("fixed"); + return PARSE_STRING_METHOD.invoke(JSON_PARSER, element.toString()); + } + return element; + } +} diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/ScoreFormatConverter.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/ScoreFormatConverter.java index 9ad307c6..cef2af65 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/ScoreFormatConverter.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/objective/ScoreFormatConverter.java @@ -2,6 +2,7 @@ import net.megavex.scoreboardlibrary.api.objective.ScoreFormat; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.RelocatedGson; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.util.ModernComponentProvider; import net.megavex.scoreboardlibrary.implementation.packetAdapter.util.reflect.ConstructorAccessor; import net.megavex.scoreboardlibrary.implementation.packetAdapter.util.reflect.ReflectUtil; @@ -49,13 +50,7 @@ private ScoreFormatConverter() { if (format == ScoreFormat.blank()) { return BLANK; } else if (format instanceof ScoreFormat.Styled) { - Object json = gson().serializer().toJsonTree(((ScoreFormat.Styled) format).style()); - if (PacketAccessors.IS_GSON_RELOCATED) { - //System.out.println("working around 2 " + json.getClass().getName()); - json = PacketAccessors.PARSE_STRING_METHOD.invoke(PacketAccessors.JSON_PARSER, json.toString()); - //System.out.println("worked around 2 " + json.getClass().getName()); - } - + Object json = RelocatedGson.convertToServerGson(gson().serializer().toJsonTree(((ScoreFormat.Styled) format).style())); Object result = PacketAccessors.CODEC_PARSE.invoke(STYLE_CODEC, PacketAccessors.JSON_OPS, json); //noinspection OptionalGetWithoutIsPresent Object style = ((Optional) PacketAccessors.RESULT_UNWRAP_METHOD.invoke(result)).get(); diff --git a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/util/ModernComponentProvider.java b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/util/ModernComponentProvider.java index 4aa9df6a..e47a9c39 100644 --- a/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/util/ModernComponentProvider.java +++ b/versions/modern/src/main/java/net/megavex/scoreboardlibrary/implementation/packetAdapter/modern/util/ModernComponentProvider.java @@ -3,6 +3,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.translation.GlobalTranslator; import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.PacketAccessors; +import net.megavex.scoreboardlibrary.implementation.packetAdapter.modern.RelocatedGson; import net.megavex.scoreboardlibrary.implementation.packetAdapter.util.reflect.MinecraftClasses; import net.megavex.scoreboardlibrary.implementation.packetAdapter.util.reflect.ReflectUtil; import org.jetbrains.annotations.NotNull; @@ -61,7 +62,7 @@ private ModernComponentProvider() { for (Method method : PacketAccessors.CHAT_SERIALIZER_CLASS.getMethods()) { if (method.getParameterCount() >= 1 && method.getParameterCount() <= 2 && - method.getParameterTypes()[0].getName().equals(PacketAccessors.GSON_PKG + ".JsonElement") + method.getParameterTypes()[0].getName().equals(RelocatedGson.SERVER_GSON_PKG + ".JsonElement") ) { try { handle = MethodHandles.lookup().unreflect(method); @@ -90,13 +91,8 @@ private ModernComponentProvider() { if (locale != null) { translated = GlobalTranslator.render(adventure, locale); } - Object json = gson().serializeToTree(translated); - if (PacketAccessors.IS_GSON_RELOCATED) { - //System.out.println("working around " + json.getClass().getName()); - json = PacketAccessors.PARSE_STRING_METHOD.invoke(PacketAccessors.JSON_PARSER, json.toString()); - //System.out.println("worked around " + json.getClass().getName()); - } + Object json = RelocatedGson.convertToServerGson(gson().serializeToTree(translated)); if (FROM_JSON_METHOD == null) { // 1.21.6+ From 1e6c8a033a15917494037d95c98a3f77e9be4fa7 Mon Sep 17 00:00:00 2001 From: vytskalt Date: Tue, 24 Feb 2026 22:32:36 +0200 Subject: [PATCH 7/7] docs updates --- INSTALLATION.md | 11 +++++++++++ README.md | 6 ++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/INSTALLATION.md b/INSTALLATION.md index 35c4d880..945f8e69 100644 --- a/INSTALLATION.md +++ b/INSTALLATION.md @@ -55,3 +55,14 @@ like [Shadow](https://gradleup.com/shadow/). ``` You will need to shade these dependencies and relocate them with [maven-shade-plugin](https://maven.apache.org/plugins/maven-shade-plugin/). + +## ViaVersion awareness + +For [ViaVersion awareness](https://github.com/vytskalt/scoreboard-library?tab=readme-ov-file#features) to be enabled, make sure to add `ViaVersion` +to `softdepend` or `depend` of your `plugin.yml`: + +```yaml +softdepend: ["ViaVersion"] +# or +depend: ["ViaVersion"] +``` diff --git a/README.md b/README.md index a12b475b..c1ce9ec1 100644 --- a/README.md +++ b/README.md @@ -13,17 +13,19 @@ Join the [Discord](https://discord.gg/v7nmTDTW8W) or create an issue for support players - Objectives. - Full support for new 1.20.4 features (score display names, custom score formats) -- Doesn't require extra dependencies (assuming you're targeting modern versions of Paper) +- No extra dependencies (assuming you're targeting modern versions of Paper) - Packet-level, meaning it works with other scoreboard plugins - Supports [Folia](https://github.com/PaperMC/Folia) - Fully async. All packet work is done asynchronously, so you can use the library from the main thread without sacrificing any performance - Automatically works with `TranslatableComponent`s. All components are translated using `GlobalTranslator` for each player's client locale and automatically update whenever the player changes it in their settings +- ViaVersion awareness: automatically detects 1.12.2- on 1.13+ servers connected through ViaVersion and sends them + the optimal packets to maximise sidebar line lengths ## Supported server versions -All Paper and Spigot versions from 1.7.10 to 1.21.11 are now natively supported. +All Paper and Spigot versions from 1.7.10 to 1.21.11 are natively supported. ## Installation