From 2f3b7791997d6737d42c675cc64753adb44a32a8 Mon Sep 17 00:00:00 2001 From: sinaioutlander <49360850+sinaioutlander@users.noreply.github.com> Date: Tue, 1 Sep 2020 18:03:44 +1000 Subject: [PATCH] 1.5.1 * Added support for Properties with an index parameter on the Reflection Window (ie. "this[index]") * Fixed a crash that occured when inspecting Il2CppSystem.Type objects * Back-end cleanups --- src/CachedObjects/CacheEnum.cs | 20 ++- src/CachedObjects/CacheList.cs | 58 +++++++-- src/CachedObjects/CacheMethod.cs | 10 +- src/CachedObjects/CacheObjectBase.cs | 181 +++++++++++++++++---------- src/CachedObjects/CacheOther.cs | 32 ++--- src/CachedObjects/CachePrimitive.cs | 2 +- src/CppExplorer.cs | 28 ++--- src/CppExplorer.csproj | 5 + src/Helpers/ReflectionHelpers.cs | 67 ++++------ src/Helpers/UIStyles.cs | 32 +++-- src/Windows/ReflectionWindow.cs | 61 ++++----- src/Windows/WindowManager.cs | 112 +++++++++-------- 12 files changed, 351 insertions(+), 257 deletions(-) diff --git a/src/CachedObjects/CacheEnum.cs b/src/CachedObjects/CacheEnum.cs index 00f3d09..9bcd5ba 100644 --- a/src/CachedObjects/CacheEnum.cs +++ b/src/CachedObjects/CacheEnum.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Reflection; using MelonLoader; using UnityEngine; @@ -15,8 +16,23 @@ namespace Explorer public override void Init() { - EnumType = Value.GetType(); - EnumNames = Enum.GetNames(EnumType); + try + { + EnumType = Value.GetType(); + } + catch + { + EnumType = (MemInfo as FieldInfo)?.FieldType ?? (MemInfo as PropertyInfo).PropertyType; + } + + if (EnumType != null) + { + EnumNames = Enum.GetNames(EnumType); + } + else + { + ReflectionException = "Unknown, could not get Enum names."; + } } public override void DrawValue(Rect window, float width) diff --git a/src/CachedObjects/CacheList.cs b/src/CachedObjects/CacheList.cs index 4b28132..88d17e4 100644 --- a/src/CachedObjects/CacheList.cs +++ b/src/CachedObjects/CacheList.cs @@ -145,16 +145,16 @@ namespace Explorer { if (m_entryType == null) { - if (this.MemberInfo != null) + if (this.MemInfo != null) { Type memberType = null; - switch (this.MemberInfo.MemberType) + switch (this.MemInfo.MemberType) { case MemberTypes.Field: - memberType = (MemberInfo as FieldInfo).FieldType; + memberType = (MemInfo as FieldInfo).FieldType; break; case MemberTypes.Property: - memberType = (MemberInfo as PropertyInfo).PropertyType; + memberType = (MemInfo as PropertyInfo).PropertyType; break; } @@ -201,17 +201,47 @@ namespace Explorer while (enumerator.MoveNext()) { var obj = enumerator.Current; - var type = ReflectionHelpers.GetActualType(obj); - if (obj is Il2CppSystem.Object iObj) + if (obj != null && ReflectionHelpers.GetActualType(obj) is Type t) { - obj = iObj.Il2CppCast(type); + if (obj is Il2CppSystem.Object iObj) + { + try + { + var cast = iObj.Il2CppCast(t); + if (cast != null) + { + obj = cast; + } + } + catch { } + } + + if (GetCacheObject(obj, t) is CacheObjectBase cached) + { + list.Add(cached); + } + else + { + list.Add(null); + } + } + else + { + list.Add(null); } - var cached = GetCacheObject(obj, null, null, type); - cached.UpdateValue(); + //var type = ReflectionHelpers.GetActualType(obj); - list.Add(cached); + //if (obj is Il2CppSystem.Object iObj) + //{ + // obj = iObj.Il2CppCast(type); + //} + + //var cached = GetCacheObject(obj, null, null, type); + //cached.UpdateValue(); + + //list.Add(cached); } m_cachedEntries = list.ToArray(); @@ -310,16 +340,18 @@ namespace Explorer GUILayout.Space(whitespace); - if (entry.Value == null) + if (entry == null || entry.Value == null) { - GUILayout.Label(i + " (null)", null); + GUILayout.Label($"[{i}] (null)", null); } else { GUI.skin.label.alignment = TextAnchor.MiddleCenter; GUILayout.Label($"[{i}]", new GUILayoutOption[] { GUILayout.Width(30) }); - entry.DrawValue(window, window.width - (whitespace + 85)); + + entry.DrawValue(window, window.width - (whitespace + 85)); } + } GUI.skin.label.alignment = TextAnchor.UpperLeft; diff --git a/src/CachedObjects/CacheMethod.cs b/src/CachedObjects/CacheMethod.cs index 6aad655..2e580ee 100644 --- a/src/CachedObjects/CacheMethod.cs +++ b/src/CachedObjects/CacheMethod.cs @@ -24,7 +24,7 @@ namespace Explorer { if (m_hasParams == null) { - m_hasParams = (MemberInfo as MethodInfo).GetParameters().Length > 0; + m_hasParams = (MemInfo as MethodInfo).GetParameters().Length > 0; } return (bool)m_hasParams; } @@ -55,7 +55,7 @@ namespace Explorer { base.Init(); - var mi = MemberInfo as MethodInfo; + var mi = MemInfo as MethodInfo; m_arguments = mi.GetParameters(); m_argumentInput = new string[m_arguments.Length]; @@ -136,12 +136,12 @@ namespace Explorer } else { - GUILayout.Label($"null ({ValueType})", null); + GUILayout.Label($"null ({ValueTypeName})", null); } } else { - GUILayout.Label($"Not yet evaluated ({ValueType})", null); + GUILayout.Label($"Not yet evaluated ({ValueTypeName})", null); } GUILayout.EndHorizontal(); @@ -150,7 +150,7 @@ namespace Explorer private void Evaluate() { - var mi = MemberInfo as MethodInfo; + var mi = MemInfo as MethodInfo; object ret = null; diff --git a/src/CachedObjects/CacheObjectBase.cs b/src/CachedObjects/CacheObjectBase.cs index a773a33..81bba82 100644 --- a/src/CachedObjects/CacheObjectBase.cs +++ b/src/CachedObjects/CacheObjectBase.cs @@ -13,67 +13,70 @@ namespace Explorer public abstract class CacheObjectBase { public object Value; - public string ValueType; + public string ValueTypeName; - // Reflection window only - public MemberInfo MemberInfo { get; set; } + // Reflection Inspector only + public MemberInfo MemInfo { get; set; } public Type DeclaringType { get; set; } public object DeclaringInstance { get; set; } - - public string RichTextName - { - get - { - if (m_richTextName == null) - { - GetRichTextName(); - } - return m_richTextName; - } - } - private string m_richTextName; + public string ReflectionException { get; set; } - public string ReflectionException; + public int PropertyIndex { get; private set; } + private string m_propertyIndexInput = "0"; + + public string RichTextName => m_richTextName ?? GetRichTextName(); + private string m_richTextName; public bool CanWrite { get { - if (MemberInfo is FieldInfo fi) - { + if (MemInfo is FieldInfo fi) return !(fi.IsLiteral && !fi.IsInitOnly); - } - else if (MemberInfo is PropertyInfo pi) - { + else if (MemInfo is PropertyInfo pi) return pi.CanWrite; - } else - { return false; - } } } - // methods + // ===== Abstract/Virtual Methods ===== // + public virtual void Init() { } + public abstract void DrawValue(Rect window, float width); + // ===== Static Methods ===== // + + /// + /// Get CacheObject from only an object instance + /// Calls GetCacheObject(obj, memberInfo, declaringInstance) with (obj, null, null) public static CacheObjectBase GetCacheObject(object obj) { 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. - /// + /// Get CacheObject from an object instance and provide the value type + /// Calls GetCacheObjectImpl directly + public static CacheObjectBase GetCacheObject(object obj, Type valueType) + { + return GetCacheObjectImpl(obj, null, null, valueType); + } + + /// + /// Get CacheObject from only a MemberInfo and declaring instance + /// Calls GetCacheObject(obj, memberInfo, declaringInstance) with (null, memberInfo, declaringInstance) + public static CacheObjectBase GetCacheObject(MemberInfo memberInfo, object declaringInstance) + { + return GetCacheObject(null, memberInfo, declaringInstance); + } + + /// + /// Get CacheObject from either an object or MemberInfo, and don't provide the type. + /// This gets the type and then calls GetCacheObjectImpl public static CacheObjectBase GetCacheObject(object obj, MemberInfo memberInfo, object declaringInstance) { - //var type = ReflectionHelpers.GetActualType(obj) ?? (memberInfo as FieldInfo)?.FieldType ?? (memberInfo as PropertyInfo)?.PropertyType; - Type type = null; if (obj != null) @@ -101,18 +104,13 @@ namespace Explorer return null; } - return GetCacheObject(obj, memberInfo, declaringInstance, type); + return GetCacheObjectImpl(obj, memberInfo, declaringInstance, type); } /// - /// Gets the CacheObject subclass for an object or MemberInfo + /// Actual GetCacheObject implementation (private) /// - /// 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. - /// The type of the object or MemberInfo value. - /// - public static CacheObjectBase GetCacheObject(object obj, MemberInfo memberInfo, object declaringInstance, Type valueType) + private static CacheObjectBase GetCacheObjectImpl(object obj, MemberInfo memberInfo, object declaringInstance, Type valueType) { CacheObjectBase holder; @@ -153,11 +151,11 @@ namespace Explorer } holder.Value = obj; - holder.ValueType = valueType.FullName; + holder.ValueTypeName = valueType.FullName; if (memberInfo != null) { - holder.MemberInfo = memberInfo; + holder.MemInfo = memberInfo; holder.DeclaringType = memberInfo.DeclaringType; holder.DeclaringInstance = declaringInstance; @@ -169,30 +167,40 @@ namespace Explorer return holder; } - // ======== Updating and Setting Value (memberinfo only) ========= + // ======== Instance Methods ========= public virtual void UpdateValue() { - if (MemberInfo == null || !string.IsNullOrEmpty(ReflectionException)) + if (MemInfo == null || !string.IsNullOrEmpty(ReflectionException)) { return; } try { - if (MemberInfo.MemberType == MemberTypes.Field) + if (MemInfo.MemberType == MemberTypes.Field) { - var fi = MemberInfo as FieldInfo; + var fi = MemInfo as FieldInfo; Value = fi.GetValue(fi.IsStatic ? null : DeclaringInstance); } - else if (MemberInfo.MemberType == MemberTypes.Property) + else if (MemInfo.MemberType == MemberTypes.Property) { - var pi = MemberInfo as PropertyInfo; + var pi = MemInfo as PropertyInfo; bool isStatic = pi.GetAccessors()[0].IsStatic; var target = isStatic ? null : DeclaringInstance; - Value = pi.GetValue(target, null); + + if (pi.GetIndexParameters().Length > 0) + { + var indexes = new object[] { PropertyIndex }; + Value = pi.GetValue(target, indexes); + } + else + { + Value = pi.GetValue(target, null); + } } - //ReflectionException = null; + + ReflectionException = null; } catch (Exception e) { @@ -204,15 +212,24 @@ namespace Explorer { try { - if (MemberInfo.MemberType == MemberTypes.Field) + if (MemInfo.MemberType == MemberTypes.Field) { - var fi = MemberInfo as FieldInfo; + var fi = MemInfo as FieldInfo; fi.SetValue(fi.IsStatic ? null : DeclaringInstance, Value); } - else if (MemberInfo.MemberType == MemberTypes.Property) + else if (MemInfo.MemberType == MemberTypes.Property) { - var pi = MemberInfo as PropertyInfo; - pi.SetValue(pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance, Value); + var pi = MemInfo as PropertyInfo; + + if (pi.GetIndexParameters().Length > 0) + { + var indexes = new object[] { PropertyIndex }; + pi.SetValue(pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance, Value, indexes); + } + else + { + pi.SetValue(pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance, Value); + } } } catch (Exception e) @@ -221,7 +238,7 @@ namespace Explorer } } - // ========= Gui Draw ========== + // ========= Instance Gui Draw ========== public const float MAX_LABEL_WIDTH = 400f; @@ -240,11 +257,15 @@ namespace Explorer ClampLabelWidth(window, ref labelWidth); } - if (MemberInfo != null) + if (MemInfo != null) { + var name = RichTextName; + if (MemInfo is PropertyInfo pi && pi.GetIndexParameters().Length > 0) + { + name += $"[{PropertyIndex}]"; + } - - GUILayout.Label(RichTextName, new GUILayoutOption[] { GUILayout.Width(labelWidth) }); + GUILayout.Label(name, new GUILayoutOption[] { GUILayout.Width(labelWidth) }); } else { @@ -255,20 +276,44 @@ namespace Explorer { GUILayout.Label("Reflection failed! (" + ReflectionException + ")", null); } - else if (Value == null && MemberInfo?.MemberType != MemberTypes.Method) + else if (Value == null && MemInfo?.MemberType != MemberTypes.Method) { - GUILayout.Label("null (" + ValueType + ")", null); + GUILayout.Label("null (" + ValueTypeName + ")", null); } else { + if (MemInfo is PropertyInfo pi && pi.GetIndexParameters().Length > 0) + { + GUILayout.Label("index:", new GUILayoutOption[] { GUILayout.Width(50) }); + + m_propertyIndexInput = GUILayout.TextField(m_propertyIndexInput, new GUILayoutOption[] { GUILayout.Width(100) }); + if (GUILayout.Button("Set", new GUILayoutOption[] { GUILayout.Width(60) })) + { + if (int.TryParse(m_propertyIndexInput, out int i)) + { + PropertyIndex = i; + UpdateValue(); + } + else + { + MelonLogger.Log($"Could not parse '{m_propertyIndexInput}' to an int!"); + } + } + + // new line and space + GUILayout.EndHorizontal(); + GUILayout.BeginHorizontal(null); + GUILayout.Space(labelWidth); + } + DrawValue(window, window.width - labelWidth - 90); } } - private void GetRichTextName() + private string GetRichTextName() { string memberColor = ""; - switch (MemberInfo.MemberType) + switch (MemInfo.MemberType) { case MemberTypes.Field: memberColor = "#c266ff"; break; @@ -278,9 +323,9 @@ namespace Explorer memberColor = "#ff8000"; break; }; - m_richTextName = $"{MemberInfo.DeclaringType.Name}.{MemberInfo.Name}"; + m_richTextName = $"{MemInfo.DeclaringType.Name}.{MemInfo.Name}"; - if (MemberInfo is MethodInfo mi) + if (MemInfo is MethodInfo mi) { m_richTextName += "("; var _params = ""; @@ -293,6 +338,8 @@ namespace Explorer m_richTextName += _params; m_richTextName += ")"; } + + return m_richTextName; } } } diff --git a/src/CachedObjects/CacheOther.cs b/src/CachedObjects/CacheOther.cs index a4d5044..b77981b 100644 --- a/src/CachedObjects/CacheOther.cs +++ b/src/CachedObjects/CacheOther.cs @@ -12,33 +12,25 @@ namespace Explorer public class CacheOther : CacheObjectBase { private MethodInfo m_toStringMethod; - private bool m_triedToGetMethod; public MethodInfo ToStringMethod { get { - if (m_toStringMethod == null && !m_triedToGetMethod) + if (m_toStringMethod == null) { - if (Value == null) return null; - - m_triedToGetMethod = true; - try { - var methods = ReflectionHelpers.GetActualType(Value) - .GetMethods(ReflectionHelpers.CommonFlags) - .Where(x => x.Name == "ToString") - .GetEnumerator(); + m_toStringMethod = ReflectionHelpers.GetActualType(Value).GetMethod("ToString", new Type[0]) + ?? typeof(object).GetMethod("ToString", new Type[0]); - while (methods.MoveNext()) - { - // just get the first (top-most level) method, then break. - m_toStringMethod = methods.Current; - break; - } + // test invoke + m_toStringMethod.Invoke(Value, null); + } + catch + { + m_toStringMethod = typeof(object).GetMethod("ToString", new Type[0]); } - catch { } } return m_toStringMethod; } @@ -48,9 +40,9 @@ namespace Explorer { string label = (string)ToStringMethod?.Invoke(Value, null) ?? Value.ToString(); - if (!label.Contains(ValueType)) + if (!label.Contains(ValueTypeName)) { - label += $" ({ValueType})"; + label += $" ({ValueTypeName})"; } if (Value is UnityEngine.Object unityObj && !label.Contains(unityObj.name)) { @@ -58,7 +50,7 @@ namespace Explorer } GUI.skin.button.alignment = TextAnchor.MiddleLeft; - if (GUILayout.Button("" + label + "", new GUILayoutOption[] { GUILayout.MaxWidth(width + 40) })) + if (GUILayout.Button("" + label + "", new GUILayoutOption[] { GUILayout.Width(width) })) { WindowManager.InspectObject(Value, out bool _); } diff --git a/src/CachedObjects/CachePrimitive.cs b/src/CachedObjects/CachePrimitive.cs index b28e6a6..4789209 100644 --- a/src/CachedObjects/CachePrimitive.cs +++ b/src/CachedObjects/CachePrimitive.cs @@ -152,7 +152,7 @@ namespace Explorer public void SetValueFromInput(string value) { - if (MemberInfo == null) + if (MemInfo == null) { MelonLogger.Log("Trying to SetValue but the MemberInfo is null!"); return; diff --git a/src/CppExplorer.cs b/src/CppExplorer.cs index 33f5e6f..0ca6742 100644 --- a/src/CppExplorer.cs +++ b/src/CppExplorer.cs @@ -133,7 +133,7 @@ namespace Explorer // value that we set back to when we close the menu or disable force-unlock. [HarmonyPatch(typeof(Cursor), nameof(Cursor.lockState), MethodType.Setter)] - public class Cursor_lockState + public class Cursor_set_lockState { [HarmonyPrefix] public static void Prefix(ref CursorLockMode value) @@ -170,19 +170,6 @@ namespace Explorer // Make it appear as though UnlockMouse is disabled to the rest of the application. - [HarmonyPatch(typeof(Cursor), nameof(Cursor.visible), MethodType.Getter)] - public class Cursor_get_visible - { - [HarmonyPostfix] - public static void Postfix(ref bool __result) - { - if (ShouldForceMouse) - { - __result = m_lastVisibleState; - } - } - } - [HarmonyPatch(typeof(Cursor), nameof(Cursor.lockState), MethodType.Getter)] public class Cursor_get_lockState { @@ -195,5 +182,18 @@ namespace Explorer } } } + + [HarmonyPatch(typeof(Cursor), nameof(Cursor.visible), MethodType.Getter)] + public class Cursor_get_visible + { + [HarmonyPostfix] + public static void Postfix(ref bool __result) + { + if (ShouldForceMouse) + { + __result = m_lastVisibleState; + } + } + } } } diff --git a/src/CppExplorer.csproj b/src/CppExplorer.csproj index d8784ad..cc1ea50 100644 --- a/src/CppExplorer.csproj +++ b/src/CppExplorer.csproj @@ -60,7 +60,9 @@ ..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnhollowerBaseLib.dll False + + ..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.dll False @@ -89,7 +91,9 @@ ..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.UI.dll False + + ..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.dll False @@ -118,6 +122,7 @@ ..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.UI.dll False + diff --git a/src/Helpers/ReflectionHelpers.cs b/src/Helpers/ReflectionHelpers.cs index 2318e08..b61bb24 100644 --- a/src/Helpers/ReflectionHelpers.cs +++ b/src/Helpers/ReflectionHelpers.cs @@ -8,6 +8,7 @@ using UnhollowerBaseLib; using UnhollowerRuntimeLib; using UnityEngine; using BF = System.Reflection.BindingFlags; +using MelonLoader; namespace Explorer { @@ -27,8 +28,9 @@ namespace Explorer { if (!typeof(Il2CppSystem.Object).IsAssignableFrom(castTo)) return obj; - var generic = m_tryCastMethodInfo.MakeGenericMethod(castTo); - return generic.Invoke(obj, null); + return m_tryCastMethodInfo + .MakeGenericMethod(castTo) + .Invoke(obj, null); } public static string ExceptionToString(Exception e) @@ -81,9 +83,10 @@ namespace Explorer { if (t.IsGenericType) { - return t.GetGenericTypeDefinition() is Type typeDef - && (typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.List<>)) - || typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.IList<>))); + var generic = t.GetGenericTypeDefinition(); + + return generic.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.List<>)) + || generic.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.IList<>)); } else { @@ -115,58 +118,36 @@ namespace Explorer return null; } - public static Type GetActualType(object m_object) + public static Type GetActualType(object obj) { - if (m_object == null) return null; + if (obj == null) return null; - if (m_object is Il2CppSystem.Object ilObject) + if (obj is Il2CppSystem.Object ilObject) { - var iltype = ilObject.GetIl2CppType(); - if (Type.GetType(iltype.AssemblyQualifiedName) is Type type) + var ilTypeName = ilObject.GetIl2CppType().AssemblyQualifiedName; + + if (Type.GetType(ilTypeName) is Type t && !t.FullName.Contains("System.RuntimeType")) { - return type; - } - else - { - return ilObject.GetType(); + return t; } + + return ilObject.GetType(); } - else - { - return m_object.GetType(); - } + + return obj.GetType(); } - public static Type[] GetAllBaseTypes(object m_object) + public static Type[] GetAllBaseTypes(object obj) { var list = new List(); - if (m_object is Il2CppSystem.Object ilObject) - { - var ilType = ilObject.GetIl2CppType(); - if (Type.GetType(ilType.AssemblyQualifiedName) is Type ilTypeToManaged) - { - list.Add(ilTypeToManaged); + var type = GetActualType(obj); + list.Add(type); - while (ilType.BaseType != null) - { - ilType = ilType.BaseType; - if (Type.GetType(ilType.AssemblyQualifiedName) is Type ilBaseTypeToManaged) - { - list.Add(ilBaseTypeToManaged); - } - } - } - } - else + while (type.BaseType != null) { - var type = m_object.GetType(); + type = type.BaseType; list.Add(type); - while (type.BaseType != null) - { - type = type.BaseType; - list.Add(type); - } } return list.ToArray(); diff --git a/src/Helpers/UIStyles.cs b/src/Helpers/UIStyles.cs index c02c91d..5ee9fef 100644 --- a/src/Helpers/UIStyles.cs +++ b/src/Helpers/UIStyles.cs @@ -33,12 +33,14 @@ namespace Explorer } } - public static void HorizontalLine(Color color) + public static void HorizontalLine(Color _color, bool small = false) { - var c = GUI.color; - GUI.color = color; - GUILayout.Box(GUIContent.none, HorizontalBar, null); - GUI.color = c; + var orig = GUI.color; + + GUI.color = _color; + GUILayout.Box(GUIContent.none, !small ? HorizontalBar : HorizontalBarSmall, null); + + GUI.color = orig; } private static GUISkin _customSkin; @@ -46,8 +48,6 @@ namespace Explorer public static Texture2D m_nofocusTex; public static Texture2D m_focusTex; - private static GUIStyle _horizBarStyle; - private static GUIStyle HorizontalBar { get @@ -63,6 +63,24 @@ namespace Explorer return _horizBarStyle; } } + private static GUIStyle _horizBarStyle; + + private static GUIStyle HorizontalBarSmall + { + get + { + if (_horizBarSmallStyle == null) + { + _horizBarSmallStyle = new GUIStyle(); + _horizBarSmallStyle.normal.background = Texture2D.whiteTexture; + _horizBarSmallStyle.margin = new RectOffset(0, 0, 2, 2); + _horizBarSmallStyle.fixedHeight = 1; + } + + return _horizBarSmallStyle; + } + } + private static GUIStyle _horizBarSmallStyle; private static GUISkin CreateWindowSkin() { diff --git a/src/Windows/ReflectionWindow.cs b/src/Windows/ReflectionWindow.cs index 272ba44..fca607b 100644 --- a/src/Windows/ReflectionWindow.cs +++ b/src/Windows/ReflectionWindow.cs @@ -13,10 +13,10 @@ namespace Explorer public class ReflectionWindow : UIWindow { public override string Title => WindowManager.TabView - ? $"[R] {ObjectType.Name}" - : $"Reflection Inspector ({ObjectType.Name})"; + ? $"[R] {TargetType.Name}" + : $"Reflection Inspector ({TargetType.Name})"; - public Type ObjectType; + public Type TargetType; private CacheObjectBase[] m_allCachedMembers; private CacheObjectBase[] m_cachedMembersFiltered; @@ -35,16 +35,11 @@ namespace Explorer public override void Init() { var type = ReflectionHelpers.GetActualType(Target); - if (type == null) - { - MelonLogger.Log($"Could not get underlying type for object! Type: {Target?.GetType().AssemblyQualifiedName}, Value ToString: {Target?.ToString()}"); - DestroyWindow(); - return; - } - ObjectType = type; + TargetType = type; var types = ReflectionHelpers.GetAllBaseTypes(Target); + CacheMembers(types); if (Target is Il2CppSystem.Object ilObject) @@ -90,13 +85,13 @@ namespace Explorer private bool ShouldProcessMember(CacheObjectBase holder) { - if (m_filter != MemberTypes.All && m_filter != holder.MemberInfo?.MemberType) return false; + if (m_filter != MemberTypes.All && m_filter != holder.MemInfo?.MemberType) return false; if (!string.IsNullOrEmpty(holder.ReflectionException) && m_hideFailedReflection) return false; - if (m_search == "" || holder.MemberInfo == null) return true; + if (m_search == "" || holder.MemInfo == null) return true; - var name = holder.MemberInfo.DeclaringType.Name + "." + holder.MemberInfo.Name; + var name = holder.MemInfo.DeclaringType.Name + "." + holder.MemInfo.Name; return name.ToLower().Contains(m_search.ToLower()); } @@ -118,7 +113,7 @@ namespace Explorer } catch { - MelonLogger.Log("Exception getting members for type: " + declaringType.Name); + MelonLogger.Log($"Exception getting members for type: {declaringType.FullName}"); continue; } @@ -140,11 +135,14 @@ namespace Explorer { if (member.MemberType == MemberTypes.Field || member.MemberType == MemberTypes.Property || member.MemberType == MemberTypes.Method) { - // ignore these - if (member.Name.Contains("Il2CppType") || member.Name.StartsWith("get_") || member.Name.StartsWith("set_")) - continue; + var name = $"{member.DeclaringType.Name}.{member.Name}"; + + // blacklist (should probably make a proper implementation) + if (name == "Type.DeclaringMethod" || member.Name.Contains("Il2CppType") || member.Name.StartsWith("get_") || member.Name.StartsWith("set_")) + { + continue; + } - var name = member.DeclaringType.Name + "." + member.Name; if (member is MethodInfo mi) { name += " ("; @@ -161,7 +159,7 @@ namespace Explorer try { - var cached = CacheObjectBase.GetCacheObject(null, member, target); + var cached = CacheObjectBase.GetCacheObject(member, target); if (cached != null) { names.Add(name); @@ -198,7 +196,7 @@ namespace Explorer } GUILayout.BeginHorizontal(null); - GUILayout.Label("Type: " + ObjectType.FullName + "", new GUILayoutOption[] { GUILayout.Width(245f) }); + GUILayout.Label("Type: " + TargetType.FullName + "", new GUILayoutOption[] { GUILayout.Width(245f) }); if (m_uObj) { GUILayout.Label("Name: " + m_uObj.name, null); @@ -298,11 +296,10 @@ namespace Explorer GUILayout.BeginVertical(GUI.skin.box, null); - int index = 0; var members = this.m_cachedMembersFiltered; - int offsetIndex = (m_pageOffset * m_limitPerPage) + index; + int start = m_pageOffset * m_limitPerPage; - if (offsetIndex >= count) + if (start >= count) { int maxOffset = (int)Mathf.Ceil((float)(m_cachedMembersFiltered.Length / (decimal)m_limitPerPage)) - 1; if (m_pageOffset > maxOffset) @@ -311,21 +308,25 @@ namespace Explorer } } - for (int j = offsetIndex; (j < offsetIndex + m_limitPerPage && j < members.Length); j++) + for (int j = start; (j < start + m_limitPerPage && j < members.Length); j++) { var holder = members[j]; GUILayout.BeginHorizontal(new GUILayoutOption[] { GUILayout.Height(25) }); - - try - { + try + { holder.Draw(rect, 180f); + } + catch + { + GUILayout.EndHorizontal(); + continue; } - catch { } - GUILayout.EndHorizontal(); - index++; + // if not last element + if (!(j == (start + m_limitPerPage - 1) || j == (members.Length - 1))) + UIStyles.HorizontalLine(new Color(0.07f, 0.07f, 0.07f), true); } GUILayout.EndVertical(); diff --git a/src/Windows/WindowManager.cs b/src/Windows/WindowManager.cs index 3ec7a57..29fc7e0 100644 --- a/src/Windows/WindowManager.cs +++ b/src/Windows/WindowManager.cs @@ -86,61 +86,6 @@ namespace Explorer // ========= Public Helpers ========= - public static bool IsMouseInWindow - { - get - { - if (!CppExplorer.ShowMenu) - { - return false; - } - - foreach (var window in Windows) - { - if (RectContainsMouse(window.m_rect)) - { - return true; - } - } - return RectContainsMouse(MainMenu.MainRect); - } - } - - private static bool RectContainsMouse(Rect rect) - { - return rect.Contains(new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y)); - } - - public static int NextWindowID() - { - return CurrentWindowID++; - } - - public static Rect GetNewWindowRect() - { - return GetNewWindowRect(ref m_lastWindowRect); - } - - public static Rect GetNewWindowRect(ref Rect lastRect) - { - Rect rect = new Rect(0, 0, 550, 700); - - var mainrect = MainMenu.MainRect; - if (mainrect.x <= (Screen.width - mainrect.width - 100)) - { - rect = new Rect(mainrect.x + mainrect.width + 20, mainrect.y, rect.width, rect.height); - } - - if (lastRect.x == rect.x) - { - rect = new Rect(rect.x + 25, rect.y + 25, rect.width, rect.height); - } - - lastRect = rect; - - return rect; - } - public static UIWindow InspectObject(object obj, out bool createdNew) { createdNew = false; @@ -206,5 +151,62 @@ namespace Explorer return new_window; } + + // === Misc Helpers === + + public static bool IsMouseInWindow + { + get + { + if (!CppExplorer.ShowMenu) + { + return false; + } + + foreach (var window in Windows) + { + if (RectContainsMouse(window.m_rect)) + { + return true; + } + } + return RectContainsMouse(MainMenu.MainRect); + } + } + + private static bool RectContainsMouse(Rect rect) + { + return rect.Contains(new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y)); + } + + public static int NextWindowID() + { + return CurrentWindowID++; + } + + public static Rect GetNewWindowRect() + { + return GetNewWindowRect(ref m_lastWindowRect); + } + + public static Rect GetNewWindowRect(ref Rect lastRect) + { + Rect rect = new Rect(0, 0, 550, 700); + + var mainrect = MainMenu.MainRect; + if (mainrect.x <= (Screen.width - mainrect.width - 100)) + { + rect = new Rect(mainrect.x + mainrect.width + 20, mainrect.y, rect.width, rect.height); + } + + if (lastRect.x == rect.x) + { + rect = new Rect(rect.x + 25, rect.y + 25, rect.width, rect.height); + } + + lastRect = rect; + + return rect; + } } }