// Object.FindFirstObjectByType API added in: // 2022.3.0f1 or newer #if UNITY_2022_3_OR_NEWER #define HAS_FIND_FIRST_OBJECT_BY_TYPE #endif // 2022.2.5f1 or newer #if UNITY_2022_2 && !(UNITY_2022_2_0 || UNITY_2022_2_1 || UNITY_2022_2_2 || UNITY_2022_2_3 || UNITY_2022_2_4) #define HAS_FIND_FIRST_OBJECT_BY_TYPE #endif // 2021.3.18f1 or newer #if UNITY_2021_3 && !(UNITY_2021_3_0 || UNITY_2021_3_1 || UNITY_2021_3_2 || UNITY_2021_3_3 || UNITY_2021_3_4 || UNITY_2021_3_5 || UNITY_2021_3_6 || UNITY_2021_3_7 || UNITY_2021_3_8 || UNITY_2021_3_9 || UNITY_2021_3_10 || UNITY_2021_3_11 || UNITY_2021_3_12 || UNITY_2021_3_13 || UNITY_2021_3_14 || UNITY_2021_3_15 || UNITY_2021_3_16 || UNITY_2021_3_17) #define HAS_FIND_FIRST_OBJECT_BY_TYPE #endif // 2020.3.45f1 or newer (48 is the final 2020.3 patch version) #if UNITY_2020_3 && (UNITY_2020_3_45 || UNITY_2020_3_46 || UNITY_2020_3_47 || UNITY_2020_3_48) #define HAS_FIND_FIRST_OBJECT_BY_TYPE #endif namespace UnityEngine.XR.Interaction.Toolkit.Utilities { /// /// Utility methods for locating component instances. /// /// The component type. static class ComponentLocatorUtility where T : Component { /// /// Cached reference to a found component of type . /// static T s_ComponentCache; /// /// Cached reference to a found component of type . /// internal static T componentCache => s_ComponentCache; /// /// Last frame that was called. /// static int s_LastTryFindFrame = -1; static bool FindWasPerformedThisFrame() => s_LastTryFindFrame == Time.frameCount; /// /// Find or create a new GameObject with component . /// /// Returns the found or created component. /// /// Does not include inactive GameObjects when finding the component, but if a component was previously created /// as a direct result of this class, it will return that component even if the GameObject is now inactive. /// public static T FindOrCreateComponent() { if (s_ComponentCache == null) { s_ComponentCache = Find(); if (s_ComponentCache == null) s_ComponentCache = new GameObject(typeof(T).Name, typeof(T)).GetComponent(); } return s_ComponentCache; } /// /// Find a component . /// /// Returns the found component, or if one could not be found. /// /// Does not include inactive GameObjects when finding the component, but if a component was previously created /// as a direct result of this class, it will return that component even if the GameObject is now inactive. /// public static T FindComponent() { TryFindComponent(out var component); return component; } /// /// Find a component . /// /// When this method returns, contains the found component, or if one could not be found. /// Returns if the component exists, otherwise returns . /// /// Does not include inactive GameObjects when finding the component, but if a component was previously created /// as a direct result of this class, it will return that component even if the GameObject is now inactive. /// /// public static bool TryFindComponent(out T component) { if (s_ComponentCache != null) { component = s_ComponentCache; return true; } s_ComponentCache = Find(); component = s_ComponentCache; return component != null; } /// /// Find a component . /// /// When this method returns, contains the found component, or if one could not be found. /// If , this method will only perform if it has not already been unsuccessfully called this frame. /// Returns if the component exists, otherwise returns . /// This function will return a cached component from a previous search regardless if is . internal static bool TryFindComponent(out T component, bool limitTryFindPerFrame) { // If a search for this component has already been unsuccessfully performed this frame, don't search again. if (limitTryFindPerFrame && FindWasPerformedThisFrame() && s_ComponentCache == null) { component = null; return false; } return TryFindComponent(out component); } static T Find() { s_LastTryFindFrame = Time.frameCount; #if HAS_FIND_FIRST_OBJECT_BY_TYPE // Preferred API return Object.FindFirstObjectByType(); #else // Fallback API return Object.FindObjectOfType(); #endif } } }