using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.SceneManagement; using Object = UnityEngine.Object; namespace Jovian.Utilities { public static class SceneUtility { public static List FindGameObjectsInScene(this Scene scene, bool includeInactive = false, Func predicate = null) { if (scene.IsValid() == false) { Debug.LogError("Scene is invalid"); return null; } var list = new List(); GameObject[] sceneObjects = scene.GetRootGameObjects(); GameObject[] loadedObjects = FindDontDestroyOnLoadObjects(); GameObject[] combinedGameobjects = new GameObject[sceneObjects.Length + loadedObjects.Length]; sceneObjects.CopyTo(combinedGameobjects, 0); loadedObjects.CopyTo(combinedGameobjects, sceneObjects.Length); foreach (var rootObject in combinedGameobjects) { var allChildTransforms = rootObject.GetComponentsInChildren(includeInactive); var allGameObjects = allChildTransforms.Select(transform => transform.gameObject); if (predicate != null) { allGameObjects = allGameObjects.Where(predicate); } list.AddRange(allGameObjects); } return list; } public static List FindGameObjectsInActiveScene(bool includeInactive = false, Func predicate = null) => FindGameObjectsInScene(SceneManager.GetActiveScene(), includeInactive, predicate); // Adding support for finding objects not in the main scenes but in DontDestroyOnLoad // From https://forum.unity.com/threads/editor-script-how-to-access-objects-under-dontdestroyonload-while-in-play-mode.442014/#post-3570916 private static GameObject[] FindDontDestroyOnLoadObjects() { if (!Application.isPlaying) { return new GameObject[] { }; // return an empty array as this method creates issues in edit mode } GameObject temp = null; try { temp = new GameObject(); Object.DontDestroyOnLoad(temp); UnityEngine.SceneManagement.Scene dontDestroyOnLoad = temp.scene; Object.DestroyImmediate(temp); temp = null; return dontDestroyOnLoad.GetRootGameObjects(); } finally { if (temp != null) Object.DestroyImmediate(temp); } } public static List FindComponentsInScene(this Scene scene, bool includeInactive = false) where TComponent : Component { if (scene.IsValid() == false) { Debug.LogError("Scene is invalid"); return null; } var list = new List(); foreach (var rootObject in scene.GetRootGameObjects()) { list.AddRange(rootObject.GetComponentsInChildren(includeInactive)); } return list; } public static List FindComponentsInScene(this Scene scene, Type componentType, bool includeInactive = false) { if (scene.IsValid() == false) { Debug.LogError("Scene is invalid"); return null; } var list = new List(); foreach (GameObject rootObject in scene.GetRootGameObjects()) { list.AddRange(rootObject.GetComponentsInChildren(componentType, includeInactive)); } return list; } public static List FindComponentsInActiveScene(bool includeInactive = false) where TComponent : Component => FindComponentsInScene(SceneManager.GetActiveScene(), includeInactive); public static List FindComponentsInActiveScene(Type componentType, bool includeInactive = false) => FindComponentsInScene(SceneManager.GetActiveScene(), componentType, includeInactive); public static List FindComponentsInAllScenes(bool includeInactive = false) where TComponent : Component { List allComponents = new(); for (int i = 0, c = SceneManager.sceneCount; i < c; i++) { allComponents.AddRange(FindComponentsInScene(SceneManager.GetSceneAt(i), includeInactive)); } return allComponents; } public static TComponent FindComponentInScene(this Scene scene, bool includeInactive = false) where TComponent : Component { if (scene.IsValid() == false) { Debug.LogError("Scene is invalid"); return null; } var list = new List(); foreach (var rootObject in scene.GetRootGameObjects()) { list.AddRange(rootObject.GetComponentsInChildren(includeInactive)); } return list.FirstOrDefault(); } public static Component FindComponentInScene(this Scene scene, Type componentType, bool includeInactive = false) { if (scene.IsValid() == false) { Debug.LogError("Scene is invalid"); return null; } var list = new List(); foreach (GameObject rootObject in scene.GetRootGameObjects()) { list.AddRange(rootObject.GetComponentsInChildren(componentType, includeInactive)); } return list.FirstOrDefault(); } public static TComponent FindComponentInActiveScene(bool includeInactive = false) where TComponent : Component => FindComponentInScene(SceneManager.GetActiveScene(), includeInactive); public static Component FindComponentInActiveScene(Type componentType, bool includeInactive = false) => FindComponentInScene(SceneManager.GetActiveScene(), componentType, includeInactive); public static TComponent FindComponentInAllScenes(bool includeInactive = false) where TComponent : Component => FindComponentsInAllScenes(includeInactive).FirstOrDefault(); public static GameObject FindGameObject(string nameQuery) { char delimiter = '/'; string[] querySegments = nameQuery.Split(delimiter); return FindGameObjectsInActiveScene(true, (gameObject) => { int queryIndex = querySegments.Length - 1; Transform compareTransform = gameObject.transform; do { if (compareTransform != null && compareTransform.name.Equals(querySegments[queryIndex])) { compareTransform = compareTransform.parent; queryIndex--; } // if compare is null and string is null that means the first query segment was /, so that's the root element - then our parent MUST be null else if (compareTransform == null && string.IsNullOrEmpty(querySegments[queryIndex])) { return true; } else { return false; } } while (queryIndex >= 0); return true; }).FirstOrDefault(); } private static Transform GetChildWithName(this Transform transform, string childName) { foreach (Transform child in transform.transform) { if (child.name.Equals(childName)) { return child; } } return null; } } }