// // /*=============================================================================== // // Copyright (C) 2025 PhantomsXR Ltd. All Rights Reserved. // // // // This file is part of the Phantom.XRMOD.QuestModule.Runtime. // // // // The XR-MOD cannot be copied, distributed, or made available to // // third-parties for commercial purposes without written permission of PhantomsXR Ltd. // // // // Contact nswell@phantomsxr.com for licensing requests. // // ===============================================================================*/ using System; using Phantom.XRMOD.ActionNotification.Runtime; using Phantom.XRMOD.Core.Runtime; using Phantom.XRMOD.Core.Runtime.Enums; using Phantom.XRMOD.Models.Runtime; using Phantom.XRMOD.XRMODUtilites.Runtime; using UnityEngine; namespace Phantom.XRMOD.QuestModule.Runtime { /// /// The main module class for Meta Quest support in XR-MOD. /// /// This class implements the interface and is responsible for managing the lifecycle of Quest-specific features /// such as Mixed Reality, Occlusion, and Meshing. It listens for configuration changes and initializes the appropriate systems. /// /// public class MetaQuestModule : IModule { readonly RuntimeExperienceConfig configures = IocContainer.GetIoc.Resolve(); /// /// Initializes a new instance of the class. /// /// Subscribes to configuration updates and notification center events. /// call to register necessary components. /// /// public MetaQuestModule() { configures.CurrentConfigures.OnValueChanged += OnConfigUpdated; ActionNotificationCenter.DefaultCenter.AddObserver(RemoveFeatureDecorators, nameof(ActionParameterDataType.RemoveFeatures)); MakeSureDependencies(); } /// /// Starts the module. /// /// Posts a notification to fetch project details. /// /// /// True if started successfully, otherwise false. public bool StartModule() { try { ActionNotificationCenter.DefaultCenter.PostNotification( nameof(ActionParameterDataType.FetchProjectDetail), new BaseNotificationData()); return true; } catch (Exception tmp_Exception) { Debug.LogError(tmp_Exception); return false; } } /// /// Pauses the module. /// /// Always returns true. public bool PauseModule() { return true; } /// /// Stops the module and unregisters dependencies from the IoC container. /// /// Always returns true. public bool StopModule() { IocContainer.GetIoc.UnRegister(); IocContainer.GetIoc.UnRegister(); IocContainer.GetIoc.UnRegister(); IocContainer.GetIoc.UnRegister(); IocContainer.GetIoc.UnRegister(); IocContainer.GetIoc.UnRegister(); IocContainer.GetIoc.UnRegister(); IocContainer.GetIoc.UnRegister(); IocContainer.GetIoc.UnRegister(); return true; } /// /// Checks if the module is available on the current platform. /// /// Always returns true. public bool IsModuleAvailability() { return true; } /// /// Registers necessary dependencies (Models, Commands, Decorators) into the IoC container. /// public void MakeSureDependencies() { IocContainer.GetIoc.Register(new ArchitectureComponentsModel()); IocContainer.GetIoc.Register(new XRRuntimeContextDataModel()); IocContainer.GetIoc.Register(new MetaQuestMeshingDecorator()); IocContainer.GetIoc.Register(new MetaQuestOcclusionDecorator()); IocContainer.GetIoc.Register(new BuildMetaQuestMRFeatureCommand()); IocContainer.GetIoc.Register(new BuildMetaQuestMeshFeatureCommand()); IocContainer.GetIoc.Register(new BuildMetaQuestSceneCaptureCommand()); IocContainer.GetIoc.Register(new BuildXRAlgorithmLifeControllerCommand()); IocContainer.GetIoc.Register(new BuildMetaQuestLocomotionFeatureCommand()); IocContainer.GetIoc.Register(new BuildMetaQuestInteracterSwitcherFeatureCommand()); } /// /// Callback to remove feature decorators when receiving the 'RemoveFeatures' notification. /// /// Notification data containing the project name. private void RemoveFeatureDecorators(BaseNotificationData _data) { var tmp_ProjectName = _data.BaseData; if (string.IsNullOrEmpty(tmp_ProjectName)) { Debug.LogError("Can not removed feature. Because project name is empty."); return; } } /// /// Validates and parses the configuration model. /// /// The configuration model to check. /// True if the configuration is valid or updated successfully, false otherwise. private bool CheckConfig(IModel _config) { if (_config is XRConfiguresModel _) return true; configures.CurrentConfigures.OnValueChanged -= OnConfigUpdated; if (configures == null || string.IsNullOrEmpty(configures.MetaData)) return false; configures.CurrentConfigures.Value = JsonUtility.FromJson(configures.MetaData); return true; } /// /// Ensures the appropriate algorithm features are executed based on the algorithm type. /// /// The type of algorithm (e.g., Meshing, Anchor). private void MakeSureAlgorithm(AlgorithmType _arAlgorithmType) { ICommand tmp_XRFeatureCommand = null; switch (_arAlgorithmType) { case AlgorithmType.Anchor: break; case AlgorithmType.Immersal: break; case AlgorithmType.Meshing: tmp_XRFeatureCommand = IocContainer.GetIoc.Resolve(); break; case AlgorithmType.None: break; default: throw new ArgumentOutOfRangeException(nameof(_arAlgorithmType), _arAlgorithmType, null); } tmp_XRFeatureCommand?.Execute(); } /// /// Adds feature decorators based on the configuration (e.g., Mixed Reality, Occlusion). /// /// The Quest configuration model. private void AddFeatureDecorator(XRConfiguresModel _config) { if (_config.MixedReality) { IocContainer.GetIoc.Resolve().Execute(); } if (_config.UseOcclusion) { IocContainer.GetIoc.Resolve().Execute(); } } /// /// Callback invoked when the module configuration is updated. /// /// Updates the current configuration value, checks device compatibility, and establishes feature decorators and algorithms. /// /// /// The updated configuration model. private void OnConfigUpdated(BaseExperienceConfigModel _config) { if (!CheckConfig(_config)) return; if (configures.CurrentConfigures.Value.SDKDeviceType != SDKDeviceType.Quest) { string tmp_LogInfo = "This experience is not available for this device."; APICallback.ThrowException(tmp_LogInfo, -1); Debug.LogError(tmp_LogInfo); return; } AddFeatureDecorator(configures.CurrentConfigures.Value as XRConfiguresModel); MakeSureAlgorithm(configures.CurrentConfigures.Value.Algorithm); } } }