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 UnityEngine;
using BF = System.Reflection.BindingFlags;
#if CPP
using ILType = Il2CppSystem.Type;
using UnhollowerBaseLib;
using UnhollowerRuntimeLib;
using System.Runtime.InteropServices;
#endif
namespace Explorer.Helpers
@ -24,21 +24,6 @@ namespace Explorer.Helpers
public static ILType ObjectType => Il2CppType.Of<UnityEngine.Object>();
public static ILType ComponentType => Il2CppType.Of<Component>();
public static ILType BehaviourType => Il2CppType.Of<Behaviour>();
private static readonly MethodInfo tryCastMethodInfo = typeof(Il2CppObjectBase).GetMethod("TryCast");
private static readonly Dictionary<Type, MethodInfo> cachedTryCastMethods = new Dictionary<Type, MethodInfo>();
public static object Il2CppCast(object obj, Type castTo)
{
if (!typeof(Il2CppSystem.Object).IsAssignableFrom(castTo)) return obj;
if (!cachedTryCastMethods.ContainsKey(castTo))
{
cachedTryCastMethods.Add(castTo, tryCastMethodInfo.MakeGenericMethod(castTo));
}
return cachedTryCastMethods[castTo].Invoke(obj, null);
}
#else
public static Type GameObjectType => typeof(GameObject);
public static Type TransformType => typeof(Transform);
@ -47,51 +32,56 @@ namespace Explorer.Helpers
public static Type BehaviourType => typeof(Behaviour);
#endif
public static bool IsEnumerable(Type t)
#if CPP
private static readonly Dictionary<Type, IntPtr> ClassPointers = new Dictionary<Type, IntPtr>();
public static object Il2CppCast(object obj, Type castTo)
{
if (typeof(IEnumerable).IsAssignableFrom(t))
if (!(obj is Il2CppSystem.Object ilObj))
return obj;
if (!typeof(Il2CppSystem.Object).IsAssignableFrom(castTo))
return obj;
IntPtr castToPtr;
if (!ClassPointers.ContainsKey(castTo))
{
return true;
castToPtr = (IntPtr)typeof(Il2CppClassPointerStore<>)
.MakeGenericType(new Type[] { castTo })
.GetField("NativeClassPtr", BF.Public | BF.Static)
.GetValue(null);
if (castToPtr == IntPtr.Zero)
{
ExplorerCore.LogWarning($"[Il2CppCast] Could not get an IntPtr for castTo '{castTo.FullName}'!");
return obj;
}
#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);
ClassPointers.Add(castTo, castToPtr);
}
else
{
return typeof(Il2CppSystem.Collections.IList).IsAssignableFrom(t);
}
#else
return false;
#endif
castToPtr = ClassPointers[castTo];
}
public static bool IsDictionary(Type t)
{
if (typeof(IDictionary).IsAssignableFrom(t))
{
return true;
IntPtr objPtr = ilObj.Pointer;
var classPtr = il2cpp_object_get_class(objPtr);
//if (RuntimeSpecificsStore.IsInjected(classPtr))
// return obj;
if (!il2cpp_class_is_assignable_from(castToPtr, classPtr))
return obj;
return Activator.CreateInstance(castTo, objPtr);
}
#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;
[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)
{
@ -169,48 +159,55 @@ namespace Explorer.Helpers
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)
{
#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;
}
#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
{
#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);
#endif
}
}

View File

@ -7,6 +7,9 @@ using UnhollowerBaseLib;
using UnityEngine;
using System.IO;
using Explorer.Helpers;
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
namespace Explorer.Unstrip.ImageConversion
{
@ -18,18 +21,41 @@ namespace Explorer.Unstrip.ImageConversion
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);
// 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);
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)
{
return ICallHelper.GetICall<d_LoadImage>("UnityEngine.ImageConversion::LoadImage")
.Invoke(tex.Pointer, data, markNonReadable);
IntPtr unmanagedArray = Marshal.AllocHGlobal(data.Length);
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