Better EntryType checking for enumerables and dicts

This commit is contained in:
Sinai 2021-05-19 19:24:33 +10:00
parent e5d2d29a47
commit 5abfa3da67
5 changed files with 124 additions and 35 deletions

View File

@ -258,6 +258,18 @@ namespace UnityExplorer
}
}
private static bool IsAssignableFrom(Type thisType, Type fromType)
{
if (!Il2CppTypeNotNull(fromType, out IntPtr fromTypePtr)
|| !Il2CppTypeNotNull(thisType, out IntPtr thisTypePtr))
{
// one or both of the types are not Il2Cpp types, use normal check
return thisType.IsAssignableFrom(fromType);
}
return il2cpp_class_is_assignable_from(thisTypePtr, fromTypePtr);
}
#endregion
@ -508,7 +520,7 @@ namespace UnityExplorer
#endregion
#region Il2cpp reflection blacklist
#region Il2cpp reflection blacklist
public override string DefaultReflectionBlacklist => string.Join(";", defaultIl2CppBlacklist);
@ -654,10 +666,54 @@ namespace UnityExplorer
"UnityEngine.XR.InputDevice.SendHapticImpulse",
};
#endregion
#endregion
#region Temp il2cpp list/dictionary fixes
protected override bool Internal_TryGetEntryType(Type enumerableType, out Type type)
{
// Check for system types (not unhollowed)
if (base.Internal_TryGetEntryType(enumerableType, out type))
return true;
// Type is either an IL2CPP enumerable, or its not generic.
if (type.IsGenericType)
{
// Temporary naive solution until IL2CPP interface support improves.
// This will work fine for most cases, but there are edge cases which would not work.
type = type.GetGenericArguments()[0];
return true;
}
// Unable to determine entry type
type = typeof(object);
return false;
}
protected override bool Internal_TryGetEntryTypes(Type type, out Type keys, out Type values)
{
if (base.Internal_TryGetEntryTypes(type, out keys, out values))
return true;
// Type is either an IL2CPP dictionary, or its not generic.
if (type.IsGenericType)
{
// Naive solution until IL2CPP interfaces improve.
var args = type.GetGenericArguments();
if (args.Length == 2)
{
keys = args[0];
values = args[1];
return true;
}
}
keys = typeof(object);
values = typeof(object);
return false;
}
#region Temp il2cpp list/dictionary fixes
// Temp fix until Unhollower interface support improves

View File

@ -495,6 +495,39 @@ namespace UnityExplorer
enumerator = (list as IEnumerable).GetEnumerator();
return true;
}
// TryGetEntryType
public static bool TryGetEntryType(Type enumerableType, out Type type)
=> Instance.Internal_TryGetEntryType(enumerableType, out type);
protected virtual bool Internal_TryGetEntryType(Type enumerableType, out Type type)
{
// Check for arrays
if (enumerableType.IsArray)
{
type = enumerableType.GetElementType();
return true;
}
// Check for implementation of IEnumerable<T>, IList<T> or ICollection<T>
foreach (var t in enumerableType.GetInterfaces())
{
if (t.IsGenericType)
{
var typeDef = t.GetGenericTypeDefinition();
if (typeDef == typeof(IEnumerable<>) || typeDef == typeof(IList<>) || typeDef == typeof(ICollection<>))
{
type = t.GetGenericArguments()[0];
return true;
}
}
}
// Unable to determine any generic element type, just use object.
type = typeof(object);
return false;
}
// IsDictionary
@ -524,5 +557,28 @@ namespace UnityExplorer
yield return new DictionaryEntry(enumerator.Key, enumerator.Value);
}
}
// TryGetEntryTypes
public static bool TryGetEntryTypes(Type dictionaryType, out Type keys, out Type values)
=> Instance.Internal_TryGetEntryTypes(dictionaryType, out keys, out values);
protected virtual bool Internal_TryGetEntryTypes(Type dictionaryType, out Type keys, out Type values)
{
foreach (var t in dictionaryType.GetInterfaces())
{
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IDictionary<,>))
{
var args = t.GetGenericArguments();
keys = args[0];
values = args[1];
return true;
}
}
keys = typeof(object);
values = typeof(object);
return false;
}
}
}

View File

@ -22,7 +22,6 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
public override void Initialize()
{
ExplorerCore.Context = RuntimeContext.IL2CPP;
//Reflection = new Il2CppReflection();
TextureUtil = new Il2CppTextureUtil();
}
@ -30,19 +29,12 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
{
try
{
//Application.add_logMessageReceived(new Action<string, string, LogType>(ExplorerCore.Instance.OnUnityLog));
var logType = ReflectionUtility.GetTypeByName("UnityEngine.Application+LogCallback");
var castMethod = logType.GetMethod("op_Implicit", new[] { typeof(Action<string, string, LogType>) });
var addMethod = typeof(Application).GetMethod("add_logMessageReceived", BF.Static | BF.Public, null, new[] { logType }, null);
addMethod.Invoke(null, new[]
{
castMethod.Invoke(null, new[] { new Action<string, string, LogType>(Application_logMessageReceived) })
});
Application.add_logMessageReceived(new Action<string, string, LogType>(Application_logMessageReceived));
}
catch
catch (Exception ex)
{
ExplorerCore.LogWarning("Exception setting up Unity log listener, make sure Unity libraries have been unstripped!");
ExplorerCore.Log(ex);
}
}

View File

@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.CacheObject;
@ -21,8 +22,8 @@ namespace UnityExplorer.UI.IValues
public override bool CanWrite => base.CanWrite && RefIDictionary != null && !RefIDictionary.IsReadOnly;
public Type KeyType;
public Type ValueType;
public Type KeysType;
public Type ValuesType;
public IDictionary RefIDictionary;
public int ItemCount => cachedEntries.Count;
@ -75,24 +76,13 @@ namespace UnityExplorer.UI.IValues
else
{
var type = value.GetActualType();
if (type.TryGetGenericArguments(out var args) && args.Length == 2)
{
KeyType = args[0];
ValueType = args[1];
}
else
{
KeyType = typeof(object);
ValueType = typeof(object);
}
ReflectionUtility.TryGetEntryTypes(type, out KeysType, out ValuesType);
CacheEntries(value);
TopLabel.text = $"[{cachedEntries.Count}] {SignatureHighlighter.Parse(type, false)}";
}
this.DictScrollPool.Refresh(true, false);
}
@ -117,7 +107,7 @@ namespace UnityExplorer.UI.IValues
else
cache = cachedEntries[idx];
cache.SetFallbackType(ValueType);
cache.SetFallbackType(ValuesType);
cache.SetKey(dictEnumerator.Current.Key);
cache.SetValueFromSource(dictEnumerator.Current.Value);

View File

@ -74,12 +74,7 @@ namespace UnityExplorer.UI.IValues
else
{
var type = value.GetActualType();
if (type.TryGetGenericArguments(out var args))
EntryType = args[0];
else if (type.HasElementType)
EntryType = type.GetElementType();
else
EntryType = typeof(object);
ReflectionUtility.TryGetEntryType(type, out EntryType);
CacheEntries(value);