Il2CppInterop
Il2CppInterop copied to clipboard
Injected fields returning injected types cause a crash
If you do the following
[BepInAutoPlugin]
public partial class TestPluginPlugin : BasePlugin
{
public override void Load()
{
ClassInjector.RegisterTypeInIl2Cpp<MyBehaviour>();
ClassInjector.RegisterTypeInIl2Cpp<MyTestObj>();
MyBehaviour myBehaviour = new GameObject().AddComponent(Il2CppType.Of<MyBehaviour>()).Cast<MyBehaviour>();
MyTestObj myTestObj = new GameObject().AddComponent(Il2CppType.Of<MyTestObj>()).Cast<MyTestObj>();
myTestObj.myBehaviour.Value = myBehaviour;
MyTestObj myNewTest = Object.Instantiate(myTestObj).Cast<MyTestObj>();
Log.LogMessage("myNewTest.myBehaviour.mySpriteRenderer: " + myNewTest.myBehaviour.Value);
}
}
public class MyBehaviour : MonoBehaviour
{
public MyBehaviour(IntPtr ptr) : base(ptr) { }
public Il2CppReferenceField<GameObject> mySpriteRenderer;
}
public class MyTestObj : MonoBehaviour
{
public MyTestObj(IntPtr ptr) : base(ptr) { }
public Il2CppReferenceField<MyBehaviour > myBehaviour;
}
The game will crash once you call Object.Instantiate(myTestObj)
Though, if you switch the return type to be something more generic i.e MonoBehaviour in myBehaviour, it works fine
💤
Decompiling that method (for my game) in ILSpy, I get some warnings, which may or may not be related.
public unsafe static T Instantiate<T>(T original) where T : Object
{
//IL_0051->IL0056: Incompatible stack types: I vs Ref
//IL_0044->IL0056: Incompatible stack types: I vs Ref
IntPtr* ptr = stackalloc IntPtr[1];
ref T reference;
if (!typeof(T).IsValueType)
{
T val = original;
reference = ref *(?*)((!(val is string)) ? IL2CPP.Il2CppObjectBaseToPtr(val as Il2CppObjectBase) : IL2CPP.ManagedStringToIl2Cpp(val as string));
}
else
{
reference = ref original;
}
*ptr = (nint)System.Runtime.CompilerServices.Unsafe.AsPointer(ref reference);
System.Runtime.CompilerServices.Unsafe.SkipInit(out IntPtr exc);
IntPtr objectPointer = IL2CPP.il2cpp_runtime_invoke(MethodInfoStoreGeneric_Instantiate_Public_Static_T_T_0<T>.Pointer, (IntPtr)0, (void**)ptr, ref exc);
Il2CppException.RaiseExceptionIfNecessary(exc);
return IL2CPP.PointerToValueGeneric<T>(objectPointer, isFieldPointer: false, valueTypeWouldBeBoxed: true);
}