using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Preloader.Core.Patching; using HarmonyLib; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Runtime; using Il2CppInterop.Runtime.Runtime.VersionSpecific.Class; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("Il2CppInteropFix.Patcher")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+2f15411dcb5b83d69331116c439ca50c214c1902")] [assembly: AssemblyProduct("Il2CppInteropFix.Patcher")] [assembly: AssemblyTitle("Il2CppInteropFix.Patcher")] [assembly: TargetPlatform("Windows7.0")] [assembly: SupportedOSPlatform("Windows7.0")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Il2CppInteropFix { internal static class FixLogger { internal static ManualLogSource Log { get; private set; } internal static bool Verbose => Environment.GetEnvironmentVariable("IL2CPP_INTEROP_FIX_VERBOSE") == "1"; internal static void Initialize(ManualLogSource log) { Log = log; } internal static void Info(string message) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)message); } } internal static void Warning(string message) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)message); } } internal static void Debug(string message) { if (Verbose) { ManualLogSource log = Log; if (log != null) { log.LogDebug((object)message); } } } internal static void Error(string message) { ManualLogSource log = Log; if (log != null) { log.LogError((object)message); } } } [PatcherPluginInfo("com.slide.il2cppinteropfix.bootstrap", "Il2CppInterop Fix Bootstrap", "1.0.0")] internal sealed class Il2CppInteropFixBootstrap : BasePatcher { private static readonly object ApplyLock = new object(); private static Harmony _harmony; private static bool _chainloaderPatched; private static ManualLogSource _log; public override void Initialize() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown _log = ((BasePatcher)this).Log; FixLogger.Initialize(_log); _harmony = new Harmony("com.slide.il2cppinteropfix.bootstrap"); AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { OnAssemblyLoaded(assemblies[i]); } } public override void Finalizer() { TryPatchChainloader(); TryApplyLookupPatch("preloader Finalizer"); } private static void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args) { OnAssemblyLoaded(args.LoadedAssembly); } private static void OnAssemblyLoaded(Assembly assembly) { string name = assembly.GetName().Name; if ((name == "Il2CppInterop.Runtime" || name == "BepInEx.Unity.IL2CPP") ? true : false) { TryApplyLookupPatch("after " + name + " load"); TryPatchChainloader(); } } private static void TryApplyLookupPatch(string stage) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown lock (ApplyLock) { if (NestedTypeLookupFix.IsLookupPatchInstalled || !AppDomain.CurrentDomain.GetAssemblies().Any((Assembly assembly) => assembly.GetName().Name == "Il2CppInterop.Runtime")) { return; } if (NestedTypeLookupFix.TryInstallLookupPatch(_harmony)) { ManualLogSource log = _log; if (log != null) { bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(51, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Il2CppInterop nested-type injection fix applied ("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(stage); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")."); } log.LogInfo(val); } } else { ManualLogSource log2 = _log; if (log2 != null) { log2.LogWarning((object)("Il2CppInterop nested-type injection fix was NOT applied (" + stage + "). Ensure Il2CppInteropFix.Patcher.dll is in BepInEx/patchers.")); } } } } private static void TryPatchChainloader() { //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Expected O, but got Unknown //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Expected O, but got Unknown //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Expected O, but got Unknown //IL_020f: Expected O, but got Unknown lock (ApplyLock) { if (_chainloaderPatched) { return; } Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly assembly2) => assembly2.GetName().Name == "BepInEx.Unity.IL2CPP"); if (assembly == null) { return; } Type type = assembly.GetType("BepInEx.Unity.IL2CPP.Il2CppInteropManager", throwOnError: false); Type type2 = assembly.GetType("BepInEx.Unity.IL2CPP.IL2CPPChainloader", throwOnError: false); MethodInfo methodInfo = type?.GetMethod("Initialize", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo methodInfo2 = type?.GetMethod("PreloadInteropAssemblies", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo methodInfo3 = type2?.GetMethod("LoadPlugin", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(PluginInfo), typeof(Assembly) }, null); if (methodInfo == null && methodInfo2 == null && methodInfo3 == null) { ManualLogSource log = _log; if (log != null) { log.LogDebug((object)("Il2CppInterop fix bootstrap: chainloader methods not ready yet " + $"(managerType={type != null}, chainloaderType={type2 != null}).")); } return; } if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Il2CppInteropFixBootstrap), "BeforeInteropInitialize", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } if (methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(Il2CppInteropFixBootstrap), "AfterPreloadInteropAssemblies", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } if (methodInfo3 != null) { _harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(Il2CppInteropFixBootstrap), "BeforePluginLoad", (Type[])null), new HarmonyMethod(typeof(Il2CppInteropFixBootstrap), "AfterPluginLoad", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } _chainloaderPatched = true; ManualLogSource log2 = _log; if (log2 != null) { log2.LogInfo((object)"Il2CppInterop fix bootstrap installed (pre-plugin)."); } } } public static void BeforeInteropInitialize() { TryApplyLookupPatch("before Il2CppInteropManager.Initialize"); } public static void AfterPreloadInteropAssemblies() { TryApplyLookupPatch("after PreloadInteropAssemblies"); } public static void BeforePluginLoad() { TryPatchChainloader(); TryApplyLookupPatch("before plugin Load"); } public static void AfterPluginLoad(PluginInfo pluginInfo, Assembly pluginAssembly) { string text = pluginAssembly?.GetName().Name ?? string.Empty; DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(18, 2); defaultInterpolatedStringHandler.AppendLiteral("Plugin loaded: "); object value; if (pluginInfo == null) { value = null; } else { BepInPlugin metadata = pluginInfo.Metadata; value = ((metadata != null) ? metadata.Name : null); } defaultInterpolatedStringHandler.AppendFormatted((string?)value); defaultInterpolatedStringHandler.AppendLiteral(" ("); defaultInterpolatedStringHandler.AppendFormatted(text); defaultInterpolatedStringHandler.AppendLiteral(")"); FixLogger.Debug(defaultInterpolatedStringHandler.ToStringAndClear()); if (string.Equals(text, "BotControl", StringComparison.Ordinal)) { NestedTypeLookupFix.LogBotControlSummary(); } } } internal sealed class NestedTypeDiagnostics { private readonly List _events = new List(); private readonly Dictionary _shortNameOwners = new Dictionary(StringComparer.Ordinal); private readonly Dictionary> _computedFullNames = new Dictionary>(StringComparer.Ordinal); internal int LookupQualifiedAdded; internal int LookupShortAdded; internal int LookupShortSkipped; internal int DeclaringLinkOk; internal int DeclaringLinkFailed; internal void RecordEvent(string line) { _events.Add(line); FixLogger.Debug(line); } internal void RecordShortNameOwner(string namespaze, string shortName, string ownerType, IntPtr image) { string key = $"{namespaze}|{shortName}|{image.ToInt64():X}"; _shortNameOwners[key] = ownerType; } internal bool TryGetShortNameOwner(string namespaze, string shortName, IntPtr image, out string ownerType) { string key = $"{namespaze}|{shortName}|{image.ToInt64():X}"; return _shortNameOwners.TryGetValue(key, out ownerType); } internal void RecordComputedFullName(string fullName, string managedType) { if (!_computedFullNames.TryGetValue(fullName, out var value)) { value = new List(); _computedFullNames[fullName] = value; } value.Add(managedType); } internal string BuildSummary() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("--- Il2CppInteropFix BotControl nested-type summary ---"); StringBuilder stringBuilder2 = stringBuilder; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(46, 3, stringBuilder2); handler.AppendLiteral("Lookup: qualified="); handler.AppendFormatted(LookupQualifiedAdded); handler.AppendLiteral(", shortAdded="); handler.AppendFormatted(LookupShortAdded); handler.AppendLiteral(", shortSkipped="); handler.AppendFormatted(LookupShortSkipped); stringBuilder3.AppendLine(ref handler); stringBuilder2 = stringBuilder; StringBuilder stringBuilder4 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(32, 2, stringBuilder2); handler.AppendLiteral("DeclaringType link: ok="); handler.AppendFormatted(DeclaringLinkOk); handler.AppendLiteral(", failed="); handler.AppendFormatted(DeclaringLinkFailed); stringBuilder4.AppendLine(ref handler); foreach (KeyValuePair> computedFullName in _computedFullNames) { if (computedFullName.Value.Count > 1) { stringBuilder2 = stringBuilder; StringBuilder stringBuilder5 = stringBuilder2; handler = new StringBuilder.AppendInterpolatedStringHandler(26, 2, stringBuilder2); handler.AppendLiteral("DUPLICATE full name '"); handler.AppendFormatted(computedFullName.Key); handler.AppendLiteral("' -> "); handler.AppendFormatted(string.Join(", ", computedFullName.Value)); stringBuilder5.AppendLine(ref handler); } } if (_events.Count > 0 && FixLogger.Verbose) { stringBuilder.AppendLine("Per-type trace:"); foreach (string @event in _events) { stringBuilder.AppendLine(" " + @event); } } stringBuilder.Append("--- end summary ---"); return stringBuilder.ToString(); } } internal static class NestedTypeLookupFix { private const Il2CppClassAttributes VisibilityMask = (Il2CppClassAttributes)7u; private const Il2CppClassAttributes NestedPublic = (Il2CppClassAttributes)2u; private const Il2CppClassAttributes NestedPrivate = (Il2CppClassAttributes)3u; private const string TargetAssemblyName = "BotControl"; private static readonly object InstallLock = new object(); private static bool _lookupPatchInstalled; private static bool _registerPatchInstalled; private static FieldInfo _injectedTypesField; private static NestedTypeDiagnostics _botControlDiagnostics; internal static bool IsLookupPatchInstalled => _lookupPatchInstalled; internal static void LogBotControlSummary() { NestedTypeDiagnostics botControlDiagnostics = _botControlDiagnostics; if (botControlDiagnostics == null) { FixLogger.Info("BotControl finished loading; no nested BotControl types were intercepted by Il2CppInteropFix."); } else { FixLogger.Info(botControlDiagnostics.BuildSummary()); } } internal static bool ShouldPassThroughToStock(Type type) { if (type == null || type.DeclaringType == null) { return true; } Assembly assembly = type.Assembly; string text = assembly.GetName().Name ?? string.Empty; if (text.StartsWith("Il2CppInterop.", StringComparison.Ordinal)) { return true; } string location = assembly.Location; if (!string.IsNullOrEmpty(location)) { string text2 = location.Replace('/', '\\'); if (text2.Contains("\\interop\\", StringComparison.OrdinalIgnoreCase) || text2.Contains("\\patchers\\", StringComparison.OrdinalIgnoreCase)) { return true; } } if (!string.Equals(text, "BotControl", StringComparison.Ordinal)) { return true; } return !IsInjectedType(type); } internal static bool TryInstallLookupPatch(Harmony harmony) { lock (InstallLock) { if (_lookupPatchInstalled) { return true; } if (!TryPatchAddTypeToLookup(harmony)) { FixLogger.Error("Failed to patch InjectorHelpers.AddTypeToLookup."); return false; } if (!TryPatchRegisterTypeInIl2Cpp(harmony)) { FixLogger.Warning("AddTypeToLookup patched, but RegisterTypeInIl2Cpp postfix was not installed."); } _lookupPatchInstalled = true; FixLogger.Info("Patches installed: AddTypeToLookup=yes, RegisterTypeInIl2Cpp=" + (_registerPatchInstalled ? "yes" : "no") + ". Set env IL2CPP_INTEROP_FIX_VERBOSE=1 for per-type trace."); return true; } } private static bool TryPatchRegisterTypeInIl2Cpp(Harmony harmony) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown if (_registerPatchInstalled) { return true; } Type type = FindLoadedType("Il2CppInterop.Runtime.Injection.ClassInjector"); Type type2 = FindLoadedType("Il2CppInterop.Runtime.Injection.RegisterTypeOptions"); if (type == null || type2 == null) { FixLogger.Warning("RegisterTypeInIl2Cpp patch skipped: ClassInjector types not found."); return false; } MethodInfo methodInfo = AccessTools.Method(type, "RegisterTypeInIl2Cpp", new Type[2] { typeof(Type), type2 }, (Type[])null); if (methodInfo == null) { FixLogger.Warning("RegisterTypeInIl2Cpp patch skipped: target method not found."); return false; } harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(NestedTypeLookupFix), "RegisterTypeInIl2CppPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _registerPatchInstalled = true; return true; } internal static void RegisterTypeInIl2CppPostfix(Type type) { if (!ShouldPassThroughToStock(type)) { NestedTypeDiagnostics botControlDiagnostics = GetBotControlDiagnostics(); string computedFullName; string text = TryLinkNestedDeclaringType(type, out computedFullName); if (text == "ok") { botControlDiagnostics.DeclaringLinkOk++; } else { botControlDiagnostics.DeclaringLinkFailed++; } botControlDiagnostics.RecordComputedFullName(computedFullName, type.FullName ?? type.Name); botControlDiagnostics.RecordEvent($"Register {type.FullName}: DeclaringType={text}, il2cppFullName='{computedFullName}'"); FixLogger.Info($"Nested register {type.Name} on {type.DeclaringType?.Name}: DeclaringType {text}, fullName='{computedFullName}'"); } } private unsafe static string TryLinkNestedDeclaringType(Type type, out string computedFullName) { computedFullName = string.Empty; try { Type declaringType = type.DeclaringType; if (declaringType == null) { return "no-managed-declaring-type"; } IntPtr nativeClassPointer = Il2CppClassPointerStore.GetNativeClassPointer(type); IntPtr nativeClassPointer2 = Il2CppClassPointerStore.GetNativeClassPointer(declaringType); if (nativeClassPointer == IntPtr.Zero) { return "native-class-missing"; } if (nativeClassPointer2 == IntPtr.Zero) { return "parent-not-registered-yet (" + declaringType.FullName + ")"; } INativeClassStruct val = UnityVersionHandler.Wrap((Il2CppClass*)(void*)nativeClassPointer); computedFullName = BuildIl2CppFullName((Il2CppClass*)(void*)nativeClassPointer); val.DeclaringType = (Il2CppClass*)(void*)nativeClassPointer2; if (val.DeclaringType == null) { return "declaring-type-set-null"; } ref Il2CppClassAttributes flags = ref val.Flags; flags = (Il2CppClassAttributes)((uint)flags & 0xFFFFFFF8u); ref Il2CppClassAttributes flags2 = ref val.Flags; flags2 = (Il2CppClassAttributes)((uint)flags2 | (uint)(type.IsNestedPublic ? 2 : 3)); computedFullName = BuildIl2CppFullName((Il2CppClass*)(void*)nativeClassPointer); return "ok"; } catch (Exception ex) { FixLogger.Warning($"DeclaringType link failed for {type.FullName}: {ex.GetType().Name}: {ex.Message}"); return "exception:" + ex.GetType().Name; } } private unsafe static string BuildIl2CppFullName(Il2CppClass* classPointer) { try { Stack stack = new Stack(); INativeClassStruct val = UnityVersionHandler.Wrap(classPointer); INativeClassStruct val2 = val; do { stack.Push(Marshal.PtrToStringUTF8(val.Name) ?? string.Empty); val2 = val; } while ((val = UnityVersionHandler.Wrap(val.DeclaringType)) != null); string text = ((val2.Namespace != IntPtr.Zero) ? (Marshal.PtrToStringUTF8(val2.Namespace) ?? string.Empty) : string.Empty); StringBuilder stringBuilder = new StringBuilder(); if (text.Length > 0) { stringBuilder.Append(text).Append('.'); } stringBuilder.Append(string.Join("+", stack)); return stringBuilder.ToString(); } catch (Exception ex) { return ""; } } private static Type FindLoadedType(string fullName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType(fullName, throwOnError: false); if (type != null) { return type; } } return AccessTools.TypeByName(fullName); } private static bool TryPatchAddTypeToLookup(Harmony harmony) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(FindLoadedType("Il2CppInterop.Runtime.Injection.InjectorHelpers"), "AddTypeToLookup", new Type[2] { typeof(Type), typeof(IntPtr) }, (Type[])null); if (methodInfo == null) { return false; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(NestedTypeLookupFix), "AddTypeToLookupPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return true; } internal static bool AddTypeToLookupPrefix(Type type, IntPtr typePointer) { if (ShouldPassThroughToStock(type)) { return true; } AddTypeToLookupImpl(type, typePointer); return false; } internal static void AddTypeToLookupImpl(Type type, IntPtr typePointer) { if (!TryBuildLookupNames(type, out var namespaze, out var klass)) { FixLogger.Warning("Lookup skipped for " + type?.FullName + ": could not build names."); return; } FieldInfo fieldInfo = AccessTools.Field(FindLoadedType("Il2CppInterop.Runtime.Injection.InjectorHelpers"), "s_ClassNameLookup"); if (fieldInfo == null) { FixLogger.Warning("s_ClassNameLookup field not found."); return; } Dictionary<(string, string, IntPtr), IntPtr> dict = (Dictionary<(string, string, IntPtr), IntPtr>)fieldInfo.GetValue(null); string name = type.Name; NestedTypeDiagnostics botControlDiagnostics = GetBotControlDiagnostics(); int num = 0; int num2 = 0; int num3 = 0; string text = null; lock (InstallLock) { foreach (IntPtr targetImage in GetTargetImages(type)) { if (TryAddLookupEntry(dict, namespaze, klass, targetImage, typePointer)) { num++; botControlDiagnostics.LookupQualifiedAdded++; } if (string.IsNullOrEmpty(name) || string.Equals(name, klass, StringComparison.Ordinal)) { continue; } if (TryAddLookupEntry(dict, namespaze, name, targetImage, typePointer)) { num2++; botControlDiagnostics.LookupShortAdded++; botControlDiagnostics.RecordShortNameOwner(namespaze, name, type.FullName ?? type.Name, targetImage); continue; } num3++; botControlDiagnostics.LookupShortSkipped++; if (text == null && botControlDiagnostics.TryGetShortNameOwner(namespaze, name, targetImage, out var ownerType)) { text = ownerType; } } } if (num3 > 0) { FixLogger.Warning($"Short lookup '{namespaze}.{name}' owned by '{text ?? "?"}'; skipped for '{type.FullName}' ({num3} images). Qualified key '{klass}' still added."); } botControlDiagnostics.RecordEvent($"Lookup {type.FullName}: klass='{klass}', images={num}, short +{num2}/skip{num3}, ptr=0x{typePointer.ToInt64():X}"); FixLogger.Info($"Lookup {type.Name}: qualified on {num} image(s), short +{num2} skip {num3}"); } private static bool TryAddLookupEntry(Dictionary<(string, string, IntPtr), IntPtr> dict, string namespaze, string klass, IntPtr image, IntPtr typePointer) { (string, string, IntPtr) key = (namespaze, klass, image); if (dict.ContainsKey(key)) { return false; } dict.Add(key, typePointer); return true; } internal static bool TryBuildLookupNames(Type type, out string namespaze, out string klass) { namespaze = string.Empty; klass = string.Empty; if (type == null) { return false; } Stack stack = new Stack(); Type type2 = type; while (type2 != null) { stack.Push(type2.Name); type2 = type2.DeclaringType; } klass = ((stack.Count <= 1) ? type.Name : string.Join("+", stack)); if (string.IsNullOrEmpty(klass)) { return false; } namespaze = type.Namespace ?? string.Empty; return true; } private static NestedTypeDiagnostics GetBotControlDiagnostics() { if (_botControlDiagnostics == null) { _botControlDiagnostics = new NestedTypeDiagnostics(); } return _botControlDiagnostics; } private static bool IsInjectedType(Type type) { FieldInfo injectedTypesField = GetInjectedTypesField(); if (injectedTypesField == null || (object)type == null || type.FullName == null) { return false; } object value = injectedTypesField.GetValue(null); if (value is ICollection collection) { return collection.Contains(type.FullName); } if (value is IEnumerable enumerable) { foreach (object item in enumerable) { if (item is string text && text == type.FullName) { return true; } } } return false; } private static FieldInfo GetInjectedTypesField() { if (_injectedTypesField != null) { return _injectedTypesField; } Type type = FindLoadedType("Il2CppInterop.Runtime.Injection.ClassInjector"); _injectedTypesField = ((type == null) ? null : AccessTools.Field(type, "InjectedTypes")); return _injectedTypesField; } private static IEnumerable GetTargetImages(Type type) { Type type2 = FindLoadedType("Il2CppInterop.Runtime.Attributes.ClassInjectionAssemblyTargetAttribute"); Attribute attribute = ((type2 == null) ? null : Attribute.GetCustomAttribute(type, type2)); if (attribute == null) { MethodInfo methodInfo = AccessTools.Method(typeof(IL2CPP), "GetIl2CppImages", (Type[])null, (Type[])null); if (!(methodInfo == null)) { return (IEnumerable)methodInfo.Invoke(null, null); } return Array.Empty(); } return (IEnumerable)AccessTools.Method(attribute.GetType(), "GetImagePointers", (Type[])null, (Type[])null).Invoke(attribute, null); } } }