using NewHorizons.Utility.OWML; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.Profiling; using UnityEngine.SceneManagement; using Object = UnityEngine.Object; namespace NewHorizons.Utility { public static class SearchUtilities { private static readonly Dictionary DontDestroyOnLoadCachedGameObjects = new Dictionary(); private static readonly Dictionary CachedGameObjects = new Dictionary(); private static readonly Dictionary CachedRootGameObjects = new Dictionary(); public static void AddToDontDestroyOnLoadCache(string path, GameObject go) { DontDestroyOnLoadCachedGameObjects[path] = go.InstantiateInactive().DontDestroyOnLoad(); } public static void ClearDontDestroyOnLoadCache() { foreach (var go in DontDestroyOnLoadCachedGameObjects.Values) { GameObject.Destroy(go); } DontDestroyOnLoadCachedGameObjects.Clear(); } public static void ClearCache() { NHLogger.LogVerbose("Clearing search cache"); CachedGameObjects.Clear(); CachedRootGameObjects.Clear(); } public static List FindObjectsOfTypeAndName(string name) where T : Object { T[] firstList = Object.FindObjectsOfType(); List finalList = new List(); for (var i = 0; i < firstList.Length; i++) { if (firstList[i].name == name) { finalList.Add(firstList[i]); } } return finalList; } public static T FindObjectOfTypeAndName(string name) where T : Object { T[] firstList = Object.FindObjectsOfType(); for (var i = 0; i < firstList.Length; i++) { if (firstList[i].name == name) { return firstList[i]; } } return null; } public static List FindResourcesOfTypeAndName(string name) where T : Object { T[] firstList = Resources.FindObjectsOfTypeAll(); List finalList = new List(); for (var i = 0; i < firstList.Length; i++) { if (firstList[i].name == name) { finalList.Add(firstList[i]); } } return finalList; } public static T FindResourceOfTypeAndName(string name) where T : Object { T[] firstList = Resources.FindObjectsOfTypeAll(); for (var i = 0; i < firstList.Length; i++) { if (firstList[i].name == name) { return firstList[i]; } } return null; } public static string GetPath(this Transform current) { if (current.parent == null) return current.name; return current.parent.GetPath() + "/" + current.name; } public static GameObject FindChild(this GameObject g, string childPath) => g.transform.Find(childPath)?.gameObject; /// /// finds active or inactive object by path, /// or recursively finds an active or inactive object by name /// public static GameObject Find(string path, bool warn = true) { if (DontDestroyOnLoadCachedGameObjects.TryGetValue(path, out var gameObject)) return gameObject; if (CachedGameObjects.TryGetValue(path, out var go)) return go; // 1: normal find Profiler.BeginSample("1"); go = GameObject.Find(path); if (go) { CachedGameObjects.Add(path, go); Profiler.EndSample(); return go; } Profiler.EndSample(); Profiler.BeginSample("2"); // 2: find inactive using root + transform.find var names = path.Split('/'); // Cache the root objects so we don't loop through all of them each time var rootName = names[0]; if (!CachedRootGameObjects.TryGetValue(rootName, out var root)) { root = SceneManager.GetActiveScene().GetRootGameObjects().FirstOrDefault(x => x.name == rootName); if (root != null) { CachedRootGameObjects.Add(rootName, root); } } var childPath = string.Join("/", names.Skip(1)); go = root ? root.FindChild(childPath) : null; if (go) { CachedGameObjects.Add(path, go); Profiler.EndSample(); return go; } Profiler.EndSample(); Profiler.BeginSample("3"); var name = names.Last(); if (warn) NHLogger.LogWarning($"Couldn't find object in path {path}, will look for potential matches for name {name}"); // 3: find resource to include inactive objects (but skip prefabs) go = Resources.FindObjectsOfTypeAll() .FirstOrDefault(x => x.name == name && x.scene.name != null); if (go) { CachedGameObjects.Add(path, go); Profiler.EndSample(); return go; } if (warn) NHLogger.LogWarning($"Couldn't find object with name {name}"); Profiler.EndSample(); return null; } public static List GetAllChildren(this GameObject parent) { var children = new List(); foreach (Transform child in parent.transform) { children.Add(child.gameObject); } return children; } /// /// transform.find but works for gameobjects with same name /// public static List FindAll(this Transform @this, string path) { var names = path.Split('/'); var currentTransforms = new List { @this }; foreach (var name in names) { var newTransforms = new List(); foreach (var currentTransform in currentTransforms) { foreach (Transform child in currentTransform) { if (child.name == name) { newTransforms.Add(child); } } } currentTransforms = newTransforms; } return currentTransforms; } } }