From 6bafab785bbcd9f795fe9a850c8c4fbe107b67de Mon Sep 17 00:00:00 2001
From: sinaioutlander <49360850+sinaioutlander@users.noreply.github.com>
Date: Sat, 22 Aug 2020 17:17:11 +1000
Subject: [PATCH] 1.4.1
* Cleanup some small bugs introduced in 1.4.0
* Added better exception handling for failed Reflection, and the ability to hide failed reflection members in the Reflection window, as well as see the error type.
* Reflection window members now display the full name instead of just the member name (eg. "Camera.main" instead of just "main").
---
src/CachedObjects/CacheEnum.cs | 7 +-
src/CachedObjects/CacheGameObject.cs | 4 +-
src/CachedObjects/CacheIl2CppObject.cs | 37 --------
src/CachedObjects/CacheList.cs | 93 ++++++++++++--------
src/CachedObjects/CacheObject.cs | 116 ++++++++++++-------------
src/CachedObjects/CacheOther.cs | 63 ++++++++++----
src/CachedObjects/CachePrimitive.cs | 4 +-
src/CachedObjects/CacheStruct.cs | 71 ---------------
src/CppExplorer.cs | 3 +-
src/CppExplorer.csproj | 2 -
src/Helpers/ReflectionHelpers.cs | 44 ++++++++++
src/MainMenu/Pages/SearchPage.cs | 10 ++-
src/Windows/ReflectionWindow.cs | 101 ++++++++++-----------
13 files changed, 276 insertions(+), 279 deletions(-)
delete mode 100644 src/CachedObjects/CacheIl2CppObject.cs
delete mode 100644 src/CachedObjects/CacheStruct.cs
diff --git a/src/CachedObjects/CacheEnum.cs b/src/CachedObjects/CacheEnum.cs
index 009d0c2..90fdae3 100644
--- a/src/CachedObjects/CacheEnum.cs
+++ b/src/CachedObjects/CacheEnum.cs
@@ -15,8 +15,11 @@ namespace Explorer
public CacheEnum(object obj)
{
- m_enumType = obj.GetType();
- m_names = Enum.GetNames(obj.GetType());
+ if (obj != null)
+ {
+ m_enumType = obj.GetType();
+ m_names = Enum.GetNames(m_enumType);
+ }
}
public override void DrawValue(Rect window, float width)
diff --git a/src/CachedObjects/CacheGameObject.cs b/src/CachedObjects/CacheGameObject.cs
index 1fded23..7025531 100644
--- a/src/CachedObjects/CacheGameObject.cs
+++ b/src/CachedObjects/CacheGameObject.cs
@@ -43,9 +43,9 @@ namespace Explorer
throw new NotImplementedException("TODO");
}
- public override void UpdateValue(object obj)
+ public override void UpdateValue()
{
- base.UpdateValue(obj);
+ base.UpdateValue();
m_gameObject = GetGameObject(Value);
}
diff --git a/src/CachedObjects/CacheIl2CppObject.cs b/src/CachedObjects/CacheIl2CppObject.cs
deleted file mode 100644
index 87b9e3e..0000000
--- a/src/CachedObjects/CacheIl2CppObject.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using UnityEngine;
-
-namespace Explorer
-{
- public class CacheIl2CppObject : CacheObject
- {
- public override void DrawValue(Rect window, float width)
- {
- var label = ValueType ?? Value.ToString();
- if (!label.Contains(ValueType))
- {
- label += $" ({ValueType})";
- }
- if (Value is UnityEngine.Object unityObj)
- {
- label = unityObj.name + " | " + label;
- }
-
- GUI.skin.button.alignment = TextAnchor.MiddleLeft;
- if (GUILayout.Button("" + label + "", new GUILayoutOption[] { GUILayout.MaxWidth(width) }))
- {
- WindowManager.InspectObject(Value, out bool _);
- }
- GUI.skin.button.alignment = TextAnchor.MiddleCenter;
- }
-
- public override void SetValue()
- {
- throw new NotImplementedException("TODO");
- }
- }
-}
diff --git a/src/CachedObjects/CacheList.cs b/src/CachedObjects/CacheList.cs
index 1af6eba..5a0f82a 100644
--- a/src/CachedObjects/CacheList.cs
+++ b/src/CachedObjects/CacheList.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
+using Mono.CSharp;
using UnityEngine;
namespace Explorer
@@ -13,30 +14,56 @@ namespace Explorer
{
public bool IsExpanded { get; set; }
public int ArrayOffset { get; set; }
- public Type EntryType { get; set; }
+
+ public Type EntryType
+ {
+ get
+ {
+ if (m_entryType == null)
+ {
+ m_entryType = Value?.GetType().GetGenericArguments()[0];
+ }
+ return m_entryType;
+ }
+ set
+ {
+ m_entryType = value;
+ }
+ }
+ private Type m_entryType;
+
+ public IEnumerable Enumerable
+ {
+ get
+ {
+ if (m_enumerable == null && Value != null)
+ {
+ m_enumerable = Value as IEnumerable ?? CppListToEnumerable(Value);
+ }
+ return m_enumerable;
+ }
+ }
private IEnumerable m_enumerable;
private CacheObject[] m_cachedEntries;
public CacheList(object obj)
{
- GetEnumerable(obj);
- EntryType = m_enumerable.GetType().GetGenericArguments()[0];
+ if (obj != null)
+ {
+ Value = obj;
+ EntryType = obj.GetType().GetGenericArguments()[0];
+ }
}
- private void GetEnumerable(object obj)
+ private IEnumerable CppListToEnumerable(object list)
{
- if (obj is IEnumerable isEnumerable)
- {
- m_enumerable = isEnumerable;
- }
- else
- {
- var listValueType = obj.GetType().GetGenericArguments()[0];
- var listType = typeof(Il2CppSystem.Collections.Generic.List<>).MakeGenericType(new Type[] { listValueType });
- var method = listType.GetMethod("ToArray");
- m_enumerable = (IEnumerable)method.Invoke(obj, new object[0]);
- }
+ if (EntryType == null) return null;
+
+ return (IEnumerable)typeof(Il2CppSystem.Collections.Generic.List<>)
+ .MakeGenericType(new Type[] { EntryType })
+ .GetMethod("ToArray")
+ .Invoke(list, new object[0]);
}
public override void DrawValue(Rect window, float width)
@@ -73,7 +100,7 @@ namespace Explorer
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null);
GUILayout.Space(190);
- int maxOffset = (int)Mathf.Ceil(count / CppExplorer.ArrayLimit);
+ int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)CppExplorer.ArrayLimit)) - 1;
GUILayout.Label($"Page {ArrayOffset + 1}/{maxOffset + 1}", new GUILayoutOption[] { GUILayout.Width(80) });
// prev/next page buttons
if (GUILayout.Button("< Prev", null))
@@ -99,7 +126,7 @@ namespace Explorer
GUILayout.BeginHorizontal(null);
GUILayout.Space(190);
- if (entry == null)
+ if (entry.Value == null)
{
GUILayout.Label("null", null);
}
@@ -108,22 +135,6 @@ namespace Explorer
GUILayout.Label(i.ToString(), new GUILayoutOption[] { GUILayout.Width(30) });
entry.DrawValue(window, window.width - 250);
-
- //var lbl = i + ": " + obj.Value.ToString() + "";
-
- //if (EntryType.IsPrimitive || typeof(string).IsAssignableFrom(EntryType))
- //{
- // GUILayout.Label(lbl, null);
- //}
- //else
- //{
- // GUI.skin.button.alignment = TextAnchor.MiddleLeft;
- // if (GUILayout.Button(lbl, null))
- // {
- // WindowManager.InspectObject(obj, out _);
- // }
- // GUI.skin.button.alignment = TextAnchor.MiddleCenter;
- //}
}
}
}
@@ -134,14 +145,20 @@ namespace Explorer
throw new NotImplementedException("TODO");
}
- public override void UpdateValue(object obj)
+ ///
+ /// Called when the user presses the "Update" button, or if AutoUpdate is on.
+ ///
+ public override void UpdateValue()
{
- GetEnumerable(Value);
+ base.UpdateValue();
+
+ if (Value == null) return;
+
+ var enumerator = Enumerable?.GetEnumerator();
+
+ if (enumerator == null) return;
var list = new List();
-
- var enumerator = m_enumerable.GetEnumerator();
-
while (enumerator.MoveNext())
{
list.Add(GetCacheObject(enumerator.Current));
diff --git a/src/CachedObjects/CacheObject.cs b/src/CachedObjects/CacheObject.cs
index 57b75c3..881c808 100644
--- a/src/CachedObjects/CacheObject.cs
+++ b/src/CachedObjects/CacheObject.cs
@@ -20,7 +20,10 @@ namespace Explorer
public ReflectionWindow.MemberInfoType MemberInfoType { get; set; }
public Type DeclaringType { get; set; }
public object DeclaringInstance { get; set; }
+ public string FullName => $"{MemberInfo.DeclaringType.Name}.{MemberInfo.Name}";
+ public string ReflectionException;
+ // methods
public abstract void DrawValue(Rect window, float width);
public abstract void SetValue();
@@ -29,73 +32,63 @@ namespace Explorer
return GetCacheObject(obj, null, null);
}
+ ///
+ /// Gets the CacheObject subclass for an object or MemberInfo
+ ///
+ /// The current value (can be null if memberInfo is not null)
+ /// The MemberInfo (can be null if obj is not null)
+ /// If MemberInfo is not null, the declaring class instance. Can be null if static.
+ ///
public static CacheObject GetCacheObject(object obj, MemberInfo memberInfo, object declaringInstance)
{
CacheObject holder;
var type = ReflectionHelpers.GetActualType(obj) ?? (memberInfo as FieldInfo)?.FieldType ?? (memberInfo as PropertyInfo)?.PropertyType;
- if (obj is Il2CppSystem.Object || typeof(Il2CppSystem.Object).IsAssignableFrom(type))
+ if ((obj is Il2CppSystem.Object || typeof(Il2CppSystem.Object).IsAssignableFrom(type))
+ && (type.FullName.Contains("UnityEngine.GameObject") || type.FullName.Contains("UnityEngine.Transform")))
{
- var name = type.FullName;
- if (name == "UnityEngine.GameObject" || name == "UnityEngine.Transform")
- {
- holder = new CacheGameObject(obj);
- }
- else
- {
- holder = new CacheIl2CppObject();
- }
+ holder = new CacheGameObject(obj);
+ }
+ else if (type.IsPrimitive || type == typeof(string))
+ {
+ holder = new CachePrimitive(obj);
+ }
+ else if (type.IsEnum)
+ {
+ holder = new CacheEnum(obj);
+ }
+ else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(type) || ReflectionHelpers.IsList(type))
+ {
+ holder = new CacheList(obj);
}
else
{
- if (type.IsPrimitive || type == typeof(string))
- {
- holder = new CachePrimitive(obj);
- }
- else if (type.IsEnum)
- {
- holder = new CacheEnum(obj);
- }
- else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(type) || ReflectionHelpers.IsList(type))
- {
- holder = new CacheList(obj);
- }
- else if (type.IsValueType)
- {
- holder = new CacheStruct(obj);
- }
- else
- {
- holder = new CacheOther();
- }
- }
-
- if (holder == null)
- {
- return null;
+ holder = new CacheOther();
}
if (memberInfo != null)
{
holder.MemberInfo = memberInfo;
holder.DeclaringType = memberInfo.DeclaringType;
-
- if (declaringInstance is Il2CppSystem.Object ilInstance && ilInstance.GetType() != memberInfo.DeclaringType)
- {
- try
- {
- holder.DeclaringInstance = ilInstance.Il2CppCast(holder.DeclaringType);
- }
- catch
- {
- holder.DeclaringInstance = declaringInstance;
- }
- }
- else
- {
- holder.DeclaringInstance = declaringInstance;
- }
+ holder.DeclaringInstance = declaringInstance;
+
+ //if (declaringInstance is Il2CppSystem.Object ilInstance && ilInstance.GetType() != memberInfo.DeclaringType)
+ //{
+ // try
+ // {
+ // holder.DeclaringInstance = ilInstance.Il2CppCast(holder.DeclaringType);
+ // }
+ // catch (Exception e)
+ // {
+ // holder.ReflectionException = ReflectionHelpers.ExceptionToString(e);
+ // holder.DeclaringInstance = declaringInstance;
+ // }
+ //}
+ //else
+ //{
+ // holder.DeclaringInstance = declaringInstance;
+ //}
if (memberInfo.MemberType == MemberTypes.Field)
{
@@ -121,14 +114,18 @@ namespace Explorer
{
if (MemberInfo != null)
{
- GUILayout.Label("" + MemberInfo.Name + ":", new GUILayoutOption[] { GUILayout.Width(labelWidth) });
+ GUILayout.Label("" + FullName + ":", new GUILayoutOption[] { GUILayout.Width(labelWidth) });
}
else
{
GUILayout.Space(labelWidth);
}
- if (Value == null)
+ if (!string.IsNullOrEmpty(ReflectionException))
+ {
+ GUILayout.Label("Reflection failed! (" + ReflectionException + ")", null);
+ }
+ else if (Value == null)
{
GUILayout.Label("null (" + this.ValueType + ")", null);
}
@@ -138,9 +135,9 @@ namespace Explorer
}
}
- public virtual void UpdateValue(object obj)
+ public virtual void UpdateValue()
{
- if (MemberInfo == null)
+ if (MemberInfo == null || !string.IsNullOrEmpty(ReflectionException))
{
return;
}
@@ -155,12 +152,15 @@ namespace Explorer
else if (MemberInfo.MemberType == MemberTypes.Property)
{
var pi = MemberInfo as PropertyInfo;
- Value = pi.GetValue(pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance, null);
+ bool isStatic = pi.GetAccessors()[0].IsStatic;
+ var target = isStatic ? null : DeclaringInstance;
+ Value = pi.GetValue(target, null);
}
+ //ReflectionException = null;
}
- catch //(Exception e)
+ catch (Exception e)
{
- //MelonLogger.Log($"Error updating MemberInfo value | {e.GetType()}: {e.Message}\r\n{e.StackTrace}");
+ ReflectionException = ReflectionHelpers.ExceptionToString(e);
}
}
diff --git a/src/CachedObjects/CacheOther.cs b/src/CachedObjects/CacheOther.cs
index 41e98b9..d2adf85 100644
--- a/src/CachedObjects/CacheOther.cs
+++ b/src/CachedObjects/CacheOther.cs
@@ -1,35 +1,64 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using System.Reflection;
using UnityEngine;
namespace Explorer
{
public class CacheOther : CacheObject
{
+ private MethodInfo m_toStringMethod;
+ private bool m_triedToGetMethod;
+
+ public MethodInfo ToStringMethod
+ {
+ get
+ {
+ if (m_toStringMethod == null && !m_triedToGetMethod)
+ {
+ if (Value == null) return null;
+
+ m_triedToGetMethod = true;
+
+ try
+ {
+ var methods = ReflectionHelpers.GetActualType(Value)
+ .GetMethods(ReflectionHelpers.CommonFlags)
+ .Where(x => x.Name == "ToString")
+ .GetEnumerator();
+
+ while (methods.MoveNext())
+ {
+ // just get the first (top-most level) method, then break.
+ m_toStringMethod = methods.Current;
+ break;
+ }
+ }
+ catch { }
+ }
+ return m_toStringMethod;
+ }
+ }
+
public override void DrawValue(Rect window, float width)
{
- string label;
- if (Value is UnityEngine.Object uObj)
+ string label = (string)ToStringMethod?.Invoke(Value, null) ?? Value.ToString();
+
+ if (!label.Contains(ValueType))
{
- label = uObj.name;
+ label += $" ({ValueType})";
}
- else
+ if (Value is UnityEngine.Object unityObj && !label.Contains(unityObj.name))
{
- label = Value.ToString();
- }
-
- string typeLabel = Value.GetType().FullName;
-
- if (!label.Contains(typeLabel))
- {
- label += $" ({typeLabel})";
+ label = unityObj.name + " | " + label;
}
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
- if (GUILayout.Button("" + label + "", new GUILayoutOption[] { GUILayout.MaxWidth(window.width - 230) }))
+ if (GUILayout.Button("" + label + "", new GUILayoutOption[] { GUILayout.MaxWidth(width) }))
{
WindowManager.InspectObject(Value, out bool _);
}
@@ -38,12 +67,12 @@ namespace Explorer
public override void SetValue()
{
-
+ throw new NotImplementedException("TODO");
}
- public override void UpdateValue(object obj)
- {
+ //public override void UpdateValue(object obj)
+ //{
- }
+ //}
}
}
diff --git a/src/CachedObjects/CachePrimitive.cs b/src/CachedObjects/CachePrimitive.cs
index 46122c1..26be983 100644
--- a/src/CachedObjects/CachePrimitive.cs
+++ b/src/CachedObjects/CachePrimitive.cs
@@ -23,6 +23,8 @@ namespace Explorer
public CachePrimitive(object obj)
{
+ if (obj == null) return;
+
if (obj is bool)
{
m_primitiveType = PrimitiveType.Bool;
@@ -35,7 +37,7 @@ namespace Explorer
{
m_primitiveType = PrimitiveType.Float;
}
- else if (obj is int)
+ else if (obj is int || obj is IntPtr || obj is uint)
{
m_primitiveType = PrimitiveType.Int;
}
diff --git a/src/CachedObjects/CacheStruct.cs b/src/CachedObjects/CacheStruct.cs
deleted file mode 100644
index 945cb5f..0000000
--- a/src/CachedObjects/CacheStruct.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Reflection;
-using UnityEngine;
-
-namespace Explorer
-{
- public class CacheStruct : CacheObject
- {
- public MethodInfo ToStringMethod { get; private set; }
- private static readonly MethodInfo m_defaultToString = typeof(object).GetMethod("ToString");
-
- public CacheStruct(object obj)
- {
- try
- {
- var methods = obj.GetType().GetMethods(ReflectionHelpers.CommonFlags).Where(x => x.Name == "ToString");
- var enumerator = methods.GetEnumerator();
- while (enumerator.MoveNext())
- {
- ToStringMethod = enumerator.Current;
- break;
- }
- }
- catch
- {
- ToStringMethod = m_defaultToString;
- }
- }
-
- public override void DrawValue(Rect window, float width)
- {
- string label;
- try
- {
- label = (string)ToStringMethod.Invoke(Value, null);
- }
- catch
- {
- label = Value.ToString();
- }
- string typeLabel = Value.GetType().FullName;
-
- if (!label.Contains(typeLabel))
- {
- label += $" ({typeLabel})";
- }
-
- GUI.skin.button.alignment = TextAnchor.MiddleLeft;
- if (GUILayout.Button("" + label + "", new GUILayoutOption[] { GUILayout.MaxWidth(window.width - 230) }))
- {
- WindowManager.InspectObject(Value, out bool _);
- }
- GUI.skin.button.alignment = TextAnchor.MiddleCenter;
- }
-
- public override void SetValue()
- {
- throw new NotImplementedException("TODO");
- }
-
- //public override void UpdateValue(object obj)
- //{
-
- //}
- }
-}
diff --git a/src/CppExplorer.cs b/src/CppExplorer.cs
index ee0d90a..afcb79d 100644
--- a/src/CppExplorer.cs
+++ b/src/CppExplorer.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using MelonLoader;
+using UnhollowerBaseLib;
namespace Explorer
{
@@ -12,7 +13,7 @@ namespace Explorer
// consts
public const string ID = "com.sinai.cppexplorer";
- public const string VERSION = "1.4.0";
+ public const string VERSION = "1.4.1";
public const string AUTHOR = "Sinai";
public const string NAME = "CppExplorer"
diff --git a/src/CppExplorer.csproj b/src/CppExplorer.csproj
index 9f352ba..d289f2e 100644
--- a/src/CppExplorer.csproj
+++ b/src/CppExplorer.csproj
@@ -140,8 +140,6 @@
-
-
diff --git a/src/Helpers/ReflectionHelpers.cs b/src/Helpers/ReflectionHelpers.cs
index 65f9284..0868a20 100644
--- a/src/Helpers/ReflectionHelpers.cs
+++ b/src/Helpers/ReflectionHelpers.cs
@@ -9,6 +9,7 @@ using UnhollowerRuntimeLib;
using UnityEngine;
using BF = System.Reflection.BindingFlags;
using ILBF = Il2CppSystem.Reflection.BindingFlags;
+using MelonLoader;
namespace Explorer
{
@@ -26,10 +27,53 @@ namespace Explorer
public static object Il2CppCast(object obj, Type castTo)
{
+ if (!typeof(Il2CppSystem.Object).IsAssignableFrom(castTo)) return obj;
+
var generic = m_tryCastMethodInfo.MakeGenericMethod(castTo);
return generic.Invoke(obj, null);
}
+ public static string ExceptionToString(Exception e)
+ {
+ if (IsFailedGeneric(e))
+ {
+ return "Unable to initialize this type.";
+ }
+ else if (IsObjectCollected(e))
+ {
+ return "Garbage collected in Il2Cpp.";
+ }
+
+ return e.GetType() + ", " + e.Message;
+ }
+
+ 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;
+ }
+
public static bool IsList(Type t)
{
return t.IsGenericType
diff --git a/src/MainMenu/Pages/SearchPage.cs b/src/MainMenu/Pages/SearchPage.cs
index 9081cbd..4de7292 100644
--- a/src/MainMenu/Pages/SearchPage.cs
+++ b/src/MainMenu/Pages/SearchPage.cs
@@ -111,7 +111,7 @@ namespace Explorer
{
// prev/next page buttons
GUILayout.BeginHorizontal(null);
- int maxOffset = (int)Mathf.Ceil(count / this.m_limit);
+ int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)m_limit)) - 1;
if (GUILayout.Button("< Prev", null))
{
if (m_pageOffset > 0) m_pageOffset--;
@@ -270,6 +270,7 @@ namespace Explorer
{
var findType = ReflectionHelpers.GetTypeByName(_type);
searchType = Il2CppSystem.Type.GetType(findType.AssemblyQualifiedName);
+ //MelonLogger.Log("Search type: " + findType.AssemblyQualifiedName);
}
catch (Exception e)
{
@@ -299,8 +300,13 @@ namespace Explorer
var allObjectsOfType = Resources.FindObjectsOfTypeAll(searchType);
+ //MelonLogger.Log("Found count: " + allObjectsOfType.Length);
+
+ int i = 0;
foreach (var obj in allObjectsOfType)
{
+ if (i >= 2000) break;
+
if (_search != "" && !obj.name.ToLower().Contains(_search.ToLower()))
{
continue;
@@ -322,6 +328,8 @@ namespace Explorer
{
matches.Add(obj);
}
+
+ i++;
}
return matches;
diff --git a/src/Windows/ReflectionWindow.cs b/src/Windows/ReflectionWindow.cs
index b1a245f..ad734b5 100644
--- a/src/Windows/ReflectionWindow.cs
+++ b/src/Windows/ReflectionWindow.cs
@@ -20,10 +20,12 @@ namespace Explorer
private CacheObject[] m_cachedMembers;
private CacheObject[] m_cachedMemberFiltered;
private int m_pageOffset;
+ private int m_limitPerPage = 20;
private bool m_autoUpdate = false;
private string m_search = "";
public MemberInfoType m_filter = MemberInfoType.Property;
+ private bool m_hideFailedReflection = true;
public enum MemberInfoType
{
@@ -72,7 +74,7 @@ namespace Explorer
{
foreach (var member in m_cachedMemberFiltered)
{
- member.UpdateValue(Target);
+ member.UpdateValue();
}
}
@@ -80,74 +82,66 @@ namespace Explorer
{
if (m_filter != MemberInfoType.All && m_filter != holder.MemberInfoType) return false;
+ if (!string.IsNullOrEmpty(holder.ReflectionException) && m_hideFailedReflection) return false;
+
if (m_search == "" || holder.MemberInfo == null) return true;
- return holder.MemberInfo.Name
+ return holder.FullName
.ToLower()
.Contains(m_search.ToLower());
}
- private void CacheMembers(Type[] types, List names = null)
+ private void CacheMembers(Type[] types)
{
- if (names == null)
- {
- names = new List();
- }
-
var list = new List();
- foreach (var type in types)
+ var names = new List();
+
+ foreach (var declaringType in types)
{
+ if (declaringType == typeof(Il2CppObjectBase)) continue;
+
MemberInfo[] infos;
+ string exception = null;
+
try
{
- infos = type.GetMembers(ReflectionHelpers.CommonFlags);
+ infos = declaringType.GetMembers(ReflectionHelpers.CommonFlags);
}
catch
{
- MelonLogger.Log("Exception getting members for type: " + type.Name);
+ MelonLogger.Log("Exception getting members for type: " + declaringType.Name);
continue;
}
+ //object value = null;
+ object target = Target;
+ if (target is Il2CppSystem.Object ilObject)
+ {
+ try
+ {
+ target = ilObject.Il2CppCast(declaringType);
+ }
+ catch (Exception e)
+ {
+ exception = ReflectionHelpers.ExceptionToString(e);
+ }
+ }
+
foreach (var member in infos)
{
- try
+ if (member.MemberType == MemberTypes.Field || member.MemberType == MemberTypes.Property)
{
- if (member.MemberType == MemberTypes.Field || member.MemberType == MemberTypes.Property)
- {
- if (member.Name == "Il2CppType") continue;
+ if (member.Name == "Il2CppType") continue;
- if (names.Contains(member.Name)) continue;
- names.Add(member.Name);
+ var name = member.DeclaringType.Name + "." + member.Name;
+ if (names.Contains(name)) continue;
+ names.Add(name);
- object value = null;
- object target = Target;
-
- if (target is Il2CppSystem.Object ilObject)
- {
- if (member.DeclaringType == typeof(Il2CppObjectBase)) continue;
-
- target = ilObject.Il2CppCast(member.DeclaringType);
- }
-
- if (member is FieldInfo)
- {
- value = (member as FieldInfo).GetValue(target);
- }
- else if (member is PropertyInfo)
- {
- value = (member as PropertyInfo).GetValue(target);
- }
-
- list.Add(CacheObject.GetCacheObject(value, member, Target));
- }
- }
- catch (Exception e)
- {
- MelonLogger.Log("Exception caching member " + member.Name + "!");
- MelonLogger.Log(e.GetType() + ", " + e.Message);
- MelonLogger.Log(e.StackTrace);
+ var cached = CacheObject.GetCacheObject(null, member, target);
+ list.Add(cached);
+ cached.ReflectionException = exception;
}
}
}
@@ -203,6 +197,13 @@ namespace Explorer
GUILayout.BeginHorizontal(null);
GUILayout.Label("Search:", new GUILayoutOption[] { GUILayout.Width(75) });
m_search = GUILayout.TextField(m_search, null);
+ GUILayout.Label("Limit per page:", new GUILayoutOption[] { GUILayout.Width(125) });
+ var limitString = m_limitPerPage.ToString();
+ limitString = GUILayout.TextField(limitString, new GUILayoutOption[] { GUILayout.Width(60) });
+ if (int.TryParse(limitString, out int i))
+ {
+ m_limitPerPage = i;
+ }
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(null);
@@ -220,6 +221,8 @@ namespace Explorer
}
GUI.color = m_autoUpdate ? Color.green : Color.red;
m_autoUpdate = GUILayout.Toggle(m_autoUpdate, "Auto-update?", new GUILayoutOption[] { GUILayout.Width(100) });
+ GUI.color = m_hideFailedReflection ? Color.green : Color.red;
+ m_hideFailedReflection = GUILayout.Toggle(m_hideFailedReflection, "Hide failed Reflection?", new GUILayoutOption[] { GUILayout.Width(150) });
GUI.color = Color.white;
GUILayout.EndHorizontal();
@@ -227,11 +230,11 @@ namespace Explorer
int count = m_cachedMemberFiltered.Length;
- if (count > 20)
+ if (count > m_limitPerPage)
{
// prev/next page buttons
GUILayout.BeginHorizontal(null);
- int maxOffset = (int)Mathf.Ceil(count / 20);
+ int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)m_limitPerPage)) - 1;
if (GUILayout.Button("< Prev", null))
{
if (m_pageOffset > 0) m_pageOffset--;
@@ -286,7 +289,7 @@ namespace Explorer
GUILayout.Label($"{title}", null);
- int offset = (m_pageOffset * 20) + index;
+ int offset = (m_pageOffset * m_limitPerPage) + index;
if (offset >= m_cachedMemberFiltered.Length)
{
@@ -294,7 +297,7 @@ namespace Explorer
offset = 0;
}
- for (int j = offset; j < offset + 20 && j < members.Length; j++)
+ for (int j = offset; j < offset + m_limitPerPage && j < members.Length; j++)
{
var holder = members[j];
@@ -314,7 +317,7 @@ namespace Explorer
GUILayout.EndHorizontal();
index++;
- if (index >= 20) break;
+ if (index >= m_limitPerPage) break;
}
}