@@ -89,36 +89,57 @@ public static boolean isSupported() {
89
89
90
90
private static final @ Nullable Class <?> CLASS_JSON_DESERIALIZER = findClass ("com.goo" .concat ("gle.gson.JsonDeserializer" )); // Hide from relocation checkers
91
91
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" ));
92
93
private static final @ Nullable Class <?> CLASS_JSON_PARSER = findClass ("com.goo" .concat ("gle.gson.JsonParser" ));
93
94
private static final @ Nullable Class <?> CLASS_CHAT_COMPONENT = findClass (
94
95
findNmsClassName ("IChatBaseComponent" ),
95
96
findMcClassName ("network.chat.IChatBaseComponent" ),
96
97
findMcClassName ("network.chat.Component" )
97
98
);
99
+ private static final @ Nullable Class <?> CLASS_COMPONENT_SERIALIZATION = findClass (findMcClassName ("network.chat.ComponentSerialization" ));
98
100
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
+ );
99
105
private static final @ Nullable Class <?> CLASS_REGISTRY_ACCESS = findClass (
100
106
findMcClassName ("core.IRegistryCustom" ),
101
107
findMcClassName ("core.RegistryAccess" )
102
108
);
103
109
private static final @ Nullable MethodHandle PARSE_JSON = findMethod (CLASS_JSON_PARSER , "parse" , CLASS_JSON_ELEMENT , String .class );
104
110
private static final @ Nullable MethodHandle GET_REGISTRY = findStaticMethod (CLASS_CRAFT_REGISTRY , "getMinecraftRegistry" , CLASS_REGISTRY_ACCESS );
105
111
private static final AtomicReference <RuntimeException > INITIALIZATION_ERROR = new AtomicReference <>(new UnsupportedOperationException ());
112
+ private static final Object JSON_OPS_INSTANCE ;
106
113
private static final Object JSON_PARSER_INSTANCE ;
107
114
private static final Object MC_TEXT_GSON ;
108
115
private static final MethodHandle TEXT_SERIALIZER_DESERIALIZE ;
109
116
private static final MethodHandle TEXT_SERIALIZER_SERIALIZE ;
110
117
private static final MethodHandle TEXT_SERIALIZER_DESERIALIZE_TREE ;
111
118
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 ;
112
123
113
124
static {
114
125
Object gson = null ;
126
+ Object jsonOpsInstance = null ;
115
127
Object jsonParserInstance = null ;
116
128
MethodHandle textSerializerDeserialize = null ;
117
129
MethodHandle textSerializerSerialize = null ;
118
130
MethodHandle textSerializerDeserializeTree = null ;
119
131
MethodHandle textSerializerSerializeTree = null ;
132
+ MethodHandle codecEncode = null ;
133
+ MethodHandle codecDecode = null ;
134
+ Object registryAccessEmpty = null ;
135
+ MethodHandle createContext = null ;
120
136
121
137
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
+ }
122
143
if (CLASS_JSON_PARSER != null ) {
123
144
jsonParserInstance = CLASS_JSON_PARSER .getDeclaredConstructor ().newInstance ();
124
145
}
@@ -218,19 +239,60 @@ public static boolean isSupported() {
218
239
}
219
240
}
220
241
}
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
+
221
278
} catch (final Throwable error ) {
222
279
INITIALIZATION_ERROR .set (new UnsupportedOperationException ("Error occurred during initialization" , error ));
223
280
}
224
281
225
282
MC_TEXT_GSON = gson ;
283
+ JSON_OPS_INSTANCE = jsonOpsInstance ;
226
284
JSON_PARSER_INSTANCE = jsonParserInstance ;
227
285
TEXT_SERIALIZER_DESERIALIZE = textSerializerDeserialize ;
228
286
TEXT_SERIALIZER_SERIALIZE = textSerializerSerialize ;
229
287
TEXT_SERIALIZER_DESERIALIZE_TREE = textSerializerDeserializeTree ;
230
288
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 ;
231
293
}
232
294
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 ) ;
234
296
235
297
@ Override
236
298
public @ NotNull Component deserialize (final @ NotNull Object input ) {
@@ -242,6 +304,12 @@ public static boolean isSupported() {
242
304
element = TEXT_SERIALIZER_SERIALIZE_TREE .invoke (input );
243
305
} else if (MC_TEXT_GSON != null ) {
244
306
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 );
245
313
} else {
246
314
return gson ().deserialize ((String ) TEXT_SERIALIZER_SERIALIZE .invoke (input ));
247
315
}
@@ -268,6 +336,14 @@ public static boolean isSupported() {
268
336
}
269
337
} else {
270
338
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
+ }
271
347
return TEXT_SERIALIZER_DESERIALIZE .invoke (gson ().serialize (component ));
272
348
} catch (final Throwable error ) {
273
349
throw new UnsupportedOperationException (error );
0 commit comments