2020-08-18 17:11:58 +10:00
|
|
|
|
using System;
|
2020-09-08 17:07:10 +10:00
|
|
|
|
using System.Collections;
|
2020-08-18 17:11:58 +10:00
|
|
|
|
using System.Collections.Generic;
|
2020-09-11 18:53:17 +10:00
|
|
|
|
using System.IO;
|
2020-11-05 17:33:04 +11:00
|
|
|
|
using System.Linq;
|
2020-09-18 18:38:11 +10:00
|
|
|
|
using System.Reflection;
|
2020-08-18 17:11:58 +10:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
using BF = System.Reflection.BindingFlags;
|
2020-10-18 21:41:04 +11:00
|
|
|
|
using System.Diagnostics.CodeAnalysis;
|
2020-09-27 22:04:23 +10:00
|
|
|
|
#if CPP
|
2020-11-16 00:50:06 +11:00
|
|
|
|
using CppType = Il2CppSystem.Type;
|
2020-09-27 22:04:23 +10:00
|
|
|
|
using UnhollowerBaseLib;
|
|
|
|
|
using UnhollowerRuntimeLib;
|
2020-10-18 04:39:50 +11:00
|
|
|
|
using System.Runtime.InteropServices;
|
2020-09-27 22:04:23 +10:00
|
|
|
|
#endif
|
2020-08-18 17:11:58 +10:00
|
|
|
|
|
2020-11-03 20:59:13 +11:00
|
|
|
|
namespace UnityExplorer.Helpers
|
2020-08-18 17:11:58 +10:00
|
|
|
|
{
|
2020-10-18 21:41:04 +11:00
|
|
|
|
[SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "External methods")]
|
2020-11-05 17:33:04 +11:00
|
|
|
|
public static class ReflectionHelpers
|
2020-08-18 17:11:58 +10:00
|
|
|
|
{
|
|
|
|
|
public static BF CommonFlags = BF.Public | BF.Instance | BF.NonPublic | BF.Static;
|
|
|
|
|
|
2020-11-13 18:46:36 +11:00
|
|
|
|
public static Type GetTypeByName(string fullName)
|
|
|
|
|
{
|
|
|
|
|
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
|
|
|
|
{
|
|
|
|
|
foreach (var type in asm.TryGetTypes())
|
|
|
|
|
{
|
|
|
|
|
if (type.FullName == fullName)
|
|
|
|
|
{
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-18 17:11:58 +10:00
|
|
|
|
|
2020-11-13 18:46:36 +11:00
|
|
|
|
return null;
|
|
|
|
|
}
|
2020-11-05 17:33:04 +11:00
|
|
|
|
|
2020-11-13 18:46:36 +11:00
|
|
|
|
public static Type[] GetAllBaseTypes(object obj) => GetAllBaseTypes(GetActualType(obj));
|
2020-11-05 17:33:04 +11:00
|
|
|
|
|
2020-11-13 18:46:36 +11:00
|
|
|
|
public static Type[] GetAllBaseTypes(Type type)
|
2020-08-18 17:11:58 +10:00
|
|
|
|
{
|
2020-11-13 18:46:36 +11:00
|
|
|
|
List<Type> list = new List<Type>();
|
2020-08-22 17:17:11 +10:00
|
|
|
|
|
2020-11-13 18:46:36 +11:00
|
|
|
|
while (type != null)
|
2020-10-28 06:39:26 +11:00
|
|
|
|
{
|
2020-11-13 18:46:36 +11:00
|
|
|
|
list.Add(type);
|
|
|
|
|
type = type.BaseType;
|
2020-10-28 06:39:26 +11:00
|
|
|
|
}
|
2020-09-21 22:45:33 +10:00
|
|
|
|
|
2020-11-13 18:46:36 +11:00
|
|
|
|
return list.ToArray();
|
|
|
|
|
}
|
2020-08-29 21:15:54 +10:00
|
|
|
|
|
2020-11-13 18:46:36 +11:00
|
|
|
|
public static Type GetActualType(object obj)
|
|
|
|
|
{
|
|
|
|
|
if (obj == null)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
var type = obj.GetType();
|
|
|
|
|
#if CPP
|
|
|
|
|
if (obj is Il2CppSystem.Object ilObject)
|
2020-08-31 18:23:19 +10:00
|
|
|
|
{
|
2020-11-16 00:50:06 +11:00
|
|
|
|
if (ilObject is CppType)
|
|
|
|
|
return typeof(CppType);
|
2020-11-13 18:46:36 +11:00
|
|
|
|
|
2020-11-16 00:50:06 +11:00
|
|
|
|
if (!string.IsNullOrEmpty(type.Namespace))
|
|
|
|
|
{
|
2020-11-14 19:51:16 +11:00
|
|
|
|
// Il2CppSystem-namespace objects should just return GetType,
|
|
|
|
|
// because using GetIl2CppType returns the System namespace type instead.
|
|
|
|
|
if (type.Namespace.StartsWith("System.") || type.Namespace.StartsWith("Il2CppSystem."))
|
|
|
|
|
return ilObject.GetType();
|
2020-11-16 00:50:06 +11:00
|
|
|
|
}
|
2020-11-13 18:46:36 +11:00
|
|
|
|
|
2020-11-13 21:39:25 +11:00
|
|
|
|
var il2cppType = ilObject.GetIl2CppType();
|
|
|
|
|
|
|
|
|
|
// check if type is injected
|
|
|
|
|
IntPtr classPtr = il2cpp_object_get_class(ilObject.Pointer);
|
|
|
|
|
if (RuntimeSpecificsStore.IsInjected(classPtr))
|
2020-11-16 21:21:04 +11:00
|
|
|
|
{
|
|
|
|
|
var typeByName = GetTypeByName(il2cppType.FullName);
|
|
|
|
|
if (typeByName != null)
|
|
|
|
|
return typeByName;
|
|
|
|
|
}
|
2020-11-13 21:39:25 +11:00
|
|
|
|
|
2020-11-16 00:50:06 +11:00
|
|
|
|
// this should be fine for all other il2cpp objects
|
|
|
|
|
var getType = GetMonoType(il2cppType);
|
2020-11-13 18:46:36 +11:00
|
|
|
|
if (getType != null)
|
|
|
|
|
return getType;
|
2020-08-31 18:23:19 +10:00
|
|
|
|
}
|
2020-11-13 18:46:36 +11:00
|
|
|
|
#endif
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2020-10-18 04:39:50 +11:00
|
|
|
|
|
2020-11-13 18:46:36 +11:00
|
|
|
|
#if CPP
|
2020-11-16 00:50:06 +11:00
|
|
|
|
private static readonly Dictionary<CppType, Type> Il2CppToMonoType = new Dictionary<CppType, Type>();
|
|
|
|
|
|
|
|
|
|
public static Type GetMonoType(CppType cppType)
|
|
|
|
|
{
|
|
|
|
|
if (Il2CppToMonoType.ContainsKey(cppType))
|
|
|
|
|
return Il2CppToMonoType[cppType];
|
|
|
|
|
|
|
|
|
|
var getType = Type.GetType(cppType.AssemblyQualifiedName);
|
|
|
|
|
Il2CppToMonoType.Add(cppType, getType);
|
|
|
|
|
return getType;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-19 16:47:18 +11:00
|
|
|
|
private static readonly Dictionary<Type, IntPtr> CppClassPointers = new Dictionary<Type, IntPtr>();
|
2020-11-13 18:46:36 +11:00
|
|
|
|
|
|
|
|
|
public static object Il2CppCast(this object obj, Type castTo)
|
|
|
|
|
{
|
|
|
|
|
if (!(obj is Il2CppSystem.Object ilObj))
|
2020-10-18 21:41:04 +11:00
|
|
|
|
return obj;
|
|
|
|
|
|
2020-11-13 18:46:36 +11:00
|
|
|
|
if (!Il2CppTypeNotNull(castTo, out IntPtr castToPtr))
|
|
|
|
|
return obj;
|
|
|
|
|
|
2020-11-19 16:47:18 +11:00
|
|
|
|
IntPtr castFromPtr = il2cpp_object_get_class(ilObj.Pointer);
|
2020-10-18 04:39:50 +11:00
|
|
|
|
|
2020-11-19 16:47:18 +11:00
|
|
|
|
if (!il2cpp_class_is_assignable_from(castToPtr, castFromPtr))
|
2020-10-18 04:39:50 +11:00
|
|
|
|
return obj;
|
|
|
|
|
|
2020-10-18 21:41:04 +11:00
|
|
|
|
if (RuntimeSpecificsStore.IsInjected(castToPtr))
|
|
|
|
|
return UnhollowerBaseLib.Runtime.ClassInjectorBase.GetMonoObjectFromIl2CppPointer(ilObj.Pointer);
|
2020-10-18 04:46:50 +11:00
|
|
|
|
|
2020-10-18 21:41:04 +11:00
|
|
|
|
return Activator.CreateInstance(castTo, ilObj.Pointer);
|
2020-08-18 17:11:58 +10:00
|
|
|
|
}
|
2020-11-13 18:46:36 +11:00
|
|
|
|
|
2020-11-19 16:47:18 +11:00
|
|
|
|
public static bool Il2CppTypeNotNull(Type type) => Il2CppTypeNotNull(type, out _);
|
2020-11-13 18:46:36 +11:00
|
|
|
|
|
|
|
|
|
public static bool Il2CppTypeNotNull(Type type, out IntPtr il2cppPtr)
|
|
|
|
|
{
|
2020-11-19 16:47:18 +11:00
|
|
|
|
if (!CppClassPointers.ContainsKey(type))
|
2020-11-13 18:46:36 +11:00
|
|
|
|
{
|
|
|
|
|
il2cppPtr = (IntPtr)typeof(Il2CppClassPointerStore<>)
|
|
|
|
|
.MakeGenericType(new Type[] { type })
|
|
|
|
|
.GetField("NativeClassPtr", BF.Public | BF.Static)
|
|
|
|
|
.GetValue(null);
|
|
|
|
|
|
2020-11-19 16:47:18 +11:00
|
|
|
|
CppClassPointers.Add(type, il2cppPtr);
|
2020-11-13 18:46:36 +11:00
|
|
|
|
}
|
|
|
|
|
else
|
2020-11-19 16:47:18 +11:00
|
|
|
|
il2cppPtr = CppClassPointers[type];
|
2020-11-13 18:46:36 +11:00
|
|
|
|
|
|
|
|
|
return il2cppPtr != IntPtr.Zero;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
|
|
|
|
public static extern bool il2cpp_class_is_assignable_from(IntPtr klass, IntPtr oklass);
|
|
|
|
|
|
|
|
|
|
[DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
|
|
|
|
public static extern IntPtr il2cpp_object_get_class(IntPtr obj);
|
|
|
|
|
|
2020-09-27 22:04:23 +10:00
|
|
|
|
#endif
|
2020-08-29 21:15:54 +10:00
|
|
|
|
|
2020-11-05 17:33:04 +11:00
|
|
|
|
public static IEnumerable<Type> TryGetTypes(this Assembly asm)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return asm.GetTypes();
|
|
|
|
|
}
|
|
|
|
|
catch (ReflectionTypeLoadException e)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return asm.GetExportedTypes();
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
return e.Types.Where(t => t != null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
return Enumerable.Empty<Type>();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-19 16:47:18 +11:00
|
|
|
|
#if CPP
|
|
|
|
|
internal static void TryLoadGameModules()
|
|
|
|
|
{
|
|
|
|
|
LoadModule("Assembly-CSharp");
|
|
|
|
|
LoadModule("Assembly-CSharp-firstpass");
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-11 18:53:17 +10:00
|
|
|
|
public static bool LoadModule(string module)
|
|
|
|
|
{
|
2020-09-29 05:40:06 +10:00
|
|
|
|
#if ML
|
2020-11-19 16:47:18 +11:00
|
|
|
|
var path = $@"MelonLoader\Managed\{module}.dll";
|
2020-09-29 05:40:06 +10:00
|
|
|
|
#else
|
|
|
|
|
var path = $@"BepInEx\unhollowed\{module}.dll";
|
|
|
|
|
#endif
|
2020-11-19 16:47:18 +11:00
|
|
|
|
|
|
|
|
|
return LoadModuleInternal(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static bool LoadModuleInternal(string fullPath)
|
|
|
|
|
{
|
|
|
|
|
if (!File.Exists(fullPath))
|
2020-10-28 06:39:26 +11:00
|
|
|
|
return false;
|
2020-09-11 18:53:17 +10:00
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2020-11-19 16:47:18 +11:00
|
|
|
|
Assembly.Load(File.ReadAllBytes(fullPath));
|
2020-09-11 18:53:17 +10:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
2020-11-19 16:47:18 +11:00
|
|
|
|
Console.WriteLine(e.GetType() + ", " + e.Message);
|
2020-09-11 18:53:17 +10:00
|
|
|
|
}
|
2020-11-19 16:47:18 +11:00
|
|
|
|
|
2020-09-29 05:40:06 +10:00
|
|
|
|
return false;
|
2020-09-11 18:53:17 +10:00
|
|
|
|
}
|
2020-11-20 17:12:40 +11:00
|
|
|
|
#else
|
|
|
|
|
public static bool LoadModule(string module) => true;
|
2020-11-19 16:47:18 +11:00
|
|
|
|
#endif
|
2020-09-11 18:53:17 +10:00
|
|
|
|
|
2020-10-18 04:39:50 +11:00
|
|
|
|
public static bool IsEnumerable(Type t)
|
2020-09-08 17:07:10 +10:00
|
|
|
|
{
|
2020-10-18 04:39:50 +11:00
|
|
|
|
if (typeof(IEnumerable).IsAssignableFrom(t))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-27 22:04:23 +10:00
|
|
|
|
#if CPP
|
2020-10-18 04:39:50 +11:00
|
|
|
|
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
|
2020-09-08 17:07:10 +10:00
|
|
|
|
{
|
2020-10-18 04:39:50 +11:00
|
|
|
|
return typeof(Il2CppSystem.Collections.Generic.List<>).IsAssignableFrom(g)
|
|
|
|
|
|| typeof(Il2CppSystem.Collections.Generic.IList<>).IsAssignableFrom(g)
|
|
|
|
|
|| typeof(Il2CppSystem.Collections.Generic.HashSet<>).IsAssignableFrom(g);
|
2020-09-08 17:07:10 +10:00
|
|
|
|
}
|
2020-10-18 04:39:50 +11:00
|
|
|
|
else
|
2020-09-08 17:07:10 +10:00
|
|
|
|
{
|
2020-10-18 04:39:50 +11:00
|
|
|
|
return typeof(Il2CppSystem.Collections.IList).IsAssignableFrom(t);
|
2020-09-08 17:07:10 +10:00
|
|
|
|
}
|
2020-10-18 04:39:50 +11:00
|
|
|
|
#else
|
|
|
|
|
return false;
|
2020-09-27 22:04:23 +10:00
|
|
|
|
#endif
|
2020-09-08 17:07:10 +10:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-18 04:39:50 +11:00
|
|
|
|
public static bool IsDictionary(Type t)
|
2020-09-08 17:07:10 +10:00
|
|
|
|
{
|
2020-10-18 04:39:50 +11:00
|
|
|
|
if (typeof(IDictionary).IsAssignableFrom(t))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-09-08 17:07:10 +10:00
|
|
|
|
|
2020-10-18 04:39:50 +11:00
|
|
|
|
#if CPP
|
|
|
|
|
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
|
|
|
|
|
{
|
|
|
|
|
return typeof(Il2CppSystem.Collections.Generic.Dictionary<,>).IsAssignableFrom(g)
|
|
|
|
|
|| typeof(Il2CppSystem.Collections.Generic.IDictionary<,>).IsAssignableFrom(g);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return typeof(Il2CppSystem.Collections.IDictionary).IsAssignableFrom(t)
|
|
|
|
|
|| typeof(Il2CppSystem.Collections.Hashtable).IsAssignableFrom(t);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
2020-09-08 17:07:10 +10:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-12 16:15:41 +11:00
|
|
|
|
public static string ExceptionToString(Exception e, bool innerMost = false)
|
2020-09-08 17:07:10 +10:00
|
|
|
|
{
|
2020-11-12 16:15:41 +11:00
|
|
|
|
while (innerMost && e.InnerException != null)
|
2020-11-16 21:21:04 +11:00
|
|
|
|
{
|
|
|
|
|
#if CPP
|
|
|
|
|
if (e.InnerException is System.Runtime.CompilerServices.RuntimeWrappedException runtimeEx)
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
2020-11-12 16:15:41 +11:00
|
|
|
|
e = e.InnerException;
|
2020-11-16 21:21:04 +11:00
|
|
|
|
}
|
2020-11-12 16:15:41 +11:00
|
|
|
|
|
2020-10-18 04:39:50 +11:00
|
|
|
|
return e.GetType() + ", " + e.Message;
|
2020-09-08 17:07:10 +10:00
|
|
|
|
}
|
2020-08-18 17:11:58 +10:00
|
|
|
|
}
|
|
|
|
|
}
|