using System; using System.Collections.Generic; using System.Linq; using Sirenix.OdinInspector; using UnityEngine; using UnityEngine.Serialization; using UnityEngine.UIElements; // ReSharper disable UsageOfDefaultStructEquality, to disable the warnings about IndexOf(currentPage). It's fine. namespace Reset.Core.Tools{ public class DebugOverlayDrawer : MonoBehaviour{ [Header("Asset References")] [BoxGroup("References")] public VisualTreeAsset valueTemplate; [BoxGroup("References")] public VisualTreeAsset pageBaseTemplate; [BoxGroup("References")] public VisualTreeAsset pageButtonTemplate; [Header("Scene References")] [BoxGroup("References")][ShowInInspector] public UIDocument root; [BoxGroup("References")]public GameObject canvasRootGameObject; [Space(10)] [ShowInInspector] public Dictionary> Pages = new(); // Page and value names [Space(5)] [ShowInInspector] public Dictionary values = new(); // Value name and value value (lol) [Space] public string pageNamePrefix = "Debug Page: "; private static float defaultLabelAlpha; // Private variables [ShowInInspector] public KeyValuePair> currentPage; public enum DebugOverlayAnchor{ TopLeft, TopRight, BottomLeft, BottomRight, Center } void Awake(){ if (Instance != null) { Destroy(this); } Instance = this; } void Start(){ SetCurrentPageVisible(); Debug.Log(valueTemplate.Instantiate().resolvedStyle.backgroundColor); defaultLabelAlpha = valueTemplate.Instantiate().style.backgroundColor.value.a; } public static DebugOverlayDrawer Instance; public static void AddOnOverlay(string pageName, string sourceName, Vector3 position){ // Make sure the page exists. If it does, use it. If not, create it GameObject thisPageObject = null; bool alreadyExisted = false; // This checks for a gameobject with the page name. Sets it if it finds it foreach (var page in Instance.Pages) { if (page.Key.name == $"{Instance.pageNamePrefix}{pageName}") { thisPageObject = page.Key; alreadyExisted = true; break; } } // Otherwise, this will make a new one and add it UIDocument thisDocument = null; if (thisPageObject == null) { // Create a new object thisPageObject = new GameObject(name: $"{Instance.pageNamePrefix}{pageName}"); // Add it to the list of page objects and set it's transform KeyValuePair> newPage = new(thisPageObject, new List()); Instance.Pages.Add(newPage.Key, newPage.Value); thisPageObject.transform.SetParent(Instance.canvasRootGameObject.transform); // Add a UI Document for it, give it the base template thisDocument = thisPageObject.AddComponent(); thisDocument.visualTreeAsset = Instance.pageBaseTemplate; // Then add a button/header to the main container VisualElement newPageButton = Instance.pageButtonTemplate.Instantiate(); Instance.root.rootVisualElement.Query("Pages").First().Add(newPageButton); ((Label)newPageButton.Query("PageLabel").First()).text = pageName; } else { thisDocument = thisPageObject.GetComponent(); } // If this is the only page, set it to the current page if (Instance.Pages.Count == 1) { Instance.currentPage = new KeyValuePair>(thisPageObject, new List()); SetCurrentPageVisible(); } // Warning for the page being null for whatever reason by this point if (thisPageObject == null) { Debug.LogError( $"Debug Overlay Manager never found a page named: {sourceName}. It failed to create one and aborted."); return; } // Now, iterate through this page and see if the variable is already tracked if (alreadyExisted && Instance.Pages[thisPageObject].Contains(sourceName)) { return; } // Since it doesn't exist, add it to the list of tracked variables Instance.Pages[thisPageObject].Add(sourceName); // Then create a new on-screen element for this variable VisualElement thisElement = (Instance.valueTemplate.Instantiate()); thisDocument.rootVisualElement.Query("ValuesContainer").First().Add(thisElement); // Set it's label ((Label)thisElement.Query("Label").First()).text = sourceName; Instance.values.Add($"{pageName}/{sourceName}", (Label)thisElement.Query("Value")); } // Publicly accessible method to change the value public static void ChangeValue(string pageName, string sourceName, string newValue){ Instance.values[$"{pageName}/{sourceName}"].text = newValue; } // Publicly accessible method to change the color public static void ChangeColor(string pageName, string sourceName, Color newColor){ VisualElement labelBG = Instance.values[$"{pageName}/{sourceName}"].parent.parent.Query("LabelBackground").First(); VisualElement valueBG = Instance.values[$"{pageName}/{sourceName}"].parent.parent.Query("ValueBackground").First(); labelBG.style.backgroundColor = (newColor * .7f).Alpha(labelBG.resolvedStyle.backgroundColor.a); valueBG.style.backgroundColor = (newColor * .6f).Alpha(valueBG.resolvedStyle.backgroundColor.a); } // Back a page public static void PreviousPage(){ // Do nothing if there's only one page if (Instance.Pages.Count == 1) { return; } // Get the index of the current page int currentIndex = Instance.Pages.ToList().IndexOf(Instance.currentPage); // Change the page with wrapping if (Instance.Pages.First().Key == Instance.currentPage.Key) { Instance.currentPage = Instance.Pages.Last(); } else { Instance.currentPage = Instance.Pages.ElementAt(currentIndex - 1); } // Set visibility SetCurrentPageVisible(); } public static void NextPage(){ // Do nothing if there's only one page if (Instance.Pages.Count == 1) { return; } // Get the index of the current page int currentIndex = Instance.Pages.ToList().IndexOf(Instance.currentPage); // Change the page with wrapping if (Instance.Pages.Last().Key == Instance.currentPage.Key) { Instance.currentPage = Instance.Pages.First(); } else { Instance.currentPage = Instance.Pages.ElementAt(currentIndex + 1); } // Set visibility SetCurrentPageVisible(); } static void SetCurrentPageVisible(){ // Set the display property for the page to enable/disable them foreach (var page in Instance.Pages) { if (page.Key == Instance.currentPage.Key) { page.Key.GetComponent().rootVisualElement.style.display = new StyleEnum(DisplayStyle.Flex); } else { page.Key.GetComponent().rootVisualElement.style.display = new StyleEnum(DisplayStyle.None); } } // Turn all the page labels into a list var pageButtons = Instance.root.rootVisualElement.Query