mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-16 14:17:51 +08:00
Better EntryType checking for enumerables and dicts
This commit is contained in:
parent
e5d2d29a47
commit
5abfa3da67
@ -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
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
@ -657,6 +669,50 @@ namespace UnityExplorer
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
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
|
#region Temp il2cpp list/dictionary fixes
|
||||||
|
|
||||||
// Temp fix until Unhollower interface support improves
|
// Temp fix until Unhollower interface support improves
|
||||||
|
@ -496,6 +496,39 @@ namespace UnityExplorer
|
|||||||
return true;
|
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
|
// IsDictionary
|
||||||
|
|
||||||
public static bool IsDictionary(Type type) => Instance.Internal_IsDictionary(type);
|
public static bool IsDictionary(Type type) => Instance.Internal_IsDictionary(type);
|
||||||
@ -524,5 +557,28 @@ namespace UnityExplorer
|
|||||||
yield return new DictionaryEntry(enumerator.Key, enumerator.Value);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
|||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
ExplorerCore.Context = RuntimeContext.IL2CPP;
|
ExplorerCore.Context = RuntimeContext.IL2CPP;
|
||||||
//Reflection = new Il2CppReflection();
|
|
||||||
TextureUtil = new Il2CppTextureUtil();
|
TextureUtil = new Il2CppTextureUtil();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,19 +29,12 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//Application.add_logMessageReceived(new Action<string, string, LogType>(ExplorerCore.Instance.OnUnityLog));
|
Application.add_logMessageReceived(new Action<string, string, LogType>(Application_logMessageReceived));
|
||||||
|
|
||||||
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) })
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
ExplorerCore.LogWarning("Exception setting up Unity log listener, make sure Unity libraries have been unstripped!");
|
ExplorerCore.LogWarning("Exception setting up Unity log listener, make sure Unity libraries have been unstripped!");
|
||||||
|
ExplorerCore.Log(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.CacheObject;
|
using UnityExplorer.UI.CacheObject;
|
||||||
@ -21,8 +22,8 @@ namespace UnityExplorer.UI.IValues
|
|||||||
|
|
||||||
public override bool CanWrite => base.CanWrite && RefIDictionary != null && !RefIDictionary.IsReadOnly;
|
public override bool CanWrite => base.CanWrite && RefIDictionary != null && !RefIDictionary.IsReadOnly;
|
||||||
|
|
||||||
public Type KeyType;
|
public Type KeysType;
|
||||||
public Type ValueType;
|
public Type ValuesType;
|
||||||
public IDictionary RefIDictionary;
|
public IDictionary RefIDictionary;
|
||||||
|
|
||||||
public int ItemCount => cachedEntries.Count;
|
public int ItemCount => cachedEntries.Count;
|
||||||
@ -75,24 +76,13 @@ namespace UnityExplorer.UI.IValues
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var type = value.GetActualType();
|
var type = value.GetActualType();
|
||||||
|
ReflectionUtility.TryGetEntryTypes(type, out KeysType, out ValuesType);
|
||||||
if (type.TryGetGenericArguments(out var args) && args.Length == 2)
|
|
||||||
{
|
|
||||||
KeyType = args[0];
|
|
||||||
ValueType = args[1];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
KeyType = typeof(object);
|
|
||||||
ValueType = typeof(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
CacheEntries(value);
|
CacheEntries(value);
|
||||||
|
|
||||||
TopLabel.text = $"[{cachedEntries.Count}] {SignatureHighlighter.Parse(type, false)}";
|
TopLabel.text = $"[{cachedEntries.Count}] {SignatureHighlighter.Parse(type, false)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.DictScrollPool.Refresh(true, false);
|
this.DictScrollPool.Refresh(true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +107,7 @@ namespace UnityExplorer.UI.IValues
|
|||||||
else
|
else
|
||||||
cache = cachedEntries[idx];
|
cache = cachedEntries[idx];
|
||||||
|
|
||||||
cache.SetFallbackType(ValueType);
|
cache.SetFallbackType(ValuesType);
|
||||||
cache.SetKey(dictEnumerator.Current.Key);
|
cache.SetKey(dictEnumerator.Current.Key);
|
||||||
cache.SetValueFromSource(dictEnumerator.Current.Value);
|
cache.SetValueFromSource(dictEnumerator.Current.Value);
|
||||||
|
|
||||||
|
@ -74,12 +74,7 @@ namespace UnityExplorer.UI.IValues
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var type = value.GetActualType();
|
var type = value.GetActualType();
|
||||||
if (type.TryGetGenericArguments(out var args))
|
ReflectionUtility.TryGetEntryType(type, out EntryType);
|
||||||
EntryType = args[0];
|
|
||||||
else if (type.HasElementType)
|
|
||||||
EntryType = type.GetElementType();
|
|
||||||
else
|
|
||||||
EntryType = typeof(object);
|
|
||||||
|
|
||||||
CacheEntries(value);
|
CacheEntries(value);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user