diff --git a/build.gradle b/build.gradle index e36fb281..7c95618c 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/' - } maven { // Mirror other people's repositories name 'diogotcRepositoryMirror' 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 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..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; @@ -114,7 +115,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."); @@ -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; } @@ -302,4 +301,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; + } + } } 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..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 @@ -75,10 +75,14 @@ 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; + 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(); @@ -110,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"; @@ -161,6 +166,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)); @@ -276,6 +287,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; @@ -283,6 +295,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) { @@ -306,6 +320,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)); } @@ -721,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( @@ -815,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() @@ -891,6 +914,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 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. */ 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); }