mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-13 21:24:41 +08:00
faster il2cpp cast, a few cleanups
This commit is contained in:
parent
e3a58bf675
commit
a49a918790
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user