XRPackageMetadata.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using UnityEditor;
  7. using UnityEngine;
  8. using UnityEditor.PackageManager;
  9. using UnityEditor.PackageManager.Requests;
  10. using UnityEngine.XR.Management;
  11. namespace UnityEditor.XR.Management.Metadata
  12. {
  13. /// <summary>
  14. /// Provides an interface for describing specific loader metadata. Package authors should implement
  15. /// this interface for each loader they provide in their package.
  16. /// </summary>
  17. public interface IXRLoaderMetadata
  18. {
  19. /// <summary>
  20. /// The user facing name for this loader. Will be used to populate the
  21. /// list in the XR Plug-in Management UI.
  22. /// </summary>
  23. string loaderName { get; }
  24. /// <summary>
  25. /// The full type name for this loader. This is used to allow management to find and
  26. /// create instances of supported loaders for your package.
  27. ///
  28. /// When your package is first installed, the XR Plug-in Management system will
  29. /// use this information to create instances of your loaders in Assets/XR/Loaders.
  30. /// </summary>
  31. string loaderType { get; }
  32. /// <summary>
  33. /// The full list of supported buildtargets for this loader. This allows the UI to only show the
  34. /// loaders appropriate for a specific build target.
  35. ///
  36. /// Returning an empty list or a list containing just <see cref="https://docs.unity3d.com/ScriptReference/BuildTargetGroup.Unknown.html">BuildTargetGroup.Unknown</see>. will make this
  37. /// loader invisible in the ui.
  38. /// </summary>
  39. List<BuildTargetGroup> supportedBuildTargets { get; }
  40. }
  41. /// <summary>
  42. /// Top level package metadata interface. Create an instance oif this interface to
  43. /// provide metadata information for your package.
  44. /// </summary>
  45. public interface IXRPackageMetadata
  46. {
  47. /// <summary>
  48. /// User facing package name. Should be the same as the value for the
  49. /// displayName keyword in the package.json file.
  50. /// </summary>
  51. string packageName { get; }
  52. /// <summary>
  53. /// The package id used to track and install the package. Must be the same value
  54. /// as the name keyword in the package.json file, otherwise installation will
  55. /// not be possible.
  56. /// </summary>
  57. string packageId { get; }
  58. /// <summary>
  59. /// This is the full type name for the settings type for your package.
  60. ///
  61. /// When your package is first installed, the XR Plug-in Management system will
  62. /// use this information to create an instance of your settings in Assets/XR/Settings.
  63. /// </summary>
  64. string settingsType { get; }
  65. /// <summary>
  66. /// List of <see cref="IXRLoaderMetadata"/> instances describing the data about the loaders
  67. /// your package supports.
  68. /// </summary>
  69. List<IXRLoaderMetadata> loaderMetadata { get; }
  70. }
  71. /// <summary>
  72. /// Provide access to the metadata store. Currently only usable as a way to assign and remove loaders
  73. /// to/from an <see cref="XRManagerSettings"/> instance.
  74. /// </summary>
  75. [InitializeOnLoad]
  76. public class XRPackageMetadataStore
  77. {
  78. const string k_WaitingPackmanQuery = "XRMGT Waiting Packman Query.";
  79. const string k_RebuildCache = "XRMGT Rebuilding Cache.";
  80. const string k_InstallingPackage = "XRMGT Installing XR Package.";
  81. const string k_AssigningPackage = "XRMGT Assigning XR Package.";
  82. const string k_UninstallingPackage = "XRMGT Uninstalling XR Package.";
  83. const string k_CachedMDStoreKey = "XR Metadata Store";
  84. static float k_TimeOutDelta = 30f;
  85. [Serializable]
  86. struct KnownPackageInfo
  87. {
  88. public string packageId;
  89. public string verifiedVersion;
  90. }
  91. [Serializable]
  92. struct CachedMDStoreInformation
  93. {
  94. public bool hasAlreadyRequestedData;
  95. public KnownPackageInfo[] knownPackageInfos;
  96. public string[] installedPackages;
  97. public string[] installablePackages;
  98. }
  99. static CachedMDStoreInformation s_CachedMDStoreInformation = new CachedMDStoreInformation()
  100. {
  101. hasAlreadyRequestedData = false,
  102. knownPackageInfos = { },
  103. installedPackages = { },
  104. installablePackages = { },
  105. };
  106. static void LoadCachedMDStoreInformation()
  107. {
  108. string data = SessionState.GetString(k_CachedMDStoreKey, "{}");
  109. s_CachedMDStoreInformation = JsonUtility.FromJson<CachedMDStoreInformation>(data);
  110. }
  111. static void StoreCachedMDStoreInformation()
  112. {
  113. SessionState.EraseString(k_CachedMDStoreKey);
  114. string data = JsonUtility.ToJson(s_CachedMDStoreInformation, true);
  115. SessionState.SetString(k_CachedMDStoreKey, data);
  116. }
  117. enum InstallationState
  118. {
  119. New,
  120. RebuildInstalledCache,
  121. StartInstallation,
  122. Installing,
  123. Assigning,
  124. Complete,
  125. Uninstalling,
  126. Log
  127. }
  128. enum LogLevel
  129. {
  130. Info,
  131. Warning,
  132. Error
  133. }
  134. [Serializable]
  135. struct LoaderAssignmentRequest
  136. {
  137. [SerializeField]
  138. public string packageId;
  139. [SerializeField]
  140. public string loaderType;
  141. [SerializeField]
  142. public BuildTargetGroup buildTargetGroup;
  143. [SerializeField]
  144. public bool needsAddRequest;
  145. [SerializeField]
  146. public ListRequest packageListRequest;
  147. [SerializeField]
  148. public AddRequest packageAddRequest;
  149. [SerializeField]
  150. #pragma warning disable CS0649
  151. public RemoveRequest packageRemoveRequest;
  152. #pragma warning disable CS0649
  153. [SerializeField]
  154. public float timeOut;
  155. [SerializeField]
  156. public InstallationState installationState;
  157. [SerializeField]
  158. public string logMessage;
  159. [SerializeField]
  160. public LogLevel logLevel;
  161. }
  162. [Serializable]
  163. struct LoaderAssignmentRequests
  164. {
  165. [SerializeField]
  166. public List<LoaderAssignmentRequest> activeRequests;
  167. }
  168. static List<LoaderAssignmentRequest> m_AddRequests = new List<LoaderAssignmentRequest>();
  169. static Dictionary<string, IXRPackage> s_Packages = new Dictionary<string, IXRPackage>();
  170. static SearchRequest s_SearchRequest = null;
  171. const string k_DefaultSessionStateString = "DEADBEEF";
  172. static bool SessionStateHasStoredData(string queueName)
  173. {
  174. return SessionState.GetString(queueName, k_DefaultSessionStateString) != XRPackageMetadataStore.k_DefaultSessionStateString;
  175. }
  176. internal static bool isCheckingInstallationRequirements => XRPackageMetadataStore.SessionStateHasStoredData(k_WaitingPackmanQuery);
  177. internal static bool isRebuildingCache => XRPackageMetadataStore.SessionStateHasStoredData(k_RebuildCache);
  178. internal static bool isInstallingPackages => XRPackageMetadataStore.SessionStateHasStoredData(k_InstallingPackage);
  179. internal static bool isUninstallingPackages => XRPackageMetadataStore.SessionStateHasStoredData(k_UninstallingPackage);
  180. internal static bool isAssigningLoaders => XRPackageMetadataStore.SessionStateHasStoredData(k_AssigningPackage);
  181. internal static bool isDoingQueueProcessing
  182. {
  183. get
  184. {
  185. return isCheckingInstallationRequirements || isRebuildingCache || isInstallingPackages || isUninstallingPackages || isAssigningLoaders;
  186. }
  187. }
  188. internal struct LoaderBuildTargetQueryResult
  189. {
  190. public string packageName;
  191. public string packageId;
  192. public string loaderName;
  193. public string loaderType;
  194. }
  195. internal static void MoveMockInListToEnd(List<LoaderBuildTargetQueryResult> loaderList)
  196. {
  197. int index = loaderList.FindIndex((x) => { return String.Compare(x.loaderType, KnownPackages.k_KnownPackageMockHMDLoader) == 0; });
  198. if (index >= 0)
  199. {
  200. var mock = loaderList[index];
  201. loaderList.RemoveAt(index);
  202. loaderList.Add(mock);
  203. }
  204. }
  205. internal static List<LoaderBuildTargetQueryResult> GetAllLoadersForBuildTarget(BuildTargetGroup buildTarget)
  206. {
  207. var ret = from pm in (from p in s_Packages.Values select p.metadata)
  208. from lm in pm.loaderMetadata
  209. where lm.supportedBuildTargets.Contains(buildTarget)
  210. orderby lm.loaderName
  211. select new LoaderBuildTargetQueryResult() { packageName = pm.packageName, packageId = pm.packageId, loaderName = lm.loaderName, loaderType = lm.loaderType };
  212. var retList = ret.Distinct().ToList<LoaderBuildTargetQueryResult>();
  213. MoveMockInListToEnd(retList);
  214. return retList;
  215. }
  216. internal static List<LoaderBuildTargetQueryResult> GetLoadersForBuildTarget(BuildTargetGroup buildTargetGroup)
  217. {
  218. var ret = from pm in (from p in s_Packages.Values select p.metadata)
  219. from lm in pm.loaderMetadata
  220. where lm.supportedBuildTargets.Contains(buildTargetGroup)
  221. orderby lm.loaderName
  222. select new LoaderBuildTargetQueryResult() { packageName = pm.packageName, packageId = pm.packageId, loaderName = lm.loaderName, loaderType = lm.loaderType };
  223. var retList = ret.ToList<LoaderBuildTargetQueryResult>();
  224. MoveMockInListToEnd(retList);
  225. return retList;
  226. }
  227. internal static IXRPackageMetadata GetMetadataForPackage(string packageId)
  228. {
  229. return s_Packages.Values.
  230. Select(x => x.metadata).
  231. FirstOrDefault(xmd => String.Compare(xmd.packageId, packageId) == 0);
  232. }
  233. internal static bool HasInstallablePackageData()
  234. {
  235. return s_CachedMDStoreInformation.installablePackages?.Any() ?? false;
  236. }
  237. internal static bool IsPackageInstalled(string package)
  238. {
  239. return (s_CachedMDStoreInformation.installedPackages?.Contains(package) ?? false)
  240. && File.Exists($"Packages/{package}/package.json");
  241. }
  242. internal static bool IsPackageInstallable(string package)
  243. {
  244. return s_CachedMDStoreInformation.installablePackages?.Contains(package) ?? false;
  245. }
  246. internal static bool IsLoaderAssigned(string loaderTypeName, BuildTargetGroup buildTargetGroup)
  247. {
  248. var settings = XRGeneralSettingsPerBuildTarget.XRGeneralSettingsForBuildTarget(buildTargetGroup);
  249. if (settings == null)
  250. return false;
  251. foreach (var loader in settings.AssignedSettings.loaders)
  252. {
  253. if (loader != null && String.Compare(loader.GetType().FullName, loaderTypeName) == 0)
  254. return true;
  255. }
  256. return false;
  257. }
  258. internal static bool IsLoaderAssigned(XRManagerSettings settings, string loaderTypeName)
  259. {
  260. if (settings == null)
  261. return false;
  262. foreach (var l in settings.loaders)
  263. {
  264. if (l != null && String.Compare(l.GetType().FullName, loaderTypeName) == 0)
  265. return true;
  266. }
  267. return false;
  268. }
  269. internal static void InstallPackageAndAssignLoaderForBuildTarget(string package, string loaderType, BuildTargetGroup buildTargetGroup)
  270. {
  271. var req = new LoaderAssignmentRequest();
  272. req.packageId = package;
  273. req.loaderType = loaderType;
  274. req.buildTargetGroup = buildTargetGroup;
  275. req.installationState = InstallationState.New;
  276. QueueLoaderRequest(req);
  277. }
  278. /// <summary>
  279. /// Assigns a loader of type loaderTypeName to the settings instance. Will instantiate an
  280. /// instance if one can't be found in the users project folder before assigning it.
  281. /// </summary>
  282. /// <param name="settings">An instance of <see cref="XRManagerSettings"/> to add the loader to.</param>
  283. /// <param name="loaderTypeName">The full type name for the loader instance to assign to settings.</param>
  284. /// <param name="buildTargetGroup">The build target group being assigned to.</param>
  285. /// <returns>True if assignment succeeds, false if not.</returns>
  286. public static bool AssignLoader(XRManagerSettings settings, string loaderTypeName, BuildTargetGroup buildTargetGroup)
  287. {
  288. var instance = EditorUtilities.GetInstanceOfTypeWithNameFromAssetDatabase(loaderTypeName);
  289. if (instance == null || !(instance is XRLoader))
  290. {
  291. instance = EditorUtilities.CreateScriptableObjectInstance(loaderTypeName,
  292. EditorUtilities.GetAssetPathForComponents(EditorUtilities.s_DefaultLoaderPath));
  293. if (instance == null)
  294. return false;
  295. }
  296. var assignedLoaders = settings.loaders;
  297. XRLoader newLoader = instance as XRLoader;
  298. if (!assignedLoaders.Contains(newLoader))
  299. {
  300. assignedLoaders.Add(newLoader);
  301. settings.loaders = new List<XRLoader>();
  302. var allLoaders = GetAllLoadersForBuildTarget(buildTargetGroup);
  303. foreach (var ldr in allLoaders)
  304. {
  305. var newInstance = EditorUtilities.GetInstanceOfTypeWithNameFromAssetDatabase(ldr.loaderType) as XRLoader;
  306. if (newInstance != null && assignedLoaders.Contains(newInstance))
  307. {
  308. settings.loaders.Add(newInstance);
  309. #if UNITY_EDITOR
  310. var loaderHelper = newLoader as XRLoaderHelper;
  311. loaderHelper?.WasAssignedToBuildTarget(buildTargetGroup);
  312. #endif
  313. }
  314. }
  315. EditorUtility.SetDirty(settings);
  316. AssetDatabase.SaveAssets();
  317. }
  318. return true;
  319. }
  320. /// <summary>
  321. /// Remove a previously assigned loader from settings. If the loader type is unknown or
  322. /// an instance of the loader can't be found in the project folder no action is taken.
  323. ///
  324. /// Removal will not delete the instance from the project folder.
  325. /// </summary>
  326. /// <param name="settings">An instance of <see cref="XRManagerSettings"/> to add the loader to.</param>
  327. /// <param name="loaderTypeName">The full type name for the loader instance to remove from settings.</param>
  328. /// <param name="buildTargetGroup">The build target group being removed from.</param>
  329. /// <returns>True if removal succeeds, false if not.</returns>
  330. public static bool RemoveLoader(XRManagerSettings settings, string loaderTypeName, BuildTargetGroup buildTargetGroup)
  331. {
  332. var instance = EditorUtilities.GetInstanceOfTypeWithNameFromAssetDatabase(loaderTypeName);
  333. if (instance == null || !(instance is XRLoader))
  334. return false;
  335. XRLoader loader = instance as XRLoader;
  336. if (settings.loaders.Contains(loader))
  337. {
  338. settings.loaders.Remove(loader);
  339. EditorUtility.SetDirty(settings);
  340. AssetDatabase.SaveAssets();
  341. #if UNITY_EDITOR
  342. var loaderHelper = loader as XRLoaderHelper;
  343. loaderHelper?.WasUnassignedFromBuildTarget(buildTargetGroup);
  344. #endif
  345. }
  346. return true;
  347. }
  348. internal static IXRPackage GetPackageForSettingsTypeNamed(string settingsTypeName)
  349. {
  350. var ret = s_Packages.Values.
  351. Where((p => String.Compare(p.metadata.settingsType, settingsTypeName, true) == 0)).
  352. Select((p) => p);
  353. return ret.Any() ? ret.First() : null;
  354. }
  355. internal static string GetCurrentStatusDisplayText()
  356. {
  357. if (XRPackageMetadataStore.isCheckingInstallationRequirements)
  358. {
  359. return "Checking installation requirements for packages...";
  360. }
  361. else if (XRPackageMetadataStore.isRebuildingCache)
  362. {
  363. return "Querying Package Manager for currently installed packages...";
  364. }
  365. else if (XRPackageMetadataStore.isInstallingPackages)
  366. {
  367. return "Installing packages...";
  368. }
  369. else if (XRPackageMetadataStore.isUninstallingPackages)
  370. {
  371. return "Uninstalling packages...";
  372. }
  373. else if (XRPackageMetadataStore.isAssigningLoaders)
  374. {
  375. return "Assigning all requested loaders...";
  376. }
  377. return "";
  378. }
  379. internal static void AddPluginPackage(IXRPackage package)
  380. {
  381. if (s_CachedMDStoreInformation.installedPackages != null && !s_CachedMDStoreInformation.installedPackages.Contains(package.metadata.packageId))
  382. {
  383. List<string> installedPackages = s_CachedMDStoreInformation.installedPackages.ToList<string>();
  384. installedPackages.Add(package.metadata.packageId);
  385. s_CachedMDStoreInformation.installedPackages = installedPackages.ToArray();
  386. StoreCachedMDStoreInformation();
  387. }
  388. InternalAddPluginPackage(package);
  389. }
  390. static void InternalAddPluginPackage(IXRPackage package)
  391. {
  392. s_Packages[package.metadata.packageId] = package;
  393. }
  394. internal static void InitKnownPluginPackages()
  395. {
  396. foreach (var knownPackage in KnownPackages.Packages)
  397. {
  398. InternalAddPluginPackage(knownPackage);
  399. }
  400. }
  401. static XRPackageMetadataStore()
  402. {
  403. InitKnownPluginPackages();
  404. EditorApplication.playModeStateChanged += PlayModeStateChanged;
  405. if (IsEditorInPlayMode())
  406. return;
  407. AssemblyReloadEvents.afterAssemblyReload += AssemblyReloadEvents_afterAssemblyReload;
  408. }
  409. static void AssemblyReloadEvents_afterAssemblyReload()
  410. {
  411. LoadCachedMDStoreInformation();
  412. if (!IsEditorInPlayMode())
  413. {
  414. if (!s_CachedMDStoreInformation.hasAlreadyRequestedData)
  415. {
  416. s_SearchRequest = Client.SearchAll(true);
  417. }
  418. RebuildInstalledCache();
  419. StartAllQueues();
  420. }
  421. }
  422. static bool IsEditorInPlayMode()
  423. {
  424. return EditorApplication.isPlayingOrWillChangePlaymode ||
  425. EditorApplication.isPlaying ||
  426. EditorApplication.isPaused;
  427. }
  428. static void PlayModeStateChanged(PlayModeStateChange state)
  429. {
  430. switch (state)
  431. {
  432. case PlayModeStateChange.ExitingEditMode:
  433. StopAllQueues();
  434. StoreCachedMDStoreInformation();
  435. break;
  436. case PlayModeStateChange.EnteredPlayMode:
  437. break;
  438. case PlayModeStateChange.EnteredEditMode:
  439. LoadCachedMDStoreInformation();
  440. StartAllQueues();
  441. break;
  442. }
  443. }
  444. static void StopAllQueues()
  445. {
  446. EditorApplication.update -= UpdateInstallablePackages;
  447. EditorApplication.update -= WaitingOnSearchQuery;
  448. EditorApplication.update -= MonitorPackageInstallation;
  449. EditorApplication.update -= MonitorPackageUninstall;
  450. EditorApplication.update -= AssignAnyRequestedLoadersUpdate;
  451. EditorApplication.update -= RebuildCache;
  452. }
  453. static void StartAllQueues()
  454. {
  455. EditorApplication.update += UpdateInstallablePackages;
  456. EditorApplication.update += WaitingOnSearchQuery;
  457. EditorApplication.update += MonitorPackageInstallation;
  458. EditorApplication.update += MonitorPackageUninstall;
  459. EditorApplication.update += AssignAnyRequestedLoadersUpdate;
  460. EditorApplication.update += RebuildCache;
  461. }
  462. static void UpdateInstallablePackages()
  463. {
  464. EditorApplication.update -= UpdateInstallablePackages;
  465. if (s_SearchRequest == null || IsEditorInPlayMode() || s_CachedMDStoreInformation.hasAlreadyRequestedData)
  466. {
  467. return;
  468. }
  469. if (!s_SearchRequest.IsCompleted)
  470. {
  471. EditorApplication.update += UpdateInstallablePackages;
  472. return;
  473. }
  474. var installablePackages = new List<string>();
  475. var knownPackageInfos = new List<KnownPackageInfo>();
  476. foreach (var package in s_SearchRequest.Result)
  477. {
  478. if (s_Packages.ContainsKey(package.name))
  479. {
  480. var kpi = new KnownPackageInfo();
  481. kpi.packageId = package.name;
  482. kpi.verifiedVersion = package.versions.verified;
  483. if (string.IsNullOrEmpty(kpi.verifiedVersion))
  484. kpi.verifiedVersion = package.versions.latestCompatible;
  485. knownPackageInfos.Add(kpi);
  486. installablePackages.Add(package.name);
  487. }
  488. }
  489. s_CachedMDStoreInformation.knownPackageInfos = knownPackageInfos.ToArray();
  490. s_CachedMDStoreInformation.installablePackages = installablePackages.ToArray();
  491. s_CachedMDStoreInformation.hasAlreadyRequestedData = true;
  492. s_SearchRequest = null;
  493. StoreCachedMDStoreInformation();
  494. }
  495. static void AddRequestToQueue(LoaderAssignmentRequest request, string queueName)
  496. {
  497. LoaderAssignmentRequests reqs;
  498. if (XRPackageMetadataStore.SessionStateHasStoredData(queueName))
  499. {
  500. string fromJson = SessionState.GetString(queueName, k_DefaultSessionStateString);
  501. reqs = JsonUtility.FromJson<LoaderAssignmentRequests>(fromJson);
  502. }
  503. else
  504. {
  505. reqs = new LoaderAssignmentRequests();
  506. reqs.activeRequests = new List<LoaderAssignmentRequest>();
  507. }
  508. reqs.activeRequests.Add(request);
  509. string json = JsonUtility.ToJson(reqs);
  510. SessionState.SetString(queueName, json);
  511. }
  512. static void SetRequestsInQueue(LoaderAssignmentRequests reqs, string queueName)
  513. {
  514. string json = JsonUtility.ToJson(reqs);
  515. SessionState.SetString(queueName, json);
  516. }
  517. static LoaderAssignmentRequests GetAllRequestsInQueue(string queueName)
  518. {
  519. var reqs = new LoaderAssignmentRequests();
  520. reqs.activeRequests = new List<LoaderAssignmentRequest>();
  521. if (XRPackageMetadataStore.SessionStateHasStoredData(queueName))
  522. {
  523. string fromJson = SessionState.GetString(queueName, k_DefaultSessionStateString);
  524. reqs = JsonUtility.FromJson<LoaderAssignmentRequests>(fromJson);
  525. SessionState.EraseString(queueName);
  526. }
  527. return reqs;
  528. }
  529. internal static void RebuildInstalledCache()
  530. {
  531. if (isRebuildingCache)
  532. return;
  533. var req = new LoaderAssignmentRequest();
  534. req.packageListRequest = Client.List(true, false);
  535. req.installationState = InstallationState.RebuildInstalledCache;
  536. req.timeOut = Time.realtimeSinceStartup + k_TimeOutDelta;
  537. QueueLoaderRequest(req);
  538. }
  539. static void RebuildCache()
  540. {
  541. EditorApplication.update -= RebuildCache;
  542. if (IsEditorInPlayMode())
  543. {
  544. return; // Use the cached data that should have been passed in the play state change.
  545. }
  546. LoaderAssignmentRequests reqs = GetAllRequestsInQueue(k_RebuildCache);
  547. if (reqs.activeRequests == null || reqs.activeRequests.Count == 0)
  548. {
  549. return;
  550. }
  551. var req = reqs.activeRequests[0];
  552. reqs.activeRequests.Remove(req);
  553. if (req.timeOut < Time.realtimeSinceStartup)
  554. {
  555. req.logMessage = $"Timeout trying to get package list after {k_TimeOutDelta}s.";
  556. req.logLevel = LogLevel.Warning;
  557. req.installationState = InstallationState.Log;
  558. QueueLoaderRequest(req);
  559. }
  560. else if (req.packageListRequest.IsCompleted)
  561. {
  562. if (req.packageListRequest.Status == StatusCode.Success)
  563. {
  564. var installedPackages = new List<string>();
  565. foreach (var packageInfo in req.packageListRequest.Result)
  566. {
  567. installedPackages.Add(packageInfo.name);
  568. }
  569. var packageIds = s_Packages.Values.
  570. Where((p) => installedPackages.Contains(p.metadata.packageId)).
  571. Select((p) => p.metadata.packageId);
  572. s_CachedMDStoreInformation.installedPackages = packageIds.ToArray();
  573. }
  574. StoreCachedMDStoreInformation();
  575. }
  576. else if (!req.packageListRequest.IsCompleted)
  577. {
  578. QueueLoaderRequest(req);
  579. }
  580. else
  581. {
  582. req.logMessage = $"Unable to rebuild installed package cache. Some state may be missing or incorrect.";
  583. req.logLevel = LogLevel.Warning;
  584. req.installationState = InstallationState.Log;
  585. QueueLoaderRequest(req);
  586. }
  587. if (reqs.activeRequests.Count > 0)
  588. {
  589. SetRequestsInQueue(reqs, k_RebuildCache);
  590. EditorApplication.update += RebuildCache;
  591. }
  592. }
  593. static void ResetManagerUiIfAvailable()
  594. {
  595. if (XRSettingsManager.Instance != null) XRSettingsManager.Instance.ResetUi = true;
  596. }
  597. static void AssignAnyRequestedLoadersUpdate()
  598. {
  599. EditorApplication.update -= AssignAnyRequestedLoadersUpdate;
  600. LoaderAssignmentRequests reqs = GetAllRequestsInQueue(k_AssigningPackage);
  601. if (reqs.activeRequests == null || reqs.activeRequests.Count == 0)
  602. return;
  603. while (reqs.activeRequests.Count > 0)
  604. {
  605. var req = reqs.activeRequests[0];
  606. reqs.activeRequests.RemoveAt(0);
  607. var settings = XRGeneralSettingsPerBuildTarget.XRGeneralSettingsForBuildTarget(req.buildTargetGroup);
  608. if (settings == null)
  609. continue;
  610. if (settings.AssignedSettings == null)
  611. {
  612. var assignedSettings = ScriptableObject.CreateInstance<XRManagerSettings>() as XRManagerSettings;
  613. settings.AssignedSettings = assignedSettings;
  614. EditorUtility.SetDirty(settings);
  615. }
  616. if (!XRPackageMetadataStore.AssignLoader(settings.AssignedSettings, req.loaderType, req.buildTargetGroup))
  617. {
  618. req.installationState = InstallationState.Log;
  619. req.logMessage = $"Unable to assign {req.packageId} for build target {req.buildTargetGroup}.";
  620. req.logLevel = LogLevel.Error;
  621. QueueLoaderRequest(req);
  622. }
  623. }
  624. ResetManagerUiIfAvailable();
  625. }
  626. internal static void AssignAnyRequestedLoaders()
  627. {
  628. EditorApplication.update += AssignAnyRequestedLoadersUpdate;
  629. }
  630. static void MonitorPackageInstallation()
  631. {
  632. EditorApplication.update -= MonitorPackageInstallation;
  633. LoaderAssignmentRequests reqs = GetAllRequestsInQueue(k_InstallingPackage);
  634. if (reqs.activeRequests.Count > 0)
  635. {
  636. var request = reqs.activeRequests[0];
  637. reqs.activeRequests.RemoveAt(0);
  638. if (request.needsAddRequest)
  639. {
  640. var versionToInstallQ = s_CachedMDStoreInformation.knownPackageInfos.
  641. Where((kpi) => String.Compare(request.packageId, kpi.packageId) == 0).
  642. Select((kpi) => kpi.verifiedVersion);
  643. var versionToInstall = versionToInstallQ.FirstOrDefault();
  644. var packageToInstall = String.IsNullOrEmpty(versionToInstall) ?
  645. request.packageId :
  646. $"{request.packageId}@{versionToInstall}";
  647. request.packageAddRequest = Client.Add(packageToInstall);
  648. request.needsAddRequest = false;
  649. request.installationState = InstallationState.Installing;
  650. s_CachedMDStoreInformation.hasAlreadyRequestedData = true;
  651. StoreCachedMDStoreInformation();
  652. QueueLoaderRequest(request);
  653. }
  654. else if (request.packageAddRequest.IsCompleted && File.Exists($"Packages/{request.packageId}/package.json"))
  655. {
  656. if (request.packageAddRequest.Status == StatusCode.Success)
  657. {
  658. if (!String.IsNullOrEmpty(request.loaderType))
  659. {
  660. request.packageAddRequest = null;
  661. request.installationState = InstallationState.Assigning;
  662. QueueLoaderRequest(request);
  663. }
  664. else
  665. {
  666. request.logMessage = $"Missing loader type. Unable to assign loader.";
  667. request.logLevel = LogLevel.Error;
  668. request.installationState = InstallationState.Log;
  669. QueueLoaderRequest(request);
  670. }
  671. }
  672. }
  673. else if (request.packageAddRequest.IsCompleted && request.packageAddRequest.Status != StatusCode.Success)
  674. {
  675. if (String.IsNullOrEmpty(request.packageId))
  676. {
  677. request.logMessage = $"Error installing package with no package id.";
  678. }
  679. else
  680. {
  681. request.logMessage = $"Error Message: {request.packageAddRequest?.Error?.message ?? "UNKNOWN" }.\nError installing package {request.packageId ?? "UNKNOWN PACKAGE ID" }.";
  682. }
  683. request.logLevel = LogLevel.Error;
  684. request.installationState = InstallationState.Log;
  685. QueueLoaderRequest(request);
  686. }
  687. else if (request.timeOut < Time.realtimeSinceStartup)
  688. {
  689. if (String.IsNullOrEmpty(request.packageId))
  690. {
  691. request.logMessage = $"Time out while installing pacakge with no package id.";
  692. }
  693. else
  694. {
  695. request.logMessage = $"Error installing package {request.packageId}. Package installation timed out. Check Package Manager UI to see if the package is installed and/or retry your operation.";
  696. }
  697. request.logLevel = LogLevel.Error;
  698. if (request.packageAddRequest.IsCompleted)
  699. {
  700. request.logMessage += $" Error message: {request.packageAddRequest.Error.message}";
  701. }
  702. request.installationState = InstallationState.Log;
  703. QueueLoaderRequest(request);
  704. }
  705. else
  706. {
  707. QueueLoaderRequest(request);
  708. }
  709. }
  710. }
  711. static void WaitingOnSearchQuery()
  712. {
  713. EditorApplication.update -= WaitingOnSearchQuery;
  714. if (s_SearchRequest != null)
  715. {
  716. EditorApplication.update += WaitingOnSearchQuery;
  717. return;
  718. }
  719. LoaderAssignmentRequests reqs = GetAllRequestsInQueue(k_WaitingPackmanQuery);
  720. if (reqs.activeRequests.Count > 0)
  721. {
  722. for (int i = 0; i < reqs.activeRequests.Count; i++)
  723. {
  724. var req = reqs.activeRequests[i];
  725. req.installationState = IsPackageInstalled(req.packageId) ? InstallationState.Assigning : InstallationState.StartInstallation;
  726. req.timeOut = Time.realtimeSinceStartup + k_TimeOutDelta;
  727. QueueLoaderRequest(req);
  728. }
  729. }
  730. }
  731. static void MonitorPackageUninstall()
  732. {
  733. EditorApplication.update -= MonitorPackageUninstall;
  734. LoaderAssignmentRequests reqs = GetAllRequestsInQueue(k_UninstallingPackage);
  735. if (reqs.activeRequests.Count > 0)
  736. {
  737. for (int i = 0; i < reqs.activeRequests.Count; i++)
  738. {
  739. var req = reqs.activeRequests[i];
  740. if (!req.packageRemoveRequest.IsCompleted)
  741. QueueLoaderRequest(req);
  742. if (req.packageRemoveRequest.Status == StatusCode.Failure)
  743. {
  744. req.installationState = InstallationState.Log;
  745. req.logMessage = req.packageRemoveRequest.Error.message;
  746. req.logLevel = LogLevel.Warning;
  747. QueueLoaderRequest(req);
  748. }
  749. }
  750. }
  751. }
  752. static void QueueLoaderRequest(LoaderAssignmentRequest req)
  753. {
  754. switch (req.installationState)
  755. {
  756. case InstallationState.New:
  757. if (!s_CachedMDStoreInformation.hasAlreadyRequestedData && !HasInstallablePackageData() && s_SearchRequest == null)
  758. {
  759. s_SearchRequest = Client.SearchAll(false);
  760. EditorApplication.update += UpdateInstallablePackages;
  761. }
  762. AddRequestToQueue(req, k_WaitingPackmanQuery);
  763. EditorApplication.update += WaitingOnSearchQuery;
  764. break;
  765. case InstallationState.RebuildInstalledCache:
  766. AddRequestToQueue(req, k_RebuildCache);
  767. EditorApplication.update += RebuildCache;
  768. break;
  769. case InstallationState.StartInstallation:
  770. req.needsAddRequest = true;
  771. req.packageAddRequest = null;
  772. req.timeOut = Time.realtimeSinceStartup + k_TimeOutDelta;
  773. AddRequestToQueue(req, k_InstallingPackage);
  774. EditorApplication.update += MonitorPackageInstallation;
  775. break;
  776. case InstallationState.Installing:
  777. AddRequestToQueue(req, k_InstallingPackage);
  778. EditorApplication.update += MonitorPackageInstallation;
  779. break;
  780. case InstallationState.Assigning:
  781. AddRequestToQueue(req, k_AssigningPackage);
  782. EditorApplication.update += AssignAnyRequestedLoadersUpdate;
  783. break;
  784. case InstallationState.Uninstalling:
  785. AddRequestToQueue(req, k_UninstallingPackage);
  786. EditorApplication.update += MonitorPackageUninstall;
  787. break;
  788. case InstallationState.Log:
  789. const string header = "XR Plug-in Management";
  790. switch(req.logLevel)
  791. {
  792. case LogLevel.Info:
  793. Debug.Log($"{header}: {req.logMessage}");
  794. break;
  795. case LogLevel.Warning:
  796. Debug.LogWarning($"{header} Warning: {req.logMessage}");
  797. break;
  798. case LogLevel.Error:
  799. Debug.LogError($"{header} error. Failure reason: {req.logMessage}.\n Check if there are any other errors in the console and make sure they are corrected before trying again.");
  800. break;
  801. }
  802. ResetManagerUiIfAvailable();
  803. break;
  804. }
  805. }
  806. }
  807. }