From 2f45890a34b516d56ebec6039c48c7115ccb9f70 Mon Sep 17 00:00:00 2001 From: Diogo Correia Date: Sun, 17 Dec 2023 19:29:19 +0100 Subject: [PATCH 1/9] chore(spigot): update ProtocolLib to 5.2.0-SNAPSHOT (#358) This adds support for MC 1.20.4. The diogotc repository has been reordered so that ProtocolLib is pulled from there first. --- build.gradle | 8 ++++---- triton-spigot/build.gradle | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index e13f1905..5850b5f0 100644 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,10 @@ allprojects { repositories { mavenLocal() mavenCentral() + maven { + name 'diogotcRepositorySnapshots' + url 'https://repo.diogotc.com/snapshots/' + } maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' content { @@ -32,10 +36,6 @@ allprojects { name 'velocity' url 'https://nexus.velocitypowered.com/repository/maven-public/' } - maven { - name 'diogotcRepositorySnapshots' - url 'https://repo.diogotc.com/snapshots/' - } } } diff --git a/triton-spigot/build.gradle b/triton-spigot/build.gradle index 970cdd85..4b0920f5 100644 --- a/triton-spigot/build.gradle +++ b/triton-spigot/build.gradle @@ -24,7 +24,7 @@ dependencies { compileOnly 'net.kyori:adventure-text-serializer-legacy:4.11.0' compileOnly 'net.kyori:adventure-text-serializer-bungeecord:4.1.2' - compileOnly 'com.comphenix.protocol:ProtocolLib:5.1.1-SNAPSHOT' + compileOnly 'com.comphenix.protocol:ProtocolLib:5.2.0-SNAPSHOT' compileOnly 'me.clip:placeholderapi:2.11.1' // Libraries available on Spigot From 35d2e9886e1163178ddc158f4de8daf6eb20307e Mon Sep 17 00:00:00 2001 From: Diogo Correia Date: Sun, 17 Dec 2023 19:38:48 +0100 Subject: [PATCH 2/9] fix(spigot): scoreboard not shown when using async mode (#359) While using the experimental ProtocolLib async mode in Triton, scoreboards, regardless if they had placeholders or not, were not shown. This was caused by the packets not arriving in the same order they were sent, since the intercepted packets arrived afterwards. This commit registers all scoreboard related packets to ensure the order is left unchanged. This was previously "fixed" in v3 in #299 by forcing scoreboard packets to be handled in the sync thread, which reduces performance. Fixes #251 --- .../spigot/packetinterceptor/ProtocolLibListener.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java index 9b6ec069..544c5a91 100644 --- a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java +++ b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java @@ -79,6 +79,9 @@ public class ProtocolLibListener implements PacketListener { private final String MERCHANT_RECIPE_SPECIAL_PRICE_FIELD; private final String MERCHANT_RECIPE_DEMAND_FIELD; + private final HandlerFunction ASYNC_PASSTHROUGH = asAsync((_packet, _player) -> { + }); + private final SignPacketHandler signPacketHandler = new SignPacketHandler(); private final AdvancementsPacketHandler advancementsPacketHandler = AdvancementsPacketHandler.newInstance(); private final EntitiesPacketHandler entitiesPacketHandler = new EntitiesPacketHandler(); @@ -161,6 +164,12 @@ private void setupPacketHandlers() { // It allows unlimited length team prefixes and suffixes packetHandlers.put(PacketType.Play.Server.SCOREBOARD_TEAM, asAsync(this::handleScoreboardTeam)); packetHandlers.put(PacketType.Play.Server.SCOREBOARD_OBJECTIVE, asAsync(this::handleScoreboardObjective)); + // Register the packets below so their order is kept between all scoreboard packets + packetHandlers.put(PacketType.Play.Server.SCOREBOARD_DISPLAY_OBJECTIVE, ASYNC_PASSTHROUGH); + packetHandlers.put(PacketType.Play.Server.SCOREBOARD_SCORE, ASYNC_PASSTHROUGH); + if (MinecraftVersion.v1_20_4.atOrAbove()) { + packetHandlers.put(PacketType.Play.Server.RESET_SCORE, ASYNC_PASSTHROUGH); + } } packetHandlers.put(PacketType.Play.Server.WINDOW_ITEMS, asAsync(this::handleWindowItems)); packetHandlers.put(PacketType.Play.Server.SET_SLOT, asAsync(this::handleSetSlot)); From 29a4ee232b88962a9f2fd825733601c273d71c22 Mon Sep 17 00:00:00 2001 From: Diogo Correia Date: Sun, 17 Dec 2023 19:42:50 +0100 Subject: [PATCH 3/9] fix(spigot): system chat packet not being translated in MC 1.20.4 (#360) Relates to #356 --- .../spigot/packetinterceptor/ProtocolLibListener.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java index 544c5a91..a29657c9 100644 --- a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java +++ b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java @@ -285,6 +285,7 @@ private void handleSystemChat(PacketEvent packet, SpigotLanguagePlayer languageP if ((ab && !main.getConfig().isActionbars()) || (!ab && !main.getConfig().isChat())) return; val stringModifier = packet.getPacket().getStrings(); + val chatModifier = packet.getPacket().getChatComponents(); Component message = null; @@ -292,6 +293,8 @@ private void handleSystemChat(PacketEvent packet, SpigotLanguagePlayer languageP if (adventureModifier.readSafely(0) != null) { message = adventureModifier.readSafely(0); + } else if (chatModifier.readSafely(0) != null) { + message = WrappedComponentUtils.deserialize(chatModifier.readSafely(0)); } else { val msgJson = stringModifier.readSafely(0); if (msgJson != null) { @@ -315,6 +318,9 @@ private void handleSystemChat(PacketEvent packet, SpigotLanguagePlayer languageP if (adventureModifier.size() > 0) { // On a Paper or fork, so we can directly set the Adventure Component adventureModifier.writeSafely(0, result); + } else if (chatModifier.size() > 0) { + // Starting on MC 1.20.3 this packet takes a chat component instead of a json string + chatModifier.writeSafely(0, WrappedComponentUtils.serialize(result)); } else { stringModifier.writeSafely(0, ComponentUtils.serializeToJson(result)); } From 3659f0063e7d80b6721ad6a495bdac3fce9e5aaf Mon Sep 17 00:00:00 2001 From: Diogo Correia Date: Sun, 17 Dec 2023 19:48:22 +0100 Subject: [PATCH 4/9] feat(spigot): support number format on scoreboard objective (#361) Closes #355 --- .../spigot/packetinterceptor/ProtocolLibListener.java | 10 +++++++++- .../triton/spigot/player/SpigotLanguagePlayer.java | 4 +++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java index a29657c9..2e13ce08 100644 --- a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java +++ b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java @@ -75,6 +75,7 @@ public class ProtocolLibListener implements PacketListener { private final Class BASE_COMPONENT_ARRAY_CLASS = BaseComponent[].class; private StructureModifier SCOREBOARD_TEAM_METADATA_MODIFIER = null; private final Class ADVENTURE_COMPONENT_CLASS = Component.class; + private final Optional> NUMBER_FORMAT_CLASS; private final Field PLAYER_ACTIVE_CONTAINER_FIELD; private final String MERCHANT_RECIPE_SPECIAL_PRICE_FIELD; private final String MERCHANT_RECIPE_DEMAND_FIELD; @@ -113,6 +114,7 @@ public ProtocolLibListener(SpigotTriton main, HandlerFunction.HandlerType... all ReflectionUtils.getClass("net.minecraft.world.inventory.ContainerPlayer") : NMSUtils.getNMSClass("ContainerPlayer"); BOSSBAR_UPDATE_TITLE_ACTION_CLASS = main.getMcVersion() >= 17 ? ReflectionUtils.getClass("net.minecraft.network.protocol.game.PacketPlayOutBoss$e") : null; + NUMBER_FORMAT_CLASS = MinecraftReflection.getOptionalNMS("network.chat.numbers.NumberFormat"); MERCHANT_RECIPE_SPECIAL_PRICE_FIELD = getMCVersion() >= 17 ? "g" : "specialPrice"; MERCHANT_RECIPE_DEMAND_FIELD = getMCVersion() >= 17 ? "h" : "demand"; @@ -736,8 +738,11 @@ private void handleScoreboardObjective(PacketEvent packet, SpigotLanguagePlayer val healthDisplay = packet.getPacket().getModifier().readSafely(2); val displayName = chatComponentsModifier.readSafely(0); + val numberFormat = NUMBER_FORMAT_CLASS + .map(numberFormatClass -> packet.getPacket().getSpecificModifier(numberFormatClass).readSafely(0)) + .orElse(null); - languagePlayer.setScoreboardObjective(objectiveName, displayName.getJson(), healthDisplay); + languagePlayer.setScoreboardObjective(objectiveName, displayName.getJson(), healthDisplay, numberFormat); parser() .translateComponent( @@ -906,6 +911,9 @@ public void refreshScoreboard(SpigotLanguagePlayer player) { packet.getStrings().writeSafely(0, key); packet.getChatComponents().writeSafely(0, WrappedChatComponent.fromJson(value.getChatJson())); packet.getModifier().writeSafely(2, value.getType()); + NUMBER_FORMAT_CLASS.ifPresent(numberFormatClass -> + packet.getSpecificModifier((Class) numberFormatClass) + .writeSafely(0, value.getNumberFormat())); ProtocolLibrary.getProtocolManager().sendServerPacket(bukkitPlayer, packet, true); }); diff --git a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/player/SpigotLanguagePlayer.java b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/player/SpigotLanguagePlayer.java index 9b7ccaa6..22a06e12 100644 --- a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/player/SpigotLanguagePlayer.java +++ b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/player/SpigotLanguagePlayer.java @@ -70,10 +70,11 @@ public SpigotLanguagePlayer(UUID p) { load(); } - public void setScoreboardObjective(String name, String chatJson, Object type) { + public void setScoreboardObjective(String name, String chatJson, Object type, Object numberFormat) { ScoreboardObjective objective = this.objectivesMap.computeIfAbsent(name, k -> new ScoreboardObjective()); objective.setChatJson(chatJson); objective.setType(type); + objective.setNumberFormat(numberFormat); } public void removeScoreboardObjective(String name) { @@ -271,6 +272,7 @@ public String toString() { public static class ScoreboardObjective { private String chatJson; private Object type; + private Object numberFormat; } @Data From c3026972e9ee6c22646513eddb1ce1f22a1d539f Mon Sep 17 00:00:00 2001 From: Diogo Correia Date: Sun, 17 Dec 2023 20:21:12 +0100 Subject: [PATCH 5/9] fix(spigot): changed field type in advancement display on MC 1.20.4 (#363) The type of field 'background' changed from MinecraftKey to Optional. Relates to #356 --- .../wrappers/WrappedAdvancementDisplay.java | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/wrappers/WrappedAdvancementDisplay.java b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/wrappers/WrappedAdvancementDisplay.java index 47a6661a..2c8463a6 100644 --- a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/wrappers/WrappedAdvancementDisplay.java +++ b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/wrappers/WrappedAdvancementDisplay.java @@ -1,15 +1,19 @@ package com.rexcantor64.triton.spigot.wrappers; import com.comphenix.protocol.reflect.EquivalentConverter; +import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; import com.comphenix.protocol.reflect.accessors.FieldAccessor; import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.utility.MinecraftVersion; import com.comphenix.protocol.wrappers.AbstractWrapper; import com.comphenix.protocol.wrappers.BukkitConverters; import com.comphenix.protocol.wrappers.Converters; import com.comphenix.protocol.wrappers.WrappedChatComponent; +import java.util.Optional; + /** * Custom ProtocolLib Wrapper of NMS' AdvancementDisplay */ @@ -19,19 +23,20 @@ public class WrappedAdvancementDisplay extends AbstractWrapper { private static Class ADVANCEMENT_FRAME_TYPE_CLASS = MinecraftReflection.getMinecraftClass("advancements.AdvancementFrameType", "AdvancementFrameType"); private static ConstructorAccessor ADVANCEMENT_DISPLAY_CONSTRUTOR = Accessors.getConstructorAccessor( ADVANCEMENT_DISPLAY, - MinecraftReflection.getItemStackClass(), - MinecraftReflection.getIChatBaseComponentClass(), - MinecraftReflection.getIChatBaseComponentClass(), - MinecraftReflection.getMinecraftKeyClass(), - ADVANCEMENT_FRAME_TYPE_CLASS, - boolean.class, - boolean.class, - boolean.class); + MinecraftReflection.getItemStackClass(), // icon + MinecraftReflection.getIChatBaseComponentClass(), // title + MinecraftReflection.getIChatBaseComponentClass(), // description + MinecraftVersion.v1_20_4.atOrAbove() ? Optional.class : MinecraftReflection.getMinecraftKeyClass(), // background + ADVANCEMENT_FRAME_TYPE_CLASS, // frame + boolean.class, // showToast + boolean.class, // announceToChat + boolean.class // hidden + ); private static FieldAccessor[] CHAT_COMPONENTS = Accessors.getFieldAccessorArray(ADVANCEMENT_DISPLAY, MinecraftReflection.getIChatBaseComponentClass(), true); private static FieldAccessor TITLE = CHAT_COMPONENTS[0]; private static FieldAccessor DESCRIPTION = CHAT_COMPONENTS[1]; private static FieldAccessor ITEM_STACK = Accessors.getFieldAccessor(ADVANCEMENT_DISPLAY, MinecraftReflection.getItemStackClass(), true); - private static FieldAccessor MINECRAFT_KEY = Accessors.getFieldAccessor(ADVANCEMENT_DISPLAY, MinecraftReflection.getMinecraftKeyClass(), true); + private static FieldAccessor MINECRAFT_KEY; private static FieldAccessor ADVANCEMENT_FRAME_TYPE = Accessors.getFieldAccessor(ADVANCEMENT_DISPLAY, ADVANCEMENT_FRAME_TYPE_CLASS, true); private static FieldAccessor[] BOOLEANS = Accessors.getFieldAccessorArray(ADVANCEMENT_DISPLAY, boolean.class, true); private static FieldAccessor SHOW_TOAST = BOOLEANS[0]; @@ -47,6 +52,15 @@ public class WrappedAdvancementDisplay extends AbstractWrapper { private boolean hasChanged = false; + static { + if (MinecraftVersion.v1_20_4.atOrAbove()) { + FuzzyReflection fuzzyReflection = FuzzyReflection.fromClass(ADVANCEMENT_DISPLAY, true); + MINECRAFT_KEY = Accessors.getFieldAccessor(fuzzyReflection.getParameterizedField(Optional.class, MinecraftReflection.getMinecraftKeyClass())); + } else { + MINECRAFT_KEY = Accessors.getFieldAccessor(ADVANCEMENT_DISPLAY, MinecraftReflection.getMinecraftKeyClass(), true); + } + } + /** * Construct a new AdvancementDisplay wrapper. */ @@ -81,14 +95,14 @@ public boolean hasChangedAndReset() { public WrappedAdvancementDisplay shallowClone() { Object newInstance = ADVANCEMENT_DISPLAY_CONSTRUTOR.invoke( - ITEM_STACK.get(handle), - TITLE.get(handle), - DESCRIPTION.get(handle), - MINECRAFT_KEY.get(handle), - ADVANCEMENT_FRAME_TYPE.get(handle), - SHOW_TOAST.get(handle), - ANNOUNCE_TO_CHAT.get(handle), - HIDDEN.get(handle) + ITEM_STACK.get(handle), + TITLE.get(handle), + DESCRIPTION.get(handle), + MINECRAFT_KEY.get(handle), + ADVANCEMENT_FRAME_TYPE.get(handle), + SHOW_TOAST.get(handle), + ANNOUNCE_TO_CHAT.get(handle), + HIDDEN.get(handle) ); X_CORD.set(newInstance, X_CORD.get(handle)); Y_CORD.set(newInstance, Y_CORD.get(handle)); @@ -98,6 +112,7 @@ public WrappedAdvancementDisplay shallowClone() { /** * Construct a wrapped advancement display from a native NMS object. + * * @param handle - the native object. * @return The wrapped advancement display object. */ From 03d9de1309eac6b0d8605b3070681277b9b824d5 Mon Sep 17 00:00:00 2001 From: Diogo Correia Date: Sun, 17 Dec 2023 20:42:35 +0100 Subject: [PATCH 6/9] fix(spigot): remove duplicate async listener for incoming packets (#365) Incoming packets where being handled both in a sync and an async thread. Fixes #364 --- .../spigot/packetinterceptor/ProtocolLibListener.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java index 2e13ce08..971ed67a 100644 --- a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java +++ b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/packetinterceptor/ProtocolLibListener.java @@ -835,9 +835,12 @@ public ListeningWhitelist getSendingWhitelist() { @Override public ListeningWhitelist getReceivingWhitelist() { val types = new ArrayList(); - types.add(PacketType.Play.Client.SETTINGS); - if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) { // MC 1.20.2 - types.add(PacketType.Configuration.Client.CLIENT_INFORMATION); + if (this.allowedTypes.contains(HandlerFunction.HandlerType.SYNC)) { + // only listen for these packets in the sync handler + types.add(PacketType.Play.Client.SETTINGS); + if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) { // MC 1.20.2 + types.add(PacketType.Configuration.Client.CLIENT_INFORMATION); + } } return ListeningWhitelist.newBuilder() From 2c0fbdb0843ba5f84182218b41f3d02f09df0231 Mon Sep 17 00:00:00 2001 From: Diogo Correia Date: Sun, 17 Dec 2023 21:36:04 +0100 Subject: [PATCH 7/9] feat(velocity): support velocity 3.3.0-SNAPSHOT (#366) --- triton-velocity/build.gradle | 4 +- .../packets/BossBarHandler.java | 8 ++-- .../packets/ChatHandler.java | 6 ++- .../packets/DisconnectHandler.java | 10 +++-- .../packets/ResourcePackHandler.java | 4 +- .../packetinterceptor/packets/TabHandler.java | 41 +++++++++++-------- .../packets/TitleHandler.java | 5 ++- .../velocity/player/RefreshFeatures.java | 13 ++++-- .../player/VelocityLanguagePlayer.java | 10 ++--- 9 files changed, 62 insertions(+), 39 deletions(-) diff --git a/triton-velocity/build.gradle b/triton-velocity/build.gradle index 1f5fd0b7..27521ab7 100644 --- a/triton-velocity/build.gradle +++ b/triton-velocity/build.gradle @@ -10,9 +10,9 @@ dependencies { compileOnly project(path: ":api") compileOnly project(path: ":core") - annotationProcessor 'com.velocitypowered:velocity-api:3.1.0' + annotationProcessor 'com.velocitypowered:velocity-api:3.3.0-SNAPSHOT' - compileOnly 'com.velocitypowered:velocity-proxy:3.2.0-SNAPSHOT' + compileOnly 'com.velocitypowered:velocity-proxy:3.3.0-SNAPSHOT' compileOnly 'io.netty:netty-codec:4.1.80.Final' diff --git a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/BossBarHandler.java b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/BossBarHandler.java index d2592c75..c47e3d42 100644 --- a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/BossBarHandler.java +++ b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/BossBarHandler.java @@ -3,10 +3,10 @@ import com.rexcantor64.triton.Triton; import com.rexcantor64.triton.api.config.FeatureSyntax; import com.rexcantor64.triton.api.language.MessageParser; -import com.rexcantor64.triton.velocity.utils.ComponentUtils; import com.rexcantor64.triton.velocity.player.VelocityLanguagePlayer; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.packet.BossBar; +import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import lombok.val; import net.kyori.adventure.text.Component; import org.jetbrains.annotations.NotNull; @@ -44,16 +44,16 @@ private FeatureSyntax getBossBarSyntax() { val text = bossBarPacket.getName(); if (text != null && (action == BossBar.ADD || action == BossBar.UPDATE_NAME)) { - player.setBossbar(uuid, bossBarPacket.getName()); + player.setBossbar(uuid, bossBarPacket.getName().getComponent()); parser() .translateComponent( - ComponentUtils.deserializeFromJson(bossBarPacket.getName(), player.getProtocolVersion()), + bossBarPacket.getName().getComponent(), player, getBossBarSyntax() ) .getResultOrToRemove(Component::empty) - .map(result -> ComponentUtils.serializeToJson(result, player.getProtocolVersion())) + .map(result -> new ComponentHolder(player.getProtocolVersion(), result)) .ifPresent(bossBarPacket::setName); } return Optional.of(bossBarPacket); diff --git a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/ChatHandler.java b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/ChatHandler.java index c5d40c69..b93e68d8 100644 --- a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/ChatHandler.java +++ b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/ChatHandler.java @@ -7,6 +7,7 @@ import com.rexcantor64.triton.velocity.utils.ComponentUtils; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.packet.chat.ChatType; +import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import com.velocitypowered.proxy.protocol.packet.chat.SystemChat; import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChat; import net.kyori.adventure.text.Component; @@ -46,10 +47,11 @@ private FeatureSyntax getActionBarSyntax() { return Objects.requireNonNull( parser().translateComponent( - systemChatPacket.getComponent(), + systemChatPacket.getComponent().getComponent(), player, actionBar ? getActionBarSyntax() : getChatSyntax() ) + .map(result -> new ComponentHolder(player.getProtocolVersion(), result)) .mapToObj( result -> Optional.of(cloneSystemChatWithComponent(systemChatPacket, result)), () -> Optional.of(systemChatPacket), @@ -80,7 +82,7 @@ private FeatureSyntax getActionBarSyntax() { ); } - private @NotNull SystemChat cloneSystemChatWithComponent(@NotNull SystemChat systemChatPacket, Component newComponent) { + private @NotNull SystemChat cloneSystemChatWithComponent(@NotNull SystemChat systemChatPacket, ComponentHolder newComponent) { return new SystemChat(newComponent, systemChatPacket.getType()); } diff --git a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/DisconnectHandler.java b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/DisconnectHandler.java index 735a2ac6..ec740d5a 100644 --- a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/DisconnectHandler.java +++ b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/DisconnectHandler.java @@ -7,6 +7,7 @@ import com.rexcantor64.triton.velocity.utils.ComponentUtils; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.packet.Disconnect; +import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -33,13 +34,16 @@ private FeatureSyntax getKickSyntax() { return Objects.requireNonNull( parser().translateComponent( - ComponentUtils.deserializeFromJson(disconnectPacket.getReason(), player.getProtocolVersion()), + disconnectPacket.getReason().getComponent(), player, getKickSyntax() ) - .map(result -> ComponentUtils.serializeToJson(result, player.getProtocolVersion())) + .map(result -> new ComponentHolder(player.getProtocolVersion(), result)) .mapToObj( - result -> Optional.of(new Disconnect(result)), + result -> { + disconnectPacket.setReason(result); + return Optional.of(disconnectPacket); + }, () -> Optional.of(disconnectPacket), Optional::empty ) diff --git a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/ResourcePackHandler.java b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/ResourcePackHandler.java index 15dc2335..403c15ed 100644 --- a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/ResourcePackHandler.java +++ b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/ResourcePackHandler.java @@ -6,6 +6,7 @@ import com.rexcantor64.triton.velocity.player.VelocityLanguagePlayer; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest; +import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import net.kyori.adventure.text.Component; import org.jetbrains.annotations.NotNull; @@ -33,11 +34,12 @@ private FeatureSyntax getResourcePackSyntax() { } parser().translateComponent( - resourcePackRequest.getPrompt(), + resourcePackRequest.getPrompt().getComponent(), player, getResourcePackSyntax() ) .getResultOrToRemove(Component::empty) + .map(result -> new ComponentHolder(player.getProtocolVersion(), result)) .ifPresent(resourcePackRequest::setPrompt); return Optional.of(resourcePackRequest); } diff --git a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/TabHandler.java b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/TabHandler.java index 9d9b78ee..9a45f66f 100644 --- a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/TabHandler.java +++ b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/TabHandler.java @@ -4,13 +4,14 @@ import com.rexcantor64.triton.api.config.FeatureSyntax; import com.rexcantor64.triton.api.language.MessageParser; import com.rexcantor64.triton.velocity.player.VelocityLanguagePlayer; -import com.rexcantor64.triton.velocity.utils.ComponentUtils; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.packet.HeaderAndFooter; import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItem; import com.velocitypowered.proxy.protocol.packet.RemovePlayerInfo; import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfo; +import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import lombok.val; +import net.kyori.adventure.text.Component; import org.jetbrains.annotations.NotNull; import java.util.Optional; @@ -18,8 +19,6 @@ public class TabHandler { - private static final String EMPTY_COMPONENT = "{\"translate\":\"\"}"; - private MessageParser parser() { return Triton.get().getMessageParser(); } @@ -37,23 +36,23 @@ private FeatureSyntax getTabSyntax() { return Optional.of(headerFooterPacket); } - player.setLastTabHeader(headerFooterPacket.getHeader()); - player.setLastTabFooter(headerFooterPacket.getFooter()); + player.setLastTabHeader(headerFooterPacket.getHeader().getComponent()); + player.setLastTabFooter(headerFooterPacket.getFooter().getComponent()); - Optional newHeader = parser().translateComponent( - ComponentUtils.deserializeFromJson(headerFooterPacket.getHeader(), player.getProtocolVersion()), + Optional newHeader = parser().translateComponent( + headerFooterPacket.getHeader().getComponent(), player, getTabSyntax() ) - .map(result -> ComponentUtils.serializeToJson(result, player.getProtocolVersion())) - .getResultOrToRemove(() -> EMPTY_COMPONENT); - Optional newFooter = parser().translateComponent( - ComponentUtils.deserializeFromJson(headerFooterPacket.getFooter(), player.getProtocolVersion()), + .getResultOrToRemove(Component::empty) + .map(result -> new ComponentHolder(player.getProtocolVersion(), result)); + Optional newFooter = parser().translateComponent( + headerFooterPacket.getFooter().getComponent(), player, getTabSyntax() ) - .map(result -> ComponentUtils.serializeToJson(result, player.getProtocolVersion())) - .getResultOrToRemove(() -> EMPTY_COMPONENT); + .getResultOrToRemove(Component::empty) + .map(result -> new ComponentHolder(player.getProtocolVersion(), result)); if (newFooter.isPresent() || newHeader.isPresent()) { return Optional.of( @@ -67,6 +66,10 @@ private FeatureSyntax getTabSyntax() { } public @NotNull Optional handlePlayerListItem(@NotNull LegacyPlayerListItem playerListItemPacket, @NotNull VelocityLanguagePlayer player) { + if (shouldNotTranslateTab()) { + return Optional.of(playerListItemPacket); + } + val items = playerListItemPacket.getItems(); val action = playerListItemPacket.getAction(); @@ -102,6 +105,9 @@ private FeatureSyntax getTabSyntax() { } public @NotNull Optional handleUpsertPlayerInfo(@NotNull UpsertPlayerInfo upsertPlayerInfoPacket, @NotNull VelocityLanguagePlayer player) { + if (shouldNotTranslateTab()) { + return Optional.of(upsertPlayerInfoPacket); + } if (!upsertPlayerInfoPacket.getActions().contains(UpsertPlayerInfo.Action.UPDATE_DISPLAY_NAME)) { return Optional.of(upsertPlayerInfoPacket); } @@ -113,13 +119,13 @@ private FeatureSyntax getTabSyntax() { } parser() .translateComponent( - item.getDisplayName(), + item.getDisplayName().getComponent(), player, getTabSyntax() ) .ifChanged(result -> { - player.cachePlayerListItem(uuid, item.getDisplayName()); - item.setDisplayName(result); + player.cachePlayerListItem(uuid, item.getDisplayName().getComponent()); + item.setDisplayName(new ComponentHolder(player.getProtocolVersion(), result)); }) .ifUnchanged(() -> player.deleteCachedPlayerListItem(uuid)) .ifToRemove(() -> player.deleteCachedPlayerListItem(uuid)); @@ -130,6 +136,9 @@ private FeatureSyntax getTabSyntax() { } public @NotNull Optional handleRemovePlayerInfo(@NotNull RemovePlayerInfo removePlayerInfoPacket, @NotNull VelocityLanguagePlayer player) { + if (shouldNotTranslateTab()) { + return Optional.of(removePlayerInfoPacket); + } for (UUID uuid : removePlayerInfoPacket.getProfilesToRemove()) { player.deleteCachedPlayerListItem(uuid); } diff --git a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/TitleHandler.java b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/TitleHandler.java index aacbc8ca..56807e20 100644 --- a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/TitleHandler.java +++ b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/packetinterceptor/packets/TitleHandler.java @@ -6,6 +6,7 @@ import com.rexcantor64.triton.velocity.player.VelocityLanguagePlayer; import com.rexcantor64.triton.velocity.utils.ComponentUtils; import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import com.velocitypowered.proxy.protocol.packet.title.GenericTitlePacket; import com.velocitypowered.proxy.protocol.packet.title.LegacyTitlePacket; import com.velocitypowered.proxy.protocol.packet.title.TitleActionbarPacket; @@ -52,11 +53,11 @@ private boolean isActionBarPacket(GenericTitlePacket titlePacket) { return Objects.requireNonNull( parser().translateComponent( - ComponentUtils.deserializeFromJson(titlePacket.getComponent(), player.getProtocolVersion()), + titlePacket.getComponent().getComponent(), player, isActionBarPacket ? getActionBarSyntax() : getTitleSyntax() ) - .map(result -> ComponentUtils.serializeToJson(result, player.getProtocolVersion())) + .map(result -> new ComponentHolder(player.getProtocolVersion(), result)) .mapToObj( result -> { titlePacket.setComponent(result); diff --git a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/player/RefreshFeatures.java b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/player/RefreshFeatures.java index 6acec6ad..1e5731fa 100644 --- a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/player/RefreshFeatures.java +++ b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/player/RefreshFeatures.java @@ -7,8 +7,10 @@ import com.velocitypowered.proxy.protocol.packet.HeaderAndFooter; import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItem; import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfo; +import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import lombok.RequiredArgsConstructor; import lombok.val; +import net.kyori.adventure.text.Component; import java.util.EnumSet; import java.util.UUID; @@ -29,11 +31,11 @@ private void refreshBossBars() { player.getCachedBossBars().forEach(this::refreshBossBar); } - private void refreshBossBar(UUID uuid, String json) { + private void refreshBossBar(UUID uuid, Component component) { val bossBarPacket = new BossBar(); bossBarPacket.setUuid(uuid); bossBarPacket.setAction(BossBar.UPDATE_NAME); - bossBarPacket.setName(json); + bossBarPacket.setName(new ComponentHolder(player.getProtocolVersion(), component)); sendPacket(bossBarPacket); } @@ -44,7 +46,10 @@ private void refreshPlayerListHeaderFooter() { if (header == null || footer == null) { return; } - val headerFooterPacket = new HeaderAndFooter(header, footer); + val headerFooterPacket = new HeaderAndFooter( + new ComponentHolder(player.getProtocolVersion(), header), + new ComponentHolder(player.getProtocolVersion(), footer) + ); sendPacket(headerFooterPacket); } @@ -56,7 +61,7 @@ private void refreshPlayerListItems() { .stream() .map(entry -> { val playerEntry = new UpsertPlayerInfo.Entry(entry.getKey()); - playerEntry.setDisplayName(entry.getValue()); + playerEntry.setDisplayName(new ComponentHolder(player.getProtocolVersion(), entry.getValue())); return playerEntry; }) .collect(Collectors.toList()); diff --git a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/player/VelocityLanguagePlayer.java b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/player/VelocityLanguagePlayer.java index d794f73a..2a586d71 100644 --- a/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/player/VelocityLanguagePlayer.java +++ b/triton-velocity/src/main/java/com/rexcantor64/triton/velocity/player/VelocityLanguagePlayer.java @@ -35,11 +35,11 @@ public class VelocityLanguagePlayer implements LanguagePlayer { @Getter(AccessLevel.PACKAGE) @Setter(AccessLevel.PUBLIC) - private String lastTabHeader; + private Component lastTabHeader; @Getter(AccessLevel.PACKAGE) @Setter(AccessLevel.PUBLIC) - private String lastTabFooter; - private final Map bossBars = new HashMap<>(); + private Component lastTabFooter; + private final Map bossBars = new HashMap<>(); private final Map playerListItemCache = new ConcurrentHashMap<>(); private boolean waitingForClientLocale = false; private String clientLocale; @@ -56,7 +56,7 @@ public static VelocityLanguagePlayer fromUUID(UUID uuid) { return player.map(VelocityLanguagePlayer::new).orElse(null); } - public void setBossbar(UUID uuid, String lastBossBar) { + public void setBossbar(UUID uuid, Component lastBossBar) { bossBars.put(uuid, lastBossBar); } @@ -64,7 +64,7 @@ public void removeBossbar(UUID uuid) { bossBars.remove(uuid); } - Map getCachedBossBars() { + Map getCachedBossBars() { return Collections.unmodifiableMap(bossBars); } From aba7a9bedc20b015df7c0f5418dd504dfb0da654 Mon Sep 17 00:00:00 2001 From: Diogo Correia Date: Mon, 18 Dec 2023 17:50:53 +0100 Subject: [PATCH 8/9] fix(spigot): detect velocity modern forwarding for proxy warning (#367) Fixes #328 --- .../triton/spigot/SpigotTriton.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/SpigotTriton.java b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/SpigotTriton.java index 6575fd66..a6a64d3f 100644 --- a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/SpigotTriton.java +++ b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/SpigotTriton.java @@ -114,7 +114,7 @@ public void onEnable() { } if (getConfig().isBungeecord()) { - if (!isSpigotProxyMode()) { + if (!isSpigotProxyMode() && !isPaperProxyMode()) { getLogger().logError("DANGER! DANGER! DANGER!"); getLogger().logError("Proxy mode is enabled on Triton but disabled on Spigot!"); getLogger().logError("A malicious player can run ANY command as the server."); @@ -302,4 +302,27 @@ public boolean isSpigotProxyMode() { return false; } } + + /** + * Use reflection to check if this Paper server has velocity modern forwarding enabled on paper-global.yml. + * This is used to show a warning if Paper is in proxy mode, but the server is not. + * + * @return Whether this Spigot server has velocity forwarding enabled on paper-global.yml. + */ + public boolean isPaperProxyMode() { + try { + Class paperConfigClass = Class.forName("io.papermc.paper.configuration.GlobalConfiguration"); + + Object instance = paperConfigClass.getMethod("get").invoke(null); + Object proxies = instance.getClass().getField("proxies").get(instance); + Object velocity = proxies.getClass().getField("velocity").get(proxies); + Object velocityEnabled = velocity.getClass().getField("enabled").get(velocity); + if (velocityEnabled == null) { + return false; + } + return (boolean) velocityEnabled; + } catch (Exception e) { + return false; + } + } } From 921977048572e6be097b39b8a7a376e7926899e0 Mon Sep 17 00:00:00 2001 From: Diogo Correia Date: Mon, 18 Dec 2023 18:12:42 +0100 Subject: [PATCH 9/9] refactor(spigot): use mc version field to detect protocollib version (#368) Closes #362 --- .../rexcantor64/triton/spigot/SpigotTriton.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/SpigotTriton.java b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/SpigotTriton.java index a6a64d3f..44180fc7 100644 --- a/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/SpigotTriton.java +++ b/triton-spigot/src/main/java/com/rexcantor64/triton/spigot/SpigotTriton.java @@ -1,6 +1,7 @@ package com.rexcantor64.triton.spigot; import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.utility.MinecraftVersion; import com.rexcantor64.triton.Triton; import com.rexcantor64.triton.api.players.LanguagePlayer; import com.rexcantor64.triton.player.PlayerManager; @@ -168,7 +169,7 @@ protected void startConfigRefreshTask() { /** * Checks if ProtocolLib is enabled and if its version matches * the expected version. - * Triton requires ProtocolLib 5.1.0 or later. + * Triton requires ProtocolLib 5.2.0 or later. * * @return Whether the plugin should continue loading * @since 3.8.2 @@ -185,13 +186,11 @@ private boolean isProtocolLibAvailable() { return true; } - val version = protocolLib.getDescription().getVersion(); - val versionParts = version.split("\\."); - val majorVersion = Integer.parseInt(versionParts[0]); - val minorVersion = Integer.parseInt(versionParts[1]); - if (majorVersion < 5 || (majorVersion == 5 && minorVersion < 1)) { - // Triton requires ProtocolLib 5.1.0 or later - getLogger().logError("ProtocolLib 5.1.0 or later is required! Older versions of ProtocolLib will only partially work, and are therefore not recommended."); + try { + MinecraftVersion ignore = MinecraftVersion.v1_20_4; + } catch (NoSuchFieldError ignore) { + // Triton requires ProtocolLib 5.2.0 or later + getLogger().logError("ProtocolLib 5.2.0 or later is required! Older versions of ProtocolLib will only partially work or not work at all, and are therefore not recommended."); getLogger().logError("If you want to enable the plugin anyway, add `i-know-what-i-am-doing: true` to Triton's config.yml."); return false; }