From 153ad2268b2fb8fd5723f77d5ed10bfb17afdee3 Mon Sep 17 00:00:00 2001 From: sinaioutlander <49360850+sinaioutlander@users.noreply.github.com> Date: Tue, 18 Aug 2020 17:11:58 +1000 Subject: [PATCH] Cleanup project structure Restructured the project somewhat and cleaned up classes so that things are where they belong. Created "Helpers" folder and put appropriate helper classes in there. Important things: - The "GameObject path" methods are now extension methods on UnityEngine.Transform - Removed AccessTools (Reflection helpers) as there was no use of it. Replaced with ReflectionHelpers class. - Some improvements to the "Object Reflection" window, should be a bit faster now. Code cleaned up significantly. --- src/CppExplorer.cs | 165 +-------- src/CppExplorer.csproj | 21 +- src/Helpers/ReflectionHelpers.cs | 105 ++++++ src/{UIStyles.cs => Helpers/UIHelpers.cs} | 110 +----- src/Helpers/UIStyles.cs | 100 ++++++ src/Helpers/UnityHelpers.cs | 51 +++ src/MainMenu/InspectUnderMouse.cs | 87 +++++ src/MainMenu/MainMenu.cs | 2 +- src/MainMenu/Pages/ScenePage.cs | 8 +- src/MainMenu/Pages/SearchPage.cs | 16 +- .../GameObjectWindow.cs | 10 +- .../Reflection/FieldInfoHolder.cs | 6 +- .../Reflection/MemberInfoHolder.cs | 0 .../Reflection/PropertyInfoHolder.cs | 6 +- .../ReflectionWindow.cs | 325 ++++++++---------- src/{Inspectors => Windows}/UIWindow.cs | 0 src/{ => Windows}/WindowManager.cs | 0 src/utils/AccessTools.cs | 65 ---- 18 files changed, 530 insertions(+), 547 deletions(-) create mode 100644 src/Helpers/ReflectionHelpers.cs rename src/{UIStyles.cs => Helpers/UIHelpers.cs} (82%) create mode 100644 src/Helpers/UIStyles.cs create mode 100644 src/Helpers/UnityHelpers.cs create mode 100644 src/MainMenu/InspectUnderMouse.cs rename src/{Inspectors => Windows}/GameObjectWindow.cs (97%) rename src/{Inspectors => Windows}/Reflection/FieldInfoHolder.cs (92%) rename src/{Inspectors => Windows}/Reflection/MemberInfoHolder.cs (100%) rename src/{Inspectors => Windows}/Reflection/PropertyInfoHolder.cs (93%) rename src/{Inspectors => Windows}/ReflectionWindow.cs (55%) rename src/{Inspectors => Windows}/UIWindow.cs (100%) rename src/{ => Windows}/WindowManager.cs (100%) delete mode 100644 src/utils/AccessTools.cs diff --git a/src/CppExplorer.cs b/src/CppExplorer.cs index 8a74d48..649b810 100644 --- a/src/CppExplorer.cs +++ b/src/CppExplorer.cs @@ -2,13 +2,8 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Text; using UnityEngine; using MelonLoader; -using UnhollowerBaseLib; -using UnhollowerRuntimeLib; -using Harmony; -using Il2CppSystem.Runtime.InteropServices; namespace Explorer { @@ -17,53 +12,23 @@ namespace Explorer // consts public const string ID = "com.sinai.cppexplorer"; - public const string VERSION = "1.3.3"; + public const string VERSION = "1.3.5"; public const string AUTHOR = "Sinai"; + public const string NAME = "IL2CPP Runtime Explorer" #if Release_Unity2018 - public const string NAME = "IL2CPP Runtime Explorer (Unity 2018)"; -#else - public const string NAME = "IL2CPP Runtime Explorer"; + + " (Unity 2018)" #endif + ; // fields public static CppExplorer Instance; - private string m_objUnderMouseName = ""; - private Camera m_main; // props public static bool ShowMenu { get; set; } = false; public static int ArrayLimit { get; set; } = 20; - public bool MouseInspect { get; set; } = false; - - // prop helpers - - public static Il2CppSystem.Type GameObjectType => Il2CppType.Of(); - public static Il2CppSystem.Type TransformType => Il2CppType.Of(); - public static Il2CppSystem.Type ObjectType => Il2CppType.Of(); - public static Il2CppSystem.Type ComponentType => Il2CppType.Of(); - - public static string ActiveSceneName - { - get - { - return UnityEngine.SceneManagement.SceneManager.GetActiveScene().name; - } - } - - public Camera MainCamera - { - get - { - if (m_main == null) - { - m_main = Camera.main; - } - return m_main; - } - } // methods @@ -76,21 +41,15 @@ namespace Explorer new MainMenu(); new WindowManager(); - // done init ShowMenu = true; } - // On scene change public override void OnLevelWasLoaded(int level) { - if (ScenePage.Instance != null) - { - ScenePage.Instance.OnSceneChange(); - SearchPage.Instance.OnSceneChange(); - } + ScenePage.Instance?.OnSceneChange(); + SearchPage.Instance?.OnSceneChange(); } - // Update public override void OnUpdate() { if (Input.GetKeyDown(KeyCode.F7)) @@ -109,43 +68,7 @@ namespace Explorer MainMenu.Instance.Update(); WindowManager.Instance.Update(); - if (Input.GetKey(KeyCode.LeftShift) && Input.GetMouseButtonDown(1)) - { - MouseInspect = !MouseInspect; - } - - if (MouseInspect) - { - InspectUnderMouse(); - } - } - else if (MouseInspect) - { - MouseInspect = false; - } - } - - private void InspectUnderMouse() - { - Ray ray = MainCamera.ScreenPointToRay(Input.mousePosition); - - if (Physics.Raycast(ray, out RaycastHit hit, 1000f)) - { - var obj = hit.transform.gameObject; - - m_objUnderMouseName = GetGameObjectPath(obj.transform); - - if (Input.GetMouseButtonDown(0)) - { - MouseInspect = false; - m_objUnderMouseName = ""; - - WindowManager.InspectObject(obj, out _); - } - } - else - { - m_objUnderMouseName = ""; + InspectUnderMouse.Update(); } } @@ -156,79 +79,7 @@ namespace Explorer MainMenu.Instance.OnGUI(); WindowManager.Instance.OnGUI(); - if (MouseInspect) - { - if (m_objUnderMouseName != "") - { - var pos = Input.mousePosition; - var rect = new Rect( - pos.x - (Screen.width / 2), // x - Screen.height - pos.y - 50, // y - Screen.width, // w - 50 // h - ); - - var origAlign = GUI.skin.label.alignment; - GUI.skin.label.alignment = TextAnchor.MiddleCenter; - - //shadow text - GUI.Label(rect, $"{m_objUnderMouseName}"); - //white text - GUI.Label(new Rect(rect.x - 1, rect.y + 1, rect.width, rect.height), m_objUnderMouseName); - - GUI.skin.label.alignment = origAlign; - } - } - } - - // ************** public helpers ************** - - public static object Il2CppCast(object obj, Type castTo) - { - var method = typeof(Il2CppObjectBase).GetMethod("TryCast"); - var generic = method.MakeGenericMethod(castTo); - return generic.Invoke(obj, null); - } - - public static string GetGameObjectPath(Transform _transform) - { - return GetGameObjectPath(_transform, true); - } - - public static string GetGameObjectPath(Transform _transform, bool _includeItemName) - { - string text = _includeItemName ? ("/" + _transform.name) : ""; - GameObject gameObject = _transform.gameObject; - while (gameObject.transform.parent != null) - { - gameObject = gameObject.transform.parent.gameObject; - text = "/" + gameObject.name + text; - } - return text; - } - - public static Type GetType(string _type) - { - try - { - foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) - { - try - { - if (asm.GetType(_type) is Type type) - { - return type; - } - } - catch { } - } - - return null; - } - catch - { - return null; - } + InspectUnderMouse.OnGUI(); } } } diff --git a/src/CppExplorer.csproj b/src/CppExplorer.csproj index 3da607f..83bd797 100644 --- a/src/CppExplorer.csproj +++ b/src/CppExplorer.csproj @@ -137,23 +137,26 @@ - - - - + + + + + + + + - + - - + + - + - \ No newline at end of file diff --git a/src/Helpers/ReflectionHelpers.cs b/src/Helpers/ReflectionHelpers.cs new file mode 100644 index 0000000..dc81c70 --- /dev/null +++ b/src/Helpers/ReflectionHelpers.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Reflection; +using UnhollowerBaseLib; +using UnhollowerRuntimeLib; +using UnityEngine; +using BF = System.Reflection.BindingFlags; +using ILBF = Il2CppSystem.Reflection.BindingFlags; + +namespace Explorer +{ + public class ReflectionHelpers + { + public static BF CommonFlags = BF.Public | BF.Instance | BF.NonPublic | BF.Static; + public static ILBF CommonFlags_IL = ILBF.Public | ILBF.NonPublic | ILBF.Instance | ILBF.Static; + + public static Il2CppSystem.Type GameObjectType => Il2CppType.Of(); + public static Il2CppSystem.Type TransformType => Il2CppType.Of(); + public static Il2CppSystem.Type ObjectType => Il2CppType.Of(); + public static Il2CppSystem.Type ComponentType => Il2CppType.Of(); + + private static readonly MethodInfo m_tryCastMethodInfo = typeof(Il2CppObjectBase).GetMethod("TryCast"); + + public static object Il2CppCast(object obj, Type castTo) + { + var generic = m_tryCastMethodInfo.MakeGenericMethod(castTo); + return generic.Invoke(obj, null); + } + + public static bool IsList(Type t) + { + return t.IsGenericType + && t.GetGenericTypeDefinition() is Type typeDef + && (typeDef.IsAssignableFrom(typeof(List<>)) || typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.List<>))); + } + + public static Type GetTypeByName(string typeName) + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + try + { + if (asm.GetType(typeName) is Type type) + { + return type; + } + } + catch { } + } + + return null; + } + + public static Type GetActualType(object m_object) + { + if (m_object is Il2CppSystem.Object ilObject) + { + var iltype = ilObject.GetIl2CppType(); + return Type.GetType(iltype.AssemblyQualifiedName); + } + else + { + return m_object.GetType(); + } + } + + public static Type[] GetAllBaseTypes(object m_object) + { + 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); + + while (ilType.BaseType != null) + { + ilType = ilType.BaseType; + if (Type.GetType(ilType.AssemblyQualifiedName) is Type ilBaseTypeToManaged) + { + list.Add(ilBaseTypeToManaged); + } + } + } + } + else + { + var type = m_object.GetType(); + list.Add(type); + while (type.BaseType != null) + { + type = type.BaseType; + list.Add(type); + } + } + + return list.ToArray(); + } + } +} diff --git a/src/UIStyles.cs b/src/Helpers/UIHelpers.cs similarity index 82% rename from src/UIStyles.cs rename to src/Helpers/UIHelpers.cs index dcf8480..75438ac 100644 --- a/src/UIStyles.cs +++ b/src/Helpers/UIHelpers.cs @@ -1,108 +1,16 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Reflection; using System.Text; -using Il2CppSystem.Collections; -//using Il2CppSystem.Reflection; -using MelonLoader; -using UnhollowerBaseLib; +using System.Threading.Tasks; using UnityEngine; using Object = UnityEngine.Object; +using System.Reflection; namespace Explorer { - public class UIStyles + public class UIHelpers { - public static Color LightGreen = new Color(Color.green.r - 0.3f, Color.green.g - 0.3f, Color.green.b - 0.3f); - - public static GUISkin WindowSkin - { - get - { - if (_customSkin == null) - { - try - { - _customSkin = CreateWindowSkin(); - } - catch - { - _customSkin = GUI.skin; - } - } - - return _customSkin; - } - } - - public static void HorizontalLine(Color color) - { - var c = GUI.color; - GUI.color = color; - GUILayout.Box(GUIContent.none, HorizontalBar, null); - GUI.color = c; - } - - private static GUISkin _customSkin; - - public static Texture2D m_nofocusTex; - public static Texture2D m_focusTex; - - private static GUIStyle _horizBarStyle; - - private static GUIStyle HorizontalBar - { - get - { - if (_horizBarStyle == null) - { - _horizBarStyle = new GUIStyle(); - _horizBarStyle.normal.background = Texture2D.whiteTexture; - _horizBarStyle.margin = new RectOffset(0, 0, 4, 4); - _horizBarStyle.fixedHeight = 2; - } - - return _horizBarStyle; - } - } - - private static GUISkin CreateWindowSkin() - { - var newSkin = Object.Instantiate(GUI.skin); - Object.DontDestroyOnLoad(newSkin); - - m_nofocusTex = MakeTex(550, 700, new Color(0.1f, 0.1f, 0.1f, 0.7f)); - m_focusTex = MakeTex(550, 700, new Color(0.3f, 0.3f, 0.3f, 1f)); - - newSkin.window.normal.background = m_nofocusTex; - newSkin.window.onNormal.background = m_focusTex; - - newSkin.box.normal.textColor = Color.white; - newSkin.window.normal.textColor = Color.white; - newSkin.button.normal.textColor = Color.white; - newSkin.textField.normal.textColor = Color.white; - newSkin.label.normal.textColor = Color.white; - - return newSkin; - } - - public static Texture2D MakeTex(int width, int height, Color col) - { - Color[] pix = new Color[width * height]; - for (int i = 0; i < pix.Length; ++i) - { - pix[i] = col; - } - Texture2D result = new Texture2D(width, height); - result.SetPixels(pix); - result.Apply(); - return result; - } - - // *********************************** METHODS FOR DRAWING VALUES IN GUI ************************************ - // helper for "Instantiate" button on UnityEngine.Objects public static void InstantiateButton(Object obj, float width = 100) { @@ -134,7 +42,7 @@ namespace Explorer } else { - color = LightGreen; + color = UIStyles.LightGreen; } } else @@ -144,7 +52,7 @@ namespace Explorer FastGameobjButton(obj, color, label, obj.activeSelf, specialInspectMethod, showSmallInspectBtn, width); } - + public static void FastGameobjButton(GameObject obj, Color activeColor, string label, bool enabled, Action specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380) { if (!obj) @@ -236,11 +144,11 @@ namespace Explorer { DrawPrimitive(ref value, rect, setTarget, setAction); } - else if (ilType != null && ilType == CppExplorer.GameObjectType || CppExplorer.TransformType.IsAssignableFrom(ilType)) - { + else if (ilType != null && ilType == ReflectionHelpers.GameObjectType || ReflectionHelpers.TransformType.IsAssignableFrom(ilType)) + { GameObject go; var ilObj = value as Il2CppSystem.Object; - if (ilType == CppExplorer.GameObjectType) + if (ilType == ReflectionHelpers.GameObjectType) { go = ilObj.TryCast(); } @@ -269,7 +177,7 @@ namespace Explorer GUILayout.Label(value.ToString(), null); } - else if (value is System.Collections.IEnumerable || ReflectionWindow.IsList(valueType)) + else if (value is System.Collections.IEnumerable || ReflectionHelpers.IsList(valueType)) { System.Collections.IEnumerable enumerable; diff --git a/src/Helpers/UIStyles.cs b/src/Helpers/UIStyles.cs new file mode 100644 index 0000000..a0286de --- /dev/null +++ b/src/Helpers/UIStyles.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace Explorer +{ + public class UIStyles + { + public static Color LightGreen = new Color(Color.green.r - 0.3f, Color.green.g - 0.3f, Color.green.b - 0.3f); + + public static GUISkin WindowSkin + { + get + { + if (_customSkin == null) + { + try + { + _customSkin = CreateWindowSkin(); + } + catch + { + _customSkin = GUI.skin; + } + } + + return _customSkin; + } + } + + public static void HorizontalLine(Color color) + { + var c = GUI.color; + GUI.color = color; + GUILayout.Box(GUIContent.none, HorizontalBar, null); + GUI.color = c; + } + + private static GUISkin _customSkin; + + public static Texture2D m_nofocusTex; + public static Texture2D m_focusTex; + + private static GUIStyle _horizBarStyle; + + private static GUIStyle HorizontalBar + { + get + { + if (_horizBarStyle == null) + { + _horizBarStyle = new GUIStyle(); + _horizBarStyle.normal.background = Texture2D.whiteTexture; + _horizBarStyle.margin = new RectOffset(0, 0, 4, 4); + _horizBarStyle.fixedHeight = 2; + } + + return _horizBarStyle; + } + } + + private static GUISkin CreateWindowSkin() + { + var newSkin = Object.Instantiate(GUI.skin); + Object.DontDestroyOnLoad(newSkin); + + m_nofocusTex = MakeTex(550, 700, new Color(0.1f, 0.1f, 0.1f, 0.7f)); + m_focusTex = MakeTex(550, 700, new Color(0.3f, 0.3f, 0.3f, 1f)); + + newSkin.window.normal.background = m_nofocusTex; + newSkin.window.onNormal.background = m_focusTex; + + newSkin.box.normal.textColor = Color.white; + newSkin.window.normal.textColor = Color.white; + newSkin.button.normal.textColor = Color.white; + newSkin.textField.normal.textColor = Color.white; + newSkin.label.normal.textColor = Color.white; + + return newSkin; + } + + public static Texture2D MakeTex(int width, int height, Color col) + { + Color[] pix = new Color[width * height]; + for (int i = 0; i < pix.Length; ++i) + { + pix[i] = col; + } + Texture2D result = new Texture2D(width, height); + result.SetPixels(pix); + result.Apply(); + return result; + } + } +} diff --git a/src/Helpers/UnityHelpers.cs b/src/Helpers/UnityHelpers.cs new file mode 100644 index 0000000..70470c9 --- /dev/null +++ b/src/Helpers/UnityHelpers.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace Explorer +{ + public static class UnityHelpers + { + private static Camera m_mainCamera; + + public static Camera MainCamera + { + get + { + if (m_mainCamera == null) + { + m_mainCamera = Camera.main; + } + return m_mainCamera; + } + } + + public static string ActiveSceneName + { + get + { + return UnityEngine.SceneManagement.SceneManager.GetActiveScene().name; + } + } + + public static string GetGameObjectPath(this Transform _transform) + { + return GetGameObjectPath(_transform, true); + } + + public static string GetGameObjectPath(this Transform _transform, bool _includeThisName) + { + string path = _includeThisName ? ("/" + _transform.name) : ""; + GameObject gameObject = _transform.gameObject; + while (gameObject.transform.parent != null) + { + gameObject = gameObject.transform.parent.gameObject; + path = "/" + gameObject.name + path; + } + return path; + } + } +} diff --git a/src/MainMenu/InspectUnderMouse.cs b/src/MainMenu/InspectUnderMouse.cs new file mode 100644 index 0000000..fd1ef65 --- /dev/null +++ b/src/MainMenu/InspectUnderMouse.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace Explorer +{ + public class InspectUnderMouse + { + public static bool EnableInspect { get; set; } = false; + + private static string m_objUnderMouseName = ""; + + public static void Update() + { + if (CppExplorer.ShowMenu) + { + if (Input.GetKey(KeyCode.LeftShift) && Input.GetMouseButtonDown(1)) + { + EnableInspect = !EnableInspect; + } + + if (EnableInspect) + { + InspectRaycast(); + } + } + else if (EnableInspect) + { + EnableInspect = false; + } + } + + public static void InspectRaycast() + { + Ray ray = UnityHelpers.MainCamera.ScreenPointToRay(Input.mousePosition); + + if (Physics.Raycast(ray, out RaycastHit hit, 1000f)) + { + var obj = hit.transform.gameObject; + + m_objUnderMouseName = obj.transform.GetGameObjectPath(); + + if (Input.GetMouseButtonDown(0)) + { + EnableInspect = false; + m_objUnderMouseName = ""; + + WindowManager.InspectObject(obj, out _); + } + } + else + { + m_objUnderMouseName = ""; + } + } + + public static void OnGUI() + { + if (EnableInspect) + { + if (m_objUnderMouseName != "") + { + var pos = Input.mousePosition; + var rect = new Rect( + pos.x - (Screen.width / 2), // x + Screen.height - pos.y - 50, // y + Screen.width, // w + 50 // h + ); + + var origAlign = GUI.skin.label.alignment; + GUI.skin.label.alignment = TextAnchor.MiddleCenter; + + //shadow text + GUI.Label(rect, $"{m_objUnderMouseName}"); + //white text + GUI.Label(new Rect(rect.x - 1, rect.y + 1, rect.width, rect.height), m_objUnderMouseName); + + GUI.skin.label.alignment = origAlign; + } + } + } + } +} diff --git a/src/MainMenu/MainMenu.cs b/src/MainMenu/MainMenu.cs index 94f00dc..640a7a3 100644 --- a/src/MainMenu/MainMenu.cs +++ b/src/MainMenu/MainMenu.cs @@ -98,7 +98,7 @@ namespace Explorer { CppExplorer.ArrayLimit = _lim; } - CppExplorer.Instance.MouseInspect = GUILayout.Toggle(CppExplorer.Instance.MouseInspect, "Inspect Under Mouse (Shift + RMB)", null); + InspectUnderMouse.EnableInspect = GUILayout.Toggle(InspectUnderMouse.EnableInspect, "Inspect Under Mouse (Shift + RMB)", null); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(null); diff --git a/src/MainMenu/Pages/ScenePage.cs b/src/MainMenu/Pages/ScenePage.cs index e5f3229..c5e61da 100644 --- a/src/MainMenu/Pages/ScenePage.cs +++ b/src/MainMenu/Pages/ScenePage.cs @@ -36,7 +36,7 @@ namespace Explorer public void OnSceneChange() { - m_currentScene = CppExplorer.ActiveSceneName; + m_currentScene = UnityHelpers.ActiveSceneName; m_currentTransform = null; CancelSearch(); @@ -155,7 +155,7 @@ namespace Explorer } else { - GUILayout.Label(CppExplorer.GetGameObjectPath(m_currentTransform), null); + GUILayout.Label(m_currentTransform.GetGameObjectPath(), null); } GUILayout.EndHorizontal(); } @@ -169,7 +169,7 @@ namespace Explorer foreach (var obj in m_objectList) { //UIStyles.GameobjButton(obj, SetTransformTarget, true, MainMenu.MainRect.width - 170); - UIStyles.FastGameobjButton(obj.RefGameObject, obj.EnabledColor, obj.Label, obj.RefGameObject.activeSelf, SetTransformTarget, true, MainMenu.MainRect.width - 170); + UIHelpers.FastGameobjButton(obj.RefGameObject, obj.EnabledColor, obj.Label, obj.RefGameObject.activeSelf, SetTransformTarget, true, MainMenu.MainRect.width - 170); } } } @@ -187,7 +187,7 @@ namespace Explorer foreach (var obj in m_searchResults) { //UIStyles.GameobjButton(obj, SetTransformTarget, true, MainMenu.MainRect.width - 170); - UIStyles.FastGameobjButton(obj.RefGameObject, obj.EnabledColor, obj.Label, obj.RefGameObject.activeSelf, SetTransformTarget, true, MainMenu.MainRect.width - 170); + UIHelpers.FastGameobjButton(obj.RefGameObject, obj.EnabledColor, obj.Label, obj.RefGameObject.activeSelf, SetTransformTarget, true, MainMenu.MainRect.width - 170); } } else diff --git a/src/MainMenu/Pages/SearchPage.cs b/src/MainMenu/Pages/SearchPage.cs index bb418cd..9f9963d 100644 --- a/src/MainMenu/Pages/SearchPage.cs +++ b/src/MainMenu/Pages/SearchPage.cs @@ -132,7 +132,7 @@ namespace Explorer bool _ = false; int __ = 0; - UIStyles.DrawValue(ref obj, ref _, ref __, _temprect); + UIHelpers.DrawValue(ref obj, ref _, ref __, _temprect); } } else @@ -263,7 +263,7 @@ namespace Explorer { try { - var findType = CppExplorer.GetType(_type); + var findType = ReflectionHelpers.GetTypeByName(_type); searchType = Il2CppSystem.Type.GetType(findType.AssemblyQualifiedName); } catch (Exception e) @@ -273,18 +273,18 @@ namespace Explorer } else if (TypeMode == TypeFilter.Object) { - searchType = CppExplorer.ObjectType; + searchType = ReflectionHelpers.ObjectType; } else if (TypeMode == TypeFilter.GameObject) { - searchType = CppExplorer.GameObjectType; + searchType = ReflectionHelpers.GameObjectType; } else if (TypeMode == TypeFilter.Component) { - searchType = CppExplorer.ComponentType; + searchType = ReflectionHelpers.ComponentType; } - if (!CppExplorer.ObjectType.IsAssignableFrom(searchType)) + if (!ReflectionHelpers.ObjectType.IsAssignableFrom(searchType)) { MelonLogger.LogError("Your Custom Class Type must inherit from UnityEngine.Object!"); return new List(); @@ -301,7 +301,7 @@ namespace Explorer continue; } - if (searchType == CppExplorer.ComponentType && CppExplorer.TransformType.IsAssignableFrom(obj.GetIl2CppType())) + if (searchType == ReflectionHelpers.ComponentType && ReflectionHelpers.TransformType.IsAssignableFrom(obj.GetIl2CppType())) { // Transforms shouldn't really be counted as Components, skip them. // They're more akin to GameObjects. @@ -346,7 +346,7 @@ namespace Explorer } else if (filter == SceneFilter.This) { - return go.scene.name == CppExplorer.ActiveSceneName; + return go.scene.name == UnityHelpers.ActiveSceneName; } else if (filter == SceneFilter.DontDestroy) { diff --git a/src/Inspectors/GameObjectWindow.cs b/src/Windows/GameObjectWindow.cs similarity index 97% rename from src/Inspectors/GameObjectWindow.cs rename to src/Windows/GameObjectWindow.cs index c3d8f66..c66fb30 100644 --- a/src/Inspectors/GameObjectWindow.cs +++ b/src/Windows/GameObjectWindow.cs @@ -133,7 +133,7 @@ namespace Explorer GUILayout.BeginHorizontal(null); GUILayout.Label("Scene: " + (m_scene == "" ? "n/a" : m_scene) + "", null); - if (m_scene == CppExplorer.ActiveSceneName) + if (m_scene == UnityHelpers.ActiveSceneName) { if (GUILayout.Button("< View in Scene Explorer", new GUILayoutOption[] { GUILayout.Width(230) })) { @@ -145,7 +145,7 @@ namespace Explorer GUILayout.BeginHorizontal(null); GUILayout.Label("Path:", new GUILayoutOption[] { GUILayout.Width(50) }); - string pathlabel = CppExplorer.GetGameObjectPath(m_object.transform); + string pathlabel = m_object.transform.GetGameObjectPath(); if (m_object.transform.parent != null) { if (GUILayout.Button("<-", new GUILayoutOption[] { GUILayout.Width(35) })) @@ -198,7 +198,7 @@ namespace Explorer GUILayout.Label("null", null); continue; } - UIStyles.GameobjButton(obj.gameObject, InspectGameObject, false, this.m_rect.width / 2 - 60); + UIHelpers.GameobjButton(obj.gameObject, InspectGameObject, false, this.m_rect.width / 2 - 60); } foreach (var obj in m_children.Where(x => x.childCount == 0)) { @@ -207,7 +207,7 @@ namespace Explorer GUILayout.Label("null", null); continue; } - UIStyles.GameobjButton(obj.gameObject, InspectGameObject, false, this.m_rect.width / 2 - 60); + UIHelpers.GameobjButton(obj.gameObject, InspectGameObject, false, this.m_rect.width / 2 - 60); } } else @@ -329,7 +329,7 @@ namespace Explorer new GUILayoutOption[] { GUILayout.Width(80) }); if (m_object.activeSelf != m_active) { m_object.SetActive(m_active); } - UIStyles.InstantiateButton(m_object, 100); + UIHelpers.InstantiateButton(m_object, 100); GUILayout.EndHorizontal(); diff --git a/src/Inspectors/Reflection/FieldInfoHolder.cs b/src/Windows/Reflection/FieldInfoHolder.cs similarity index 92% rename from src/Inspectors/Reflection/FieldInfoHolder.cs rename to src/Windows/Reflection/FieldInfoHolder.cs index 24b44a6..b10eb9c 100644 --- a/src/Inspectors/Reflection/FieldInfoHolder.cs +++ b/src/Windows/Reflection/FieldInfoHolder.cs @@ -28,7 +28,7 @@ namespace Explorer { var declaringType = this.fieldInfo.DeclaringType; - var cast = CppExplorer.Il2CppCast(obj, declaringType); + var cast = ReflectionHelpers.Il2CppCast(obj, declaringType); m_value = this.fieldInfo.GetValue(fieldInfo.IsStatic ? null : cast); } else @@ -44,7 +44,7 @@ namespace Explorer public override void Draw(ReflectionWindow window) { - UIStyles.DrawMember(ref m_value, ref this.IsExpanded, ref this.arrayOffset, this.fieldInfo, window.m_rect, window.m_object, SetValue); + UIHelpers.DrawMember(ref m_value, ref this.IsExpanded, ref this.arrayOffset, this.fieldInfo, window.m_rect, window.Target, SetValue); } public override void SetValue(object obj) @@ -103,7 +103,7 @@ namespace Explorer { var declaringType = this.fieldInfo.DeclaringType; - var cast = CppExplorer.Il2CppCast(obj, declaringType); + var cast = ReflectionHelpers.Il2CppCast(obj, declaringType); fieldInfo.SetValue(fieldInfo.IsStatic ? null : cast, m_value); } else diff --git a/src/Inspectors/Reflection/MemberInfoHolder.cs b/src/Windows/Reflection/MemberInfoHolder.cs similarity index 100% rename from src/Inspectors/Reflection/MemberInfoHolder.cs rename to src/Windows/Reflection/MemberInfoHolder.cs diff --git a/src/Inspectors/Reflection/PropertyInfoHolder.cs b/src/Windows/Reflection/PropertyInfoHolder.cs similarity index 93% rename from src/Inspectors/Reflection/PropertyInfoHolder.cs rename to src/Windows/Reflection/PropertyInfoHolder.cs index 594bb0a..508c565 100644 --- a/src/Inspectors/Reflection/PropertyInfoHolder.cs +++ b/src/Windows/Reflection/PropertyInfoHolder.cs @@ -23,7 +23,7 @@ namespace Explorer public override void Draw(ReflectionWindow window) { - UIStyles.DrawMember(ref m_value, ref this.IsExpanded, ref this.arrayOffset, this.propInfo, window.m_rect, window.m_object, SetValue); + UIHelpers.DrawMember(ref m_value, ref this.IsExpanded, ref this.arrayOffset, this.propInfo, window.m_rect, window.Target, SetValue); } public override void UpdateValue(object obj) @@ -40,7 +40,7 @@ namespace Explorer } else { - var cast = CppExplorer.Il2CppCast(obj, declaringType); + var cast = ReflectionHelpers.Il2CppCast(obj, declaringType); m_value = this.propInfo.GetValue(this.propInfo.GetAccessors()[0].IsStatic ? null : cast, null); } } @@ -114,7 +114,7 @@ namespace Explorer } var declaring = propInfo.DeclaringType; - var cast = CppExplorer.Il2CppCast(obj, declaring); + var cast = ReflectionHelpers.Il2CppCast(obj, declaring); propInfo.SetValue(propInfo.GetAccessors()[0].IsStatic ? null : cast, m_value, null); } diff --git a/src/Inspectors/ReflectionWindow.cs b/src/Windows/ReflectionWindow.cs similarity index 55% rename from src/Inspectors/ReflectionWindow.cs rename to src/Windows/ReflectionWindow.cs index 33ccd89..5a4b880 100644 --- a/src/Inspectors/ReflectionWindow.cs +++ b/src/Windows/ReflectionWindow.cs @@ -1,4 +1,5 @@ using System; +using System.CodeDom; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -14,11 +15,11 @@ namespace Explorer { public override string Name { get => "Object Reflection"; set => Name = value; } - public Type m_objectType; - public object m_object; + public Type ObjectType; + //public object Target; - private List m_FieldInfos; - private List m_PropertyInfos; + private FieldInfoHolder[] m_FieldInfos; + private PropertyInfoHolder[] m_PropertyInfos; private bool m_autoUpdate = false; private string m_search = ""; @@ -33,25 +34,21 @@ namespace Explorer public override void Init() { - m_object = Target; - - m_FieldInfos = new List(); - m_PropertyInfos = new List(); - - var type = GetActualType(m_object); + var type = ReflectionHelpers.GetActualType(Target); if (type == null) { - MelonLogger.Log("could not get underlying type for object. ToString(): " + m_object.ToString()); + MelonLogger.Log("Could not get underlying type for object. ToString(): " + Target.ToString()); return; } - try - { - m_objectType = type; - GetFields(m_object); - GetProperties(m_object); - } - catch { } + ObjectType = type; + + var types = ReflectionHelpers.GetAllBaseTypes(Target); + + CacheFields(types); + CacheProperties(types); + + MelonLogger.Log("Cached properties: " + m_PropertyInfos.Length); UpdateValues(true); } @@ -66,29 +63,106 @@ namespace Explorer private void UpdateValues(bool forceAll = false) { - if (forceAll || m_filter == MemberFilter.Both || m_filter == MemberFilter.Field) - { - foreach (var holder in this.m_FieldInfos) - { - if (forceAll || m_search == "" || holder.fieldInfo.Name.ToLower().Contains(m_search.ToLower())) - { - holder.UpdateValue(m_object); - } - } - } + UpdateMemberList(forceAll, this.m_FieldInfos, MemberFilter.Field); + UpdateMemberList(forceAll, this.m_PropertyInfos, MemberFilter.Property); + } - if (forceAll || m_filter == MemberFilter.Both || m_filter == MemberFilter.Property) + private void UpdateMemberList(bool forceAll, MemberInfoHolder[] list, MemberFilter filter) + { + if (forceAll || m_filter == MemberFilter.Both || m_filter == filter) { - foreach (var holder in this.m_PropertyInfos) + foreach (var holder in list) { - if (forceAll || m_search == "" || holder.propInfo.Name.ToLower().Contains(m_search.ToLower())) + if (forceAll || ShouldUpdateMemberInfo(holder)) { - holder.UpdateValue(m_object); + holder.UpdateValue(Target); } } } } + private bool ShouldUpdateMemberInfo(MemberInfoHolder holder) + { + var memberName = holder is FieldInfoHolder ? + (holder as FieldInfoHolder).fieldInfo.Name : + (holder as PropertyInfoHolder).propInfo.Name; + + return m_search == "" || memberName.ToLower().Contains(m_search.ToLower()); + } + + private void CacheProperties(Type[] types, List names = null) + { + if (names == null) + { + names = new List(); + } + + var list = new List(); + + foreach (var type in types) + { + PropertyInfo[] propInfos = new PropertyInfo[0]; + + try + { + propInfos = type.GetProperties(ReflectionHelpers.CommonFlags); + } + catch (TypeLoadException) + { + MelonLogger.Log($"Couldn't get Properties for Type '{type.Name}', it may not support Il2Cpp Reflection at the moment."); + } + + foreach (var pi in propInfos) + { + // this member causes a crash when inspected, so just skipping it for now. + if (pi.Name == "Il2CppType") + { + continue; + } + + if (names.Contains(pi.Name)) + { + continue; + } + names.Add(pi.Name); + + var piHolder = new PropertyInfoHolder(type, pi); + list.Add(piHolder); + } + } + + m_PropertyInfos = list.ToArray(); + } + + private void CacheFields(Type[] types, List names = null) + { + if (names == null) + { + names = new List(); + } + + var list = new List(); + + foreach (var type in types) + { + foreach (var fi in type.GetFields(ReflectionHelpers.CommonFlags)) + { + if (names.Contains(fi.Name)) + { + continue; + } + names.Add(fi.Name); + + var fiHolder = new FieldInfoHolder(type, fi); + list.Add(fiHolder); + } + } + + m_FieldInfos = list.ToArray(); + } + + // =========== GUI DRAW =========== // + public override void WindowFunction(int windowID) { try @@ -98,13 +172,13 @@ namespace Explorer GUILayout.BeginArea(new Rect(5, 25, m_rect.width - 10, m_rect.height - 35), GUI.skin.box); GUILayout.BeginHorizontal(null); - GUILayout.Label("Type: " + m_objectType.Name + "", null); + GUILayout.Label("Type: " + ObjectType.Name + "", null); - bool unityObj = m_object is UnityEngine.Object; + bool unityObj = Target is UnityEngine.Object; if (unityObj) { - GUILayout.Label("Name: " + (m_object as UnityEngine.Object).name, null); + GUILayout.Label("Name: " + (Target as UnityEngine.Object).name, null); } GUILayout.EndHorizontal(); @@ -114,9 +188,9 @@ namespace Explorer GUILayout.Label("Tools:", new GUILayoutOption[] { GUILayout.Width(80) }); - UIStyles.InstantiateButton((UnityEngine.Object)m_object); + UIHelpers.InstantiateButton((UnityEngine.Object)Target); - if (m_object is Component comp && comp.gameObject is GameObject obj) + if (Target is Component comp && comp.gameObject is GameObject obj) { GUI.skin.label.alignment = TextAnchor.MiddleRight; GUILayout.Label("GameObject:", null); @@ -163,40 +237,12 @@ namespace Explorer if (m_filter == MemberFilter.Both || m_filter == MemberFilter.Field) { - UIStyles.HorizontalLine(Color.grey); - - GUILayout.Label("Fields", null); - - foreach (var holder in this.m_FieldInfos) - { - if (m_search != "" && !holder.fieldInfo.Name.ToLower().Contains(m_search.ToLower())) - { - continue; - } - - GUILayout.BeginHorizontal(new GUILayoutOption[] { GUILayout.Height(25) }); - holder.Draw(this); - GUILayout.EndHorizontal(); - } + DrawMembers(this.m_FieldInfos, "Fields"); } if (m_filter == MemberFilter.Both || m_filter == MemberFilter.Property) { - UIStyles.HorizontalLine(Color.grey); - - GUILayout.Label("Properties", null); - - foreach (var holder in this.m_PropertyInfos) - { - if (m_search != "" && !holder.propInfo.Name.ToLower().Contains(m_search.ToLower())) - { - continue; - } - - GUILayout.BeginHorizontal(new GUILayoutOption[] { GUILayout.Height(25) }); - holder.Draw(this); - GUILayout.EndHorizontal(); - } + DrawMembers(this.m_PropertyInfos, "Properties"); } GUILayout.EndScrollView(); @@ -213,6 +259,27 @@ namespace Explorer } } + private void DrawMembers(MemberInfoHolder[] members, string title) + { + UIStyles.HorizontalLine(Color.grey); + + GUILayout.Label($"{title}", null); + + foreach (var holder in members) + { + var memberName = (holder as FieldInfoHolder)?.fieldInfo.Name ?? (holder as PropertyInfoHolder)?.propInfo.Name; + + if (m_search != "" && !memberName.ToLower().Contains(m_search.ToLower())) + { + continue; + } + + GUILayout.BeginHorizontal(new GUILayoutOption[] { GUILayout.Height(25) }); + holder.Draw(this); + GUILayout.EndHorizontal(); + } + } + private void FilterToggle(MemberFilter mode, string label) { if (m_filter == mode) @@ -229,129 +296,5 @@ namespace Explorer } GUI.color = Color.white; } - - // ============ HELPERS =============== - - public Type GetActualType(object m_object) - { - if (m_object is Il2CppSystem.Object ilObject) - { - var iltype = ilObject.GetIl2CppType(); - return Type.GetType(iltype.AssemblyQualifiedName); - } - else - { - return m_object.GetType(); - } - } - - public Type[] GetAllBaseTypes(object m_object) - { - 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); - - while (ilType.BaseType != null) - { - ilType = ilType.BaseType; - if (Type.GetType(ilType.AssemblyQualifiedName) is Type ilBaseTypeToManaged) - { - list.Add(ilBaseTypeToManaged); - } - } - } - } - else - { - var type = m_object.GetType(); - list.Add(type); - while (type.BaseType != null) - { - type = type.BaseType; - list.Add(type); - } - } - - return list.ToArray(); - } - - public static bool IsList(Type t) - { - return t.IsGenericType - && t.GetGenericTypeDefinition() is Type typeDef - && (typeDef.IsAssignableFrom(typeof(List<>)) || typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.List<>))); - } - - private void GetProperties(object m_object, List names = null) - { - if (names == null) - { - names = new List(); - } - - var types = GetAllBaseTypes(m_object); - - foreach (var type in types) - { - PropertyInfo[] propInfos = new PropertyInfo[0]; - - try - { - propInfos = type.GetProperties(At.flags); - } - catch (TypeLoadException) - { - MelonLogger.Log($"Couldn't get Properties for Type '{type.Name}', it may not support Il2Cpp Reflection at the moment."); - } - - foreach (var pi in propInfos) - { - // this member causes a crash when inspected, so just skipping it for now. - if (pi.Name == "Il2CppType") - { - continue; - } - - if (names.Contains(pi.Name)) - { - continue; - } - names.Add(pi.Name); - - var piHolder = new PropertyInfoHolder(type, pi); - m_PropertyInfos.Add(piHolder); - } - } - } - - private void GetFields(object m_object, List names = null) - { - if (names == null) - { - names = new List(); - } - - var types = GetAllBaseTypes(m_object); - - foreach (var type in types) - { - foreach (var fi in type.GetFields(At.flags)) - { - if (names.Contains(fi.Name)) - { - continue; - } - names.Add(fi.Name); - - var fiHolder = new FieldInfoHolder(type, fi); - m_FieldInfos.Add(fiHolder); - } - } - } } } diff --git a/src/Inspectors/UIWindow.cs b/src/Windows/UIWindow.cs similarity index 100% rename from src/Inspectors/UIWindow.cs rename to src/Windows/UIWindow.cs diff --git a/src/WindowManager.cs b/src/Windows/WindowManager.cs similarity index 100% rename from src/WindowManager.cs rename to src/Windows/WindowManager.cs diff --git a/src/utils/AccessTools.cs b/src/utils/AccessTools.cs deleted file mode 100644 index 3d6ef49..0000000 --- a/src/utils/AccessTools.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Reflection; - -namespace Explorer -{ - /// - /// AccessTools - /// Some helpers for Reflection (GetValue, SetValue, Call, InheritBaseValues) - /// - public static class At - { - public static Il2CppSystem.Reflection.BindingFlags ilFlags = Il2CppSystem.Reflection.BindingFlags.Public - | Il2CppSystem.Reflection.BindingFlags.NonPublic - | Il2CppSystem.Reflection.BindingFlags.Instance - | Il2CppSystem.Reflection.BindingFlags.Static; - - public static BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static; - - //reflection call - public static object Call(object obj, string method, params object[] args) - { - var methodInfo = obj.GetType().GetMethod(method, flags); - if (methodInfo != null) - { - return methodInfo.Invoke(obj, args); - } - return null; - } - - // set value - public static void SetValue(T value, Type type, object obj, string field) - { - FieldInfo fieldInfo = type.GetField(field, flags); - if (fieldInfo != null) - { - fieldInfo.SetValue(obj, value); - } - } - - // get value - public static object GetValue(Type type, object obj, string value) - { - FieldInfo fieldInfo = type.GetField(value, flags); - if (fieldInfo != null) - { - return fieldInfo.GetValue(obj); - } - else - { - return null; - } - } - - // inherit base values - public static void InheritBaseValues(object _derived, object _base) - { - foreach (FieldInfo fi in _base.GetType().GetFields(flags)) - { - try { _derived.GetType().GetField(fi.Name).SetValue(_derived, fi.GetValue(_base)); } catch { } - } - - return; - } - } -}