Skip to content

Commit 362a435

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

File tree

1 file changed

+77
-1
lines changed

1 file changed

+77
-1
lines changed

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

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,36 +89,57 @@ public static boolean isSupported() {
8989

9090
private static final @Nullable Class<?> CLASS_JSON_DESERIALIZER = findClass("com.goo".concat("gle.gson.JsonDeserializer")); // Hide from relocation checkers
9191
private static final @Nullable Class<?> CLASS_JSON_ELEMENT = findClass("com.goo".concat("gle.gson.JsonElement"));
92+
private static final @Nullable Class<?> CLASS_JSON_OPS = findClass("com.mo".concat("jang.serialization.JsonOps"));
9293
private static final @Nullable Class<?> CLASS_JSON_PARSER = findClass("com.goo".concat("gle.gson.JsonParser"));
9394
private static final @Nullable Class<?> CLASS_CHAT_COMPONENT = findClass(
9495
findNmsClassName("IChatBaseComponent"),
9596
findMcClassName("network.chat.IChatBaseComponent"),
9697
findMcClassName("network.chat.Component")
9798
);
99+
private static final @Nullable Class<?> CLASS_COMPONENT_SERIALIZATION = findClass(findMcClassName("network.chat.ComponentSerialization"));
98100
private static final @Nullable Class<?> CLASS_CRAFT_REGISTRY = findCraftClass("CraftRegistry");
101+
private static final @Nullable Class<?> CLASS_HOLDERLOOKUP_PROVIDER = findClass(
102+
findMcClassName("core.HolderLookup$Provider"), // Paper mapping
103+
findMcClassName("core.HolderLookup$a") // Spigot mapping
104+
);
99105
private static final @Nullable Class<?> CLASS_REGISTRY_ACCESS = findClass(
100106
findMcClassName("core.IRegistryCustom"),
101107
findMcClassName("core.RegistryAccess")
102108
);
103109
private static final @Nullable MethodHandle PARSE_JSON = findMethod(CLASS_JSON_PARSER, "parse", CLASS_JSON_ELEMENT, String.class);
104110
private static final @Nullable MethodHandle GET_REGISTRY = findStaticMethod(CLASS_CRAFT_REGISTRY, "getMinecraftRegistry", CLASS_REGISTRY_ACCESS);
105111
private static final AtomicReference<RuntimeException> INITIALIZATION_ERROR = new AtomicReference<>(new UnsupportedOperationException());
112+
private static final Object JSON_OPS_INSTANCE;
106113
private static final Object JSON_PARSER_INSTANCE;
107114
private static final Object MC_TEXT_GSON;
108115
private static final MethodHandle TEXT_SERIALIZER_DESERIALIZE;
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;
126+
Object jsonOpsInstance = null;
115127
Object jsonParserInstance = null;
116128
MethodHandle textSerializerDeserialize = null;
117129
MethodHandle textSerializerSerialize = null;
118130
MethodHandle textSerializerDeserializeTree = null;
119131
MethodHandle textSerializerSerializeTree = null;
132+
MethodHandle codecEncode = null;
133+
MethodHandle codecDecode = null;
134+
Object registryAccessEmpty = null;
135+
MethodHandle createContext = null;
120136

121137
try {
138+
if (CLASS_JSON_OPS != null) {
139+
final Field instanceField = CLASS_JSON_OPS.getField("INSTANCE");
140+
instanceField.setAccessible(true);
141+
jsonOpsInstance = instanceField.get(null);
142+
}
122143
if (CLASS_JSON_PARSER != null) {
123144
jsonParserInstance = CLASS_JSON_PARSER.getDeclaredConstructor().newInstance();
124145
}
@@ -218,19 +239,60 @@ public static boolean isSupported() {
218239
}
219240
}
220241
}
242+
if (CLASS_REGISTRY_ACCESS != null) {
243+
for (final Field field : CLASS_REGISTRY_ACCESS.getDeclaredFields()) {
244+
field.setAccessible(true);
245+
if (Modifier.isStatic(field.getModifiers()) && CLASS_REGISTRY_ACCESS.isAssignableFrom(field.getType())) {
246+
registryAccessEmpty = field.get(null);
247+
break;
248+
}
249+
}
250+
if (registryAccessEmpty != null && CLASS_HOLDERLOOKUP_PROVIDER != null) {
251+
for (final Method m : CLASS_HOLDERLOOKUP_PROVIDER.getDeclaredMethods()) {
252+
m.setAccessible(true);
253+
if (m.getParameterCount() == 1 && m.getParameterTypes()[0].getSimpleName().equals("DynamicOps") && m.getReturnType().getSimpleName().contains("RegistryOps")) {
254+
createContext = lookup().unreflect(m).bindTo(registryAccessEmpty);
255+
break;
256+
}
257+
}
258+
}
259+
}
260+
if (CLASS_COMPONENT_SERIALIZATION != null) {
261+
for (final Field f : CLASS_COMPONENT_SERIALIZATION.getDeclaredFields()) {
262+
if (Modifier.isStatic(f.getModifiers()) && f.getType().getSimpleName().equals("Codec")) {
263+
f.setAccessible(true);
264+
final Object codecInstance = f.get(null);
265+
final Class<?> codecClass = codecInstance.getClass();
266+
for (final Method m : codecClass.getDeclaredMethods()) {
267+
if (m.getName().equals("decode")) {
268+
codecDecode = lookup().unreflect(m).bindTo(codecInstance);
269+
} else if (m.getName().equals("encode")) {
270+
codecEncode = lookup().unreflect(m).bindTo(codecInstance);
271+
}
272+
}
273+
break;
274+
}
275+
}
276+
}
277+
221278
} catch (final Throwable error) {
222279
INITIALIZATION_ERROR.set(new UnsupportedOperationException("Error occurred during initialization", error));
223280
}
224281

225282
MC_TEXT_GSON = gson;
283+
JSON_OPS_INSTANCE = jsonOpsInstance;
226284
JSON_PARSER_INSTANCE = jsonParserInstance;
227285
TEXT_SERIALIZER_DESERIALIZE = textSerializerDeserialize;
228286
TEXT_SERIALIZER_SERIALIZE = textSerializerSerialize;
229287
TEXT_SERIALIZER_DESERIALIZE_TREE = textSerializerDeserializeTree;
230288
TEXT_SERIALIZER_SERIALIZE_TREE = textSerializerSerializeTree;
289+
COMPONENTSERIALIZATION_CODEC_ENCODE = codecEncode;
290+
COMPONENTSERIALIZATION_CODEC_DECODE = codecDecode;
291+
REGISTRY_ACCESS_EMPTY = registryAccessEmpty;
292+
CREATE_SERIALIZATION_CONTEXT = createContext;
231293
}
232294

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);
295+
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 && JSON_OPS_INSTANCE != null);
234296

235297
@Override
236298
public @NotNull Component deserialize(final @NotNull Object input) {
@@ -242,6 +304,12 @@ public static boolean isSupported() {
242304
element = TEXT_SERIALIZER_SERIALIZE_TREE.invoke(input);
243305
} else if (MC_TEXT_GSON != null) {
244306
element = ((Gson) MC_TEXT_GSON).toJsonTree(input);
307+
} else if (COMPONENTSERIALIZATION_CODEC_ENCODE != null && REGISTRY_ACCESS_EMPTY != null && CREATE_SERIALIZATION_CONTEXT != null) {
308+
final Object serializationContext = CREATE_SERIALIZATION_CONTEXT.invoke(REGISTRY_ACCESS_EMPTY, JSON_OPS_INSTANCE);
309+
final Object result = COMPONENTSERIALIZATION_CODEC_ENCODE.invoke(serializationContext, input, null);
310+
final Method getOrThrow = result.getClass().getMethod("getOrThrow", java.util.function.Function.class);
311+
final Object jsonElement = getOrThrow.invoke(result, (java.util.function.Function<Throwable, RuntimeException>) RuntimeException::new);
312+
return gson().serializer().fromJson(jsonElement.toString(), Component.class);
245313
} else {
246314
return gson().deserialize((String) TEXT_SERIALIZER_SERIALIZE.invoke(input));
247315
}
@@ -268,6 +336,14 @@ public static boolean isSupported() {
268336
}
269337
} else {
270338
try {
339+
if (COMPONENTSERIALIZATION_CODEC_DECODE != null && REGISTRY_ACCESS_EMPTY != null && CREATE_SERIALIZATION_CONTEXT != null) {
340+
final Object serializationContext = CREATE_SERIALIZATION_CONTEXT.invoke(JSON_OPS_INSTANCE);
341+
final Object result = COMPONENTSERIALIZATION_CODEC_DECODE.invoke(serializationContext, gson().serializeToTree(component));
342+
final Method getOrThrow = result.getClass().getMethod("getOrThrow", java.util.function.Function.class);
343+
final Object pair = getOrThrow.invoke(result, (java.util.function.Function<Throwable, RuntimeException>) RuntimeException::new);
344+
final Method getFirst = pair.getClass().getMethod("getFirst");
345+
return getFirst.invoke(pair);
346+
}
271347
return TEXT_SERIALIZER_DESERIALIZE.invoke(gson().serialize(component));
272348
} catch (final Throwable error) {
273349
throw new UnsupportedOperationException(error);

0 commit comments

Comments
 (0)