using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using UnityEngine; using UnityEngine.XR.Management; using UnityEditor.XR.Management.Metadata; namespace UnityEditor.XR.Management { #if UNITY_EDITOR [InitializeOnLoad] #endif /// Container class that holds general settings for each build target group installed in Unity. public class XRGeneralSettingsPerBuildTarget : ScriptableObject, ISerializationCallbackReceiver { [SerializeField] List Keys = new List(); [SerializeField] List Values = new List(); Dictionary Settings = new Dictionary(); #if UNITY_EDITOR static XRGeneralSettingsPerBuildTarget() { EditorApplication.playModeStateChanged -= PlayModeStateChanged; EditorApplication.playModeStateChanged += PlayModeStateChanged; } // Simple class to give us updates when the asset database changes. class AssetCallbacks : AssetPostprocessor { static bool m_Upgrade = true; static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) { if (m_Upgrade) { m_Upgrade = false; BeginUpgradeSettings(); } } static void BeginUpgradeSettings() { string searchText = "t:XRGeneralSettings"; string[] assets = AssetDatabase.FindAssets(searchText); if (assets.Length > 0) { string path = AssetDatabase.GUIDToAssetPath(assets[0]); XRGeneralSettingsUpgrade.UpgradeSettingsToPerBuildTarget(path); } } } void OnEnable() { foreach (var setting in Settings.Values) { var assignedSettings = setting.AssignedSettings; if (assignedSettings == null) continue; var filteredLoaders = from ldr in assignedSettings.activeLoaders where ldr != null select ldr; assignedSettings.TrySetLoaders(filteredLoaders.ToList()); } XRGeneralSettings.Instance = XRGeneralSettingsForBuildTarget(BuildTargetGroup.Standalone); } static void PlayModeStateChanged(PlayModeStateChange state) { XRGeneralSettingsPerBuildTarget buildTargetSettings = null; EditorBuildSettings.TryGetConfigObject(XRGeneralSettings.k_SettingsKey, out buildTargetSettings); if (buildTargetSettings == null) { buildTargetSettings = GetOrCreate(); } XRGeneralSettings instance = buildTargetSettings.SettingsForBuildTarget(BuildTargetGroup.Standalone); if (instance == null || !instance.InitManagerOnStart) return; instance.InternalPlayModeStateChanged(state); } internal static bool ContainsLoaderForAnyBuildTarget(string loaderTypeName) { XRGeneralSettingsPerBuildTarget buildTargetSettings = null; EditorBuildSettings.TryGetConfigObject(XRGeneralSettings.k_SettingsKey, out buildTargetSettings); if (buildTargetSettings == null) return false; foreach (var settings in buildTargetSettings.Settings.Values) { if (XRPackageMetadataStore.IsLoaderAssigned(settings.Manager, loaderTypeName)) return true; } return false; } [MethodImpl(MethodImplOptions.Synchronized)] internal static XRGeneralSettingsPerBuildTarget GetOrCreate() { EditorBuildSettings.TryGetConfigObject(XRGeneralSettings.k_SettingsKey, out var generalSettings); if (generalSettings == null) { string searchText = "t:XRGeneralSettings"; string[] assets = AssetDatabase.FindAssets(searchText); if (assets.Length > 0) { string path = AssetDatabase.GUIDToAssetPath(assets[0]); generalSettings = AssetDatabase.LoadAssetAtPath(path, typeof(XRGeneralSettingsPerBuildTarget)) as XRGeneralSettingsPerBuildTarget; } } if (generalSettings == null) { generalSettings = CreateInstance(typeof(XRGeneralSettingsPerBuildTarget)) as XRGeneralSettingsPerBuildTarget; string assetPath = EditorUtilities.GetAssetPathForComponents(EditorUtilities.s_DefaultGeneralSettingsPath); if (!string.IsNullOrEmpty(assetPath)) { assetPath = Path.Combine(assetPath, "XRGeneralSettings.asset"); AssetDatabase.CreateAsset(generalSettings, assetPath); } } EditorBuildSettings.AddConfigObject(XRGeneralSettings.k_SettingsKey, generalSettings, true); return generalSettings; } #endif /// /// Query this settings store to see if there are settings for a specific . /// /// Build target to check /// True if there are settings, otherwise false. public bool HasSettingsForBuildTarget(BuildTargetGroup buildTargetGroup) { return SettingsForBuildTarget(buildTargetGroup) != null; } /// /// Create default settings for a given build target. /// /// This will overwrite any current settings for that build target. /// /// Build target to create default settings for. public void CreateDefaultSettingsForBuildTarget(BuildTargetGroup buildTargetGroup) { var settings = ScriptableObject.CreateInstance() as XRGeneralSettings; SetSettingsForBuildTarget(buildTargetGroup, settings); settings.name = $"{buildTargetGroup.ToString()} Settings"; AssetDatabase.AddObjectToAsset(settings, AssetDatabase.GetAssetOrScenePath(this)); AssetDatabase.SaveAssets(); } /// Set specific settings for a given build target. /// /// An enum specifying which platform group this build is for. /// An instance of to assign for the given key. public void SetSettingsForBuildTarget(BuildTargetGroup targetGroup, XRGeneralSettings settings) { // Ensures the editor's "runtime instance" is the most current for standalone settings if (targetGroup == BuildTargetGroup.Standalone) XRGeneralSettings.Instance = settings; Settings[targetGroup] = settings; } /// Get specific settings for a given build target. /// An enum specifying which platform group this build is for. /// The instance of assigned to the key, or null if not. public XRGeneralSettings SettingsForBuildTarget(BuildTargetGroup targetGroup) { XRGeneralSettings ret = null; Settings.TryGetValue(targetGroup, out ret); return ret; } /// /// Check if current settings instance has an instance of . /// /// An enum specifying which platform group this build is for. /// True if it exists, false otherwise. public bool HasManagerSettingsForBuildTarget(BuildTargetGroup targetGroup) { return (SettingsForBuildTarget(targetGroup)?.Manager ?? null) != null; } /// /// Create a new default instance of for a build target. Requires /// that the there exists a settings instance for the build target. If there isn't, then one is created. /// /// This will overwrite any current settings for that build target. /// /// An enum specifying which platform group this build is for. public void CreateDefaultManagerSettingsForBuildTarget(BuildTargetGroup targetGroup) { if (!HasSettingsForBuildTarget(targetGroup)) CreateDefaultSettingsForBuildTarget(targetGroup); var xrManagerSettings = ScriptableObject.CreateInstance() as XRManagerSettings; xrManagerSettings.name = $"{targetGroup.ToString()} Providers"; SettingsForBuildTarget(targetGroup).Manager = xrManagerSettings; AssetDatabase.AddObjectToAsset(xrManagerSettings, AssetDatabase.GetAssetOrScenePath(this)); AssetDatabase.SaveAssets(); } /// /// Return the current instance of for a build target. /// /// An enum specifying which platform group this build is for. /// public XRManagerSettings ManagerSettingsForBuildTarget(BuildTargetGroup targetGroup) { return SettingsForBuildTarget(targetGroup)?.Manager ?? null; } /// Serialization override. public void OnBeforeSerialize() { Keys.Clear(); Values.Clear(); foreach (var kv in Settings) { Keys.Add(kv.Key); Values.Add(kv.Value); } } /// Serialization override. public void OnAfterDeserialize() { Settings = new Dictionary(); for (int i = 0; i < Math.Min(Keys.Count, Values.Count); i++) { Settings.Add(Keys[i], Values[i]); } } /// Given a build target, get the general settings container assigned to it. /// An enum specifying which platform group this build is for. /// The instance of assigned to the key, or null if not. public static XRGeneralSettings XRGeneralSettingsForBuildTarget(BuildTargetGroup targetGroup) { XRGeneralSettingsPerBuildTarget buildTargetSettings = null; EditorBuildSettings.TryGetConfigObject(XRGeneralSettings.k_SettingsKey, out buildTargetSettings); if (buildTargetSettings == null) return null; return buildTargetSettings.SettingsForBuildTarget(targetGroup); } } }