Files
2026-04-02 07:22:33 +02:00

203 lines
8.0 KiB
C#

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<GameObject> FindGameObjectsInScene(this Scene scene, bool includeInactive = false, Func<GameObject, bool> predicate = null) {
if (scene.IsValid() == false)
{
Debug.LogError("Scene is invalid");
return null;
}
var list = new List<GameObject>();
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<Transform>(includeInactive);
var allGameObjects = allChildTransforms.Select(transform => transform.gameObject);
if (predicate != null)
{
allGameObjects = allGameObjects.Where(predicate);
}
list.AddRange(allGameObjects);
}
return list;
}
public static List<GameObject> FindGameObjectsInActiveScene(bool includeInactive = false, Func<GameObject, bool> 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<TComponent> FindComponentsInScene<TComponent>(this Scene scene, bool includeInactive = false) where TComponent : Component {
if (scene.IsValid() == false)
{
Debug.LogError("Scene is invalid");
return null;
}
var list = new List<TComponent>();
foreach (var rootObject in scene.GetRootGameObjects())
{
list.AddRange(rootObject.GetComponentsInChildren<TComponent>(includeInactive));
}
return list;
}
public static List<Component> FindComponentsInScene(this Scene scene, Type componentType, bool includeInactive = false) {
if (scene.IsValid() == false)
{
Debug.LogError("Scene is invalid");
return null;
}
var list = new List<Component>();
foreach (GameObject rootObject in scene.GetRootGameObjects())
{
list.AddRange(rootObject.GetComponentsInChildren(componentType, includeInactive));
}
return list;
}
public static List<TComponent> FindComponentsInActiveScene<TComponent>(bool includeInactive = false) where TComponent : Component
=> FindComponentsInScene<TComponent>(SceneManager.GetActiveScene(), includeInactive);
public static List<Component> FindComponentsInActiveScene(Type componentType, bool includeInactive = false)
=> FindComponentsInScene(SceneManager.GetActiveScene(), componentType, includeInactive);
public static List<TComponent> FindComponentsInAllScenes<TComponent>(bool includeInactive = false) where TComponent : Component {
List<TComponent> allComponents = new();
for (int i = 0, c = SceneManager.sceneCount; i < c; i++)
{
allComponents.AddRange(FindComponentsInScene<TComponent>(SceneManager.GetSceneAt(i), includeInactive));
}
return allComponents;
}
public static TComponent FindComponentInScene<TComponent>(this Scene scene, bool includeInactive = false) where TComponent : Component {
if (scene.IsValid() == false)
{
Debug.LogError("Scene is invalid");
return null;
}
var list = new List<TComponent>();
foreach (var rootObject in scene.GetRootGameObjects())
{
list.AddRange(rootObject.GetComponentsInChildren<TComponent>(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<Component>();
foreach (GameObject rootObject in scene.GetRootGameObjects())
{
list.AddRange(rootObject.GetComponentsInChildren(componentType, includeInactive));
}
return list.FirstOrDefault();
}
public static TComponent FindComponentInActiveScene<TComponent>(bool includeInactive = false) where TComponent : Component
=> FindComponentInScene<TComponent>(SceneManager.GetActiveScene(), includeInactive);
public static Component FindComponentInActiveScene(Type componentType, bool includeInactive = false)
=> FindComponentInScene(SceneManager.GetActiveScene(), componentType, includeInactive);
public static TComponent FindComponentInAllScenes<TComponent>(bool includeInactive = false) where TComponent : Component
=> FindComponentsInAllScenes<TComponent>(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;
}
}
}