@@ -89,36 +89,55 @@ 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 MethodHandle CREATE_SERIALIZATION_CONTEXT ;
112
122
113
123
static {
114
124
Object gson = null ;
125
+ Object jsonOpsInstance = null ;
115
126
Object jsonParserInstance = null ;
116
127
MethodHandle textSerializerDeserialize = null ;
117
128
MethodHandle textSerializerSerialize = null ;
118
129
MethodHandle textSerializerDeserializeTree = null ;
119
130
MethodHandle textSerializerSerializeTree = null ;
131
+ MethodHandle codecEncode = null ;
132
+ MethodHandle codecDecode = null ;
133
+ MethodHandle createContext = null ;
120
134
121
135
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
+ }
122
141
if (CLASS_JSON_PARSER != null ) {
123
142
jsonParserInstance = CLASS_JSON_PARSER .getDeclaredConstructor ().newInstance ();
124
143
}
@@ -217,20 +236,50 @@ public static boolean isSupported() {
217
236
textSerializerSerializeTree = insertArguments (lookup ().unreflect (serializeTreeWithRegistryAccess ), 1 , registryAccess );
218
237
}
219
238
}
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
+ }
220
265
}
221
266
} catch (final Throwable error ) {
222
267
INITIALIZATION_ERROR .set (new UnsupportedOperationException ("Error occurred during initialization" , error ));
223
268
}
224
269
225
270
MC_TEXT_GSON = gson ;
271
+ JSON_OPS_INSTANCE = jsonOpsInstance ;
226
272
JSON_PARSER_INSTANCE = jsonParserInstance ;
227
273
TEXT_SERIALIZER_DESERIALIZE = textSerializerDeserialize ;
228
274
TEXT_SERIALIZER_SERIALIZE = textSerializerSerialize ;
229
275
TEXT_SERIALIZER_DESERIALIZE_TREE = textSerializerDeserializeTree ;
230
276
TEXT_SERIALIZER_SERIALIZE_TREE = textSerializerSerializeTree ;
277
+ COMPONENTSERIALIZATION_CODEC_ENCODE = codecEncode ;
278
+ COMPONENTSERIALIZATION_CODEC_DECODE = codecDecode ;
279
+ CREATE_SERIALIZATION_CONTEXT = createContext ;
231
280
}
232
281
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 ) ;
234
283
235
284
@ Override
236
285
public @ NotNull Component deserialize (final @ NotNull Object input ) {
@@ -242,6 +291,12 @@ public static boolean isSupported() {
242
291
element = TEXT_SERIALIZER_SERIALIZE_TREE .invoke (input );
243
292
} else if (MC_TEXT_GSON != null ) {
244
293
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 );
245
300
} else {
246
301
return gson ().deserialize ((String ) TEXT_SERIALIZER_SERIALIZE .invoke (input ));
247
302
}
@@ -268,6 +323,14 @@ public static boolean isSupported() {
268
323
}
269
324
} else {
270
325
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
+ }
271
334
return TEXT_SERIALIZER_DESERIALIZE .invoke (gson ().serialize (component ));
272
335
} catch (final Throwable error ) {
273
336
throw new UnsupportedOperationException (error );
0 commit comments