diff --git a/Dependencies/SupportModules/Il2Cpp/InteropInterface.cs b/Dependencies/SupportModules/Il2Cpp/InteropInterface.cs index 60ad60927..06668b909 100644 --- a/Dependencies/SupportModules/Il2Cpp/InteropInterface.cs +++ b/Dependencies/SupportModules/Il2Cpp/InteropInterface.cs @@ -3,7 +3,6 @@ using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; -using Il2CppInterop.Runtime.Runtime; using System; using System.Reflection; @@ -28,6 +27,8 @@ public FieldInfo MethodBaseToIl2CppFieldInfo(MethodBase method) public void RegisterTypeInIl2CppDomain(Type type, bool logSuccess) => ClassInjector.RegisterTypeInIl2Cpp(type, new() { LogSuccess = logSuccess }); + public void RegisterTypeInIl2CppDomainWithInterfaces(Type type, Type[] interfaces, bool logSuccess) + => ClassInjector.RegisterTypeInIl2Cpp(type, new() { LogSuccess = logSuccess, Interfaces = interfaces }); public bool IsInheritedFromIl2CppObjectBase(Type type) => (type != null) && type.IsSubclassOf(typeof(Il2CppObjectBase)); diff --git a/MelonLoader/Attributes/RegisterTypeInIl2CppWithInterfaces.cs b/MelonLoader/Attributes/RegisterTypeInIl2CppWithInterfaces.cs new file mode 100644 index 000000000..d0bbc1d14 --- /dev/null +++ b/MelonLoader/Attributes/RegisterTypeInIl2CppWithInterfaces.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace MelonLoader +{ + [AttributeUsage(AttributeTargets.Class)] + public class RegisterTypeInIl2CppWithInterfaces : Attribute //Naming violation? + { + internal static List registrationQueue = new List(); + internal static bool ready; + internal bool LogSuccess = true; + internal Type[] Interfaces; + internal bool GetInterfacesFromType; + + public RegisterTypeInIl2CppWithInterfaces() + { + GetInterfacesFromType = true; + } + + public RegisterTypeInIl2CppWithInterfaces(bool logSuccess) + { + LogSuccess = logSuccess; + GetInterfacesFromType = true; + } + + public RegisterTypeInIl2CppWithInterfaces(params Type[] interfaces) + { + Interfaces = interfaces; + } + + public RegisterTypeInIl2CppWithInterfaces(bool logSuccess, params Type[] interfaces) + { + LogSuccess = logSuccess; + Interfaces = interfaces; + } + + public static void RegisterAssembly(Assembly asm) + { + if (!MelonUtils.IsGameIl2Cpp()) + return; + + if (!ready) + { + registrationQueue.Add(asm); + return; + } + + IEnumerable typeTbl = asm.GetValidTypes(); + if ((typeTbl == null) || (typeTbl.Count() <= 0)) + return; + + foreach (Type type in typeTbl) + { + object[] attTbl = type.GetCustomAttributes(typeof(RegisterTypeInIl2CppWithInterfaces), false); + if ((attTbl == null) || (attTbl.Length <= 0)) + continue; + + RegisterTypeInIl2CppWithInterfaces att = (RegisterTypeInIl2CppWithInterfaces)attTbl[0]; + if (att == null) + continue; + + Type[] interfaceArr = att.GetInterfacesFromType + ? type.GetInterfaces() + : att.Interfaces; + + InteropSupport.RegisterTypeInIl2CppDomainWithInterfaces(type, + interfaceArr, + att.LogSuccess); + } + } + + internal static void SetReady() + { + ready = true; + + if (registrationQueue == null) + return; + + foreach (var asm in registrationQueue) + RegisterAssembly(asm); + + registrationQueue = null; + } + } +} \ No newline at end of file diff --git a/MelonLoader/Core.cs b/MelonLoader/Core.cs index 3ee549429..241e94910 100644 --- a/MelonLoader/Core.cs +++ b/MelonLoader/Core.cs @@ -143,6 +143,7 @@ internal static int Start() AddUnityDebugLog(); RegisterTypeInIl2Cpp.SetReady(); + RegisterTypeInIl2CppWithInterfaces.SetReady(); MelonEvents.MelonHarmonyInit.Invoke(); MelonEvents.OnApplicationStart.Invoke(); diff --git a/MelonLoader/Melons/MelonAssembly.cs b/MelonLoader/Melons/MelonAssembly.cs index 18449b19d..fd985a10d 100644 --- a/MelonLoader/Melons/MelonAssembly.cs +++ b/MelonLoader/Melons/MelonAssembly.cs @@ -291,6 +291,7 @@ public void LoadMelons() } RegisterTypeInIl2Cpp.RegisterAssembly(Assembly); + RegisterTypeInIl2CppWithInterfaces.RegisterAssembly(Assembly); if (rottenMelons.Count != 0) { diff --git a/MelonLoader/Utils/InteropSupport.cs b/MelonLoader/Utils/InteropSupport.cs index 2d738ad73..dd11bab9e 100644 --- a/MelonLoader/Utils/InteropSupport.cs +++ b/MelonLoader/Utils/InteropSupport.cs @@ -13,6 +13,7 @@ public interface Interface FieldInfo MethodBaseToIl2CppFieldInfo(MethodBase method); int? GetIl2CppMethodCallerCount(MethodBase method); void RegisterTypeInIl2CppDomain(Type type, bool logSuccess); + void RegisterTypeInIl2CppDomainWithInterfaces(Type type, Type[] interfaces, bool logSuccess); IntPtr CopyMethodInfoStruct(IntPtr ptr); } internal static Interface SMInterface; @@ -89,7 +90,9 @@ public static T Il2CppObjectPtrToIl2CppObject(IntPtr ptr) return SMInterface.GetIl2CppMethodCallerCount(method); } - public static void RegisterTypeInIl2CppDomain(Type type) => RegisterTypeInIl2CppDomain(type, true); + public static void RegisterTypeInIl2CppDomain(Type type) + => RegisterTypeInIl2CppDomain(type, true); + public static void RegisterTypeInIl2CppDomain(Type type, bool logSuccess) { ValidateInterface(); @@ -98,6 +101,21 @@ public static void RegisterTypeInIl2CppDomain(Type type, bool logSuccess) SMInterface.RegisterTypeInIl2CppDomain(type, logSuccess); } + public static void RegisterTypeInIl2CppDomainWithInterfaces(Type type, Type[] interfaces) + => RegisterTypeInIl2CppDomainWithInterfaces(type, interfaces, true); + + public static void RegisterTypeInIl2CppDomainWithInterfaces(Type type, Type[] interfaces, bool logSuccess) + { + ValidateInterface(); + if (type == null) + throw new NullReferenceException("The type cannot be null."); + if (interfaces == null) + throw new NullReferenceException("The interfaces cannot be null."); + if (interfaces.Length <= 0) + throw new NullReferenceException("The interfaces cannot be empty."); + SMInterface.RegisterTypeInIl2CppDomainWithInterfaces(type, interfaces, logSuccess); + } + public static IntPtr CopyMethodInfoStruct(IntPtr ptr) { ValidateInterface();