using System; using System.Collections.Generic; #if !UNITY_2019_2_OR_NEWER using UnityEngine.Experimental; #endif #if USE_XR_MANAGEMENT using UnityEngine.XR.Management; #endif namespace UnityEngine.XR.ARFoundation { /// /// A base class for subsystems whose lifetime is managed by a MonoBehaviour. /// /// The Subsystem which provides this manager data. /// The SubsystemDescriptor required to create the Subsystem. public class SubsystemLifecycleManager : MonoBehaviour where TSubsystem : Subsystem where TSubsystemDescriptor : SubsystemDescriptor { /// /// Get the TSubsystem whose lifetime this component manages. /// public TSubsystem subsystem { get; private set; } /// /// The descriptor for the subsystem. /// /// /// The descriptor for the subsystem. /// public TSubsystemDescriptor descriptor { get { return (subsystem == null) ? null : subsystem.SubsystemDescriptor; } } bool m_CleanupSubsystemOnDestroy = true; /// /// Creates a TSubsystem. /// /// The first Subsystem of matching the TSubsystemDescriptor, or null if there aren't any. protected virtual TSubsystem CreateSubsystem() { SubsystemManager.GetSubsystemDescriptors(s_SubsystemDescriptors); if (s_SubsystemDescriptors.Count > 0) { var descriptor = s_SubsystemDescriptors[0]; if (s_SubsystemDescriptors.Count > 1) { Debug.LogWarningFormat("Multiple {0} found. Using {1}", typeof(TSubsystem).Name, descriptor.id); } return descriptor.Create(); } else { return null; } } /// /// Creates a subsystem if subsystem is null. /// protected void CreateSubsystemIfNecessary() { // Use the subsystem that has been instantiated by XR Management // if available, otherwise create the subsystem. if (subsystem == null) { subsystem = GetActiveSubsystemInstance(); // If the subsystem has already been created by XR management, it controls the lifetime // of the subsystem. if (subsystem != null) m_CleanupSubsystemOnDestroy = false; } if (subsystem == null) subsystem = CreateSubsystem(); } /// /// Returns the active TSubsystem instance if present, otherwise returns null. /// protected TSubsystem GetActiveSubsystemInstance() { TSubsystem activeSubsystem = null; #if USE_XR_MANAGEMENT // If the XR management package has been included, query the currently // active loader for the created subsystem, if one exists. if (XRGeneralSettings.Instance != null && XRGeneralSettings.Instance.Manager != null) { XRLoader loader = XRGeneralSettings.Instance.Manager.activeLoader; if (loader != null) activeSubsystem = loader.GetLoadedSubsystem(); } #endif // If XR management is not used or no loader has been set, check for // any active subsystem instances in the SubsystemManager. if (activeSubsystem == null) { SubsystemManager.GetInstances(s_SubsystemInstances); #if !UNITY_2019_3_OR_NEWER foreach (var instance in s_SubsystemInstances) { if (!s_DestroyedSubsystemTypes.Contains(instance)) { return instance; } } #else if (s_SubsystemInstances.Count > 0) { activeSubsystem = s_SubsystemInstances[0]; } #endif } return activeSubsystem; } /// /// Creates the TSubsystem. /// protected virtual void OnEnable() { CreateSubsystemIfNecessary(); if (subsystem != null) { OnBeforeStart(); // The derived class may disable the // component if it has invalid state if (enabled) { subsystem.Start(); OnAfterStart(); } } } /// /// Stops the TSubsystem. /// protected virtual void OnDisable() { if (subsystem != null) subsystem.Stop(); } /// /// Destroys the TSubsystem. /// protected virtual void OnDestroy() { if (m_CleanupSubsystemOnDestroy && subsystem != null) { #if !UNITY_2019_3_OR_NEWER s_DestroyedSubsystemTypes.Add(subsystem); #endif subsystem.Destroy(); } subsystem = null; } /// /// Invoked after creating the subsystem and before calling Start on it. /// The is not null. /// protected virtual void OnBeforeStart() { } /// /// Invoked after calling Start on it the Subsystem. /// The is not null. /// protected virtual void OnAfterStart() { } static List s_SubsystemDescriptors = new List(); static List s_SubsystemInstances = new List(); #if !UNITY_2019_3_OR_NEWER static HashSet s_DestroyedSubsystemTypes = new HashSet(); #endif } }