diff --git a/Il2CppInterop.Generator/Passes/Pass80UnstripMethods.cs b/Il2CppInterop.Generator/Passes/Pass80UnstripMethods.cs index 30c0fe4c..d64773dc 100644 --- a/Il2CppInterop.Generator/Passes/Pass80UnstripMethods.cs +++ b/Il2CppInterop.Generator/Passes/Pass80UnstripMethods.cs @@ -130,7 +130,8 @@ private static PropertyDefinition GetOrCreateProperty(MethodDefinition unityMeth unityMethod.DeclaringType.Properties.Single( it => it.SetMethod == unityMethod || it.GetMethod == unityMethod); var newProperty = newMethod.DeclaringType.Properties.SingleOrDefault(it => - it.Name == unityProperty.Name && it.Parameters.Count == unityProperty.Parameters.Count); + it.Name == unityProperty.Name && it.Parameters.Count == unityProperty.Parameters.Count && + it.Parameters.SequenceEqual(unityProperty.Parameters, new TypeComparer())); if (newProperty == null) { newProperty = new PropertyDefinition(unityProperty.Name, PropertyAttributes.None, @@ -228,4 +229,23 @@ private static PropertyDefinition GetOrCreateProperty(MethodDefinition unityMeth return newType; } + + //Stolen from: https://github.com/kremnev8/Il2CppInterop/blob/2c4a31f95f8aa6afe910aca0f8044efb80259d20/Il2CppInterop.Generator/Passes/Pass11ComputeTypeSpecifics.cs#L223 + internal sealed class TypeComparer : IEqualityComparer + { + public bool Equals(ParameterDefinition x, ParameterDefinition y) + { + if (x == null) + return y == null; + if (y == null) + return false; + + return x.ParameterType.FullName.Equals(y.ParameterType.FullName); + } + + public int GetHashCode(ParameterDefinition obj) + { + return obj.ParameterType.FullName.GetHashCode(); + } + } } diff --git a/Il2CppInterop.HarmonySupport/HarmonyBackendComponent.cs b/Il2CppInterop.HarmonySupport/HarmonyBackendComponent.cs index 1c1499e6..89661413 100644 --- a/Il2CppInterop.HarmonySupport/HarmonyBackendComponent.cs +++ b/Il2CppInterop.HarmonySupport/HarmonyBackendComponent.cs @@ -1,6 +1,7 @@ using HarmonyLib.Public.Patching; using Il2CppInterop.Common.Host; -using Il2CppInterop.Runtime.InteropTypes; +using Il2CppInterop.Runtime; +using Il2CppInterop.Runtime.Injection; namespace Il2CppInterop.HarmonySupport; @@ -21,7 +22,10 @@ internal class HarmonySupportComponent : IHostComponent private static void TryResolve(object sender, PatchManager.PatcherResolverEventArgs args) { - if (args.Original.DeclaringType?.IsSubclassOf(typeof(Il2CppObjectBase)) != true) + var declaringType = args.Original.DeclaringType; + if (declaringType == null) return; + if (Il2CppType.From(declaringType, false) == null || + ClassInjector.IsManagedTypeInjected(declaringType)) { return; } diff --git a/Il2CppInterop.Runtime/DelegateSupport.cs b/Il2CppInterop.Runtime/DelegateSupport.cs index 124f8d96..88a6528b 100644 --- a/Il2CppInterop.Runtime/DelegateSupport.cs +++ b/Il2CppInterop.Runtime/DelegateSupport.cs @@ -37,9 +37,11 @@ internal static Type GetOrCreateDelegateType(MethodSignature signature, MethodIn private static Type CreateDelegateType(MethodInfo managedMethodInner, MethodSignature signature) { - var newType = ModuleBuilder.DefineType( - "Il2CppToManagedDelegate_" + managedMethodInner.DeclaringType.FullName + "_" + signature.GetHashCode() + (signature.HasThis ? "HasThis" : "") + - (signature.ConstructedFromNative ? "FromNative" : ""), TypeAttributes.Sealed | TypeAttributes.Public, + var typeName = "Il2CppToManagedDelegate_" + managedMethodInner.DeclaringType + "_" + signature.GetHashCode() + + (signature.HasThis ? "HasThis" : "") + + (signature.ConstructedFromNative ? "FromNative" : ""); + + var newType = ModuleBuilder.DefineType(typeName, TypeAttributes.Sealed | TypeAttributes.Public, typeof(MulticastDelegate)); newType.SetCustomAttribute(new CustomAttributeBuilder( typeof(UnmanagedFunctionPointerAttribute).GetConstructor(new[] { typeof(CallingConvention) })!, diff --git a/Il2CppInterop.Runtime/Injection/ClassInjector.cs b/Il2CppInterop.Runtime/Injection/ClassInjector.cs index 82de25db..06de02f7 100644 --- a/Il2CppInterop.Runtime/Injection/ClassInjector.cs +++ b/Il2CppInterop.Runtime/Injection/ClassInjector.cs @@ -128,6 +128,13 @@ public static bool IsTypeRegisteredInIl2Cpp(Type type) var currentPointer = Il2CppClassPointerStore.GetNativeClassPointer(type); if (currentPointer != IntPtr.Zero) return true; + if (IsManagedTypeInjected(type)) return true; + + return false; + } + + internal static bool IsManagedTypeInjected(Type type) + { lock (InjectedTypes) { if (InjectedTypes.Contains(type.FullName)) @@ -305,7 +312,12 @@ public static void RegisterTypeInIl2Cpp(Type type, RegisterTypeOptions options) methodPointerArray[0] = ConvertStaticMethod(FinalizeDelegate, "Finalize", classPointer); var finalizeMethod = UnityVersionHandler.Wrap(methodPointerArray[0]); - if (!type.IsAbstract) methodPointerArray[1] = ConvertStaticMethod(CreateEmptyCtor(type, fieldsToInject), ".ctor", classPointer); + var fieldsToInitialize = type + .GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + .Where(IsFieldEligible) + .ToArray(); + + if (!type.IsAbstract) methodPointerArray[1] = ConvertStaticMethod(CreateEmptyCtor(type, fieldsToInitialize), ".ctor", classPointer); var infos = new Dictionary<(string, int, bool), int>(eligibleMethods.Length); for (var i = 0; i < eligibleMethods.Length; i++) { @@ -372,6 +384,18 @@ static void FindAbstractMethods(List list, INativeClass } var abstractV = 0; + + INativeMethodInfoStruct HandleAbstractMethod(int position) + { + if (!extendsAbstract) throw new NullReferenceException("VTable method was null even though base type isn't abstract"); + + var nativeMethodInfoStruct = abstractBaseMethods[abstractV++]; + + vTablePointer[position].method = nativeMethodInfoStruct.MethodInfoPointer; + vTablePointer[position].methodPtr = nativeMethodInfoStruct.MethodPointer; + return nativeMethodInfoStruct; + } + for (var i = 0; i < baseClassPointer.VtableCount; i++) { vTablePointer[i] = baseVTablePointer[i]; @@ -380,18 +404,18 @@ static void FindAbstractMethods(List list, INativeClass if (baseVTablePointer[i].method == default) { - if (!extendsAbstract) throw new NullReferenceException("VTable method was null even though base type isn't abstract"); - - baseMethod = abstractBaseMethods[abstractV++]; - - vTablePointer[i].method = baseMethod.MethodInfoPointer; - vTablePointer[i].methodPtr = baseMethod.MethodPointer; + baseMethod = HandleAbstractMethod(i); } else { baseMethod = UnityVersionHandler.Wrap(vTablePointer[i].method); } + if (baseMethod.Name == IntPtr.Zero) + { + baseMethod = HandleAbstractMethod(i); + } + var methodName = Marshal.PtrToStringAnsi(baseMethod.Name); if (methodName == "Finalize") // slot number is not static diff --git a/Il2CppInterop.Runtime/InteropTypes/Fields/Il2CppReferenceField.cs b/Il2CppInterop.Runtime/InteropTypes/Fields/Il2CppReferenceField.cs index bc2b8af1..ee5c8024 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Fields/Il2CppReferenceField.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Fields/Il2CppReferenceField.cs @@ -28,7 +28,7 @@ public TRefObj Value public void Set(TRefObj value) { - *GetPointerToData() = value.Pointer; + *GetPointerToData() = value != null ? value.Pointer : IntPtr.Zero; } public static implicit operator TRefObj(Il2CppReferenceField _this)