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

Commit 5abfa3d

Browse files
committed
Better EntryType checking for enumerables and dicts
1 parent e5d2d29 commit 5abfa3d

File tree

5 files changed

+124
-35
lines changed

5 files changed

+124
-35
lines changed

src/Core/Reflection/Il2CppReflection.cs

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,18 @@ internal override object Internal_TryCast(object obj, Type castTo)
258258
}
259259
}
260260

261+
private static bool IsAssignableFrom(Type thisType, Type fromType)
262+
{
263+
if (!Il2CppTypeNotNull(fromType, out IntPtr fromTypePtr)
264+
|| !Il2CppTypeNotNull(thisType, out IntPtr thisTypePtr))
265+
{
266+
// one or both of the types are not Il2Cpp types, use normal check
267+
return thisType.IsAssignableFrom(fromType);
268+
}
269+
270+
return il2cpp_class_is_assignable_from(thisTypePtr, fromTypePtr);
271+
}
272+
261273
#endregion
262274

263275

@@ -508,7 +520,7 @@ internal bool DoLoadModule(string fullPath, bool suppressWarning = false)
508520
#endregion
509521

510522

511-
#region Il2cpp reflection blacklist
523+
#region Il2cpp reflection blacklist
512524

513525
public override string DefaultReflectionBlacklist => string.Join(";", defaultIl2CppBlacklist);
514526

@@ -654,10 +666,54 @@ internal bool DoLoadModule(string fullPath, bool suppressWarning = false)
654666
"UnityEngine.XR.InputDevice.SendHapticImpulse",
655667
};
656668

657-
#endregion
669+
#endregion
658670

659671

660-
#region Temp il2cpp list/dictionary fixes
672+
protected override bool Internal_TryGetEntryType(Type enumerableType, out Type type)
673+
{
674+
// Check for system types (not unhollowed)
675+
if (base.Internal_TryGetEntryType(enumerableType, out type))
676+
return true;
677+
678+
// Type is either an IL2CPP enumerable, or its not generic.
679+
680+
if (type.IsGenericType)
681+
{
682+
// Temporary naive solution until IL2CPP interface support improves.
683+
// This will work fine for most cases, but there are edge cases which would not work.
684+
type = type.GetGenericArguments()[0];
685+
return true;
686+
}
687+
688+
// Unable to determine entry type
689+
type = typeof(object);
690+
return false;
691+
}
692+
693+
protected override bool Internal_TryGetEntryTypes(Type type, out Type keys, out Type values)
694+
{
695+
if (base.Internal_TryGetEntryTypes(type, out keys, out values))
696+
return true;
697+
698+
// Type is either an IL2CPP dictionary, or its not generic.
699+
if (type.IsGenericType)
700+
{
701+
// Naive solution until IL2CPP interfaces improve.
702+
var args = type.GetGenericArguments();
703+
if (args.Length == 2)
704+
{
705+
keys = args[0];
706+
values = args[1];
707+
return true;
708+
}
709+
}
710+
711+
keys = typeof(object);
712+
values = typeof(object);
713+
return false;
714+
}
715+
716+
#region Temp il2cpp list/dictionary fixes
661717

662718
// Temp fix until Unhollower interface support improves
663719

src/Core/Reflection/ReflectionUtility.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,39 @@ protected virtual bool Internal_TryGetEnumerator(object list, out IEnumerator en
495495
enumerator = (list as IEnumerable).GetEnumerator();
496496
return true;
497497
}
498+
499+
// TryGetEntryType
500+
501+
public static bool TryGetEntryType(Type enumerableType, out Type type)
502+
=> Instance.Internal_TryGetEntryType(enumerableType, out type);
503+
504+
protected virtual bool Internal_TryGetEntryType(Type enumerableType, out Type type)
505+
{
506+
// Check for arrays
507+
if (enumerableType.IsArray)
508+
{
509+
type = enumerableType.GetElementType();
510+
return true;
511+
}
512+
513+
// Check for implementation of IEnumerable<T>, IList<T> or ICollection<T>
514+
foreach (var t in enumerableType.GetInterfaces())
515+
{
516+
if (t.IsGenericType)
517+
{
518+
var typeDef = t.GetGenericTypeDefinition();
519+
if (typeDef == typeof(IEnumerable<>) || typeDef == typeof(IList<>) || typeDef == typeof(ICollection<>))
520+
{
521+
type = t.GetGenericArguments()[0];
522+
return true;
523+
}
524+
}
525+
}
526+
527+
// Unable to determine any generic element type, just use object.
528+
type = typeof(object);
529+
return false;
530+
}
498531

499532
// IsDictionary
500533

@@ -524,5 +557,28 @@ private IEnumerator<DictionaryEntry> EnumerateDictionary(IDictionary dict)
524557
yield return new DictionaryEntry(enumerator.Key, enumerator.Value);
525558
}
526559
}
560+
561+
// TryGetEntryTypes
562+
563+
public static bool TryGetEntryTypes(Type dictionaryType, out Type keys, out Type values)
564+
=> Instance.Internal_TryGetEntryTypes(dictionaryType, out keys, out values);
565+
566+
protected virtual bool Internal_TryGetEntryTypes(Type dictionaryType, out Type keys, out Type values)
567+
{
568+
foreach (var t in dictionaryType.GetInterfaces())
569+
{
570+
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IDictionary<,>))
571+
{
572+
var args = t.GetGenericArguments();
573+
keys = args[0];
574+
values = args[1];
575+
return true;
576+
}
577+
}
578+
579+
keys = typeof(object);
580+
values = typeof(object);
581+
return false;
582+
}
527583
}
528584
}

src/Core/Runtime/Il2Cpp/Il2CppProvider.cs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,19 @@ public class Il2CppProvider : RuntimeProvider
2222
public override void Initialize()
2323
{
2424
ExplorerCore.Context = RuntimeContext.IL2CPP;
25-
//Reflection = new Il2CppReflection();
2625
TextureUtil = new Il2CppTextureUtil();
2726
}
2827

2928
public override void SetupEvents()
3029
{
3130
try
3231
{
33-
//Application.add_logMessageReceived(new Action<string, string, LogType>(ExplorerCore.Instance.OnUnityLog));
34-
35-
var logType = ReflectionUtility.GetTypeByName("UnityEngine.Application+LogCallback");
36-
var castMethod = logType.GetMethod("op_Implicit", new[] { typeof(Action<string, string, LogType>) });
37-
var addMethod = typeof(Application).GetMethod("add_logMessageReceived", BF.Static | BF.Public, null, new[] { logType }, null);
38-
addMethod.Invoke(null, new[]
39-
{
40-
castMethod.Invoke(null, new[] { new Action<string, string, LogType>(Application_logMessageReceived) })
41-
});
32+
Application.add_logMessageReceived(new Action<string, string, LogType>(Application_logMessageReceived));
4233
}
43-
catch
34+
catch (Exception ex)
4435
{
4536
ExplorerCore.LogWarning("Exception setting up Unity log listener, make sure Unity libraries have been unstripped!");
37+
ExplorerCore.Log(ex);
4638
}
4739
}
4840

src/UI/IValues/InteractiveDictionary.cs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections;
33
using System.Collections.Generic;
44
using System.Linq;
5+
using System.Reflection;
56
using UnityEngine;
67
using UnityEngine.UI;
78
using UnityExplorer.UI.CacheObject;
@@ -21,8 +22,8 @@ public class InteractiveDictionary : InteractiveValue, ICellPoolDataSource<Cache
2122

2223
public override bool CanWrite => base.CanWrite && RefIDictionary != null && !RefIDictionary.IsReadOnly;
2324

24-
public Type KeyType;
25-
public Type ValueType;
25+
public Type KeysType;
26+
public Type ValuesType;
2627
public IDictionary RefIDictionary;
2728

2829
public int ItemCount => cachedEntries.Count;
@@ -75,24 +76,13 @@ public override void SetValue(object value)
7576
else
7677
{
7778
var type = value.GetActualType();
78-
79-
if (type.TryGetGenericArguments(out var args) && args.Length == 2)
80-
{
81-
KeyType = args[0];
82-
ValueType = args[1];
83-
}
84-
else
85-
{
86-
KeyType = typeof(object);
87-
ValueType = typeof(object);
88-
}
79+
ReflectionUtility.TryGetEntryTypes(type, out KeysType, out ValuesType);
8980

9081
CacheEntries(value);
9182

9283
TopLabel.text = $"[{cachedEntries.Count}] {SignatureHighlighter.Parse(type, false)}";
9384
}
9485

95-
9686
this.DictScrollPool.Refresh(true, false);
9787
}
9888

@@ -117,7 +107,7 @@ private void CacheEntries(object value)
117107
else
118108
cache = cachedEntries[idx];
119109

120-
cache.SetFallbackType(ValueType);
110+
cache.SetFallbackType(ValuesType);
121111
cache.SetKey(dictEnumerator.Current.Key);
122112
cache.SetValueFromSource(dictEnumerator.Current.Value);
123113

src/UI/IValues/InteractiveList.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,7 @@ public override void SetValue(object value)
7474
else
7575
{
7676
var type = value.GetActualType();
77-
if (type.TryGetGenericArguments(out var args))
78-
EntryType = args[0];
79-
else if (type.HasElementType)
80-
EntryType = type.GetElementType();
81-
else
82-
EntryType = typeof(object);
77+
ReflectionUtility.TryGetEntryType(type, out EntryType);
8378

8479
CacheEntries(value);
8580

0 commit comments

Comments
 (0)