using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.Profiling; using Object = UnityEngine.Object; namespace Coffee.UIParticleInternal { /// /// Extension methods for Component class. /// internal static class ComponentExtensions { /// /// Get components in children of a specific type in the hierarchy of a GameObject. /// public static T[] GetComponentsInChildren(this Component self, int depth) where T : Component { var results = ListPool.Rent(); self.GetComponentsInChildren_Internal(results, depth); var array = results.ToArray(); ListPool.Return(ref results); return array; } /// /// Get components in children of a specific type in the hierarchy of a GameObject. /// public static void GetComponentsInChildren(this Component self, List results, int depth) where T : Component { results.Clear(); self.GetComponentsInChildren_Internal(results, depth); } private static void GetComponentsInChildren_Internal(this Component self, List results, int depth) where T : Component { if (!self || results == null || depth < 0) return; var tr = self.transform; if (tr.TryGetComponent(out var t)) { results.Add(t); } if (depth - 1 < 0) return; var childCount = tr.childCount; for (var i = 0; i < childCount; i++) { tr.GetChild(i).GetComponentsInChildren_Internal(results, depth - 1); } } /// /// Get or add a component of a specific type to a GameObject. /// public static T GetOrAddComponent(this Component self) where T : Component { if (!self) return null; return self.TryGetComponent(out var component) ? component : self.gameObject.AddComponent(); } /// /// Get the root component of a specific type in the hierarchy of a GameObject. /// public static T GetRootComponent(this Component self) where T : Component { T component = null; var transform = self.transform; while (transform) { if (transform.TryGetComponent(out var c)) { component = c; } transform = transform.parent; } return component; } /// /// Get a component of a specific type in the parent hierarchy of a GameObject. /// public static T GetComponentInParent(this Component self, bool includeSelf, Transform stopAfter, Predicate valid) where T : Component { var tr = includeSelf ? self.transform : self.transform.parent; while (tr) { if (tr.TryGetComponent(out var c) && valid(c)) return c; if (tr == stopAfter) return null; tr = tr.parent; } return null; } /// /// Add a component of a specific type to the children of a GameObject. /// public static void AddComponentOnChildren(this Component self, HideFlags hideFlags, bool includeSelf) where T : Component { if (self == null) return; Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Self"); if (includeSelf && !self.TryGetComponent(out _)) { var c = self.gameObject.AddComponent(); c.hideFlags = hideFlags; } Profiler.EndSample(); Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Child"); var childCount = self.transform.childCount; for (var i = 0; i < childCount; i++) { var child = self.transform.GetChild(i); if (child.TryGetComponent(out _)) continue; var c = child.gameObject.AddComponent(); c.hideFlags = hideFlags; } Profiler.EndSample(); } #if !UNITY_2021_2_OR_NEWER && !UNITY_2020_3_45 && !UNITY_2020_3_46 && !UNITY_2020_3_47 && !UNITY_2020_3_48 public static T GetComponentInParent(this Component self, bool includeInactive) where T : Component { if (!self) return null; if (!includeInactive) return self.GetComponentInParent(); var current = self.transform; while (current) { if (current.TryGetComponent(out var c)) return c; current = current.parent; } return null; } #endif #if UNITY_EDITOR /// /// Verify whether it can be converted to the specified component. /// internal static bool CanConvertTo(this Object context) where T : MonoBehaviour { return context && context.GetType() != typeof(T); } /// /// Convert to the specified component. /// internal static void ConvertTo(this Object context) where T : MonoBehaviour { var target = context as MonoBehaviour; if (target == null) return; var so = new SerializedObject(target); so.Update(); var oldEnable = target.enabled; target.enabled = false; // Find MonoScript of the specified component. foreach (var script in Resources.FindObjectsOfTypeAll()) { if (script.GetClass() != typeof(T)) { continue; } // Set 'm_Script' to convert. so.FindProperty("m_Script").objectReferenceValue = script; so.ApplyModifiedProperties(); break; } if (so.targetObject is MonoBehaviour mb) { mb.enabled = oldEnable; } } #endif } }