From 0d4b4dc82663ed51c3a4ba19fbbecb70d79ef732 Mon Sep 17 00:00:00 2001 From: sinaioutlander <49360850+sinaioutlander@users.noreply.github.com> Date: Sat, 24 Oct 2020 20:18:42 +1100 Subject: [PATCH] Debug console basically finished and working (using TMP now) --- src/Explorer.csproj | 22 +++ src/ExplorerCore.cs | 14 +- src/UI/ForceUnlockCursor.cs | 14 +- src/UI/Main/DebugConsole.cs | 133 ++++++++++++++++++ src/UI/Main/MainMenu.cs | 15 +- src/UI/UIFactory.cs | 107 ++++++++++++-- src/UI/UIManager.cs | 6 + .../ColorUtility/ColorUtilityUnstrip.cs | 23 +++ 8 files changed, 311 insertions(+), 23 deletions(-) create mode 100644 src/UI/Main/DebugConsole.cs create mode 100644 src/Unstrip/ColorUtility/ColorUtilityUnstrip.cs diff --git a/src/Explorer.csproj b/src/Explorer.csproj index f7bc8ae..d452a9e 100644 --- a/src/Explorer.csproj +++ b/src/Explorer.csproj @@ -87,6 +87,10 @@ ..\lib\UnityEngine.dll False + + ..\lib\Unity.TextMeshPro.dll + False + @@ -124,6 +128,10 @@ $(MLCppGameFolder)\MelonLoader\Managed\Il2CppSystem.Core.dll False + + $(MLCppGameFolder)\MelonLoader\Managed\Unity.TextMeshPro.dll + False + $(MLCppGameFolder)\MelonLoader\Managed\UnityEngine.dll False @@ -136,6 +144,10 @@ $(MLCppGameFolder)\MelonLoader\Managed\UnityEngine.PhysicsModule.dll False + + $(MLCppGameFolder)\MelonLoader\Managed\UnityEngine.TextCoreModule.dll + False + $(MLCppGameFolder)\MelonLoader\Managed\UnityEngine.TextRenderingModule.dll False @@ -179,6 +191,10 @@ $(BIECppGameFolder)\BepInEx\unhollowed\Il2CppSystem.Core.dll False + + $(BIECppGameFolder)\BepInEx\unhollowed\Unity.TextMeshPro.dll + False + $(BIECppGameFolder)\BepInEx\unhollowed\UnityEngine.dll False @@ -191,6 +207,10 @@ $(BIECppGameFolder)\BepInEx\unhollowed\UnityEngine.PhysicsModule.dll False + + $(BIECppGameFolder)\BepInEx\unhollowed\UnityEngine.TextCoreModule.dll + False + $(BIECppGameFolder)\BepInEx\unhollowed\UnityEngine.TextRenderingModule.dll False @@ -232,6 +252,7 @@ + @@ -243,6 +264,7 @@ + diff --git a/src/ExplorerCore.cs b/src/ExplorerCore.cs index e8b716e..0995ad1 100644 --- a/src/ExplorerCore.cs +++ b/src/ExplorerCore.cs @@ -4,6 +4,7 @@ using System.Linq; using ExplorerBeta.Config; using ExplorerBeta.Input; using ExplorerBeta.UI; +using ExplorerBeta.UI.Main; using UnityEngine; namespace ExplorerBeta @@ -58,7 +59,7 @@ namespace ExplorerBeta ShowMenu = true; Log($"{NAME} initialized."); - } + } private static void SetShowMenu(bool show) { @@ -96,6 +97,10 @@ namespace ExplorerBeta m_doneUIInit = true; } } + else + { + UIManager.Update(); + } if (InputManager.GetKeyDown(ModConfig.Instance.Main_Menu_Toggle)) { @@ -105,11 +110,7 @@ namespace ExplorerBeta if (ShowMenu) { ForceUnlockCursor.Update(); - UIManager.Update(); - - //// TODO: - //InspectUnderMouse.Update(); } } @@ -120,6 +121,7 @@ namespace ExplorerBeta public static void Log(object message) { + DebugConsole.Log(message?.ToString()); #if ML MelonLoader.MelonLogger.Log(message?.ToString()); #else @@ -129,6 +131,7 @@ namespace ExplorerBeta public static void LogWarning(object message) { + DebugConsole.Log(message?.ToString(), "FFFF00"); #if ML MelonLoader.MelonLogger.LogWarning(message?.ToString()); #else @@ -138,6 +141,7 @@ namespace ExplorerBeta public static void LogError(object message) { + DebugConsole.Log(message?.ToString(), "FF0000"); #if ML MelonLoader.MelonLogger.LogError(message?.ToString()); #else diff --git a/src/UI/ForceUnlockCursor.cs b/src/UI/ForceUnlockCursor.cs index 9a619c8..bf66234 100644 --- a/src/UI/ForceUnlockCursor.cs +++ b/src/UI/ForceUnlockCursor.cs @@ -4,6 +4,7 @@ using ExplorerBeta.Helpers; using UnityEngine.EventSystems; using ExplorerBeta.UI; using ExplorerBeta.Input; +using BF = System.Reflection.BindingFlags; #if ML using Harmony; #else @@ -49,8 +50,17 @@ namespace ExplorerBeta.UI } // Get current cursor state and enable cursor - m_lastLockMode = Cursor.lockState; - m_lastVisibleState = Cursor.visible; + try + { + //m_lastLockMode = Cursor.lockState; + m_lastLockMode = (CursorLockMode?)typeof(Cursor).GetProperty("lockState", BF.Public | BF.Static)?.GetValue(null, null) + ?? CursorLockMode.None; + + //m_lastVisibleState = Cursor.visible; + m_lastVisibleState = (bool?)typeof(Cursor).GetProperty("visible", BF.Public | BF.Static)?.GetValue(null, null) + ?? false; + } + catch { } // Setup Harmony Patches TryPatch(typeof(EventSystem), "current", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_EventSystem_set_current))), true); diff --git a/src/UI/Main/DebugConsole.cs b/src/UI/Main/DebugConsole.cs new file mode 100644 index 0000000..38d8c7a --- /dev/null +++ b/src/UI/Main/DebugConsole.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Explorer.Unstrip.ColorUtility; +using ExplorerBeta.Input; +using ExplorerBeta.Unstrip.Resources; +using TMPro; +using UnhollowerRuntimeLib; +using UnityEngine; +using UnityEngine.UI; + +namespace ExplorerBeta.UI.Main +{ + // TODO: + // - Maybe hook into Unity's debug logs + // - Buttons for clear, save to file, etc..? + + public class DebugConsole + { + public static DebugConsole Instance { get; private set; } + + public static GameObject CanvasRoot; + //private static GameObject Panel; + + public readonly List AllMessages; + public readonly List MessageHolders; + + private TMP_InputField m_textInput; + + // todo probably put this in UImanager, use for C# console too + //internal static Font m_consoleFont; + //private const int MAX_MESSAGES = 100; + + public DebugConsole(GameObject parent) + { + Instance = this; + + AllMessages = new List(); + MessageHolders = new List(); + + try + { + ConstructUI(parent); + } + catch (Exception e) + { + ExplorerCore.Log(e); + } + } + + // todo: get scrollbar working with inputfield somehow + + public void ConstructUI(GameObject parent) + { + var obj = UIFactory.CreateHorizontalGroup(parent, new Color(0.1f, 0.1f, 0.1f, 1.0f)); + var mainGroup = obj.GetComponent(); + mainGroup.childControlHeight = true; + mainGroup.childControlWidth = true; + mainGroup.childForceExpandHeight = true; + mainGroup.childForceExpandWidth = true; + + var mainImage = obj.GetComponent(); + mainImage.maskable = true; + + var mask = obj.AddComponent(); + mask.showMaskGraphic = true; + + var mainLayout = obj.AddComponent(); + mainLayout.preferredHeight = 230; + mainLayout.flexibleHeight = 0; + + var input = UIFactory.CreateTMPInput(obj); + + var inputLayout = input.AddComponent(); + inputLayout.preferredWidth = 500; + inputLayout.flexibleWidth = 9999; + + var scroll = UIFactory.CreateScrollbar(obj); + + var scrollLayout = scroll.AddComponent(); + scrollLayout.preferredWidth = 25; + scrollLayout.flexibleWidth = 0; + + var scroller = scroll.GetComponent(); + scroller.direction = Scrollbar.Direction.TopToBottom; + var scrollColors = scroller.colors; + scrollColors.normalColor = new Color(0.5f, 0.5f, 0.5f, 1.0f); + //try { scrollColors.selectedColor = scrollColors.normalColor; } catch { } + scroller.colors = scrollColors; + + var tmpInput = input.GetComponent(); + tmpInput.scrollSensitivity = 15; + tmpInput.verticalScrollbar = scroller; + + m_textInput = input.GetComponent(); + + for (int i = 0; i < 100; i++) + { + Log("hello " + i); + } + + Log("hello", Color.red); + Log("hello", Color.yellow); + } + + public static void Log(string message) + { + Log(message, null); + } + + public static void Log(string message, Color color) + { + Log(message, color.ToHex()); + } + + public static void Log(string message, string hexColor) + { + if (Instance == null) + return; + + Instance.AllMessages.Add(message); + + if (Instance.m_textInput) + { + if (hexColor != null) + message = $"{message}"; + + Instance.m_textInput.text = $"{message}\n{Instance.m_textInput.text}"; + } + } + } +} diff --git a/src/UI/Main/MainMenu.cs b/src/UI/Main/MainMenu.cs index a328d41..c3e1c33 100644 --- a/src/UI/Main/MainMenu.cs +++ b/src/UI/Main/MainMenu.cs @@ -75,14 +75,14 @@ namespace ExplorerBeta.UI.Main var colors = button.colors; colors.normalColor = m_navButtonSelected; - colors.selectedColor = m_navButtonSelected; + //try { colors.selectedColor = m_navButtonSelected; } catch { } button.colors = colors; if (m_lastNavButtonPressed && m_lastNavButtonPressed != button) { var oldColors = m_lastNavButtonPressed.colors; oldColors.normalColor = m_navButtonNormal; - oldColors.selectedColor = m_navButtonNormal; + //try { oldColors.selectedColor = m_navButtonNormal; } catch { } m_lastNavButtonPressed.colors = oldColors; } @@ -110,6 +110,13 @@ namespace ExplorerBeta.UI.Main ConstructNavbar(content); ConstructMainViewport(content); + + ConstructDebugConsole(content); + } + + private void ConstructDebugConsole(GameObject content) + { + new DebugConsole(content); } private void ConstructTitleBar(GameObject content) @@ -176,8 +183,6 @@ namespace ExplorerBeta.UI.Main private void ConstructNavbar(GameObject content) { - // Todo add pages programatically - var navbarObj = UIFactory.CreateHorizontalGroup(content); var navGroup = navbarObj.GetComponent(); @@ -210,7 +215,7 @@ namespace ExplorerBeta.UI.Main // Set button colors var colorBlock = btn.colors; colorBlock.normalColor = m_navButtonNormal; - colorBlock.selectedColor = colorBlock.normalColor; + //try { colorBlock.selectedColor = colorBlock.normalColor; } catch { } colorBlock.highlightedColor = m_navButtonHighlight; colorBlock.pressedColor = m_navButtonSelected; btn.colors = colorBlock; diff --git a/src/UI/UIFactory.cs b/src/UI/UIFactory.cs index f857a8a..de9b2a4 100644 --- a/src/UI/UIFactory.cs +++ b/src/UI/UIFactory.cs @@ -2,12 +2,13 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using TMPro; using UnityEngine; using UnityEngine.UI; namespace ExplorerBeta.UI { - public static class UIFactory + public static class UIFactory { private static Vector2 s_ThickElementSize = new Vector2(160f, 30f); private static Vector2 s_ThinElementSize = new Vector2(160f, 20f); @@ -35,7 +36,7 @@ namespace ExplorerBeta.UI var rect = obj.AddComponent(); if (size != default) - { + { rect.sizeDelta = size; } @@ -72,7 +73,7 @@ namespace ExplorerBeta.UI SetLayerRecursively(child); } - private static void SetLayerRecursively(GameObject go) + public static void SetLayerRecursively(GameObject go) { go.layer = 5; Transform transform = go.transform; @@ -145,7 +146,7 @@ namespace ExplorerBeta.UI } public static GameObject CreateHorizontalGroup(GameObject parent, Color color = default) - { + { var groupObj = CreateUIObject("HorizontalLayout", parent); var horiGroup = groupObj.AddComponent(); @@ -162,15 +163,16 @@ namespace ExplorerBeta.UI } public static GameObject CreateLabel(GameObject parent, TextAnchor alignment) - { + { GameObject labelObj = CreateUIObject("Label", parent, s_ThinElementSize); var text = labelObj.AddComponent(); SetDefaultTextValues(text); text.alignment = alignment; + text.supportRichText = true; return labelObj; - } + } public static GameObject CreateButton(GameObject parent) { @@ -333,6 +335,86 @@ namespace ExplorerBeta.UI return toggleObj; } + public static GameObject CreateTMPInput(GameObject parent) + { + GameObject mainObj = CreateUIObject("InputField (TMP)", parent); + + Image mainImage = mainObj.AddComponent(); + mainImage.type = Image.Type.Sliced; + mainImage.color = new Color(38f / 255f, 38f / 255f, 38f / 255f, 1.0f); + + var mainInput = mainObj.AddComponent(); + mainInput.navigation.mode = Navigation.Mode.None; + mainInput.richText = true; + mainInput.isRichTextEditingAllowed = true; + mainInput.lineType = TMP_InputField.LineType.MultiLineNewline; + mainInput.interactable = true; + mainInput.transition = Selectable.Transition.ColorTint; + mainInput.onFocusSelectAll = false; + + var mainColors = mainInput.colors; + mainColors.normalColor = new Color(1, 1, 1, 1); + mainColors.highlightedColor = new Color(245f / 255f, 245f / 255f, 245f / 255f, 1.0f); + mainColors.pressedColor = new Color(200f / 255f, 200f / 255f, 200f / 255f, 1.0f); + mainColors.highlightedColor = new Color(245f / 255f, 245f / 255f, 245f / 255f, 1.0f); + mainInput.colors = mainColors; + + var mainGroup = mainObj.AddComponent(); + mainGroup.childControlHeight = true; + mainGroup.childControlWidth = true; + mainGroup.childForceExpandWidth = true; + mainGroup.childForceExpandHeight = true; + + var textArea = CreateUIObject("Text Area", mainObj); + textArea.AddComponent(); + + var textAreaRect = textArea.GetComponent(); + textAreaRect.anchorMin = new Vector2(0, 0); + textAreaRect.anchorMax = new Vector2(1, 1); + textAreaRect.offsetMin = new Vector2(10, 7); + textAreaRect.offsetMax = new Vector2(10, 6); + + mainInput.textViewport = textArea.GetComponent(); + + var placeHolderObj = CreateUIObject("Placeholder", textArea); + var placeholderText = placeHolderObj.AddComponent(); + placeholderText.fontSize = 16; + placeholderText.text = "Nothing logged yet..."; + placeholderText.color = new Color(0.5f, 0.5f, 0.5f, 1.0f); + + var placeHolderRect = placeHolderObj.GetComponent(); + placeHolderRect.anchorMin = Vector2.zero; + placeHolderRect.anchorMax = Vector2.one; + placeHolderRect.offsetMin = Vector2.zero; + placeHolderRect.offsetMax = Vector2.zero; + + var placeholderLayout = placeHolderObj.AddComponent(); + placeholderLayout.preferredWidth = 990; + placeholderLayout.flexibleWidth = 500; + + mainInput.placeholder = placeholderText; + + var inputTextObj = CreateUIObject("Text", textArea); + var inputText = inputTextObj.AddComponent(); + inputText.fontSize = 16; + inputText.text = ""; + inputText.color = new Color(1f, 1f, 1f, 1f); + + var inputTextRect = inputTextObj.GetComponent(); + inputTextRect.anchorMin = Vector2.zero; + inputTextRect.anchorMax = Vector2.one; + inputTextRect.offsetMin = Vector2.zero; + inputTextRect.offsetMax = Vector2.zero; + + var test = inputTextObj.AddComponent(); + test.preferredWidth = 990; + test.flexibleWidth = 500; + + mainInput.textComponent = inputText; + + return mainObj; + } + public static GameObject CreateInputField(GameObject parent) { GameObject inputObj = CreateUIObject("InputField", parent, s_ThickElementSize); @@ -528,7 +610,7 @@ namespace ExplorerBeta.UI return dropdownObj; } - public static GameObject CreateScrollView(GameObject parent, out GameObject content) + public static GameObject CreateScrollView(GameObject parent, out GameObject content, Color color = default) { GameObject scrollObj = CreateUIObject("Scroll View", parent); @@ -602,14 +684,17 @@ namespace ExplorerBeta.UI scrollRect.scrollSensitivity = 25; Image scrollImage = scrollObj.AddComponent(); - scrollImage.sprite = UIResources.background; - scrollImage.type = Image.Type.Sliced; - scrollImage.color = s_PanelColor; - viewportObj.AddComponent().showMaskGraphic = false; + scrollImage.type = Image.Type.Filled; + + scrollImage.color = (color == default) ? new Color(0.3f, 0.3f, 0.3f, 1f) : color; Image viewportImage = viewportObj.AddComponent(); viewportImage.sprite = UIResources.mask; viewportImage.type = Image.Type.Sliced; + viewportImage.color = new Color(1, 1, 1, 1); + + var mask = viewportObj.AddComponent(); + mask.showMaskGraphic = false; return scrollObj; } diff --git a/src/UI/UIManager.cs b/src/UI/UIManager.cs index 80d2776..be63109 100644 --- a/src/UI/UIManager.cs +++ b/src/UI/UIManager.cs @@ -28,6 +28,12 @@ namespace ExplorerBeta.UI // Create submodules new MainMenu(); + + // Force refresh of anchors (?) + Canvas.ForceUpdateCanvases(); + + CanvasRoot.SetActive(false); + CanvasRoot.SetActive(true); } public static void SetEventSystem() diff --git a/src/Unstrip/ColorUtility/ColorUtilityUnstrip.cs b/src/Unstrip/ColorUtility/ColorUtilityUnstrip.cs new file mode 100644 index 0000000..8611c9a --- /dev/null +++ b/src/Unstrip/ColorUtility/ColorUtilityUnstrip.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace Explorer.Unstrip.ColorUtility +{ + public static class ColorUtilityUnstrip + { + public static string ToHex(this Color color) + { + var color32 = new Color32( + (byte)Mathf.Clamp(Mathf.RoundToInt(color.r * 255f), 0, 255), + (byte)Mathf.Clamp(Mathf.RoundToInt(color.g * 255f), 0, 255), + (byte)Mathf.Clamp(Mathf.RoundToInt(color.b * 255f), 0, 255), + 1 + ); + + return string.Format("{0:X2}{1:X2}{2:X2}", color32.r, color32.g, color32.b); + } + } +}