@@ -54,7 +54,9 @@ public class StructureCache {
54
54
private static final Map <PacketType , StructureModifier <Object >> STRUCTURE_MODIFIER_CACHE = new ConcurrentHashMap <>();
55
55
56
56
// packet data serializer which always returns an empty nbt tag compound
57
+ private static final Object TRICK_INIT_LOCK = new Object ();
57
58
private static boolean TRICK_TRIED = false ;
59
+
58
60
private static ConstructorAccessor TRICKED_DATA_SERIALIZER_BASE ;
59
61
private static ConstructorAccessor TRICKED_DATA_SERIALIZER_JSON ;
60
62
@@ -164,45 +166,50 @@ public static boolean tryInitTrickDataSerializer() {
164
166
return TRICKED_DATA_SERIALIZER_BASE != null ;
165
167
}
166
168
167
- // prevent double init
168
- TRICK_TRIED = true ;
169
-
170
- try {
171
- // create an empty instance of a nbt tag compound / text compound that we can re-use when needed
172
- Object textCompound = WrappedChatComponent .fromText ("" ).getHandle ();
173
- Object compound = Accessors .getConstructorAccessor (MinecraftReflection .getNBTCompoundClass ()).invoke ();
174
- // base builder which intercepts a few methods
175
- DynamicType .Builder <?> baseBuilder = ByteBuddyFactory .getInstance ()
176
- .createSubclass (MinecraftReflection .getPacketDataSerializerClass ())
177
- .name (MinecraftMethods .class .getPackage ().getName () + ".ProtocolLibTricksNmsDataSerializerBase" )
178
- .method (ElementMatchers .returns (MinecraftReflection .getNBTCompoundClass ())
179
- .and (ElementMatchers .takesArguments (MinecraftReflection .getNBTReadLimiterClass ())))
180
- .intercept (FixedValue .value (compound ))
181
- .method (ElementMatchers .returns (MinecraftReflection .getIChatBaseComponentClass ()))
182
- .intercept (FixedValue .value (textCompound ))
183
- .method (ElementMatchers .returns (PublicKey .class ).and (ElementMatchers .takesNoArguments ()))
184
- .intercept (FixedValue .nullValue ());
185
- Class <?> serializerBase = baseBuilder .make ()
186
- .load (ByteBuddyFactory .getInstance ().getClassLoader (), Default .INJECTION )
187
- .getLoaded ();
188
- TRICKED_DATA_SERIALIZER_BASE = Accessors .getConstructorAccessor (serializerBase , ByteBuf .class );
189
-
190
- // extended builder which intercepts the read string method as well
191
- Class <?> withStringIntercept = baseBuilder
192
- .name (MinecraftMethods .class .getPackage ().getName () + ".ProtocolLibTricksNmsDataSerializerJson" )
193
- .method (ElementMatchers .returns (String .class ).and (ElementMatchers .takesArguments (int .class )))
194
- .intercept (FixedValue .value ("{}" ))
195
- .make ()
196
- .load (ByteBuddyFactory .getInstance ().getClassLoader (), Default .INJECTION )
197
- .getLoaded ();
198
- TRICKED_DATA_SERIALIZER_JSON = Accessors .getConstructorAccessor (withStringIntercept , ByteBuf .class );
199
-
200
- // worked
201
- return true ;
202
- } catch (Exception ignored ) {
203
- }
169
+ synchronized (TRICK_INIT_LOCK ) {
170
+ if (TRICK_TRIED ) {
171
+ return TRICKED_DATA_SERIALIZER_BASE != null ;
172
+ }
204
173
205
- // didn't work
206
- return false ;
174
+ try {
175
+ // create an empty instance of a nbt tag compound / text compound that we can re-use when needed
176
+ Object textCompound = WrappedChatComponent .fromText ("" ).getHandle ();
177
+ Object compound = Accessors .getConstructorAccessor (MinecraftReflection .getNBTCompoundClass ()).invoke ();
178
+ // base builder which intercepts a few methods
179
+ DynamicType .Builder <?> baseBuilder = ByteBuddyFactory .getInstance ()
180
+ .createSubclass (MinecraftReflection .getPacketDataSerializerClass ())
181
+ .name (MinecraftMethods .class .getPackage ().getName () + ".ProtocolLibTricksNmsDataSerializerBase" )
182
+ .method (ElementMatchers .returns (MinecraftReflection .getNBTCompoundClass ())
183
+ .and (ElementMatchers .takesArguments (MinecraftReflection .getNBTReadLimiterClass ())))
184
+ .intercept (FixedValue .value (compound ))
185
+ .method (ElementMatchers .returns (MinecraftReflection .getIChatBaseComponentClass ()))
186
+ .intercept (FixedValue .value (textCompound ))
187
+ .method (ElementMatchers .returns (PublicKey .class ).and (ElementMatchers .takesNoArguments ()))
188
+ .intercept (FixedValue .nullValue ());
189
+ Class <?> serializerBase = baseBuilder .make ()
190
+ .load (ByteBuddyFactory .getInstance ().getClassLoader (), Default .INJECTION )
191
+ .getLoaded ();
192
+ TRICKED_DATA_SERIALIZER_BASE = Accessors .getConstructorAccessor (serializerBase , ByteBuf .class );
193
+
194
+ // extended builder which intercepts the read string method as well
195
+ Class <?> withStringIntercept = baseBuilder
196
+ .name (MinecraftMethods .class .getPackage ().getName () + ".ProtocolLibTricksNmsDataSerializerJson" )
197
+ .method (ElementMatchers .returns (String .class ).and (ElementMatchers .takesArguments (int .class )))
198
+ .intercept (FixedValue .value ("{}" ))
199
+ .make ()
200
+ .load (ByteBuddyFactory .getInstance ().getClassLoader (), Default .INJECTION )
201
+ .getLoaded ();
202
+ TRICKED_DATA_SERIALIZER_JSON = Accessors .getConstructorAccessor (withStringIntercept , ByteBuf .class );
203
+
204
+ // worked
205
+ return true ;
206
+ } catch (Exception ignored ) {
207
+ } finally {
208
+ TRICK_TRIED = true ;
209
+ }
210
+
211
+ // didn't work
212
+ return false ;
213
+ }
207
214
}
208
215
}
0 commit comments