resolve packet instance construction concurrency issue (#2312)
This commit is contained in:
parent
c7753a9d5b
commit
ab32f938d7
|
@ -54,7 +54,9 @@ public class StructureCache {
|
|||
private static final Map<PacketType, StructureModifier<Object>> STRUCTURE_MODIFIER_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
// packet data serializer which always returns an empty nbt tag compound
|
||||
private static final Object TRICK_INIT_LOCK = new Object();
|
||||
private static boolean TRICK_TRIED = false;
|
||||
|
||||
private static ConstructorAccessor TRICKED_DATA_SERIALIZER_BASE;
|
||||
private static ConstructorAccessor TRICKED_DATA_SERIALIZER_JSON;
|
||||
|
||||
|
@ -164,45 +166,50 @@ public class StructureCache {
|
|||
return TRICKED_DATA_SERIALIZER_BASE != null;
|
||||
}
|
||||
|
||||
// prevent double init
|
||||
TRICK_TRIED = true;
|
||||
synchronized (TRICK_INIT_LOCK) {
|
||||
if (TRICK_TRIED) {
|
||||
return TRICKED_DATA_SERIALIZER_BASE != null;
|
||||
}
|
||||
|
||||
try {
|
||||
// create an empty instance of a nbt tag compound / text compound that we can re-use when needed
|
||||
Object textCompound = WrappedChatComponent.fromText("").getHandle();
|
||||
Object compound = Accessors.getConstructorAccessor(MinecraftReflection.getNBTCompoundClass()).invoke();
|
||||
// base builder which intercepts a few methods
|
||||
DynamicType.Builder<?> baseBuilder = ByteBuddyFactory.getInstance()
|
||||
.createSubclass(MinecraftReflection.getPacketDataSerializerClass())
|
||||
.name(MinecraftMethods.class.getPackage().getName() + ".ProtocolLibTricksNmsDataSerializerBase")
|
||||
.method(ElementMatchers.returns(MinecraftReflection.getNBTCompoundClass())
|
||||
.and(ElementMatchers.takesArguments(MinecraftReflection.getNBTReadLimiterClass())))
|
||||
.intercept(FixedValue.value(compound))
|
||||
.method(ElementMatchers.returns(MinecraftReflection.getIChatBaseComponentClass()))
|
||||
.intercept(FixedValue.value(textCompound))
|
||||
.method(ElementMatchers.returns(PublicKey.class).and(ElementMatchers.takesNoArguments()))
|
||||
.intercept(FixedValue.nullValue());
|
||||
Class<?> serializerBase = baseBuilder.make()
|
||||
.load(ByteBuddyFactory.getInstance().getClassLoader(), Default.INJECTION)
|
||||
.getLoaded();
|
||||
TRICKED_DATA_SERIALIZER_BASE = Accessors.getConstructorAccessor(serializerBase, ByteBuf.class);
|
||||
try {
|
||||
// create an empty instance of a nbt tag compound / text compound that we can re-use when needed
|
||||
Object textCompound = WrappedChatComponent.fromText("").getHandle();
|
||||
Object compound = Accessors.getConstructorAccessor(MinecraftReflection.getNBTCompoundClass()).invoke();
|
||||
// base builder which intercepts a few methods
|
||||
DynamicType.Builder<?> baseBuilder = ByteBuddyFactory.getInstance()
|
||||
.createSubclass(MinecraftReflection.getPacketDataSerializerClass())
|
||||
.name(MinecraftMethods.class.getPackage().getName() + ".ProtocolLibTricksNmsDataSerializerBase")
|
||||
.method(ElementMatchers.returns(MinecraftReflection.getNBTCompoundClass())
|
||||
.and(ElementMatchers.takesArguments(MinecraftReflection.getNBTReadLimiterClass())))
|
||||
.intercept(FixedValue.value(compound))
|
||||
.method(ElementMatchers.returns(MinecraftReflection.getIChatBaseComponentClass()))
|
||||
.intercept(FixedValue.value(textCompound))
|
||||
.method(ElementMatchers.returns(PublicKey.class).and(ElementMatchers.takesNoArguments()))
|
||||
.intercept(FixedValue.nullValue());
|
||||
Class<?> serializerBase = baseBuilder.make()
|
||||
.load(ByteBuddyFactory.getInstance().getClassLoader(), Default.INJECTION)
|
||||
.getLoaded();
|
||||
TRICKED_DATA_SERIALIZER_BASE = Accessors.getConstructorAccessor(serializerBase, ByteBuf.class);
|
||||
|
||||
// extended builder which intercepts the read string method as well
|
||||
Class<?> withStringIntercept = baseBuilder
|
||||
.name(MinecraftMethods.class.getPackage().getName() + ".ProtocolLibTricksNmsDataSerializerJson")
|
||||
.method(ElementMatchers.returns(String.class).and(ElementMatchers.takesArguments(int.class)))
|
||||
.intercept(FixedValue.value("{}"))
|
||||
.make()
|
||||
.load(ByteBuddyFactory.getInstance().getClassLoader(), Default.INJECTION)
|
||||
.getLoaded();
|
||||
TRICKED_DATA_SERIALIZER_JSON = Accessors.getConstructorAccessor(withStringIntercept, ByteBuf.class);
|
||||
// extended builder which intercepts the read string method as well
|
||||
Class<?> withStringIntercept = baseBuilder
|
||||
.name(MinecraftMethods.class.getPackage().getName() + ".ProtocolLibTricksNmsDataSerializerJson")
|
||||
.method(ElementMatchers.returns(String.class).and(ElementMatchers.takesArguments(int.class)))
|
||||
.intercept(FixedValue.value("{}"))
|
||||
.make()
|
||||
.load(ByteBuddyFactory.getInstance().getClassLoader(), Default.INJECTION)
|
||||
.getLoaded();
|
||||
TRICKED_DATA_SERIALIZER_JSON = Accessors.getConstructorAccessor(withStringIntercept, ByteBuf.class);
|
||||
|
||||
// worked
|
||||
return true;
|
||||
} catch (Exception ignored) {
|
||||
// worked
|
||||
return true;
|
||||
} catch (Exception ignored) {
|
||||
} finally {
|
||||
TRICK_TRIED = true;
|
||||
}
|
||||
|
||||
// didn't work
|
||||
return false;
|
||||
}
|
||||
|
||||
// didn't work
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue