// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using Microsoft.MixedReality.Toolkit.Boundary; using Microsoft.MixedReality.Toolkit.CameraSystem; using Microsoft.MixedReality.Toolkit.Diagnostics; using Microsoft.MixedReality.Toolkit.Input; using Microsoft.MixedReality.Toolkit.SceneSystem; using Microsoft.MixedReality.Toolkit.SpatialAwareness; using Microsoft.MixedReality.Toolkit.Teleport; using System; using System.Collections.Generic; using UnityEngine; namespace Microsoft.MixedReality.Toolkit { /// /// Utility class to easily access references to core runtime Mixed Reality Toolkit Services /// If deallocating and re-allocating a new system at runtime, ResetCacheReferences() should be used to get a proper reference /// public static class CoreServices { private static IMixedRealityBoundarySystem boundarySystem; /// /// Cached reference to the active instance of the boundary system. /// If system is destroyed, reference will be invalid. Please use ResetCacheReferences() /// public static IMixedRealityBoundarySystem BoundarySystem => boundarySystem ?? (boundarySystem = GetService()); private static IMixedRealityCameraSystem cameraSystem; /// /// Cached reference to the active instance of the camera system. /// If system is destroyed, reference will be invalid. Please use ResetCacheReferences() /// public static IMixedRealityCameraSystem CameraSystem => cameraSystem ?? (cameraSystem = GetService()); private static IMixedRealityDiagnosticsSystem diagnosticsSystem; /// /// Cached reference to the active instance of the diagnostics system. /// If system is destroyed, reference will be invalid. Please use ResetCacheReferences() /// public static IMixedRealityDiagnosticsSystem DiagnosticsSystem => diagnosticsSystem ?? (diagnosticsSystem = GetService()); private static IMixedRealityFocusProvider focusProvider; /// /// Cached reference to the active instance of the focus provider. /// If system is destroyed, reference will be invalid. Please use ResetCacheReferences() /// public static IMixedRealityFocusProvider FocusProvider => focusProvider ?? (focusProvider = GetService()); private static IMixedRealityInputSystem inputSystem; /// /// Cached reference to the active instance of the input system. /// If system is destroyed, reference will be invalid. Please use ResetCacheReferences() /// public static IMixedRealityInputSystem InputSystem => inputSystem ?? (inputSystem = GetService()); private static IMixedRealityRaycastProvider raycastProvider; /// /// Cached reference to the active instance of the raycast provider. /// If system is destroyed, reference will be invalid. Please use ResetCacheReferences() /// public static IMixedRealityRaycastProvider RaycastProvider => raycastProvider ?? (raycastProvider = GetService()); private static IMixedRealitySceneSystem sceneSystem; /// /// Cached reference to the active instance of the scene system. /// If system is destroyed, reference will be invalid. Please use ResetCacheReferences() /// public static IMixedRealitySceneSystem SceneSystem => sceneSystem ?? (sceneSystem = GetService()); private static IMixedRealitySpatialAwarenessSystem spatialAwarenessSystem; /// /// Cached reference to the active instance of the spatial awareness system. /// If system is destroyed, reference will be invalid. Please use ResetCacheReferences() /// public static IMixedRealitySpatialAwarenessSystem SpatialAwarenessSystem => spatialAwarenessSystem ?? (spatialAwarenessSystem = GetService()); private static IMixedRealityTeleportSystem teleportSystem; /// /// Cached reference to the active instance of the teleport system. /// If system is destroyed, reference will be invalid. Please use ResetCacheReferences() /// public static IMixedRealityTeleportSystem TeleportSystem => teleportSystem ?? (teleportSystem = GetService()); /// /// Resets all cached system references to null /// public static void ResetCacheReferences() { serviceCache.Clear(); boundarySystem = null; cameraSystem = null; diagnosticsSystem = null; focusProvider = null; inputSystem = null; raycastProvider = null; sceneSystem = null; spatialAwarenessSystem = null; teleportSystem = null; } /// /// Clears the cache of the reference with key of given type if present and applicable /// /// interface of service to key against. Must be of type IMixedRealityService /// true if successfully cleared, false otherwise public static bool ResetCacheReference(Type serviceType) { if (typeof(IMixedRealityService).IsAssignableFrom(serviceType)) { if (serviceCache.ContainsKey(serviceType)) { serviceCache.Remove(serviceType); ResetCacheReferenceFromType(serviceType); return true; } } else { Debug.Log("Cache only contains types that implement IMixedRealityService"); } return false; } private static void ResetCacheReferenceFromType(Type serviceType) { if (typeof(IMixedRealityBoundarySystem).IsAssignableFrom(serviceType)) { boundarySystem = null; } else if (typeof(IMixedRealityCameraSystem).IsAssignableFrom(serviceType)) { cameraSystem = null; } else if (typeof(IMixedRealityDiagnosticsSystem).IsAssignableFrom(serviceType)) { diagnosticsSystem = null; } else if (typeof(IMixedRealityFocusProvider).IsAssignableFrom(serviceType)) { focusProvider = null; } else if (typeof(IMixedRealityInputSystem).IsAssignableFrom(serviceType)) { inputSystem = null; } else if (typeof(IMixedRealityRaycastProvider).IsAssignableFrom(serviceType)) { raycastProvider = null; } else if (typeof(IMixedRealitySceneSystem).IsAssignableFrom(serviceType)) { sceneSystem = null; } else if (typeof(IMixedRealitySpatialAwarenessSystem).IsAssignableFrom(serviceType)) { sceneSystem = null; } else if (typeof(IMixedRealityTeleportSystem).IsAssignableFrom(serviceType)) { teleportSystem = null; } } /// /// Gets first matching or extension thereof for CoreServices.InputSystem /// public static T GetInputSystemDataProvider() where T : IMixedRealityInputDeviceManager { return GetDataProvider(InputSystem); } /// /// Gets first matching or extension thereof for CoreServices.SpatialAwarenessSystem /// public static T GetSpatialAwarenessSystemDataProvider() where T : IMixedRealitySpatialAwarenessObserver { return GetDataProvider(SpatialAwarenessSystem); } /// /// Gets first matching or extension thereof for CoreServices.CameraSystem /// public static T GetCameraSystemDataProvider() where T : IMixedRealityCameraSettingsProvider { return GetDataProvider(CameraSystem); } /// /// Gets first matching data provider of provided type T registered to the provided mixed reality service. /// /// Type of data provider to return. Must implement and/or extend from /// This function will attempt to get first available data provider registered to this service. /// /// Service parameter is expected to implement . If not, then will return default(T) /// public static T GetDataProvider(IMixedRealityService service) where T : IMixedRealityDataProvider { if (service is IMixedRealityDataProviderAccess dataProviderAccess) { return dataProviderAccess.GetDataProvider(); } return default(T); } // We do not want to keep a service around so use WeakReference private static readonly Dictionary> serviceCache = new Dictionary>(); private static T GetService() where T : IMixedRealityService { Type serviceType = typeof(T); // See if we already have a WeakReference entry for this service type if (serviceCache.TryGetValue(serviceType, out WeakReference weakService)) { IMixedRealityService svc; // If our reference object is still alive, return it if (weakService.TryGetTarget(out svc)) { return (T)svc; } // Our reference object has been collected by the GC. Try to get the latest service if available serviceCache.Remove(serviceType); } // This is the first request for the given service type. See if it is available and if so, add entry T service; if (!MixedRealityServiceRegistry.TryGetService(out service)) { return default(T); } serviceCache.Add(serviceType, new WeakReference(service, false)); return service; } } }