using System; using System.Collections.Generic; using System.Linq; using UnityExplorer.UI; using UnityExplorer.UI.Modules; using UnityExplorer.UI.Shared; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; using UnityExplorer.Unstrip; namespace UnityExplorer.Inspectors { public class SceneExplorer { public static SceneExplorer Instance; public SceneExplorer() { Instance = this; ConstructScenePane(); } private static bool Hiding; private const float UPDATE_INTERVAL = 1f; private float m_timeOfLastSceneUpdate; private GameObject m_selectedSceneObject; private int m_currentSceneHandle = -1; private int m_lastCount; private Dropdown m_sceneDropdown; private Text m_scenePathText; private GameObject m_mainInspectBtn; private GameObject m_backButtonObj; public PageHandler m_sceneListPageHandler; private GameObject m_sceneListContent; private GameObject[] m_allSceneListObjects = new GameObject[0]; private readonly List m_sceneShortList = new List(); private readonly List m_sceneListTexts = new List(); public static int DontDestroyHandle => DontDestroyObject.scene.handle; internal static GameObject DontDestroyObject { get { if (!m_dontDestroyObject) { m_dontDestroyObject = new GameObject("DontDestroyMe"); GameObject.DontDestroyOnLoad(m_dontDestroyObject); } return m_dontDestroyObject; } } internal static GameObject m_dontDestroyObject; public void Init() { RefreshActiveScenes(); } public void Update() { if (Hiding || Time.realtimeSinceStartup - m_timeOfLastSceneUpdate < UPDATE_INTERVAL) { return; } RefreshActiveScenes(); if (!m_selectedSceneObject) { if (m_currentSceneHandle != -1) { SetSceneObjectList(SceneUnstrip.GetRootGameObjects(m_currentSceneHandle)); } } else { RefreshSelectedSceneObject(); } } public int GetSceneHandle(string sceneName) { if (sceneName == "DontDestroyOnLoad") return DontDestroyHandle; for (int i = 0; i < SceneManager.sceneCount; i++) { var scene = SceneManager.GetSceneAt(i); if (scene.name == sceneName) return scene.handle; } return -1; } internal void OnSceneChange() { m_sceneDropdown.OnCancel(null); RefreshActiveScenes(); } private void RefreshActiveScenes() { var names = new List(); var handles = new List(); for (int i = 0; i < SceneManager.sceneCount; i++) { Scene scene = SceneManager.GetSceneAt(i); int handle = scene.handle; if (scene == null || handle == -1 || string.IsNullOrEmpty(scene.name)) continue; handles.Add(handle); names.Add(scene.name); } names.Add("DontDestroyOnLoad"); handles.Add(DontDestroyHandle); m_sceneDropdown.options.Clear(); foreach (string scene in names) { m_sceneDropdown.options.Add(new Dropdown.OptionData { text = scene }); } if (!handles.Contains(m_currentSceneHandle)) { //m_sceneDropdown.transform.Find("Label").GetComponent().text = names[0]; m_sceneDropdown.itemText.text = names[0]; SetTargetScene(handles[0]); } } public void SetTargetScene(string name) => SetTargetScene(GetSceneHandle(name)); public void SetTargetScene(int handle) { if (handle == -1) return; m_currentSceneHandle = handle; GameObject[] rootObjs = SceneUnstrip.GetRootGameObjects(handle); SetSceneObjectList(rootObjs); m_selectedSceneObject = null; if (m_backButtonObj.activeSelf) { m_backButtonObj.SetActive(false); m_mainInspectBtn.SetActive(false); } m_scenePathText.text = "Scene root:"; //m_scenePathText.ForceMeshUpdate(); } public void SetTargetObject(GameObject obj) { if (!obj) return; m_scenePathText.text = obj.name; //m_scenePathText.ForceMeshUpdate(); m_selectedSceneObject = obj; RefreshSelectedSceneObject(); if (!m_backButtonObj.activeSelf) { m_backButtonObj.SetActive(true); m_mainInspectBtn.SetActive(true); } } private void RefreshSelectedSceneObject() { GameObject[] list = new GameObject[m_selectedSceneObject.transform.childCount]; for (int i = 0; i < m_selectedSceneObject.transform.childCount; i++) { list[i] = m_selectedSceneObject.transform.GetChild(i).gameObject; } SetSceneObjectList(list); } private void SetSceneObjectList(GameObject[] objects) { m_allSceneListObjects = objects; RefreshSceneObjectList(); } private void SceneListObjectClicked(int index) { if (index >= m_sceneShortList.Count || !m_sceneShortList[index]) { return; } SetTargetObject(m_sceneShortList[index]); } private void OnSceneListPageTurn() { RefreshSceneObjectList(); } private void RefreshSceneObjectList() { m_timeOfLastSceneUpdate = Time.realtimeSinceStartup; var objects = m_allSceneListObjects; m_sceneListPageHandler.ListCount = objects.Length; //int startIndex = m_sceneListPageHandler.StartIndex; int newCount = 0; foreach (var itemIndex in m_sceneListPageHandler) { newCount++; // normalized index starting from 0 var i = itemIndex - m_sceneListPageHandler.StartIndex; if (itemIndex >= objects.Length) { if (i > m_lastCount || i >= m_sceneListTexts.Count) break; GameObject label = m_sceneListTexts[i].transform.parent.parent.gameObject; if (label.activeSelf) label.SetActive(false); } else { GameObject obj = objects[itemIndex]; if (!obj) continue; if (i >= m_sceneShortList.Count) { m_sceneShortList.Add(obj); AddObjectListButton(); } else { m_sceneShortList[i] = obj; } var text = m_sceneListTexts[i]; var name = obj.name; if (obj.transform.childCount > 0) name = $"[{obj.transform.childCount}] {name}"; text.text = name; text.color = obj.activeSelf ? Color.green : Color.red; var label = text.transform.parent.parent.gameObject; if (!label.activeSelf) { label.SetActive(true); } } } m_lastCount = newCount; } #region UI CONSTRUCTION public void ConstructScenePane() { GameObject leftPane = UIFactory.CreateVerticalGroup(HomePage.Instance.Content, new Color(72f / 255f, 72f / 255f, 72f / 255f)); LayoutElement leftLayout = leftPane.AddComponent(); leftLayout.minWidth = 350; leftLayout.flexibleWidth = 0; VerticalLayoutGroup leftGroup = leftPane.GetComponent(); leftGroup.padding.left = 8; leftGroup.padding.right = 8; leftGroup.padding.top = 8; leftGroup.padding.bottom = 8; leftGroup.spacing = 5; leftGroup.childControlWidth = true; leftGroup.childControlHeight = true; leftGroup.childForceExpandWidth = true; leftGroup.childForceExpandHeight = true; GameObject titleObj = UIFactory.CreateLabel(leftPane, TextAnchor.UpperLeft); Text titleLabel = titleObj.GetComponent(); titleLabel.text = "Scene Explorer"; titleLabel.fontSize = 20; LayoutElement titleLayout = titleObj.AddComponent(); titleLayout.minHeight = 30; titleLayout.flexibleHeight = 0; GameObject sceneDropdownObj = UIFactory.CreateDropdown(leftPane, out m_sceneDropdown); LayoutElement dropdownLayout = sceneDropdownObj.AddComponent(); dropdownLayout.minHeight = 40; dropdownLayout.flexibleHeight = 0; dropdownLayout.minWidth = 320; dropdownLayout.flexibleWidth = 2; #if CPP m_sceneDropdown.onValueChanged.AddListener(new Action((int val) => { SetSceneFromDropdown(val); })); #else m_sceneDropdown.onValueChanged.AddListener((int val) => { SetSceneFromDropdown(val); }); #endif void SetSceneFromDropdown(int val) { string scene = m_sceneDropdown.options[val].text; SetTargetScene(scene); } GameObject scenePathGroupObj = UIFactory.CreateHorizontalGroup(leftPane, new Color(1, 1, 1, 0f)); HorizontalLayoutGroup scenePathGroup = scenePathGroupObj.GetComponent(); scenePathGroup.childControlHeight = true; scenePathGroup.childControlWidth = true; scenePathGroup.childForceExpandHeight = true; scenePathGroup.childForceExpandWidth = true; scenePathGroup.spacing = 5; LayoutElement scenePathLayout = scenePathGroupObj.AddComponent(); scenePathLayout.minHeight = 20; scenePathLayout.minWidth = 335; scenePathLayout.flexibleWidth = 0; m_backButtonObj = UIFactory.CreateButton(scenePathGroupObj); Text backButtonText = m_backButtonObj.GetComponentInChildren(); backButtonText.text = "◄"; LayoutElement backButtonLayout = m_backButtonObj.AddComponent(); backButtonLayout.minWidth = 40; backButtonLayout.flexibleWidth = 0; Button backButton = m_backButtonObj.GetComponent