ComponentExtensions.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEditor;
  4. using UnityEngine;
  5. using UnityEngine.Profiling;
  6. using Object = UnityEngine.Object;
  7. namespace Coffee.UIParticleInternal
  8. {
  9. /// <summary>
  10. /// Extension methods for Component class.
  11. /// </summary>
  12. internal static class ComponentExtensions
  13. {
  14. /// <summary>
  15. /// Get components in children of a specific type in the hierarchy of a GameObject.
  16. /// </summary>
  17. public static T[] GetComponentsInChildren<T>(this Component self, int depth)
  18. where T : Component
  19. {
  20. var results = InternalListPool<T>.Rent();
  21. self.GetComponentsInChildren_Internal(results, depth);
  22. var array = results.ToArray();
  23. InternalListPool<T>.Return(ref results);
  24. return array;
  25. }
  26. /// <summary>
  27. /// Get components in children of a specific type in the hierarchy of a GameObject.
  28. /// </summary>
  29. public static void GetComponentsInChildren<T>(this Component self, List<T> results, int depth)
  30. where T : Component
  31. {
  32. results.Clear();
  33. self.GetComponentsInChildren_Internal(results, depth);
  34. }
  35. private static void GetComponentsInChildren_Internal<T>(this Component self, List<T> results, int depth)
  36. where T : Component
  37. {
  38. if (!self || results == null || depth < 0) return;
  39. var tr = self.transform;
  40. if (tr.TryGetComponent<T>(out var t))
  41. {
  42. results.Add(t);
  43. }
  44. if (depth - 1 < 0) return;
  45. var childCount = tr.childCount;
  46. for (var i = 0; i < childCount; i++)
  47. {
  48. tr.GetChild(i).GetComponentsInChildren_Internal(results, depth - 1);
  49. }
  50. }
  51. /// <summary>
  52. /// Get or add a component of a specific type to a GameObject.
  53. /// </summary>
  54. public static T GetOrAddComponent<T>(this Component self) where T : Component
  55. {
  56. if (!self) return null;
  57. return self.TryGetComponent<T>(out var component)
  58. ? component
  59. : self.gameObject.AddComponent<T>();
  60. }
  61. /// <summary>
  62. /// Get the root component of a specific type in the hierarchy of a GameObject.
  63. /// </summary>
  64. public static T GetRootComponent<T>(this Component self) where T : Component
  65. {
  66. T component = null;
  67. var transform = self.transform;
  68. while (transform)
  69. {
  70. if (transform.TryGetComponent<T>(out var c))
  71. {
  72. component = c;
  73. }
  74. transform = transform.parent;
  75. }
  76. return component;
  77. }
  78. /// <summary>
  79. /// Get a component of a specific type in the parent hierarchy of a GameObject.
  80. /// </summary>
  81. public static T GetComponentInParent<T>(this Component self, bool includeSelf, Transform stopAfter,
  82. Predicate<T> valid)
  83. where T : Component
  84. {
  85. var tr = includeSelf ? self.transform : self.transform.parent;
  86. while (tr)
  87. {
  88. if (tr.TryGetComponent<T>(out var c) && valid(c)) return c;
  89. if (tr == stopAfter) return null;
  90. tr = tr.parent;
  91. }
  92. return null;
  93. }
  94. /// <summary>
  95. /// Add a component of a specific type to the children of a GameObject.
  96. /// </summary>
  97. public static void AddComponentOnChildren<T>(this Component self, HideFlags hideFlags, bool includeSelf)
  98. where T : Component
  99. {
  100. if (self == null) return;
  101. Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Self");
  102. if (includeSelf && !self.TryGetComponent<T>(out _))
  103. {
  104. var c = self.gameObject.AddComponent<T>();
  105. c.hideFlags = hideFlags;
  106. }
  107. Profiler.EndSample();
  108. Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Child");
  109. var childCount = self.transform.childCount;
  110. for (var i = 0; i < childCount; i++)
  111. {
  112. var child = self.transform.GetChild(i);
  113. if (child.TryGetComponent<T>(out _)) continue;
  114. var c = child.gameObject.AddComponent<T>();
  115. c.hideFlags = hideFlags;
  116. }
  117. Profiler.EndSample();
  118. }
  119. /// <summary>
  120. /// Add a component of a specific type to the children of a GameObject.
  121. /// </summary>
  122. public static void AddComponentOnChildren<T>(this Component self, bool includeSelf)
  123. where T : Component
  124. {
  125. if (self == null) return;
  126. Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Self");
  127. if (includeSelf && !self.TryGetComponent<T>(out _))
  128. {
  129. self.gameObject.AddComponent<T>();
  130. }
  131. Profiler.EndSample();
  132. Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Child");
  133. var childCount = self.transform.childCount;
  134. for (var i = 0; i < childCount; i++)
  135. {
  136. var child = self.transform.GetChild(i);
  137. if (child.TryGetComponent<T>(out _)) continue;
  138. child.gameObject.AddComponent<T>();
  139. }
  140. Profiler.EndSample();
  141. }
  142. #if !UNITY_2021_2_OR_NEWER && !UNITY_2020_3_45 && !UNITY_2020_3_46 && !UNITY_2020_3_47 && !UNITY_2020_3_48
  143. public static T GetComponentInParent<T>(this Component self, bool includeInactive) where T : Component
  144. {
  145. if (!self) return null;
  146. if (!includeInactive) return self.GetComponentInParent<T>();
  147. var current = self.transform;
  148. while (current)
  149. {
  150. if (current.TryGetComponent<T>(out var c)) return c;
  151. current = current.parent;
  152. }
  153. return null;
  154. }
  155. #endif
  156. #if UNITY_EDITOR
  157. /// <summary>
  158. /// Verify whether it can be converted to the specified component.
  159. /// </summary>
  160. internal static bool CanConvertTo<T>(this Object context) where T : MonoBehaviour
  161. {
  162. return context && context.GetType() != typeof(T);
  163. }
  164. /// <summary>
  165. /// Convert to the specified component.
  166. /// </summary>
  167. internal static void ConvertTo<T>(this Object context) where T : MonoBehaviour
  168. {
  169. var target = context as MonoBehaviour;
  170. if (target == null) return;
  171. var so = new SerializedObject(target);
  172. so.Update();
  173. var oldEnable = target.enabled;
  174. target.enabled = false;
  175. // Find MonoScript of the specified component.
  176. foreach (var script in MonoImporter.GetAllRuntimeMonoScripts())
  177. {
  178. if (script.GetClass() != typeof(T))
  179. {
  180. continue;
  181. }
  182. // Set 'm_Script' to convert.
  183. so.FindProperty("m_Script").objectReferenceValue = script;
  184. so.ApplyModifiedProperties();
  185. break;
  186. }
  187. if (so.targetObject is MonoBehaviour mb)
  188. {
  189. mb.enabled = oldEnable;
  190. }
  191. }
  192. #endif
  193. }
  194. }