Skip to content
This repository was archived by the owner on May 9, 2023. It is now read-only.

Commit a49a918

Browse files
committed
faster il2cpp cast, a few cleanups
1 parent e3a58bf commit a49a918

File tree

3 files changed

+112
-103
lines changed

3 files changed

+112
-103
lines changed

src/Helpers/ReflectionHelpers.cs

Lines changed: 82 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
using System.Reflection;
66
using UnityEngine;
77
using BF = System.Reflection.BindingFlags;
8-
98
#if CPP
109
using ILType = Il2CppSystem.Type;
1110
using UnhollowerBaseLib;
1211
using UnhollowerRuntimeLib;
12+
using System.Runtime.InteropServices;
1313
#endif
1414

1515
namespace Explorer.Helpers
@@ -20,78 +20,68 @@ public class ReflectionHelpers
2020

2121
#if CPP
2222
public static ILType GameObjectType => Il2CppType.Of<GameObject>();
23-
public static ILType TransformType => Il2CppType.Of<Transform>();
24-
public static ILType ObjectType => Il2CppType.Of<UnityEngine.Object>();
25-
public static ILType ComponentType => Il2CppType.Of<Component>();
26-
public static ILType BehaviourType => Il2CppType.Of<Behaviour>();
23+
public static ILType TransformType => Il2CppType.Of<Transform>();
24+
public static ILType ObjectType => Il2CppType.Of<UnityEngine.Object>();
25+
public static ILType ComponentType => Il2CppType.Of<Component>();
26+
public static ILType BehaviourType => Il2CppType.Of<Behaviour>();
27+
#else
28+
public static Type GameObjectType => typeof(GameObject);
29+
public static Type TransformType => typeof(Transform);
30+
public static Type ObjectType => typeof(UnityEngine.Object);
31+
public static Type ComponentType => typeof(Component);
32+
public static Type BehaviourType => typeof(Behaviour);
33+
#endif
2734

28-
private static readonly MethodInfo tryCastMethodInfo = typeof(Il2CppObjectBase).GetMethod("TryCast");
29-
private static readonly Dictionary<Type, MethodInfo> cachedTryCastMethods = new Dictionary<Type, MethodInfo>();
35+
#if CPP
36+
private static readonly Dictionary<Type, IntPtr> ClassPointers = new Dictionary<Type, IntPtr>();
3037

3138
public static object Il2CppCast(object obj, Type castTo)
3239
{
33-
if (!typeof(Il2CppSystem.Object).IsAssignableFrom(castTo)) return obj;
40+
if (!(obj is Il2CppSystem.Object ilObj))
41+
return obj;
3442

35-
if (!cachedTryCastMethods.ContainsKey(castTo))
36-
{
37-
cachedTryCastMethods.Add(castTo, tryCastMethodInfo.MakeGenericMethod(castTo));
38-
}
43+
if (!typeof(Il2CppSystem.Object).IsAssignableFrom(castTo))
44+
return obj;
3945

40-
return cachedTryCastMethods[castTo].Invoke(obj, null);
41-
}
42-
#else
43-
public static Type GameObjectType => typeof(GameObject);
44-
public static Type TransformType => typeof(Transform);
45-
public static Type ObjectType => typeof(UnityEngine.Object);
46-
public static Type ComponentType => typeof(Component);
47-
public static Type BehaviourType => typeof(Behaviour);
48-
#endif
49-
50-
public static bool IsEnumerable(Type t)
51-
{
52-
if (typeof(IEnumerable).IsAssignableFrom(t))
46+
IntPtr castToPtr;
47+
if (!ClassPointers.ContainsKey(castTo))
5348
{
54-
return true;
55-
}
49+
castToPtr = (IntPtr)typeof(Il2CppClassPointerStore<>)
50+
.MakeGenericType(new Type[] { castTo })
51+
.GetField("NativeClassPtr", BF.Public | BF.Static)
52+
.GetValue(null);
5653

57-
#if CPP
58-
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
59-
{
60-
return typeof(Il2CppSystem.Collections.Generic.List<>).IsAssignableFrom(g)
61-
|| typeof(Il2CppSystem.Collections.Generic.IList<>).IsAssignableFrom(g)
62-
|| typeof(Il2CppSystem.Collections.Generic.HashSet<>).IsAssignableFrom(g);
54+
if (castToPtr == IntPtr.Zero)
55+
{
56+
ExplorerCore.LogWarning($"[Il2CppCast] Could not get an IntPtr for castTo '{castTo.FullName}'!");
57+
return obj;
58+
}
59+
60+
ClassPointers.Add(castTo, castToPtr);
6361
}
6462
else
6563
{
66-
return typeof(Il2CppSystem.Collections.IList).IsAssignableFrom(t);
64+
castToPtr = ClassPointers[castTo];
6765
}
68-
#else
69-
return false;
70-
#endif
66+
67+
IntPtr objPtr = ilObj.Pointer;
68+
var classPtr = il2cpp_object_get_class(objPtr);
69+
70+
//if (RuntimeSpecificsStore.IsInjected(classPtr))
71+
// return obj;
72+
73+
if (!il2cpp_class_is_assignable_from(castToPtr, classPtr))
74+
return obj;
75+
76+
return Activator.CreateInstance(castTo, objPtr);
7177
}
7278

73-
public static bool IsDictionary(Type t)
74-
{
75-
if (typeof(IDictionary).IsAssignableFrom(t))
76-
{
77-
return true;
78-
}
79+
[DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
80+
public static extern bool il2cpp_class_is_assignable_from(IntPtr klass, IntPtr oklass);
7981

80-
#if CPP
81-
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
82-
{
83-
return typeof(Il2CppSystem.Collections.Generic.Dictionary<,>).IsAssignableFrom(g)
84-
|| typeof(Il2CppSystem.Collections.Generic.IDictionary<,>).IsAssignableFrom(g);
85-
}
86-
else
87-
{
88-
return typeof(Il2CppSystem.Collections.IDictionary).IsAssignableFrom(t)
89-
|| typeof(Il2CppSystem.Collections.Hashtable).IsAssignableFrom(t);
90-
}
91-
#else
92-
return false;
82+
[DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
83+
public static extern IntPtr il2cpp_object_get_class(IntPtr obj);
9384
#endif
94-
}
9585

9686
public static Type GetTypeByName(string fullName)
9787
{
@@ -169,48 +159,55 @@ public static bool LoadModule(string module)
169159
return false;
170160
}
171161

172-
public static string ExceptionToString(Exception e)
162+
public static bool IsEnumerable(Type t)
173163
{
164+
if (typeof(IEnumerable).IsAssignableFrom(t))
165+
{
166+
return true;
167+
}
168+
174169
#if CPP
175-
if (IsFailedGeneric(e))
170+
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
176171
{
177-
return "Unable to initialize this type.";
172+
return typeof(Il2CppSystem.Collections.Generic.List<>).IsAssignableFrom(g)
173+
|| typeof(Il2CppSystem.Collections.Generic.IList<>).IsAssignableFrom(g)
174+
|| typeof(Il2CppSystem.Collections.Generic.HashSet<>).IsAssignableFrom(g);
178175
}
179-
else if (IsObjectCollected(e))
176+
else
180177
{
181-
return "Garbage collected in Il2Cpp.";
178+
return typeof(Il2CppSystem.Collections.IList).IsAssignableFrom(t);
182179
}
180+
#else
181+
return false;
183182
#endif
184-
return e.GetType() + ", " + e.Message;
185183
}
186184

187-
#if CPP
188-
public static bool IsFailedGeneric(Exception e)
185+
public static bool IsDictionary(Type t)
189186
{
190-
return IsExceptionOfType(e, typeof(TargetInvocationException)) && IsExceptionOfType(e, typeof(TypeLoadException));
191-
}
187+
if (typeof(IDictionary).IsAssignableFrom(t))
188+
{
189+
return true;
190+
}
192191

193-
public static bool IsObjectCollected(Exception e)
194-
{
195-
return IsExceptionOfType(e, typeof(ObjectCollectedException));
192+
#if CPP
193+
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
194+
{
195+
return typeof(Il2CppSystem.Collections.Generic.Dictionary<,>).IsAssignableFrom(g)
196+
|| typeof(Il2CppSystem.Collections.Generic.IDictionary<,>).IsAssignableFrom(g);
197+
}
198+
else
199+
{
200+
return typeof(Il2CppSystem.Collections.IDictionary).IsAssignableFrom(t)
201+
|| typeof(Il2CppSystem.Collections.Hashtable).IsAssignableFrom(t);
202+
}
203+
#else
204+
return false;
205+
#endif
196206
}
197207

198-
public static bool IsExceptionOfType(Exception e, Type t, bool strict = true, bool checkInner = true)
208+
public static string ExceptionToString(Exception e)
199209
{
200-
bool isType;
201-
202-
if (strict)
203-
isType = e.GetType() == t;
204-
else
205-
isType = t.IsAssignableFrom(e.GetType());
206-
207-
if (isType) return true;
208-
209-
if (e.InnerException != null && checkInner)
210-
return IsExceptionOfType(e.InnerException, t, strict);
211-
else
212-
return false;
210+
return e.GetType() + ", " + e.Message;
213211
}
214-
#endif
215212
}
216213
}

src/Helpers/Texture2DHelpers.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -143,21 +143,7 @@ public static void SaveTextureAsPNG(Texture2D tex, string dir, string name, bool
143143
}
144144
else
145145
{
146-
#if CPP
147-
// The Il2Cpp EncodeToPNG() method does return System.Byte[],
148-
// but for some reason it is not recognized or valid.
149-
// Simple fix is iterating into a new array manually.
150-
151-
byte[] safeData = new byte[data.Length];
152-
for (int i = 0; i < data.Length; i++)
153-
{
154-
safeData[i] = (byte)data[i]; // not sure if cast is needed
155-
}
156-
157-
File.WriteAllBytes(savepath, safeData);
158-
#else
159146
File.WriteAllBytes(savepath, data);
160-
#endif
161147
}
162148
}
163149

src/Unstrip/ImageConversion/ImageConversionUnstrip.cs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
using UnityEngine;
88
using System.IO;
99
using Explorer.Helpers;
10+
using System.Runtime.InteropServices;
11+
using Unity.Collections;
12+
using Unity.Collections.LowLevel.Unsafe;
1013

1114
namespace Explorer.Unstrip.ImageConversion
1215
{
@@ -18,18 +21,41 @@ public static class ImageConversionUnstrip
1821

1922
public static byte[] EncodeToPNG(this Texture2D tex)
2023
{
21-
return ICallHelper.GetICall<d_EncodeToPNG>("UnityEngine.ImageConversion::EncodeToPNG")
24+
var data = ICallHelper.GetICall<d_EncodeToPNG>("UnityEngine.ImageConversion::EncodeToPNG")
2225
.Invoke(tex.Pointer);
26+
27+
// The Il2Cpp EncodeToPNG() method does return System.Byte[],
28+
// but for some reason it is not recognized or valid.
29+
// Simple fix is iterating into a new array manually.
30+
31+
byte[] safeData = new byte[data.Length];
32+
for (int i = 0; i < data.Length; i++)
33+
{
34+
safeData[i] = (byte)data[i]; // not sure if cast is needed
35+
}
36+
37+
return safeData;
2338
}
2439

40+
// ******** LoadImage not yet working. ********
41+
2542
// bool ImageConversion.LoadImage(this Texture2D tex, byte[] data, bool markNonReadable);
2643

27-
internal delegate bool d_LoadImage(IntPtr tex, byte[] data, bool markNonReadable);
44+
internal delegate bool d_LoadImage(IntPtr tex, IntPtr data, bool markNonReadable);
2845

2946
public static bool LoadImage(this Texture2D tex, byte[] data, bool markNonReadable)
3047
{
31-
return ICallHelper.GetICall<d_LoadImage>("UnityEngine.ImageConversion::LoadImage")
32-
.Invoke(tex.Pointer, data, markNonReadable);
48+
IntPtr unmanagedArray = Marshal.AllocHGlobal(data.Length);
49+
Marshal.Copy(data, 0, unmanagedArray, data.Length);
50+
51+
var ret = ICallHelper.GetICall<d_LoadImage>("UnityEngine.ImageConversion::LoadImage")
52+
.Invoke(tex.Pointer, unmanagedArray, markNonReadable);
53+
54+
// var ret = tex.LoadRawTextureDataImpl(unmanagedArray, data.Length);
55+
56+
Marshal.FreeHGlobal(unmanagedArray);
57+
58+
return ret;
3359
}
3460

3561
// Helper for LoadImage from filepath

0 commit comments

Comments
 (0)