29
29
import java .lang .reflect .Field ;
30
30
import java .lang .reflect .Method ;
31
31
import java .lang .reflect .Modifier ;
32
+ import java .lang .reflect .ParameterizedType ;
33
+ import java .lang .reflect .Type ;
32
34
import java .util .ArrayList ;
33
35
import java .util .Arrays ;
34
36
import java .util .Comparator ;
@@ -95,7 +97,9 @@ public static boolean isSupported() {
95
97
findMcClassName ("network.chat.IChatBaseComponent" ),
96
98
findMcClassName ("network.chat.Component" )
97
99
);
100
+ private static final @ Nullable Class <?> CLASS_COMPONENT_SERIALIZATION = findClass (findMcClassName ("network.chat.ComponentSerialization" ));
98
101
private static final @ Nullable Class <?> CLASS_CRAFT_REGISTRY = findCraftClass ("CraftRegistry" );
102
+ private static final @ Nullable Class <?> CLASS_HOLDERLOOKUP_PROVIDER = findClass (findMcClassName ("core.HolderLookup$Provider" ));
99
103
private static final @ Nullable Class <?> CLASS_REGISTRY_ACCESS = findClass (
100
104
findMcClassName ("core.IRegistryCustom" ),
101
105
findMcClassName ("core.RegistryAccess" )
@@ -109,6 +113,10 @@ public static boolean isSupported() {
109
113
private static final MethodHandle TEXT_SERIALIZER_SERIALIZE ;
110
114
private static final MethodHandle TEXT_SERIALIZER_DESERIALIZE_TREE ;
111
115
private static final MethodHandle TEXT_SERIALIZER_SERIALIZE_TREE ;
116
+ private static final MethodHandle COMPONENTSERIALIZATION_CODEC_ENCODE ;
117
+ private static final MethodHandle COMPONENTSERIALIZATION_CODEC_DECODE ;
118
+ private static final Object REGISTRY_ACCESS_EMPTY ;
119
+ private static final MethodHandle CREATE_SERIALIZATION_CONTEXT ;
112
120
113
121
static {
114
122
Object gson = null ;
@@ -117,6 +125,10 @@ public static boolean isSupported() {
117
125
MethodHandle textSerializerSerialize = null ;
118
126
MethodHandle textSerializerDeserializeTree = null ;
119
127
MethodHandle textSerializerSerializeTree = null ;
128
+ MethodHandle codecEncode = null ;
129
+ MethodHandle codecDecode = null ;
130
+ Object registryAccessEmpty = null ;
131
+ MethodHandle createContext = null ;
120
132
121
133
try {
122
134
if (CLASS_JSON_PARSER != null ) {
@@ -218,6 +230,42 @@ public static boolean isSupported() {
218
230
}
219
231
}
220
232
}
233
+ if (CLASS_REGISTRY_ACCESS != null ) {
234
+ for (Field field : CLASS_REGISTRY_ACCESS .getDeclaredFields ()) {
235
+ field .setAccessible (true );
236
+ if (Modifier .isStatic (field .getModifiers ()) && CLASS_REGISTRY_ACCESS .isAssignableFrom (field .getType ())) {
237
+ registryAccessEmpty = field .get (null );
238
+ break ;
239
+ }
240
+ }
241
+ if (registryAccessEmpty != null && CLASS_HOLDERLOOKUP_PROVIDER != null ) {
242
+ for (Method m : CLASS_HOLDERLOOKUP_PROVIDER .getDeclaredMethods ()) {
243
+ m .setAccessible (true );
244
+ if (m .getParameterCount () == 1 && m .getParameterTypes ()[0 ].getSimpleName ().equals ("DynamicOps" ) && m .getReturnType ().getSimpleName ().contains ("RegistryOps" )) {
245
+ createContext = lookup ().unreflect (m ).bindTo (registryAccessEmpty );
246
+ break ;
247
+ }
248
+ }
249
+ }
250
+ }
251
+ if (CLASS_COMPONENT_SERIALIZATION != null ) {
252
+ for (Field f : CLASS_COMPONENT_SERIALIZATION .getDeclaredFields ()) {
253
+ if (Modifier .isStatic (f .getModifiers ()) && f .getType ().getSimpleName ().equals ("Codec" )) {
254
+ f .setAccessible (true );
255
+ Object codecInstance = f .get (null );
256
+ Class <?> codecClass = codecInstance .getClass ();
257
+ for (Method m : codecClass .getDeclaredMethods ()) {
258
+ if (m .getName ().equals ("decode" )) {
259
+ codecDecode = lookup ().unreflect (m ).bindTo (codecInstance );
260
+ } else if (m .getName ().equals ("encode" )) {
261
+ codecEncode = lookup ().unreflect (m ).bindTo (codecInstance );
262
+ }
263
+ }
264
+ break ;
265
+ }
266
+ }
267
+ }
268
+
221
269
} catch (final Throwable error ) {
222
270
INITIALIZATION_ERROR .set (new UnsupportedOperationException ("Error occurred during initialization" , error ));
223
271
}
@@ -228,9 +276,13 @@ public static boolean isSupported() {
228
276
TEXT_SERIALIZER_SERIALIZE = textSerializerSerialize ;
229
277
TEXT_SERIALIZER_DESERIALIZE_TREE = textSerializerDeserializeTree ;
230
278
TEXT_SERIALIZER_SERIALIZE_TREE = textSerializerSerializeTree ;
279
+ COMPONENTSERIALIZATION_CODEC_ENCODE = codecEncode ;
280
+ COMPONENTSERIALIZATION_CODEC_DECODE = codecDecode ;
281
+ REGISTRY_ACCESS_EMPTY = registryAccessEmpty ;
282
+ CREATE_SERIALIZATION_CONTEXT = createContext ;
231
283
}
232
284
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 );
285
+ 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 ) ;
234
286
235
287
@ Override
236
288
public @ NotNull Component deserialize (final @ NotNull Object input ) {
@@ -242,6 +294,13 @@ public static boolean isSupported() {
242
294
element = TEXT_SERIALIZER_SERIALIZE_TREE .invoke (input );
243
295
} else if (MC_TEXT_GSON != null ) {
244
296
element = ((Gson ) MC_TEXT_GSON ).toJsonTree (input );
297
+ } else if (COMPONENTSERIALIZATION_CODEC_ENCODE != null && REGISTRY_ACCESS_EMPTY != null && CREATE_SERIALIZATION_CONTEXT != null ) {
298
+ final Object jsonOps = Class .forName ("com.mojang.serialization.JsonOps" ).getField ("INSTANCE" ).get (null );
299
+ final Object serializationContext = CREATE_SERIALIZATION_CONTEXT .invoke (REGISTRY_ACCESS_EMPTY , jsonOps );
300
+ Object result = COMPONENTSERIALIZATION_CODEC_ENCODE .invoke (serializationContext , input , null );
301
+ Method getOrThrow = result .getClass ().getMethod ("getOrThrow" , java .util .function .Function .class );
302
+ Object jsonElement = getOrThrow .invoke (result , (java .util .function .Function <Throwable , RuntimeException >) RuntimeException ::new );
303
+ return gson ().serializer ().fromJson (jsonElement .toString (), Component .class );
245
304
} else {
246
305
return gson ().deserialize ((String ) TEXT_SERIALIZER_SERIALIZE .invoke (input ));
247
306
}
@@ -268,6 +327,15 @@ public static boolean isSupported() {
268
327
}
269
328
} else {
270
329
try {
330
+ if (COMPONENTSERIALIZATION_CODEC_DECODE != null && REGISTRY_ACCESS_EMPTY != null && CREATE_SERIALIZATION_CONTEXT != null ) {
331
+ final Object jsonOps = Class .forName ("com.mojang.serialization.JsonOps" ).getField ("INSTANCE" ).get (null );
332
+ final Object serializationContext = CREATE_SERIALIZATION_CONTEXT .invoke (jsonOps );
333
+ Object result = COMPONENTSERIALIZATION_CODEC_DECODE .invoke (serializationContext , gson ().serializeToTree (component ));
334
+ Method getOrThrow = result .getClass ().getMethod ("getOrThrow" , java .util .function .Function .class );
335
+ Object pair = getOrThrow .invoke (result , (java .util .function .Function <Throwable , RuntimeException >) RuntimeException ::new );
336
+ Method getFirst = pair .getClass ().getMethod ("getFirst" );
337
+ return getFirst .invoke (pair );
338
+ }
271
339
return TEXT_SERIALIZER_DESERIALIZE .invoke (gson ().serialize (component ));
272
340
} catch (final Throwable error ) {
273
341
throw new UnsupportedOperationException (error );
0 commit comments