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;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
2020-09-11 18:53:17 +10:00
|
|
|
|
using System.IO;
|
|
|
|
|
using MelonLoader;
|
2020-08-18 17:11:58 +10:00
|
|
|
|
using UnhollowerBaseLib;
|
|
|
|
|
using UnhollowerRuntimeLib;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using BF = System.Reflection.BindingFlags;
|
2020-09-08 17:07:10 +10:00
|
|
|
|
using ILType = Il2CppSystem.Type;
|
2020-08-18 17:11:58 +10:00
|
|
|
|
|
|
|
|
|
namespace Explorer
|
|
|
|
|
{
|
|
|
|
|
public class ReflectionHelpers
|
|
|
|
|
{
|
|
|
|
|
public static BF CommonFlags = BF.Public | BF.Instance | BF.NonPublic | BF.Static;
|
|
|
|
|
|
2020-09-08 17:07:10 +10:00
|
|
|
|
public static ILType GameObjectType => Il2CppType.Of<GameObject>();
|
|
|
|
|
public static ILType TransformType => Il2CppType.Of<Transform>();
|
|
|
|
|
public static ILType ObjectType => Il2CppType.Of<UnityEngine.Object>();
|
|
|
|
|
public static ILType ComponentType => Il2CppType.Of<Component>();
|
|
|
|
|
public static ILType BehaviourType => Il2CppType.Of<Behaviour>();
|
2020-08-18 17:11:58 +10:00
|
|
|
|
|
|
|
|
|
private static readonly MethodInfo m_tryCastMethodInfo = typeof(Il2CppObjectBase).GetMethod("TryCast");
|
|
|
|
|
|
|
|
|
|
public static object Il2CppCast(object obj, Type castTo)
|
|
|
|
|
{
|
2020-08-22 17:17:11 +10:00
|
|
|
|
if (!typeof(Il2CppSystem.Object).IsAssignableFrom(castTo)) return obj;
|
|
|
|
|
|
2020-09-01 18:03:44 +10:00
|
|
|
|
return m_tryCastMethodInfo
|
|
|
|
|
.MakeGenericMethod(castTo)
|
|
|
|
|
.Invoke(obj, null);
|
2020-08-18 17:11:58 +10:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-06 21:33:09 +10:00
|
|
|
|
public static bool IsEnumerable(Type t)
|
2020-08-29 21:15:54 +10:00
|
|
|
|
{
|
2020-09-07 17:05:37 +10:00
|
|
|
|
return typeof(IEnumerable).IsAssignableFrom(t);
|
2020-08-29 21:15:54 +10:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-11 00:17:13 +10:00
|
|
|
|
// Checks for Il2Cpp List or HashSet.
|
|
|
|
|
public static bool IsCppEnumerable(Type t)
|
2020-08-18 17:11:58 +10:00
|
|
|
|
{
|
2020-09-07 17:05:37 +10:00
|
|
|
|
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
|
2020-08-31 18:23:19 +10:00
|
|
|
|
{
|
2020-09-07 17:05:37 +10:00
|
|
|
|
return typeof(Il2CppSystem.Collections.Generic.List<>).IsAssignableFrom(g)
|
2020-09-11 00:17:13 +10:00
|
|
|
|
|| typeof(Il2CppSystem.Collections.Generic.IList<>).IsAssignableFrom(g)
|
|
|
|
|
|| typeof(Il2CppSystem.Collections.Generic.HashSet<>).IsAssignableFrom(g);
|
2020-08-31 18:23:19 +10:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-09-07 17:05:37 +10:00
|
|
|
|
return typeof(Il2CppSystem.Collections.IList).IsAssignableFrom(t);
|
2020-08-31 18:23:19 +10:00
|
|
|
|
}
|
2020-08-18 17:11:58 +10:00
|
|
|
|
}
|
|
|
|
|
|
2020-08-29 21:15:54 +10:00
|
|
|
|
public static bool IsDictionary(Type t)
|
|
|
|
|
{
|
2020-09-07 17:05:37 +10:00
|
|
|
|
if (typeof(IDictionary).IsAssignableFrom(t))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
2020-08-29 21:15:54 +10:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-08 06:21:45 +10:00
|
|
|
|
public static Type GetTypeByName(string fullName)
|
2020-08-18 17:11:58 +10:00
|
|
|
|
{
|
|
|
|
|
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
|
|
|
|
{
|
2020-09-08 17:07:10 +10:00
|
|
|
|
foreach (var type in asm.TryGetTypes())
|
2020-08-18 17:11:58 +10:00
|
|
|
|
{
|
2020-09-08 06:21:45 +10:00
|
|
|
|
if (type.FullName == fullName)
|
2020-08-18 17:11:58 +10:00
|
|
|
|
{
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-01 18:03:44 +10:00
|
|
|
|
public static Type GetActualType(object obj)
|
2020-08-18 17:11:58 +10:00
|
|
|
|
{
|
2020-09-01 18:03:44 +10:00
|
|
|
|
if (obj == null) return null;
|
2020-08-22 00:16:05 +10:00
|
|
|
|
|
2020-09-11 00:17:13 +10:00
|
|
|
|
// Need to use GetIl2CppType for Il2CppSystem Objects
|
2020-09-01 18:03:44 +10:00
|
|
|
|
if (obj is Il2CppSystem.Object ilObject)
|
2020-08-18 17:11:58 +10:00
|
|
|
|
{
|
2020-09-11 00:17:13 +10:00
|
|
|
|
// Prevent weird behaviour when inspecting an Il2CppSystem.Type object.
|
|
|
|
|
if (ilObject is ILType)
|
2020-08-30 23:29:37 +10:00
|
|
|
|
{
|
2020-09-11 00:17:13 +10:00
|
|
|
|
return typeof(ILType);
|
2020-08-30 23:29:37 +10:00
|
|
|
|
}
|
2020-09-01 18:03:44 +10:00
|
|
|
|
|
2020-09-11 00:17:13 +10:00
|
|
|
|
return Type.GetType(ilObject.GetIl2CppType().AssemblyQualifiedName) ?? obj.GetType();
|
2020-08-18 17:11:58 +10:00
|
|
|
|
}
|
2020-09-01 18:03:44 +10:00
|
|
|
|
|
2020-09-11 00:17:13 +10:00
|
|
|
|
// It's a normal object, this is fine
|
2020-09-01 18:03:44 +10:00
|
|
|
|
return obj.GetType();
|
2020-08-18 17:11:58 +10:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-01 18:03:44 +10:00
|
|
|
|
public static Type[] GetAllBaseTypes(object obj)
|
2020-08-18 17:11:58 +10:00
|
|
|
|
{
|
|
|
|
|
var list = new List<Type>();
|
|
|
|
|
|
2020-09-01 18:03:44 +10:00
|
|
|
|
var type = GetActualType(obj);
|
2020-08-18 17:11:58 +10:00
|
|
|
|
|
2020-09-11 00:17:13 +10:00
|
|
|
|
while (type != null)
|
2020-08-18 17:11:58 +10:00
|
|
|
|
{
|
|
|
|
|
list.Add(type);
|
2020-09-11 00:17:13 +10:00
|
|
|
|
type = type.BaseType;
|
2020-08-18 17:11:58 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return list.ToArray();
|
|
|
|
|
}
|
2020-09-08 17:07:10 +10:00
|
|
|
|
|
2020-09-11 18:53:17 +10:00
|
|
|
|
public static bool LoadModule(string module)
|
|
|
|
|
{
|
|
|
|
|
var path = $@"MelonLoader\Managed\{module}";
|
|
|
|
|
if (!File.Exists(path)) return false;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Assembly.Load(File.ReadAllBytes(path));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
MelonLogger.Log(e.GetType() + ", " + e.Message);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-08 17:07:10 +10:00
|
|
|
|
public static string ExceptionToString(Exception e)
|
|
|
|
|
{
|
|
|
|
|
if (IsFailedGeneric(e))
|
|
|
|
|
{
|
|
|
|
|
return "Unable to initialize this type.";
|
|
|
|
|
}
|
|
|
|
|
else if (IsObjectCollected(e))
|
|
|
|
|
{
|
|
|
|
|
return "Garbage collected in Il2Cpp.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return e.GetType() + ", " + e.Message;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool IsFailedGeneric(Exception e)
|
|
|
|
|
{
|
|
|
|
|
return IsExceptionOfType(e, typeof(TargetInvocationException)) && IsExceptionOfType(e, typeof(TypeLoadException));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool IsObjectCollected(Exception e)
|
|
|
|
|
{
|
|
|
|
|
return IsExceptionOfType(e, typeof(ObjectCollectedException));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool IsExceptionOfType(Exception e, Type t, bool strict = true, bool checkInner = true)
|
|
|
|
|
{
|
|
|
|
|
bool isType;
|
|
|
|
|
|
|
|
|
|
if (strict)
|
|
|
|
|
isType = e.GetType() == t;
|
|
|
|
|
else
|
|
|
|
|
isType = t.IsAssignableFrom(e.GetType());
|
|
|
|
|
|
|
|
|
|
if (isType) return true;
|
|
|
|
|
|
|
|
|
|
if (e.InnerException != null && checkInner)
|
|
|
|
|
return IsExceptionOfType(e.InnerException, t, strict);
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-08-18 17:11:58 +10:00
|
|
|
|
}
|
|
|
|
|
}
|