using System; using System.Collections.Generic; using UnityEngine; using UnityEditor.XR.Management.Metadata; namespace UnityEditor.XR.Management { /// Interface for specifying package initialization information public interface XRPackageInitializationBase { /// Package name property /// The name of the package string PackageName { get; } /// The loader full type name for this package /// Loader fulltype name string LoaderFullTypeName { get; } /// The loader type name for this package /// Loader type name string LoaderTypeName { get; } /// The settings full type name for this package /// Settings full type name string SettingsFullTypeName { get; } /// The settings type name for this package /// Settings type name string SettingsTypeName { get; } /// Package initialization key /// The init key for the package string PackageInitKey { get; } /// Initialize package settings /// The scriptable object instance to initialize /// True if successful, false if not. bool PopulateSettingsOnInitialization(ScriptableObject obj); } [InitializeOnLoad] class XRPackageInitializationBootstrap { static XRPackageInitializationBootstrap() { if (!EditorApplication.isPlayingOrWillChangePlaymode) { EditorApplication.update += BeginPackageInitialization; } EditorApplication.playModeStateChanged += PlayModeStateChanged; } private static void PlayModeStateChanged(PlayModeStateChange state) { switch (state) { case PlayModeStateChange.EnteredPlayMode: BeginPackageInitialization(); break; case PlayModeStateChange.EnteredEditMode: BeginPackageInitialization(); break; } } internal static void BeginPackageInitialization() { EditorApplication.update -= BeginPackageInitialization; foreach (var t in TypeLoaderExtensions.GetAllTypesWithInterface()) { if (t.IsInterface || t.FullName.Contains("Unity.XR.Management.TestPackage") || t.FullName.Contains("UnityEditor.XR.Management.Metadata.KnownPackages")) continue; IXRPackage package = Activator.CreateInstance(t) as IXRPackage; if (package == null) { Debug.LogError($"Unable to find an implementation for expected package type {t.FullName}."); continue; } InitPackage(package); } foreach (var t in TypeLoaderExtensions.GetAllTypesWithInterface()) { if (t.IsInterface) continue; XRPackageInitializationBase packageInit = Activator.CreateInstance(t) as XRPackageInitializationBase; if (packageInit == null) { Debug.LogError($"Unable to find an implementation for expected package type {t.FullName}."); continue; } InitPackage(packageInit); } if (XRSettingsManager.Instance != null) XRSettingsManager.Instance.ResetUi = true; } internal static void InitPackage(IXRPackage package) { var packageMetadata = package.metadata; if (packageMetadata == null) { Debug.LogError($"Package {package.GetType().Name} has a package definition but has no metadata. Skipping initialization."); return; } XRPackageMetadataStore.AddPluginPackage(package); if (!InitializePackageFromMetadata(package, packageMetadata)) { Debug.LogWarning( String.Format("{0} package Initialization not completed. You will need to create any instances of the loaders and settings manually before you can use the intended XR Plug-in Package.", packageMetadata.packageName)); } } static bool InitializePackageFromMetadata(IXRPackage package, IXRPackageMetadata packageMetadata) { bool ret = true; ret = ret && InitializeLoaderFromMetadata(packageMetadata.packageName, packageMetadata.loaderMetadata); ret = ret && InitializeSettingsFromMetadata(package, packageMetadata.packageName, packageMetadata.settingsType); return ret; } static bool InitializeLoaderFromMetadata(string packageName, List loaderMetadatas) { if (String.IsNullOrEmpty(packageName)) return false; if (loaderMetadatas == null || loaderMetadatas.Count == 0) { Debug.LogWarning($"Package {packageName} has no loader metadata. Skipping loader initialization."); return true; } bool ret = true; foreach (var loader in loaderMetadatas) { bool hasInstance = EditorUtilities.AssetDatabaseHasInstanceOfType(loader.loaderType); if (!hasInstance) { var obj = EditorUtilities.CreateScriptableObjectInstance(loader.loaderType, EditorUtilities.GetAssetPathForComponents(EditorUtilities.s_DefaultLoaderPath)); hasInstance = (obj != null); if (!hasInstance) { Debug.LogError($"Error creating instance of loader {loader.loaderName} for package {packageName}"); } } ret |= hasInstance; } return ret; } static bool InitializeSettingsFromMetadata(IXRPackage package, string packageName, string settingsType) { if (String.IsNullOrEmpty(packageName)) return false; if (settingsType == null) { Debug.LogWarning($"Package {packageName} has no settings metadata. Skipping settings initialization."); return true; } bool ret = EditorUtilities.AssetDatabaseHasInstanceOfType(settingsType); if (!ret) { var obj = EditorUtilities.CreateScriptableObjectInstance( settingsType, EditorUtilities.GetAssetPathForComponents(EditorUtilities.s_DefaultSettingsPath)); ret = package.PopulateNewSettingsInstance(obj); } return ret; } static void InitPackage(XRPackageInitializationBase packageInit) { if (!InitializeLoaderInstance(packageInit)) { Debug.LogWarning( String.Format("{0} Loader Initialization not completed. You will need to create an instance of the loader manually before you can use the intended XR Plug-in Package.", packageInit.PackageName)); } if (!InitializeSettingsInstance(packageInit)) { Debug.LogWarning( String.Format("{0} Settings Initialization not completed. You will need to create an instance of settings to customize options specific to this package.", packageInit.PackageName)); } } static bool InitializeLoaderInstance(XRPackageInitializationBase packageInit) { bool ret = EditorUtilities.AssetDatabaseHasInstanceOfType(packageInit.LoaderTypeName); if (!ret) { var obj = EditorUtilities.CreateScriptableObjectInstance(packageInit.LoaderFullTypeName, EditorUtilities.GetAssetPathForComponents(EditorUtilities.s_DefaultLoaderPath)); ret = (obj != null); } return ret; } static bool InitializeSettingsInstance(XRPackageInitializationBase packageInit) { bool ret = EditorUtilities.AssetDatabaseHasInstanceOfType(packageInit.SettingsTypeName); if (!ret) { var obj = EditorUtilities.CreateScriptableObjectInstance(packageInit.SettingsFullTypeName, EditorUtilities.GetAssetPathForComponents(EditorUtilities.s_DefaultSettingsPath)); ret = packageInit.PopulateSettingsOnInitialization(obj); } return ret; } } }