public static IntPtr GetIl2CppNestedType(IntPtr enclosingType, string nestedTypeName)
        {
            if (enclosingType == IntPtr.Zero)
            {
                return(IntPtr.Zero);
            }

            IntPtr iter = IntPtr.Zero;
            IntPtr nestedTypePtr;

            if (il2cpp_class_is_inflated(enclosingType))
            {
                LogSupport.Trace("Original class was inflated, falling back to reflection");
                if (GetNestedTypeViaReflection == null)
                {
                    // todo: clean up this ugly reflection hack
                    GetNestedTypeViaReflection = AppDomain.CurrentDomain.GetAssemblies()
                                                 .FirstOrDefault(it => it.GetName().Name == "UnhollowerRuntimeLib")
                                                 ?.GetType("UnhollowerRuntimeLib.RuntimeReflectionHelper")
                                                 ?.GetMethod("GetNestedTypeViaReflection", BindingFlags.Static | BindingFlags.Public)?.CreateDelegate(typeof(Func <IntPtr, string, IntPtr>)) as Func <IntPtr, string, IntPtr>;
                }

                var result = GetNestedTypeViaReflection?.Invoke(enclosingType, nestedTypeName);
                if (result != null)
                {
                    return(result.Value);
                }
            }
            while ((nestedTypePtr = il2cpp_class_get_nested_types(enclosingType, ref iter)) != IntPtr.Zero)
            {
                if (Marshal.PtrToStringAnsi(il2cpp_class_get_name(nestedTypePtr)) == nestedTypeName)
                {
                    return(nestedTypePtr);
                }
            }

            LogSupport.Error($"Nested type {nestedTypeName} on {Marshal.PtrToStringAnsi(il2cpp_class_get_name(enclosingType))} not found!");

            return(IntPtr.Zero);
        }
        public static IntPtr GetIl2CppMethod(IntPtr clazz, string methodName, params string[] argTypes)
        {
            if (clazz == IntPtr.Zero)
            {
                return(NativeStructUtils.GetMethodInfoForMissingMethod(methodName + "(" + string.Join(", ", argTypes) + ")"));
            }

            for (var index = 0; index < argTypes.Length; index++)
            {
                var argType = argTypes[index];
                argTypes[index] = Regex.Replace(argType, "\\`\\d+", "").Replace('/', '.');
            }

            var    methodsSeen = 0;
            var    lastMethod  = IntPtr.Zero;
            IntPtr iter        = IntPtr.Zero;
            IntPtr method;

            while ((method = il2cpp_class_get_methods(clazz, ref iter)) != IntPtr.Zero)
            {
                if (Marshal.PtrToStringAnsi(il2cpp_method_get_name(method)) != methodName)
                {
                    continue;
                }

                if (il2cpp_method_get_param_count(method) != argTypes.Length)
                {
                    continue;
                }

                methodsSeen++;
                lastMethod = method;

                var badType = false;
                for (var i = 0; i < argTypes.Length; i++)
                {
                    var paramType = il2cpp_method_get_param(method, (uint)i);
                    var typeName  = Marshal.PtrToStringAnsi(il2cpp_type_get_name(paramType));
                    if (typeName != argTypes[i])
                    {
                        badType = true;
                        break;
                    }
                }

                if (badType)
                {
                    continue;
                }

                return(method);
            }

            var className = Marshal.PtrToStringAnsi(il2cpp_class_get_name(clazz));

            LogSupport.Trace($"Method {className}::{methodName} was stubbed with a random matching method of the same name");

            if (methodsSeen == 1)
            {
                return(lastMethod);
            }

            LogSupport.Trace($"Unable to find method {className}::{methodName}; signature follows");
            foreach (var argType in argTypes)
            {
                LogSupport.Trace($"    {argType}");
            }
            LogSupport.Trace("Available methods of this name follow:");
            iter = IntPtr.Zero;
            while ((method = il2cpp_class_get_methods(clazz, ref iter)) != IntPtr.Zero)
            {
                if (Marshal.PtrToStringAnsi(il2cpp_method_get_name(method)) != methodName)
                {
                    continue;
                }

                var nParams = il2cpp_method_get_param_count(method);
                LogSupport.Trace("Method starts");
                for (var i = 0; i < nParams; i++)
                {
                    var paramType = il2cpp_method_get_param(method, (uint)i);
                    var typeName  = Marshal.PtrToStringAnsi(il2cpp_type_get_name(paramType));
                    LogSupport.Trace($"    {typeName}");
                }

                return(method);
            }

            return(NativeStructUtils.GetMethodInfoForMissingMethod(className + "::" + methodName + "(" + string.Join(", ", argTypes) + ")"));
        }