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
}
}