Skip to content

Commit bbbb799

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

File tree

1 file changed

+64
-1
lines changed

1 file changed

+64
-1
lines changed

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

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,36 +89,55 @@ 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 MethodHandle CREATE_SERIALIZATION_CONTEXT;
112122

113123
static {
114124
Object gson = null;
125+
Object jsonOpsInstance = null;
115126
Object jsonParserInstance = null;
116127
MethodHandle textSerializerDeserialize = null;
117128
MethodHandle textSerializerSerialize = null;
118129
MethodHandle textSerializerDeserializeTree = null;
119130
MethodHandle textSerializerSerializeTree = null;
131+
MethodHandle codecEncode = null;
132+
MethodHandle codecDecode = null;
133+
MethodHandle createContext = null;
120134

121135
try {
136+
if (CLASS_JSON_OPS != null) {
137+
final Field instanceField = CLASS_JSON_OPS.getField("INSTANCE");
138+
instanceField.setAccessible(true);
139+
jsonOpsInstance = instanceField.get(null);
140+
}
122141
if (CLASS_JSON_PARSER != null) {
123142
jsonParserInstance = CLASS_JSON_PARSER.getDeclaredConstructor().newInstance();
124143
}
@@ -217,20 +236,50 @@ public static boolean isSupported() {
217236
textSerializerSerializeTree = insertArguments(lookup().unreflect(serializeTreeWithRegistryAccess), 1, registryAccess);
218237
}
219238
}
239+
if (registryAccess != null && CLASS_HOLDERLOOKUP_PROVIDER != null) {
240+
for (final Method m : CLASS_HOLDERLOOKUP_PROVIDER.getDeclaredMethods()) {
241+
m.setAccessible(true);
242+
if (m.getParameterCount() == 1 && m.getParameterTypes()[0].getSimpleName().equals("DynamicOps") && m.getReturnType().getSimpleName().contains("RegistryOps")) {
243+
createContext = lookup().unreflect(m).bindTo(registryAccess);
244+
break;
245+
}
246+
}
247+
}
248+
if (CLASS_COMPONENT_SERIALIZATION != null) {
249+
for (final Field f : CLASS_COMPONENT_SERIALIZATION.getDeclaredFields()) {
250+
if (Modifier.isStatic(f.getModifiers()) && f.getType().getSimpleName().equals("Codec")) {
251+
f.setAccessible(true);
252+
final Object codecInstance = f.get(null);
253+
final Class<?> codecClass = codecInstance.getClass();
254+
for (final Method m : codecClass.getDeclaredMethods()) {
255+
if (m.getName().equals("decode")) {
256+
codecDecode = lookup().unreflect(m).bindTo(codecInstance);
257+
} else if (m.getName().equals("encode")) {
258+
codecEncode = lookup().unreflect(m).bindTo(codecInstance);
259+
}
260+
}
261+
break;
262+
}
263+
}
264+
}
220265
}
221266
} catch (final Throwable error) {
222267
INITIALIZATION_ERROR.set(new UnsupportedOperationException("Error occurred during initialization", error));
223268
}
224269

225270
MC_TEXT_GSON = gson;
271+
JSON_OPS_INSTANCE = jsonOpsInstance;
226272
JSON_PARSER_INSTANCE = jsonParserInstance;
227273
TEXT_SERIALIZER_DESERIALIZE = textSerializerDeserialize;
228274
TEXT_SERIALIZER_SERIALIZE = textSerializerSerialize;
229275
TEXT_SERIALIZER_DESERIALIZE_TREE = textSerializerDeserializeTree;
230276
TEXT_SERIALIZER_SERIALIZE_TREE = textSerializerSerializeTree;
277+
COMPONENTSERIALIZATION_CODEC_ENCODE = codecEncode;
278+
COMPONENTSERIALIZATION_CODEC_DECODE = codecDecode;
279+
CREATE_SERIALIZATION_CONTEXT = createContext;
231280
}
232281

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);
282+
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 && CREATE_SERIALIZATION_CONTEXT != null && JSON_OPS_INSTANCE != null);
234283

235284
@Override
236285
public @NotNull Component deserialize(final @NotNull Object input) {
@@ -242,6 +291,12 @@ public static boolean isSupported() {
242291
element = TEXT_SERIALIZER_SERIALIZE_TREE.invoke(input);
243292
} else if (MC_TEXT_GSON != null) {
244293
element = ((Gson) MC_TEXT_GSON).toJsonTree(input);
294+
} else if (COMPONENTSERIALIZATION_CODEC_ENCODE != null && CREATE_SERIALIZATION_CONTEXT != null) {
295+
final Object serializationContext = CREATE_SERIALIZATION_CONTEXT.invoke(JSON_OPS_INSTANCE);
296+
final Object result = COMPONENTSERIALIZATION_CODEC_ENCODE.invoke(input, serializationContext, null);
297+
final Method getOrThrow = result.getClass().getMethod("getOrThrow", java.util.function.Function.class);
298+
final Object jsonElement = getOrThrow.invoke(result, (java.util.function.Function<Throwable, RuntimeException>) RuntimeException::new);
299+
return gson().serializer().fromJson(jsonElement.toString(), Component.class);
245300
} else {
246301
return gson().deserialize((String) TEXT_SERIALIZER_SERIALIZE.invoke(input));
247302
}
@@ -268,6 +323,14 @@ public static boolean isSupported() {
268323
}
269324
} else {
270325
try {
326+
if (COMPONENTSERIALIZATION_CODEC_DECODE != null && CREATE_SERIALIZATION_CONTEXT != null) {
327+
final Object serializationContext = CREATE_SERIALIZATION_CONTEXT.invoke(JSON_OPS_INSTANCE);
328+
final Object result = COMPONENTSERIALIZATION_CODEC_DECODE.invoke(serializationContext, gson().serializeToTree(component));
329+
final Method getOrThrow = result.getClass().getMethod("getOrThrow", java.util.function.Function.class);
330+
final Object pair = getOrThrow.invoke(result, (java.util.function.Function<Throwable, RuntimeException>) RuntimeException::new);
331+
final Method getFirst = pair.getClass().getMethod("getFirst");
332+
return getFirst.invoke(pair);
333+
}
271334
return TEXT_SERIALIZER_DESERIALIZE.invoke(gson().serialize(component));
272335
} catch (final Throwable error) {
273336
throw new UnsupportedOperationException(error);

0 commit comments

Comments
 (0)