Skip to content

Commit b9f2b85

Browse files
committed
Add Bukkit 1.21.6 support
1 parent 7ece7ac commit b9f2b85

File tree

1 file changed

+72
-1
lines changed

1 file changed

+72
-1
lines changed

platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/MinecraftComponentSerializer.java

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import java.lang.reflect.Field;
3030
import java.lang.reflect.Method;
3131
import java.lang.reflect.Modifier;
32+
import java.lang.reflect.ParameterizedType;
33+
import java.lang.reflect.Type;
3234
import java.util.ArrayList;
3335
import java.util.Arrays;
3436
import java.util.Comparator;
@@ -95,7 +97,12 @@ public static boolean isSupported() {
9597
findMcClassName("network.chat.IChatBaseComponent"),
9698
findMcClassName("network.chat.Component")
9799
);
100+
private static final @Nullable Class<?> CLASS_COMPONENT_SERIALIZATION = findClass(findMcClassName("network.chat.ComponentSerialization"));
98101
private static final @Nullable Class<?> CLASS_CRAFT_REGISTRY = findCraftClass("CraftRegistry");
102+
private static final @Nullable Class<?> CLASS_HOLDERLOOKUP_PROVIDER = findClass(
103+
findMcClassName("core.HolderLookup$Provider"), // Paper mapping
104+
findMcClassName("core.HolderLookup$a") // Spigot mapping
105+
);
99106
private static final @Nullable Class<?> CLASS_REGISTRY_ACCESS = findClass(
100107
findMcClassName("core.IRegistryCustom"),
101108
findMcClassName("core.RegistryAccess")
@@ -109,6 +116,10 @@ public static boolean isSupported() {
109116
private static final MethodHandle TEXT_SERIALIZER_SERIALIZE;
110117
private static final MethodHandle TEXT_SERIALIZER_DESERIALIZE_TREE;
111118
private static final MethodHandle TEXT_SERIALIZER_SERIALIZE_TREE;
119+
private static final MethodHandle COMPONENTSERIALIZATION_CODEC_ENCODE;
120+
private static final MethodHandle COMPONENTSERIALIZATION_CODEC_DECODE;
121+
private static final Object REGISTRY_ACCESS_EMPTY;
122+
private static final MethodHandle CREATE_SERIALIZATION_CONTEXT;
112123

113124
static {
114125
Object gson = null;
@@ -117,6 +128,10 @@ public static boolean isSupported() {
117128
MethodHandle textSerializerSerialize = null;
118129
MethodHandle textSerializerDeserializeTree = null;
119130
MethodHandle textSerializerSerializeTree = null;
131+
MethodHandle codecEncode = null;
132+
MethodHandle codecDecode = null;
133+
Object registryAccessEmpty = null;
134+
MethodHandle createContext = null;
120135

121136
try {
122137
if (CLASS_JSON_PARSER != null) {
@@ -218,6 +233,42 @@ public static boolean isSupported() {
218233
}
219234
}
220235
}
236+
if (CLASS_REGISTRY_ACCESS != null) {
237+
for (Field field : CLASS_REGISTRY_ACCESS.getDeclaredFields()) {
238+
field.setAccessible(true);
239+
if (Modifier.isStatic(field.getModifiers()) && CLASS_REGISTRY_ACCESS.isAssignableFrom(field.getType())) {
240+
registryAccessEmpty = field.get(null);
241+
break;
242+
}
243+
}
244+
if (registryAccessEmpty != null && CLASS_HOLDERLOOKUP_PROVIDER != null) {
245+
for (Method m : CLASS_HOLDERLOOKUP_PROVIDER.getDeclaredMethods()) {
246+
m.setAccessible(true);
247+
if (m.getParameterCount() == 1 && m.getParameterTypes()[0].getSimpleName().equals("DynamicOps") && m.getReturnType().getSimpleName().contains("RegistryOps")) {
248+
createContext = lookup().unreflect(m).bindTo(registryAccessEmpty);
249+
break;
250+
}
251+
}
252+
}
253+
}
254+
if (CLASS_COMPONENT_SERIALIZATION != null) {
255+
for (Field f : CLASS_COMPONENT_SERIALIZATION.getDeclaredFields()) {
256+
if (Modifier.isStatic(f.getModifiers()) && f.getType().getSimpleName().equals("Codec")) {
257+
f.setAccessible(true);
258+
Object codecInstance = f.get(null);
259+
Class<?> codecClass = codecInstance.getClass();
260+
for (Method m : codecClass.getDeclaredMethods()) {
261+
if (m.getName().equals("decode")) {
262+
codecDecode = lookup().unreflect(m).bindTo(codecInstance);
263+
} else if (m.getName().equals("encode")) {
264+
codecEncode = lookup().unreflect(m).bindTo(codecInstance);
265+
}
266+
}
267+
break;
268+
}
269+
}
270+
}
271+
221272
} catch (final Throwable error) {
222273
INITIALIZATION_ERROR.set(new UnsupportedOperationException("Error occurred during initialization", error));
223274
}
@@ -228,9 +279,13 @@ public static boolean isSupported() {
228279
TEXT_SERIALIZER_SERIALIZE = textSerializerSerialize;
229280
TEXT_SERIALIZER_DESERIALIZE_TREE = textSerializerDeserializeTree;
230281
TEXT_SERIALIZER_SERIALIZE_TREE = textSerializerSerializeTree;
282+
COMPONENTSERIALIZATION_CODEC_ENCODE = codecEncode;
283+
COMPONENTSERIALIZATION_CODEC_DECODE = codecDecode;
284+
REGISTRY_ACCESS_EMPTY = registryAccessEmpty;
285+
CREATE_SERIALIZATION_CONTEXT = createContext;
231286
}
232287

233-
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);
288+
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) || (COMPONENTSERIALIZATION_CODEC_ENCODE != null && COMPONENTSERIALIZATION_CODEC_DECODE != null && REGISTRY_ACCESS_EMPTY != null && CREATE_SERIALIZATION_CONTEXT != null);
234289

235290
@Override
236291
public @NotNull Component deserialize(final @NotNull Object input) {
@@ -242,6 +297,13 @@ public static boolean isSupported() {
242297
element = TEXT_SERIALIZER_SERIALIZE_TREE.invoke(input);
243298
} else if (MC_TEXT_GSON != null) {
244299
element = ((Gson) MC_TEXT_GSON).toJsonTree(input);
300+
} else if (COMPONENTSERIALIZATION_CODEC_ENCODE != null && REGISTRY_ACCESS_EMPTY != null && CREATE_SERIALIZATION_CONTEXT != null) {
301+
final Object jsonOps = Class.forName("com.mojang.serialization.JsonOps").getField("INSTANCE").get(null);
302+
final Object serializationContext = CREATE_SERIALIZATION_CONTEXT.invoke(REGISTRY_ACCESS_EMPTY, jsonOps);
303+
Object result = COMPONENTSERIALIZATION_CODEC_ENCODE.invoke(serializationContext, input, null);
304+
Method getOrThrow = result.getClass().getMethod("getOrThrow", java.util.function.Function.class);
305+
Object jsonElement = getOrThrow.invoke(result, (java.util.function.Function<Throwable, RuntimeException>) RuntimeException::new);
306+
return gson().serializer().fromJson(jsonElement.toString(), Component.class);
245307
} else {
246308
return gson().deserialize((String) TEXT_SERIALIZER_SERIALIZE.invoke(input));
247309
}
@@ -268,6 +330,15 @@ public static boolean isSupported() {
268330
}
269331
} else {
270332
try {
333+
if (COMPONENTSERIALIZATION_CODEC_DECODE != null && REGISTRY_ACCESS_EMPTY != null && CREATE_SERIALIZATION_CONTEXT != null) {
334+
final Object jsonOps = Class.forName("com.mojang.serialization.JsonOps").getField("INSTANCE").get(null);
335+
final Object serializationContext = CREATE_SERIALIZATION_CONTEXT.invoke(jsonOps);
336+
Object result = COMPONENTSERIALIZATION_CODEC_DECODE.invoke(serializationContext, gson().serializeToTree(component));
337+
Method getOrThrow = result.getClass().getMethod("getOrThrow", java.util.function.Function.class);
338+
Object pair = getOrThrow.invoke(result, (java.util.function.Function<Throwable, RuntimeException>) RuntimeException::new);
339+
Method getFirst = pair.getClass().getMethod("getFirst");
340+
return getFirst.invoke(pair);
341+
}
271342
return TEXT_SERIALIZER_DESERIALIZE.invoke(gson().serialize(component));
272343
} catch (final Throwable error) {
273344
throw new UnsupportedOperationException(error);

0 commit comments

Comments
 (0)