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; using UnityExplorer.Helpers; namespace UnityExplorer.Inspectors { public class SceneExplorer { public static SceneExplorer Instance; internal static Action OnToggleShow; public SceneExplorer() { Instance = this; ConstructScenePane(); } private static bool Hiding; private const float UPDATE_INTERVAL = 1f; private float m_timeOfLastSceneUpdate; // private int m_currentSceneHandle = -1; public static Scene DontDestroyScene => DontDestroyObject.scene; internal Scene m_currentScene; internal Scene[] m_currentScenes = new Scene[0]; private GameObject m_selectedSceneObject; private int m_lastCount; private Dropdown m_sceneDropdown; private Text m_sceneDropdownText; private Text m_scenePathText; private GameObject m_mainInspectBtn; private GameObject m_backButtonObj; public PageHandler m_pageHandler; private GameObject m_pageContent; private GameObject[] m_allObjects = new GameObject[0]; private readonly List m_shortList = new List(); private readonly List m_shortListTexts = new List(); private readonly List m_shortListToggles = new List(); 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() { RefreshSceneSelector(); } public void Update() { if (Hiding || Time.realtimeSinceStartup - m_timeOfLastSceneUpdate < UPDATE_INTERVAL) { return; } RefreshSceneSelector(); if (!m_selectedSceneObject) { if (m_currentScene != default) { #if CPP SetSceneObjectList(SceneUnstrip.GetRootGameObjects(m_currentScene.handle)); #else SetSceneObjectList(m_currentScene.GetRootGameObjects()); #endif } } else { RefreshSelectedSceneObject(); } } //#if CPP // public int GetSceneHandle(string sceneName) // { // if (sceneName == "DontDestroyOnLoad") // return DontDestroyScene; // for (int i = 0; i < SceneManager.sceneCount; i++) // { // var scene = SceneManager.GetSceneAt(i); // if (scene.name == sceneName) // return scene.handle; // } // return -1; // } //#endif internal void OnSceneChange() { m_sceneDropdown.OnCancel(null); RefreshSceneSelector(); } private void RefreshSceneSelector() { var names = new List(); var scenes = new List(); for (int i = 0; i < SceneManager.sceneCount; i++) { Scene scene = SceneManager.GetSceneAt(i); if (scene == default) continue; scenes.Add(scene); names.Add(scene.name); } names.Add("DontDestroyOnLoad"); scenes.Add(DontDestroyScene); m_sceneDropdown.options.Clear(); foreach (string scene in names) { m_sceneDropdown.options.Add(new Dropdown.OptionData { text = scene }); } if (!names.Contains(m_sceneDropdownText.text)) { m_sceneDropdownText.text = names[0]; SetTargetScene(scenes[0]); } m_currentScenes = scenes.ToArray(); } //#if CPP // public void SetTargetScene(string name) => SetTargetScene(scene.handle); //#endif public void SetTargetScene(Scene scene) { if (scene == default) return; m_currentScene = scene; #if CPP GameObject[] rootObjs = SceneUnstrip.GetRootGameObjects(scene.handle); #else GameObject[] rootObjs = SceneUnstrip.GetRootGameObjects(scene); #endif 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_allObjects = objects; RefreshSceneObjectList(); } private void SceneListObjectClicked(int index) { if (index >= m_shortList.Count || !m_shortList[index]) { return; } var obj = m_shortList[index]; if (obj.transform.childCount > 0) SetTargetObject(obj); else InspectorManager.Instance.Inspect(obj); } private void OnSceneListPageTurn() { RefreshSceneObjectList(); } private void OnToggleClicked(int index, bool val) { if (index >= m_shortList.Count || !m_shortList[index]) return; var obj = m_shortList[index]; obj.SetActive(val); } private void RefreshSceneObjectList() { m_timeOfLastSceneUpdate = Time.realtimeSinceStartup; var objects = m_allObjects; m_pageHandler.ListCount = objects.Length; //int startIndex = m_sceneListPageHandler.StartIndex; int newCount = 0; foreach (var itemIndex in m_pageHandler) { newCount++; // normalized index starting from 0 var i = itemIndex - m_pageHandler.StartIndex; if (itemIndex >= objects.Length) { if (i > m_lastCount || i >= m_shortListTexts.Count) break; GameObject label = m_shortListTexts[i].transform.parent.parent.gameObject; if (label.activeSelf) label.SetActive(false); } else { GameObject obj = objects[itemIndex]; if (!obj) continue; if (i >= m_shortList.Count) { m_shortList.Add(obj); AddObjectListButton(); } else { m_shortList[i] = obj; } var text = m_shortListTexts[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 tog = m_shortListToggles[i]; tog.isOn = obj.activeSelf; 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 = 4; leftGroup.padding.right = 4; leftGroup.padding.top = 8; leftGroup.padding.bottom = 4; leftGroup.spacing = 4; 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; m_sceneDropdownText = m_sceneDropdown.transform.Find("Label").GetComponent(); m_sceneDropdown.onValueChanged.AddListener((int val) => { SetSceneFromDropdown(val); }); void SetSceneFromDropdown(int val) { //string scene = m_sceneDropdown.options[val].text; SetTargetScene(m_currentScenes[val]); } 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