faster il2cpp cast, a few cleanups

This commit is contained in:
sinaioutlander 2020-10-18 04:39:50 +11:00
parent e3a58bf675
commit a49a918790
3 changed files with 125 additions and 116 deletions

View File

@ -5,11 +5,11 @@ using System.IO;
using System.Reflection; using System.Reflection;
using UnityEngine; using UnityEngine;
using BF = System.Reflection.BindingFlags; using BF = System.Reflection.BindingFlags;
#if CPP #if CPP
using ILType = Il2CppSystem.Type; using ILType = Il2CppSystem.Type;
using UnhollowerBaseLib; using UnhollowerBaseLib;
using UnhollowerRuntimeLib; using UnhollowerRuntimeLib;
using System.Runtime.InteropServices;
#endif #endif
namespace Explorer.Helpers namespace Explorer.Helpers
@ -20,79 +20,69 @@ namespace Explorer.Helpers
#if CPP #if CPP
public static ILType GameObjectType => Il2CppType.Of<GameObject>(); public static ILType GameObjectType => Il2CppType.Of<GameObject>();
public static ILType TransformType => Il2CppType.Of<Transform>(); public static ILType TransformType => Il2CppType.Of<Transform>();
public static ILType ObjectType => Il2CppType.Of<UnityEngine.Object>(); public static ILType ObjectType => Il2CppType.Of<UnityEngine.Object>();
public static ILType ComponentType => Il2CppType.Of<Component>(); public static ILType ComponentType => Il2CppType.Of<Component>();
public static ILType BehaviourType => Il2CppType.Of<Behaviour>(); public static ILType BehaviourType => Il2CppType.Of<Behaviour>();
#else
public static Type GameObjectType => typeof(GameObject);
public static Type TransformType => typeof(Transform);
public static Type ObjectType => typeof(UnityEngine.Object);
public static Type ComponentType => typeof(Component);
public static Type BehaviourType => typeof(Behaviour);
#endif
private static readonly MethodInfo tryCastMethodInfo = typeof(Il2CppObjectBase).GetMethod("TryCast"); #if CPP
private static readonly Dictionary<Type, MethodInfo> cachedTryCastMethods = new Dictionary<Type, MethodInfo>(); private static readonly Dictionary<Type, IntPtr> ClassPointers = new Dictionary<Type, IntPtr>();
public static object Il2CppCast(object obj, Type castTo) public static object Il2CppCast(object obj, Type castTo)
{ {
if (!typeof(Il2CppSystem.Object).IsAssignableFrom(castTo)) return obj; if (!(obj is Il2CppSystem.Object ilObj))
return obj;
if (!cachedTryCastMethods.ContainsKey(castTo)) if (!typeof(Il2CppSystem.Object).IsAssignableFrom(castTo))
return obj;
IntPtr castToPtr;
if (!ClassPointers.ContainsKey(castTo))
{ {
cachedTryCastMethods.Add(castTo, tryCastMethodInfo.MakeGenericMethod(castTo)); castToPtr = (IntPtr)typeof(Il2CppClassPointerStore<>)
} .MakeGenericType(new Type[] { castTo })
.GetField("NativeClassPtr", BF.Public | BF.Static)
.GetValue(null);
return cachedTryCastMethods[castTo].Invoke(obj, null); if (castToPtr == IntPtr.Zero)
} {
#else ExplorerCore.LogWarning($"[Il2CppCast] Could not get an IntPtr for castTo '{castTo.FullName}'!");
public static Type GameObjectType => typeof(GameObject); return obj;
public static Type TransformType => typeof(Transform); }
public static Type ObjectType => typeof(UnityEngine.Object);
public static Type ComponentType => typeof(Component);
public static Type BehaviourType => typeof(Behaviour);
#endif
public static bool IsEnumerable(Type t) ClassPointers.Add(castTo, castToPtr);
{
if (typeof(IEnumerable).IsAssignableFrom(t))
{
return true;
}
#if CPP
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
{
return typeof(Il2CppSystem.Collections.Generic.List<>).IsAssignableFrom(g)
|| typeof(Il2CppSystem.Collections.Generic.IList<>).IsAssignableFrom(g)
|| typeof(Il2CppSystem.Collections.Generic.HashSet<>).IsAssignableFrom(g);
} }
else else
{ {
return typeof(Il2CppSystem.Collections.IList).IsAssignableFrom(t); castToPtr = ClassPointers[castTo];
}
#else
return false;
#endif
}
public static bool IsDictionary(Type t)
{
if (typeof(IDictionary).IsAssignableFrom(t))
{
return true;
} }
#if CPP IntPtr objPtr = ilObj.Pointer;
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g) var classPtr = il2cpp_object_get_class(objPtr);
{
return typeof(Il2CppSystem.Collections.Generic.Dictionary<,>).IsAssignableFrom(g) //if (RuntimeSpecificsStore.IsInjected(classPtr))
|| typeof(Il2CppSystem.Collections.Generic.IDictionary<,>).IsAssignableFrom(g); // return obj;
}
else if (!il2cpp_class_is_assignable_from(castToPtr, classPtr))
{ return obj;
return typeof(Il2CppSystem.Collections.IDictionary).IsAssignableFrom(t)
|| typeof(Il2CppSystem.Collections.Hashtable).IsAssignableFrom(t); return Activator.CreateInstance(castTo, objPtr);
}
#else
return false;
#endif
} }
[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);
#endif
public static Type GetTypeByName(string fullName) public static Type GetTypeByName(string fullName)
{ {
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
@ -169,48 +159,55 @@ namespace Explorer.Helpers
return false; return false;
} }
public static bool IsEnumerable(Type t)
{
if (typeof(IEnumerable).IsAssignableFrom(t))
{
return true;
}
#if CPP
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
{
return typeof(Il2CppSystem.Collections.Generic.List<>).IsAssignableFrom(g)
|| typeof(Il2CppSystem.Collections.Generic.IList<>).IsAssignableFrom(g)
|| typeof(Il2CppSystem.Collections.Generic.HashSet<>).IsAssignableFrom(g);
}
else
{
return typeof(Il2CppSystem.Collections.IList).IsAssignableFrom(t);
}
#else
return false;
#endif
}
public static bool IsDictionary(Type t)
{
if (typeof(IDictionary).IsAssignableFrom(t))
{
return true;
}
#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
}
public static string ExceptionToString(Exception e) public static string ExceptionToString(Exception e)
{ {
#if CPP
if (IsFailedGeneric(e))
{
return "Unable to initialize this type.";
}
else if (IsObjectCollected(e))
{
return "Garbage collected in Il2Cpp.";
}
#endif
return e.GetType() + ", " + e.Message; return e.GetType() + ", " + e.Message;
} }
#if CPP
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;
}
#endif
} }
} }

View File

@ -143,21 +143,7 @@ namespace Explorer.Helpers
} }
else else
{ {
#if CPP
// The Il2Cpp EncodeToPNG() method does return System.Byte[],
// but for some reason it is not recognized or valid.
// Simple fix is iterating into a new array manually.
byte[] safeData = new byte[data.Length];
for (int i = 0; i < data.Length; i++)
{
safeData[i] = (byte)data[i]; // not sure if cast is needed
}
File.WriteAllBytes(savepath, safeData);
#else
File.WriteAllBytes(savepath, data); File.WriteAllBytes(savepath, data);
#endif
} }
} }

View File

@ -7,6 +7,9 @@ using UnhollowerBaseLib;
using UnityEngine; using UnityEngine;
using System.IO; using System.IO;
using Explorer.Helpers; using Explorer.Helpers;
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
namespace Explorer.Unstrip.ImageConversion namespace Explorer.Unstrip.ImageConversion
{ {
@ -18,18 +21,41 @@ namespace Explorer.Unstrip.ImageConversion
public static byte[] EncodeToPNG(this Texture2D tex) public static byte[] EncodeToPNG(this Texture2D tex)
{ {
return ICallHelper.GetICall<d_EncodeToPNG>("UnityEngine.ImageConversion::EncodeToPNG") var data = ICallHelper.GetICall<d_EncodeToPNG>("UnityEngine.ImageConversion::EncodeToPNG")
.Invoke(tex.Pointer); .Invoke(tex.Pointer);
// The Il2Cpp EncodeToPNG() method does return System.Byte[],
// but for some reason it is not recognized or valid.
// Simple fix is iterating into a new array manually.
byte[] safeData = new byte[data.Length];
for (int i = 0; i < data.Length; i++)
{
safeData[i] = (byte)data[i]; // not sure if cast is needed
}
return safeData;
} }
// ******** LoadImage not yet working. ********
// bool ImageConversion.LoadImage(this Texture2D tex, byte[] data, bool markNonReadable); // bool ImageConversion.LoadImage(this Texture2D tex, byte[] data, bool markNonReadable);
internal delegate bool d_LoadImage(IntPtr tex, byte[] data, bool markNonReadable); internal delegate bool d_LoadImage(IntPtr tex, IntPtr data, bool markNonReadable);
public static bool LoadImage(this Texture2D tex, byte[] data, bool markNonReadable) public static bool LoadImage(this Texture2D tex, byte[] data, bool markNonReadable)
{ {
return ICallHelper.GetICall<d_LoadImage>("UnityEngine.ImageConversion::LoadImage") IntPtr unmanagedArray = Marshal.AllocHGlobal(data.Length);
.Invoke(tex.Pointer, data, markNonReadable); Marshal.Copy(data, 0, unmanagedArray, data.Length);
var ret = ICallHelper.GetICall<d_LoadImage>("UnityEngine.ImageConversion::LoadImage")
.Invoke(tex.Pointer, unmanagedArray, markNonReadable);
// var ret = tex.LoadRawTextureDataImpl(unmanagedArray, data.Length);
Marshal.FreeHGlobal(unmanagedArray);
return ret;
} }
// Helper for LoadImage from filepath // Helper for LoadImage from filepath