From 86be7be31529de3f2efd3e7d0c9d00555f3237ef Mon Sep 17 00:00:00 2001 From: 56738 Date: Wed, 6 Dec 2023 10:16:56 +0100 Subject: [PATCH 1/2] Fix MinecraftComponentSerializer on 1.20.3 --- .../bukkit/MinecraftComponentSerializer.java | 85 +++++++++++++------ 1 file changed, 58 insertions(+), 27 deletions(-) diff --git a/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/MinecraftComponentSerializer.java b/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/MinecraftComponentSerializer.java index f46539b8..1628fa31 100644 --- a/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/MinecraftComponentSerializer.java +++ b/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/MinecraftComponentSerializer.java @@ -34,7 +34,6 @@ import java.util.concurrent.atomic.AtomicReference; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.ComponentSerializer; -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -93,11 +92,15 @@ public static boolean isSupported() { private static final Object MC_TEXT_GSON; private static final MethodHandle TEXT_SERIALIZER_DESERIALIZE; private static final MethodHandle TEXT_SERIALIZER_SERIALIZE; + private static final MethodHandle TEXT_SERIALIZER_DESERIALIZE_TREE; + private static final MethodHandle TEXT_SERIALIZER_SERIALIZE_TREE; static { Object gson = null; MethodHandle textSerializerDeserialize = null; MethodHandle textSerializerSerialize = null; + MethodHandle textSerializerDeserializeTree = null; + MethodHandle textSerializerSerializeTree = null; try { if (CLASS_CHAT_COMPONENT != null) { @@ -126,26 +129,45 @@ public static boolean isSupported() { if (gsonField != null) { gsonField.setAccessible(true); gson = gsonField.get(null); - } else { - final Method[] declaredMethods = chatSerializerClass.getDeclaredMethods(); - final Method deserialize = Arrays.stream(declaredMethods) - .filter(m -> Modifier.isStatic(m.getModifiers())) - .filter(m -> CLASS_CHAT_COMPONENT.isAssignableFrom(m.getReturnType())) - .filter(m -> m.getParameterCount() == 1 && m.getParameterTypes()[0].equals(String.class)) - .min(Comparator.comparing(Method::getName)) // prefer the #a method - .orElse(null); - final Method serialize = Arrays.stream(declaredMethods) - .filter(m -> Modifier.isStatic(m.getModifiers())) - .filter(m -> m.getReturnType().equals(String.class)) - .filter(m -> m.getParameterCount() == 1 && CLASS_CHAT_COMPONENT.isAssignableFrom(m.getParameterTypes()[0])) - .findFirst() - .orElse(null); - if (deserialize != null) { - textSerializerDeserialize = lookup().unreflect(deserialize); - } - if (serialize != null) { - textSerializerSerialize = lookup().unreflect(serialize); - } + } + } + for (final Class serializerClass : CLASS_CHAT_COMPONENT.getClasses()) { + final Method[] declaredMethods = serializerClass.getDeclaredMethods(); + final Method deserialize = Arrays.stream(declaredMethods) + .filter(m -> Modifier.isStatic(m.getModifiers())) + .filter(m -> CLASS_CHAT_COMPONENT.isAssignableFrom(m.getReturnType())) + .filter(m -> m.getParameterCount() == 1 && m.getParameterTypes()[0].equals(String.class)) + .min(Comparator.comparing(Method::getName)) // prefer the #a method + .orElse(null); + final Method serialize = Arrays.stream(declaredMethods) + .filter(m -> Modifier.isStatic(m.getModifiers())) + .filter(m -> m.getReturnType().equals(String.class)) + .filter(m -> m.getParameterCount() == 1 && CLASS_CHAT_COMPONENT.isAssignableFrom(m.getParameterTypes()[0])) + .findFirst() + .orElse(null); + final Method deserializeTree = Arrays.stream(declaredMethods) + .filter(m -> Modifier.isStatic(m.getModifiers())) + .filter(m -> CLASS_CHAT_COMPONENT.isAssignableFrom(m.getReturnType())) + .filter(m -> m.getParameterCount() == 1 && m.getParameterTypes()[0].equals(JsonElement.class)) + .findFirst() + .orElse(null); + final Method serializeTree = Arrays.stream(declaredMethods) + .filter(m -> Modifier.isStatic(m.getModifiers())) + .filter(m -> m.getReturnType().equals(JsonElement.class)) + .filter(m -> m.getParameterCount() == 1 && CLASS_CHAT_COMPONENT.isAssignableFrom(m.getParameterTypes()[0])) + .findFirst() + .orElse(null); + if (deserialize != null) { + textSerializerDeserialize = lookup().unreflect(deserialize); + } + if (serialize != null) { + textSerializerSerialize = lookup().unreflect(serialize); + } + if (deserializeTree != null) { + textSerializerDeserializeTree = lookup().unreflect(deserializeTree); + } + if (serializeTree != null) { + textSerializerSerializeTree = lookup().unreflect(serializeTree); } } } @@ -156,20 +178,26 @@ public static boolean isSupported() { MC_TEXT_GSON = gson; TEXT_SERIALIZER_DESERIALIZE = textSerializerDeserialize; TEXT_SERIALIZER_SERIALIZE = textSerializerSerialize; + TEXT_SERIALIZER_DESERIALIZE_TREE = textSerializerDeserializeTree; + TEXT_SERIALIZER_SERIALIZE_TREE = textSerializerSerializeTree; } - private static final boolean SUPPORTED = MC_TEXT_GSON != null || (TEXT_SERIALIZER_DESERIALIZE != null && TEXT_SERIALIZER_SERIALIZE != null); + private static final boolean SUPPORTED = MC_TEXT_GSON != null || (TEXT_SERIALIZER_DESERIALIZE != null && TEXT_SERIALIZER_SERIALIZE != null) || (TEXT_SERIALIZER_DESERIALIZE_TREE != null && TEXT_SERIALIZER_SERIALIZE_TREE != null); @Override public @NotNull Component deserialize(final @NotNull Object input) { if (!SUPPORTED) throw INITIALIZATION_ERROR.get(); try { - if (MC_TEXT_GSON != null) { - final JsonElement element = ((Gson) MC_TEXT_GSON).toJsonTree(input); - return gson().serializer().fromJson(element, Component.class); + final JsonElement element; + if (TEXT_SERIALIZER_SERIALIZE_TREE != null) { + element = (JsonElement) TEXT_SERIALIZER_SERIALIZE_TREE.invoke(input); + } else if (MC_TEXT_GSON != null) { + element = ((Gson) MC_TEXT_GSON).toJsonTree(input); + } else { + return gson().deserialize((String) TEXT_SERIALIZER_SERIALIZE.invoke(input)); } - return GsonComponentSerializer.gson().deserialize((String) TEXT_SERIALIZER_SERIALIZE.invoke(input)); + return gson().serializer().fromJson(element, Component.class); } catch (final Throwable error) { throw new UnsupportedOperationException(error); } @@ -179,9 +207,12 @@ public static boolean isSupported() { public @NotNull Object serialize(final @NotNull Component component) { if (!SUPPORTED) throw INITIALIZATION_ERROR.get(); - if (MC_TEXT_GSON != null) { + if (TEXT_SERIALIZER_DESERIALIZE_TREE != null || MC_TEXT_GSON != null) { final JsonElement json = gson().serializer().toJsonTree(component); try { + if (TEXT_SERIALIZER_DESERIALIZE_TREE != null) { + return TEXT_SERIALIZER_DESERIALIZE_TREE.invoke(json); + } return ((Gson) MC_TEXT_GSON).fromJson(json, CLASS_CHAT_COMPONENT); } catch (final Throwable error) { throw new UnsupportedOperationException(error); From aab58dd6ba557a64064fc45451b679893e8a8e82 Mon Sep 17 00:00:00 2001 From: 56738 Date: Wed, 20 Dec 2023 20:40:18 +0100 Subject: [PATCH 2/2] Fix Bukkit 1.7.10 support --- .../adventure/platform/bukkit/CraftBukkitFacet.java | 6 ++++-- .../platform/bukkit/MinecraftComponentSerializer.java | 9 ++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/CraftBukkitFacet.java b/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/CraftBukkitFacet.java index 67cdabaf..8a84ae5d 100644 --- a/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/CraftBukkitFacet.java +++ b/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/CraftBukkitFacet.java @@ -259,8 +259,10 @@ public Object createMessage(final @NotNull V viewer, final @NotNull Component me findMcClassName("network.protocol.game.ClientboundChatPacket"), findMcClassName("network.protocol.game.ClientboundSystemChatPacket") ); - // ClientboundSystemChatPacket constructor changed for 1.19.1 - chatPacketConstructor = findConstructor(chatPacketClass, CLASS_CHAT_COMPONENT, boolean.class); + if (MESSAGE_TYPE_CHAT == Integer.valueOf(0)) { + // ClientboundSystemChatPacket constructor changed for 1.19.1 + chatPacketConstructor = findConstructor(chatPacketClass, CLASS_CHAT_COMPONENT, boolean.class); + } if (chatPacketConstructor == null) { // ClientboundSystemChatPacket constructor changed for 1.19 chatPacketConstructor = findConstructor(chatPacketClass, CLASS_CHAT_COMPONENT, int.class); diff --git a/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/MinecraftComponentSerializer.java b/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/MinecraftComponentSerializer.java index 1628fa31..ecfd5a81 100644 --- a/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/MinecraftComponentSerializer.java +++ b/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/MinecraftComponentSerializer.java @@ -29,8 +29,10 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.List; import java.util.concurrent.atomic.AtomicReference; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.ComponentSerializer; @@ -131,7 +133,12 @@ public static boolean isSupported() { gson = gsonField.get(null); } } - for (final Class serializerClass : CLASS_CHAT_COMPONENT.getClasses()) { + final List> candidates = new ArrayList<>(); + if (chatSerializerClass != null) { + candidates.add(chatSerializerClass); + } + candidates.addAll(Arrays.asList(CLASS_CHAT_COMPONENT.getClasses())); + for (final Class serializerClass : candidates) { final Method[] declaredMethods = serializerClass.getDeclaredMethods(); final Method deserialize = Arrays.stream(declaredMethods) .filter(m -> Modifier.isStatic(m.getModifiers()))