From a3a6b3fd07082afc5c153d4d7f5cf64e9446b291 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Fri, 22 Dec 2023 02:29:36 -0800 Subject: [PATCH] Correctly version component serialization 1.20.3+ has some additional options (EMIT_COMPACT_TEXT_COMPONENT, EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, VALIDATE_STRICT_EVENTS) that should be disabled in older versions. The OptionState is constructed manually due to https://github.com/KyoriPowered/adventure/issues/1015, which is a bug that makes JSONOptions.BY_DATA_VERSION use incorrect options for 1.20.3+ options. This also fixes incorrect building of the ping serializer, as it should only use the component serializer to serialize Component.class and nothing else. --- .../velocitypowered/proxy/VelocityServer.java | 35 ++++++++++----- .../proxy/protocol/ProtocolUtils.java | 44 ++++++++++++++++++- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index 76d087fab..f113164b8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -116,16 +116,28 @@ public class VelocityServer implements ProxyServer, ForwardingAudience { .registerTypeHierarchyAdapter(Favicon.class, FaviconSerializer.INSTANCE) .registerTypeHierarchyAdapter(GameProfile.class, GameProfileSerializer.INSTANCE) .create(); - private static final Gson PRE_1_16_PING_SERIALIZER = ProtocolUtils - .getJsonChatSerializer(ProtocolVersion.MINECRAFT_1_15_2) - .serializer() - .newBuilder() + private static final Gson PRE_1_16_PING_SERIALIZER = new GsonBuilder() + .registerTypeHierarchyAdapter( + Component.class, + ProtocolUtils.getJsonChatSerializer(ProtocolVersion.MINECRAFT_1_15_2) + .serializer().getAdapter(Component.class) + ) .registerTypeHierarchyAdapter(Favicon.class, FaviconSerializer.INSTANCE) .create(); - private static final Gson POST_1_16_PING_SERIALIZER = ProtocolUtils - .getJsonChatSerializer(ProtocolVersion.MINECRAFT_1_16) - .serializer() - .newBuilder() + private static final Gson PRE_1_20_3_PING_SERIALIZER = new GsonBuilder() + .registerTypeHierarchyAdapter( + Component.class, + ProtocolUtils.getJsonChatSerializer(ProtocolVersion.MINECRAFT_1_20_2) + .serializer().getAdapter(Component.class) + ) + .registerTypeHierarchyAdapter(Favicon.class, FaviconSerializer.INSTANCE) + .create(); + private static final Gson MODERN_PING_SERIALIZER = new GsonBuilder() + .registerTypeHierarchyAdapter( + Component.class, + ProtocolUtils.getJsonChatSerializer(ProtocolVersion.MINECRAFT_1_20_3) + .serializer().getAdapter(Component.class) + ) .registerTypeHierarchyAdapter(Favicon.class, FaviconSerializer.INSTANCE) .create(); @@ -762,8 +774,11 @@ public class VelocityServer implements ProxyServer, ForwardingAudience { */ public static Gson getPingGsonInstance(ProtocolVersion version) { if (version == ProtocolVersion.UNKNOWN - || version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) { - return POST_1_16_PING_SERIALIZER; + || version.compareTo(ProtocolVersion.MINECRAFT_1_20_3) >= 0) { + return MODERN_PING_SERIALIZER; + } + if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) { + return PRE_1_20_3_PING_SERIALIZER; } return PRE_1_16_PING_SERIALIZER; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index bd1e6257f..04a609e93 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -46,6 +46,8 @@ import net.kyori.adventure.nbt.BinaryTagType; import net.kyori.adventure.nbt.BinaryTagTypes; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.kyori.adventure.text.serializer.json.JSONOptions; +import net.kyori.option.OptionState; /** * Utilities for writing and reading data in the Minecraft protocol. @@ -58,10 +60,47 @@ public enum ProtocolUtils { .downsampleColors() .emitLegacyHoverEvent() .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) + .options( + OptionState.optionState() + // before 1.16 + .value(JSONOptions.EMIT_RGB, Boolean.FALSE) + .value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.LEGACY_ONLY) + // before 1.20.3 + .value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.FALSE) + .value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.FALSE) + .value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.FALSE) + .build() + ) + .build(); + private static final GsonComponentSerializer PRE_1_20_3_SERIALIZER = + GsonComponentSerializer.builder() + .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) + .options( + OptionState.optionState() + // after 1.16 + .value(JSONOptions.EMIT_RGB, Boolean.TRUE) + .value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.MODERN_ONLY) + // before 1.20.3 + .value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.FALSE) + .value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.FALSE) + .value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.FALSE) + .build() + ) .build(); private static final GsonComponentSerializer MODERN_SERIALIZER = GsonComponentSerializer.builder() .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) + .options( + OptionState.optionState() + // after 1.16 + .value(JSONOptions.EMIT_RGB, Boolean.TRUE) + .value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.MODERN_ONLY) + // after 1.20.3 + .value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.TRUE) + .value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.TRUE) + .value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.TRUE) + .build() + ) .build(); public static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB @@ -671,9 +710,12 @@ public enum ProtocolUtils { * @return the appropriate {@link GsonComponentSerializer} */ public static GsonComponentSerializer getJsonChatSerializer(ProtocolVersion version) { - if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) { + if (version.compareTo(ProtocolVersion.MINECRAFT_1_20_3) >= 0) { return MODERN_SERIALIZER; } + if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) { + return PRE_1_20_3_SERIALIZER; + } return PRE_1_16_SERIALIZER; }