From 39d9585f1ddfab22ecb26093b415fc79da6c0644 Mon Sep 17 00:00:00 2001 From: sinaioutlander <49360850+sinaioutlander@users.noreply.github.com> Date: Sun, 11 Oct 2020 22:57:46 +1100 Subject: [PATCH] 2.0.4 * Added ability to see and change the layer of a gameobject from the GameObject inspector more easily, and shows you the actual layer name (where possible). * Fixed an issue related to the recently-added clickthrough prevention and resize drag * Fixed write-only properties in the inspector * A few other minor fixes --- README.md | 5 +- src/CacheObject/CacheProperty.cs | 21 ++++- src/Explorer.csproj | 1 + src/ExplorerCore.cs | 10 ++- src/Input/InputManager.cs | 2 +- src/Tests/TestClass.cs | 11 ++- src/UI/ForceUnlockCursor.cs | 28 +++---- src/UI/Inspectors/GameObjectInspector.cs | 48 +++++++++++- .../Struct/InteractivePrimitive.cs | 40 ++++++---- src/UI/Main/OptionsPage.cs | 10 +++ src/UI/Shared/ResizeDrag.cs | 76 ++++++------------- src/UI/TabViewWindow.cs | 10 ++- src/UI/WindowManager.cs | 40 +++++----- src/Unstrip/LayerMask/LayerMaskUnstrip.cs | 32 ++++++++ src/Unstrip/Scene/SceneUnstrip.cs | 2 +- 15 files changed, 217 insertions(+), 119 deletions(-) create mode 100644 src/Unstrip/LayerMask/LayerMaskUnstrip.cs diff --git a/README.md b/README.md index 5a17ab1..e6c164b 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,10 @@ There is a simple Mod Config for the Explorer. You can access the settings via t * Whether or not to show the Bitwise Editing helper when inspecting integers `Enable Tab View` (bool) | Default: `true` -* Whether or not all inspector windows a grouped into a single window with tabs. +* Whether or not all inspector windows a grouped into a single window with tabs. + +`Default Output Path` (string) | Default: `Mods\Explorer` +* Where output is generated to, by default (for Texture PNG saving, etc). ## Mouse Control diff --git a/src/CacheObject/CacheProperty.cs b/src/CacheObject/CacheProperty.cs index 3a23272..ab61ae3 100644 --- a/src/CacheObject/CacheProperty.cs +++ b/src/CacheObject/CacheProperty.cs @@ -35,11 +35,26 @@ namespace Explorer.CacheObject try { var pi = MemInfo as PropertyInfo; - var target = pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance; - IValue.Value = pi.GetValue(target, ParseArguments()); + if (pi.CanRead) + { + var target = pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance; - base.UpdateValue(); + IValue.Value = pi.GetValue(target, ParseArguments()); + + base.UpdateValue(); + } + else // create a dummy value for Write-Only properties. + { + if (IValue.ValueType == typeof(string)) + { + IValue.Value = ""; + } + else + { + IValue.Value = Activator.CreateInstance(IValue.ValueType); + } + } } catch (Exception e) { diff --git a/src/Explorer.csproj b/src/Explorer.csproj index 2a3aa9b..e9cf1e5 100644 --- a/src/Explorer.csproj +++ b/src/Explorer.csproj @@ -262,6 +262,7 @@ + diff --git a/src/ExplorerCore.cs b/src/ExplorerCore.cs index 05acfd9..3991c51 100644 --- a/src/ExplorerCore.cs +++ b/src/ExplorerCore.cs @@ -10,7 +10,7 @@ namespace Explorer public class ExplorerCore { public const string NAME = "Explorer " + VERSION + " (" + PLATFORM + ", " + MODLOADER + ")"; - public const string VERSION = "2.0.3"; + public const string VERSION = "2.0.4"; public const string AUTHOR = "Sinai"; public const string GUID = "com.sinai.explorer"; @@ -31,6 +31,12 @@ namespace Explorer public ExplorerCore() { + if (Instance != null) + { + Log("An instance of Explorer is already active!"); + return; + } + Instance = this; ModConfig.OnLoad(); @@ -87,7 +93,7 @@ namespace Explorer WindowManager.Instance.OnGUI(); InspectUnderMouse.OnGUI(); - if (WindowManager.IsMouseInWindow) + if (!ResizeDrag.IsMouseInResizeArea && WindowManager.IsMouseInWindow) { InputManager.ResetInputAxes(); } diff --git a/src/Input/InputManager.cs b/src/Input/InputManager.cs index 8e036c3..6979398 100644 --- a/src/Input/InputManager.cs +++ b/src/Input/InputManager.cs @@ -44,7 +44,7 @@ namespace Explorer #if CPP internal delegate void d_ResetInputAxes(); - internal static d_ResetInputAxes ResetInputAxes_iCall => + internal static d_ResetInputAxes ResetInputAxes_iCall = IL2CPP.ResolveICall("UnityEngine.Input::ResetInputAxes"); public static void ResetInputAxes() => ResetInputAxes_iCall(); diff --git a/src/Tests/TestClass.cs b/src/Tests/TestClass.cs index 5ec70f3..237a4fe 100644 --- a/src/Tests/TestClass.cs +++ b/src/Tests/TestClass.cs @@ -15,16 +15,13 @@ namespace Explorer.Tests public static class StaticTestClass { public static int StaticProperty => 5; - public static int StaticField = 69; - public static List StaticList = new List { "one", "two", "three", }; - public static void StaticMethod() { } } @@ -34,6 +31,14 @@ namespace Explorer.Tests public static TestClass Instance => m_instance ?? (m_instance = new TestClass()); private static TestClass m_instance; + public static bool ReadSetOnlyProperty => m_setOnlyProperty; + + public static bool SetOnlyProperty + { + set => m_setOnlyProperty = value; + } + private static bool m_setOnlyProperty; + public Texture2D TestTexture = UIStyles.MakeTex(200, 200, Color.white); public static Sprite TestSprite; diff --git a/src/UI/ForceUnlockCursor.cs b/src/UI/ForceUnlockCursor.cs index a6ec1bf..239dad7 100644 --- a/src/UI/ForceUnlockCursor.cs +++ b/src/UI/ForceUnlockCursor.cs @@ -17,32 +17,25 @@ namespace Explorer.UI } private static bool m_forceUnlock; - private static CursorLockMode m_lastLockMode; - private static bool m_lastVisibleState; - private static bool m_currentlySettingCursor = false; - public static bool ShouldForceMouse => ExplorerCore.ShowMenu && Unlock; - private static Type CursorType => m_cursorType ?? (m_cursorType = ReflectionHelpers.GetTypeByName("UnityEngine.Cursor")); + private static CursorLockMode m_lastLockMode; + private static bool m_lastVisibleState; + + private static bool m_currentlySettingCursor = false; + + private static Type CursorType + => m_cursorType + ?? (m_cursorType = ReflectionHelpers.GetTypeByName("UnityEngine.Cursor")); private static Type m_cursorType; public static void Init() { try { - // Check if Cursor class is loaded if (CursorType == null) { - ExplorerCore.Log("Trying to manually load Cursor module..."); - - if (ReflectionHelpers.LoadModule("UnityEngine.CoreModule") && CursorType != null) - { - ExplorerCore.Log("Ok!"); - } - else - { - throw new Exception("Could not load UnityEngine.Cursor module!"); - } + throw new Exception("Could not find Type 'UnityEngine.Cursor'!"); } // Get current cursor state and enable cursor @@ -91,7 +84,8 @@ namespace Explorer.UI } catch (Exception e) { - ExplorerCore.Log($"[NON-FATAL] Couldn't patch a method: {e.Message}"); + string s = setter ? "set_" : "get_" ; + ExplorerCore.Log($"Unable to patch Cursor.{s}{property}: {e.Message}"); } } diff --git a/src/UI/Inspectors/GameObjectInspector.cs b/src/UI/Inspectors/GameObjectInspector.cs index cb70a34..c1a6388 100644 --- a/src/UI/Inspectors/GameObjectInspector.cs +++ b/src/UI/Inspectors/GameObjectInspector.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using UnityEngine; using Explorer.UI.Shared; using Explorer.UI.Main; +using Explorer.Unstrip.LayerMasks; #if CPP using UnhollowerRuntimeLib; #endif @@ -17,6 +18,8 @@ namespace Explorer.UI.Inspectors public GameObject TargetGO; + public bool pendingDestroy; + private static bool m_hideControls; // gui element holders @@ -43,6 +46,8 @@ namespace Explorer.UI.Inspectors private bool m_autoUpdateTransform; private bool m_localContext; + private int m_layer; + private readonly List m_cachedDestroyList = new List(); private string m_addComponentInput = ""; @@ -104,16 +109,16 @@ namespace Explorer.UI.Inspectors { try { + if (pendingDestroy) return; + if (Target == null) { - ExplorerCore.Log("Target is null!"); - DestroyWindow(); + DestroyOnException(new Exception("Target was destroyed.")); return; } if (!TargetGO && !GetObjectAsGameObject()) { - ExplorerCore.Log("Target was destroyed!"); - DestroyWindow(); + DestroyOnException(new Exception("Target was destroyed.")); return; } @@ -132,6 +137,8 @@ namespace Explorer.UI.Inspectors TargetGO.transform.localScale = m_frozenScale; } + m_layer = TargetGO.layer; + // update child objects var childList = new List(); for (int i = 0; i < TargetGO.transform.childCount; i++) @@ -163,6 +170,7 @@ namespace Explorer.UI.Inspectors private void DestroyOnException(Exception e) { ExplorerCore.Log($"Exception drawing GameObject Window: {e.GetType()}, {e.Message}"); + pendingDestroy = true; DestroyWindow(); } @@ -204,6 +212,8 @@ namespace Explorer.UI.Inspectors public override void WindowFunction(int windowID) { + if (pendingDestroy) return; + try { var rect = WindowManager.TabView ? TabViewWindow.Instance.m_rect : this.m_rect; @@ -250,6 +260,8 @@ namespace Explorer.UI.Inspectors GUIUnstrip.TextArea(m_name, new GUILayoutOption[0]); GUILayout.EndHorizontal(); + LayerControls(); + // --- Horizontal Columns section --- GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); @@ -280,6 +292,34 @@ namespace Explorer.UI.Inspectors } } + private void LayerControls() + { + GUIUnstrip.BeginHorizontal(); + GUILayout.Label("Layer:", new GUILayoutOption[] { GUILayout.Width(50) }); + + if (GUILayout.Button("<", new GUILayoutOption[] { GUILayout.Width(30) })) + { + if (m_layer > 0) + { + m_layer--; + if (TargetGO) TargetGO.layer = m_layer; + } + } + if (GUILayout.Button(">", new GUILayoutOption[] { GUILayout.Width(30) })) + { + if (m_layer < 32) + { + m_layer++; + if (TargetGO) TargetGO.layer = m_layer; + } + } + + GUILayout.Label($"{m_layer} ({LayerMaskUnstrip.LayerToName(m_layer)})", + new GUILayoutOption[] { GUILayout.Width(200) }); + + GUILayout.EndHorizontal(); + } + private void TransformList(Rect m_rect) { GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null); diff --git a/src/UI/InteractiveValue/Struct/InteractivePrimitive.cs b/src/UI/InteractiveValue/Struct/InteractivePrimitive.cs index 5c00b05..c21bceb 100644 --- a/src/UI/InteractiveValue/Struct/InteractivePrimitive.cs +++ b/src/UI/InteractiveValue/Struct/InteractivePrimitive.cs @@ -80,12 +80,13 @@ namespace Explorer.UI if (OwnerCacheObject.CanWrite) { - b = GUILayout.Toggle(b, label, new GUILayoutOption[0]); - if (b != (bool)Value) - { - Value = b; - OwnerCacheObject.SetValue(); - } + Value = GUILayout.Toggle(b, label, new GUILayoutOption[] { GUILayout.Width(60) }); + DrawApplyButton(); + //if (b != (bool)Value) + //{ + // Value = b; + // OwnerCacheObject.SetValue(); + //} } else { @@ -104,13 +105,8 @@ namespace Explorer.UI GUILayout.Label("" + ValueType.Name + "", new GUILayoutOption[] { GUILayout.Width(50) }); m_valueToString = GUIUnstrip.TextArea(m_valueToString, new GUILayoutOption[] { GUILayout.ExpandWidth(true) }); - if (OwnerCacheObject.CanWrite) - { - if (GUILayout.Button("Apply", new GUILayoutOption[] { GUILayout.Width(60) })) - { - SetValueFromInput(); - } - } + + DrawApplyButton(); if (ModConfig.Instance.Bitwise_Support && m_canBitwiseOperate) { @@ -129,6 +125,24 @@ namespace Explorer.UI GUILayout.EndVertical(); } + private void DrawApplyButton() + { + if (OwnerCacheObject.CanWrite) + { + if (GUILayout.Button("Apply", new GUILayoutOption[] { GUILayout.Width(60) })) + { + if (m_isBool) + { + OwnerCacheObject.SetValue(); + } + else + { + SetValueFromInput(); + } + } + } + } + private void DrawBitwise() { if (OwnerCacheObject.CanWrite) diff --git a/src/UI/Main/OptionsPage.cs b/src/UI/Main/OptionsPage.cs index 42e071a..5453eee 100644 --- a/src/UI/Main/OptionsPage.cs +++ b/src/UI/Main/OptionsPage.cs @@ -63,26 +63,36 @@ namespace Explorer.UI.Main toggleKeyInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f); GUILayout.EndHorizontal(); + UIStyles.HorizontalLine(Color.black, true); + GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); GUILayout.Label($"Default Window Size:", new GUILayoutOption[] { GUILayout.Width(215f) }); defaultSizeInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f); GUILayout.EndHorizontal(); + UIStyles.HorizontalLine(Color.black, true); + GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); GUILayout.Label($"Default Items per Page:", new GUILayoutOption[] { GUILayout.Width(215f) }); defaultPageLimitInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f); GUILayout.EndHorizontal(); + UIStyles.HorizontalLine(Color.black, true); + GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); GUILayout.Label($"Enable Bitwise Editing:", new GUILayoutOption[] { GUILayout.Width(215f) }); bitwiseSupportInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f); GUILayout.EndHorizontal(); + UIStyles.HorizontalLine(Color.black, true); + GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); GUILayout.Label($"Enable Tab View:", new GUILayoutOption[] { GUILayout.Width(215f) }); tabViewInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f); GUILayout.EndHorizontal(); + UIStyles.HorizontalLine(Color.black, true); + GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); GUILayout.Label($"Default Output Path:", new GUILayoutOption[] { GUILayout.Width(215f) }); defaultOutputPathInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f); diff --git a/src/UI/Shared/ResizeDrag.cs b/src/UI/Shared/ResizeDrag.cs index 24a649e..b62f677 100644 --- a/src/UI/Shared/ResizeDrag.cs +++ b/src/UI/Shared/ResizeDrag.cs @@ -8,18 +8,17 @@ namespace Explorer.UI.Shared { public class ResizeDrag { -#if CPP private static bool RESIZE_FAILED = false; -#endif + + public static bool IsResizing = false; + public static bool IsMouseInResizeArea = false; private static readonly GUIContent gcDrag = new GUIContent("<-- Drag to resize -->"); - private static bool isResizing = false; private static Rect m_currentResize; private static int m_currentWindow; public static Rect ResizeWindow(Rect _rect, int ID) { -#if CPP if (!RESIZE_FAILED) { var origRect = _rect; @@ -29,31 +28,40 @@ namespace Explorer.UI.Shared GUIUnstrip.BeginHorizontal(GUIContent.none, GUI.skin.box, null); GUI.skin.label.alignment = TextAnchor.MiddleCenter; -#if ML - GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) }); +#if BIE +#if CPP // Temporary for BepInEx IL2CPP + GUILayout.Button("<-- Drag to resize -->", new GUILayoutOption[] { GUILayout.Height(15) }); #else - GUILayout.Button("<-- Drag to resize -->", new GUILayoutOption[] { GUILayout.Height(15) }); + GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) }); +#endif +#else + GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) }); #endif - var r = GUIUnstrip.GetLastRect(); - + var resizeDragArea = GUIUnstrip.GetLastRect(); var mousePos = InputManager.MousePosition; try { var mouse = GUIUnstrip.ScreenToGUIPoint(new Vector2(mousePos.x, Screen.height - mousePos.y)); - if (r.Contains(mouse) && InputManager.GetMouseButtonDown(0)) + if (resizeDragArea.Contains(mouse)) { - isResizing = true; - m_currentWindow = ID; - m_currentResize = new Rect(mouse.x, mouse.y, _rect.width, _rect.height); + IsMouseInResizeArea = true; + + if (InputManager.GetMouseButton(0)) + { + IsResizing = true; + m_currentWindow = ID; + m_currentResize = new Rect(mouse.x, mouse.y, _rect.width, _rect.height); + } } else if (!InputManager.GetMouseButton(0)) { - isResizing = false; + IsMouseInResizeArea = false; + IsResizing = false; } - if (isResizing && ID == m_currentWindow) + if (IsResizing && ID == m_currentWindow) { _rect.width = Mathf.Max(100, m_currentResize.width + (mouse.x - m_currentResize.x)); _rect.height = Mathf.Max(100, m_currentResize.height + (mouse.y - m_currentResize.y)); @@ -81,8 +89,6 @@ namespace Explorer.UI.Shared //ExplorerCore.Log(e.StackTrace); return origRect; } - - GUI.skin.label.alignment = TextAnchor.UpperLeft; } else { @@ -111,44 +117,8 @@ namespace Explorer.UI.Shared } GUILayout.EndHorizontal(); - GUI.skin.label.alignment = TextAnchor.UpperLeft; } -#else // mono - - GUIUnstrip.BeginHorizontal(GUIContent.none, GUI.skin.box, null); - - GUI.skin.label.alignment = TextAnchor.MiddleCenter; - GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) }); - - //var r = GUILayoutUtility.GetLastRect(); - var r = GUILayoutUtility.GetLastRect(); - - var mousePos = InputManager.MousePosition; - - var mouse = GUIUnstrip.ScreenToGUIPoint(new Vector2(mousePos.x, Screen.height - mousePos.y)); - if (r.Contains(mouse) && InputManager.GetMouseButtonDown(0)) - { - isResizing = true; - m_currentWindow = ID; - m_currentResize = new Rect(mouse.x, mouse.y, _rect.width, _rect.height); - } - else if (!InputManager.GetMouseButton(0)) - { - isResizing = false; - } - - if (isResizing && ID == m_currentWindow) - { - _rect.width = Mathf.Max(100, m_currentResize.width + (mouse.x - m_currentResize.x)); - _rect.height = Mathf.Max(100, m_currentResize.height + (mouse.y - m_currentResize.y)); - _rect.xMax = Mathf.Min(Screen.width, _rect.xMax); // modifying xMax affects width, not x - _rect.yMax = Mathf.Min(Screen.height, _rect.yMax); // modifying yMax affects height, not y - } - - GUILayout.EndHorizontal(); - -#endif GUI.skin.label.alignment = TextAnchor.MiddleLeft; return _rect; diff --git a/src/UI/TabViewWindow.cs b/src/UI/TabViewWindow.cs index ec16055..524d1cb 100644 --- a/src/UI/TabViewWindow.cs +++ b/src/UI/TabViewWindow.cs @@ -70,6 +70,15 @@ namespace Explorer.UI int rowCount = 0; for (int i = 0; i < WindowManager.Windows.Count; i++) { + var window = WindowManager.Windows[i]; + + // Prevent trying to draw destroyed UnityEngine.Objects + // before the WindowManager removes them. + if (window.Target is UnityEngine.Object uObj && !uObj) + { + continue; + } + if (rowCount >= tabPerRow) { rowCount = 0; @@ -82,7 +91,6 @@ namespace Explorer.UI string color = focused ? "" : ""; GUI.color = focused ? Color.green : Color.white; - var window = WindowManager.Windows[i]; if (GUILayout.Button(color + window.Title + "", new GUILayoutOption[] { GUILayout.Width(200) })) { TargetTabID = i; diff --git a/src/UI/WindowManager.cs b/src/UI/WindowManager.cs index c07627c..fbb07ab 100644 --- a/src/UI/WindowManager.cs +++ b/src/UI/WindowManager.cs @@ -11,6 +11,26 @@ namespace Explorer.UI public static bool TabView = Config.ModConfig.Instance.Tab_View; + public static bool IsMouseInWindow + { + get + { + if (!ExplorerCore.ShowMenu) + { + return false; + } + + foreach (var window in Windows) + { + if (RectContainsMouse(window.m_rect)) + { + return true; + } + } + return RectContainsMouse(MainMenu.MainRect); + } + } + public static List Windows = new List(); public static int CurrentWindowID { get; set; } = 500000; private static Rect m_lastWindowRect; @@ -123,26 +143,6 @@ namespace Explorer.UI return new_window; } - public static bool IsMouseInWindow - { - get - { - if (!ExplorerCore.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) { var mousePos = InputManager.MousePosition; diff --git a/src/Unstrip/LayerMask/LayerMaskUnstrip.cs b/src/Unstrip/LayerMask/LayerMaskUnstrip.cs new file mode 100644 index 0000000..2695602 --- /dev/null +++ b/src/Unstrip/LayerMask/LayerMaskUnstrip.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; +#if CPP +using UnhollowerBaseLib; +#endif + +namespace Explorer.Unstrip.LayerMasks +{ + public static class LayerMaskUnstrip + { +#if CPP + internal delegate IntPtr d_LayerToName(int layer); + internal static d_LayerToName LayerToName_iCall = + IL2CPP.ResolveICall("UnityEngine.LayerMask::LayerToName"); + + public static string LayerToName(int layer) + { + var ptr = LayerToName_iCall(layer); + + return IL2CPP.Il2CppStringToManaged(ptr); + } +#else + public static string LayerToName(int layer) + { + return LayerMask.LayerToName(layer); + } +#endif + } +} diff --git a/src/Unstrip/Scene/SceneUnstrip.cs b/src/Unstrip/Scene/SceneUnstrip.cs index 25fb324..6c3ee3e 100644 --- a/src/Unstrip/Scene/SceneUnstrip.cs +++ b/src/Unstrip/Scene/SceneUnstrip.cs @@ -26,7 +26,7 @@ namespace Explorer.Unstrip.Scenes IL2CPP.ResolveICall("UnityEngine.SceneManagement.Scene::GetRootGameObjectsInternal"); //Scene.rootCount; - public static int GetRootCount_Internal(UnityEngine.SceneManagement.Scene scene) + public static int GetRootCount_Internal(Scene scene) { return GetRootCountInternal_iCall(scene.handle); }