// // /*===============================================================================
// // 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);
}
}
}