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; } }