/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * Licensed under the Oculus SDK License Agreement (the "License"); * you may not use the Oculus SDK except in compliance with the License, * which is provided at the time of installation or download, or which * otherwise accompanies this software in either electronic or hard copy form. * * You may obtain a copy of the License at * * https://developer.oculus.com/licenses/oculussdk/ * * Unless required by applicable law or agreed to in writing, the Oculus SDK * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if OVR_UNITY_ASSET_STORE #if USING_XR_MANAGEMENT && (USING_XR_SDK_OCULUS || USING_XR_SDK_OPENXR) #define USING_XR_SDK #endif #if UNITY_2020_1_OR_NEWER #define REQUIRES_XR_SDK #endif using UnityEngine; using UnityEditor; using UnityEditor.Callbacks; using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.IO; using System.Diagnostics; using Oculus.VR.Editor; [InitializeOnLoad] public class OVRPluginUpdater : IOVRPluginInfoSupplier { enum PluginPlatform { Android, AndroidUniversal, AndroidOpenXR, OSXUniversal, Win, Win64, Win64OpenXR, } class PluginPackage { public string RootPath; public System.Version Version; public Dictionary Plugins = new Dictionary(); public bool IsBundledPluginPackage() { return (RootPath == GetBundledPluginRootPath()); } public bool IsEnabled() { foreach (PluginPlatform platform in Enum.GetValues(typeof(PluginPlatform))) { string path = ""; if (Plugins.TryGetValue(platform, out path) && File.Exists(path)) { return true; } } return false; } public bool IsWin64Enabled() { string path = ""; if (Plugins.TryGetValue(PluginPlatform.Win64, out path)) { if (File.Exists(path)) { string basePath = GetCurrentProjectPath(); string relPath = path.Substring(basePath.Length + 1); PluginImporter pi = PluginImporter.GetAtPath(relPath) as PluginImporter; if (pi != null) { return pi.GetCompatibleWithPlatform(BuildTarget.StandaloneWindows64) && pi.GetCompatibleWithEditor(); } } } return false; } public bool IsWin64Present() { string path = ""; if (Plugins.TryGetValue(PluginPlatform.Win64, out path)) { string disabledPath = path + GetDisabledPluginSuffix(); if (File.Exists(path) || File.Exists(disabledPath)) { return true; } } return false; } public bool IsWin64OpenXREnabled() { string path = ""; if (Plugins.TryGetValue(PluginPlatform.Win64OpenXR, out path)) { if (File.Exists(path)) { string basePath = GetCurrentProjectPath(); string relPath = path.Substring(basePath.Length + 1); PluginImporter pi = PluginImporter.GetAtPath(relPath) as PluginImporter; if (pi != null) { return pi.GetCompatibleWithPlatform(BuildTarget.StandaloneWindows64) && pi.GetCompatibleWithEditor(); } } } return false; } public bool IsWin64OpenXRPresent() { string path = ""; if (Plugins.TryGetValue(PluginPlatform.Win64OpenXR, out path)) { string disabledPath = path + GetDisabledPluginSuffix(); if (File.Exists(path) || File.Exists(disabledPath)) { return true; } } return false; } public bool IsAndroidUniversalEnabled() { string path = ""; if (Plugins.TryGetValue(PluginPlatform.AndroidUniversal, out path)) { if (File.Exists(path)) { string basePath = GetCurrentProjectPath(); string relPath = path.Substring(basePath.Length + 1); PluginImporter pi = PluginImporter.GetAtPath(relPath) as PluginImporter; if (pi != null) { return pi.GetCompatibleWithPlatform(BuildTarget.Android); } } } return false; } public bool IsAndroidUniversalPresent() { string path = ""; if (Plugins.TryGetValue(PluginPlatform.AndroidUniversal, out path)) { string disabledPath = path + GetDisabledPluginSuffix(); if (File.Exists(path) || File.Exists(disabledPath)) { return true; } } return false; } public bool IsAndroidOpenXREnabled() { string path = ""; if (Plugins.TryGetValue(PluginPlatform.AndroidOpenXR, out path)) { if (File.Exists(path)) { string basePath = GetCurrentProjectPath(); string relPath = path.Substring(basePath.Length + 1); PluginImporter pi = PluginImporter.GetAtPath(relPath) as PluginImporter; if (pi != null) { return pi.GetCompatibleWithPlatform(BuildTarget.Android); } } } return false; } public bool IsAndroidOpenXRPresent() { string path = ""; if (Plugins.TryGetValue(PluginPlatform.AndroidOpenXR, out path)) { string disabledPath = path + GetDisabledPluginSuffix(); if (File.Exists(path) || File.Exists(disabledPath)) { return true; } } return false; } } private static bool restartPending = false; private static bool unityRunningInBatchmode = false; private static bool unityVersionSupportsAndroidUniversal = true; private static bool enableAndroidUniversalSupport = true; private static System.Version invalidVersion = new System.Version("0.0.0"); private static System.Version minimalProductionVersionForOpenXR = new Version(1, 63, 0); static OVRPluginUpdater() { EditorApplication.delayCall += OnDelayCall; } static void OnDelayCall() { if (System.Environment.CommandLine.Contains("-batchmode")) { unityRunningInBatchmode = true; } if (enableAndroidUniversalSupport) { unityVersionSupportsAndroidUniversal = true; } if (ShouldAttemptPluginUpdate()) { AttemptPluginUpdate(true); } } private static PluginPackage GetPluginPackage(string rootPath) { return new PluginPackage() { RootPath = rootPath, Version = GetPluginVersion(rootPath), Plugins = new Dictionary() { { PluginPlatform.Android, rootPath + GetPluginBuildTargetSubPath(PluginPlatform.Android) }, { PluginPlatform.AndroidUniversal, rootPath + GetPluginBuildTargetSubPath(PluginPlatform.AndroidUniversal) }, { PluginPlatform.AndroidOpenXR, rootPath + GetPluginBuildTargetSubPath(PluginPlatform.AndroidOpenXR) }, { PluginPlatform.OSXUniversal, rootPath + GetPluginBuildTargetSubPath(PluginPlatform.OSXUniversal) }, { PluginPlatform.Win, rootPath + GetPluginBuildTargetSubPath(PluginPlatform.Win) }, { PluginPlatform.Win64, rootPath + GetPluginBuildTargetSubPath(PluginPlatform.Win64) }, { PluginPlatform.Win64OpenXR, rootPath + GetPluginBuildTargetSubPath(PluginPlatform.Win64OpenXR) }, } }; } private static PluginPackage GetBundledPluginPackage() { return GetPluginPackage(GetBundledPluginRootPath()); } private static List GetAllUtilitiesPluginPackages() { string pluginRootPath = GetUtilitiesPluginRootPath(); List packages = new List(); if (Directory.Exists(pluginRootPath)) { var dirs = Directory.GetDirectories(pluginRootPath); foreach (string dir in dirs) { packages.Add(GetPluginPackage(dir)); } } return packages; } private static string GetCurrentProjectPath() { return Directory.GetParent(Application.dataPath).FullName; } private static string GetUtilitiesPluginRootPath() { return Path.Combine(OVRPluginInfo.GetUtilitiesRootPath(), "Plugins"); } private static string GetBundledPluginRootPath() { string basePath = EditorApplication.applicationContentsPath; string pluginPath = @"/UnityExtensions/Unity/VR"; return basePath + pluginPath; } private static string GetPluginBuildTargetSubPath(PluginPlatform target) { string path = string.Empty; switch (target) { case PluginPlatform.Android: path = @"/Android/OVRPlugin.aar"; break; case PluginPlatform.AndroidUniversal: path = @"/AndroidUniversal/OVRPlugin.aar"; break; case PluginPlatform.AndroidOpenXR: path = @"/AndroidOpenXR/OVRPlugin.aar"; break; case PluginPlatform.OSXUniversal: path = @"/OSXUniversal/OVRPlugin.bundle"; break; case PluginPlatform.Win: path = @"/Win/OVRPlugin.dll"; break; case PluginPlatform.Win64: path = @"/Win64/OVRPlugin.dll"; break; case PluginPlatform.Win64OpenXR: path = @"/Win64OpenXR/OVRPlugin.dll"; break; default: throw new ArgumentException("Attempted GetPluginBuildTargetSubPath() for unsupported BuildTarget: " + target); } return path; } private static string GetDisabledPluginSuffix() { return @".disabled"; } private static System.Version GetPluginVersion(string path) { System.Version pluginVersion = invalidVersion; try { pluginVersion = new System.Version(Path.GetFileName(path)); } catch { pluginVersion = invalidVersion; } if (pluginVersion == invalidVersion) { //Unable to determine version from path, fallback to Win64 DLL meta data path += GetPluginBuildTargetSubPath(PluginPlatform.Win64); if (!File.Exists(path)) { path += GetDisabledPluginSuffix(); if (!File.Exists(path)) { return invalidVersion; } } FileVersionInfo pluginVersionInfo = FileVersionInfo.GetVersionInfo(path); if (pluginVersionInfo == null || pluginVersionInfo.ProductVersion == null || pluginVersionInfo.ProductVersion == "") { return invalidVersion; } pluginVersion = new System.Version(pluginVersionInfo.ProductVersion); } return pluginVersion; } public static string GetVersionDescription(System.Version version) { return IsVersionValid(version) ? version.ToString() : "(Unknown)"; } private static bool IsVersionValid(Version version) { return version != invalidVersion; } public static string GetEnabledUtilsPluginRootPath() { PluginPackage package = GetEnabledUtilsPluginPkg(); if (package == null) { return null; } else { return package.RootPath; } } private static bool ShouldAttemptPluginUpdate() { if (unityRunningInBatchmode || OVRPluginInfo.IsInsidePackageDistribution()) { return false; } else { return !UnitySupportsEnabledAndroidPlugin() || (autoUpdateEnabled && !restartPending && !Application.isPlaying); } } private static void DisableAllUtilitiesPluginPackages() { List allUtilsPluginPkgs = GetAllUtilitiesPluginPackages(); foreach (PluginPackage pluginPkg in allUtilsPluginPkgs) { foreach (string path in pluginPkg.Plugins.Values) { if ((Directory.Exists(path)) || (File.Exists(path))) { string basePath = GetCurrentProjectPath(); string relPath = path.Substring(basePath.Length + 1); string relDisabledPath = relPath + GetDisabledPluginSuffix(); AssetDatabase.MoveAsset(relPath, relDisabledPath); AssetDatabase.ImportAsset(relDisabledPath, ImportAssetOptions.ForceUpdate); } } } AssetDatabase.Refresh(); AssetDatabase.SaveAssets(); } private static void EnablePluginPackage(PluginPackage pluginPkg) { UnityEngine.Debug.Log("OVRPlugin with OpenXR backend is activated by default"); foreach (var kvp in pluginPkg.Plugins) { PluginPlatform platform = kvp.Key; string path = kvp.Value; if ((Directory.Exists(path + GetDisabledPluginSuffix())) || (File.Exists(path + GetDisabledPluginSuffix()))) { string basePath = GetCurrentProjectPath(); string relPath = path.Substring(basePath.Length + 1); string relDisabledPath = relPath + GetDisabledPluginSuffix(); AssetDatabase.MoveAsset(relDisabledPath, relPath); AssetDatabase.ImportAsset(relPath, ImportAssetOptions.ForceUpdate); PluginImporter pi = PluginImporter.GetAtPath(relPath) as PluginImporter; if (pi == null) { continue; } // Disable support for all platforms, then conditionally enable desired support below pi.SetCompatibleWithEditor(false); pi.SetCompatibleWithAnyPlatform(false); pi.SetCompatibleWithPlatform(BuildTarget.Android, false); pi.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows, false); pi.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows64, false); pi.SetCompatibleWithPlatform(BuildTarget.StandaloneOSX, false); switch (platform) { case PluginPlatform.Android: break; case PluginPlatform.AndroidUniversal: break; case PluginPlatform.AndroidOpenXR: pi.SetCompatibleWithPlatform(BuildTarget.Android, unityVersionSupportsAndroidUniversal); break; case PluginPlatform.OSXUniversal: pi.SetCompatibleWithPlatform(BuildTarget.StandaloneOSX, true); pi.SetCompatibleWithEditor(true); pi.SetEditorData("CPU", "AnyCPU"); pi.SetEditorData("OS", "OSX"); pi.SetPlatformData("Editor", "CPU", "AnyCPU"); pi.SetPlatformData("Editor", "OS", "OSX"); break; case PluginPlatform.Win: break; case PluginPlatform.Win64: break; case PluginPlatform.Win64OpenXR: pi.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows64, true); pi.SetCompatibleWithEditor(true); pi.SetEditorData("CPU", "X86_64"); pi.SetEditorData("OS", "Windows"); pi.SetPlatformData("Editor", "CPU", "X86_64"); pi.SetPlatformData("Editor", "OS", "Windows"); break; default: throw new ArgumentException("Attempted EnablePluginPackage() for unsupported BuildTarget: " + platform); } AssetDatabase.ImportAsset(relPath, ImportAssetOptions.ForceUpdate); } } AssetDatabase.Refresh(); AssetDatabase.SaveAssets(); } private static readonly string autoUpdateEnabledKey = "Oculus_Utilities_OVRPluginUpdater_AutoUpdate2_" + OVRManager.utilitiesVersion; private static bool autoUpdateEnabled { get => PlayerPrefs.GetInt(autoUpdateEnabledKey, 1) == 1; set { PlayerPrefs.SetInt(autoUpdateEnabledKey, value ? 1 : 0); PlayerPrefs.Save(); } } private static PluginPackage GetEnabledUtilsPluginPkg() { List allUtilsPluginPkgs = GetAllUtilitiesPluginPackages(); PluginPackage enabledUtilsPluginPkg = null; foreach (PluginPackage pluginPkg in allUtilsPluginPkgs) { if (pluginPkg.IsEnabled()) { if ((enabledUtilsPluginPkg == null) || (pluginPkg.Version > enabledUtilsPluginPkg.Version)) { enabledUtilsPluginPkg = pluginPkg; } } } return enabledUtilsPluginPkg; } const string k_disablePluginMenuStr = "Oculus/Tools/OVR Utilities Plugin/Set OVRPlugin to Package Manager-provided (Disable OVR Utilities Plugin version)"; [MenuItem(k_disablePluginMenuStr, true, 102)] private static bool IsDisableOVRPluginMenuEnabled() { //This section controls whether we draw a checkmark next to this menu item (it's currently active...) Menu.SetChecked(k_disablePluginMenuStr, GetEnabledUtilsPluginPkg() == null); //And this section controls whether the menu item is enabled (you're allowed to toggle it) return true; } [MenuItem(k_disablePluginMenuStr, false, 102)] private static void AttemptPluginDisable() { if (OVRPluginInfo.IsInsidePackageDistribution()) { UnityEngine.Debug.LogError("Unable to change plugin when using package distribution"); return; } PluginPackage enabledUtilsPluginPkg = GetEnabledUtilsPluginPkg(); if (enabledUtilsPluginPkg == null) { if (unityRunningInBatchmode || EditorUtility.DisplayDialog("Disable Oculus Utilities Plugin", "The OVRPlugin included with Oculus Utilities is already disabled." + " The OVRPlugin installed through the Package Manager will continue to be used.\n", "Ok", "")) { return; } } else { if (unityRunningInBatchmode || EditorUtility.DisplayDialog("Disable Oculus Utilities Plugin", "Do you want to disable the OVRPlugin included with Oculus Utilities and revert to the OVRPlugin installed through the Package Manager?\n\n" + "Current version: " + GetVersionDescription(enabledUtilsPluginPkg.Version), "Yes", "No")) { DisableAllUtilitiesPluginPackages(); autoUpdateEnabled = false; if (unityRunningInBatchmode || EditorUtility.DisplayDialog("Restart Unity", "Now you will be using the OVRPlugin installed through Package Manager." + "\n\nPlease restart the Unity Editor to complete the update process.", "Restart", "Not Now")) { RestartUnityEditor(); } } } } [MenuItem("Oculus/Tools/OVR Utilities Plugin/Manual Update OVRPlugin (to OVR Utilities version)", false, 0)] private static void RunPluginUpdate() { if (OVRPluginInfo.IsInsidePackageDistribution()) { UnityEngine.Debug.LogError("Unable to change plugin when using package distribution"); return; } autoUpdateEnabled = true; AttemptPluginUpdate(false); } private static void BatchmodeActivateOVRPluginOpenXR() { OnDelayCall(); // manually invoke when running editor in batchmode ActivateOVRPluginOpenXR(); } const string k_setToOpenXRPluginMenuStr = "Oculus/Tools/OVR Utilities Plugin/Set OVRPlugin to OpenXR"; [MenuItem(k_setToOpenXRPluginMenuStr, true, 100)] private static bool IsActivateOVRPluginOpenXRMenuEnabled() { //This section controls whether we draw a checkmark next to this menu item (it's currently active...) Menu.SetChecked(k_setToOpenXRPluginMenuStr, IsOVRPluginOpenXRActivatedInternal()); //And this section controls whether the menu item is enabled (you're allowed to toggle it) #if !USING_XR_SDK && !REQUIRES_XR_SDK return false; #else return true; #endif } [MenuItem(k_setToOpenXRPluginMenuStr, false, 100)] private static void ActivateOVRPluginOpenXR() { if (!unityVersionSupportsAndroidUniversal) { UnityEngine.Debug.LogError( "Unexpected error: Unity must support AndroidUniversal version of Oculus Utilities Plugin for accessing OpenXR"); return; } if (OVRPluginInfo.IsInsidePackageDistribution()) { UnityEngine.Debug.LogError("Unable to change plugin when using package distribution"); return; } #if !USING_XR_SDK && !REQUIRES_XR_SDK UnityEngine.Debug.LogError("Oculus Utilities Plugin with OpenXR only supports XR Plug-in Management with Oculus XR Plugin"); return; #else List allUtilsPluginPkgs = GetAllUtilitiesPluginPackages(); PluginPackage enabledUtilsPluginPkg = null; foreach (PluginPackage pluginPkg in allUtilsPluginPkgs) { if (pluginPkg.IsEnabled()) { enabledUtilsPluginPkg = pluginPkg; break; } } if (enabledUtilsPluginPkg == null) { UnityEngine.Debug.LogError( "Unable to Activate OVRPlugin with OpenXR: Oculus Utilities Plugin package not activated"); return; } if (!enabledUtilsPluginPkg.IsAndroidOpenXRPresent() && !enabledUtilsPluginPkg.IsWin64OpenXRPresent()) { UnityEngine.Debug.LogError( "Unable to Activate OVRPlugin with OpenXR: Both AndroidOpenXR/OVRPlugin.aar or Win64OpenXR/OVRPlugin.dll does not exist"); return; } if (enabledUtilsPluginPkg.IsAndroidOpenXREnabled() && enabledUtilsPluginPkg.IsWin64OpenXREnabled()) { if (!unityRunningInBatchmode) { EditorUtility.DisplayDialog("Unable to Activate OVRPlugin with OpenXR", "Both AndroidOpenXR/OVRPlugin.aar and Win64OpenXR/OVRPlugin.dll already enabled", "Ok"); } return; } if (enabledUtilsPluginPkg.Version < minimalProductionVersionForOpenXR) { if (!unityRunningInBatchmode) { bool accepted = EditorUtility.DisplayDialog("Warning", "OVRPlugin with OpenXR backend is experimental before v31. You may expect to encounter stability issues and/or missing functionalities, " + "including but not limited to, fixed foveated rendering / composition layer / display refresh rates / etc." + "\n\n" + "Also, OVRPlugin with OpenXR backend only supports XR Plug-in Management with Oculus XR Plugin on Quest", "Continue", "Cancel"); if (!accepted) { return; } } } if (enabledUtilsPluginPkg.IsAndroidOpenXRPresent() && !enabledUtilsPluginPkg.IsAndroidOpenXREnabled()) { if (enabledUtilsPluginPkg.IsAndroidUniversalEnabled()) { string androidUniveralPluginPath = enabledUtilsPluginPkg.Plugins[PluginPlatform.AndroidUniversal]; string androidUniveralPluginBasePath = GetCurrentProjectPath(); string androidUniveralPluginRelPath = androidUniveralPluginPath.Substring(androidUniveralPluginBasePath.Length + 1); PluginImporter pi = PluginImporter.GetAtPath(androidUniveralPluginRelPath) as PluginImporter; if (pi != null) { pi.SetCompatibleWithPlatform(BuildTarget.Android, false); AssetDatabase.ImportAsset(androidUniveralPluginRelPath, ImportAssetOptions.ForceUpdate); } else { UnityEngine.Debug.LogWarning("Unable to find PluginImporter: " + androidUniveralPluginRelPath); } } { string androidOpenXRPluginPath = enabledUtilsPluginPkg.Plugins[PluginPlatform.AndroidOpenXR]; string androidOpenXRPluginBasePath = GetCurrentProjectPath(); string androidOpenXRPluginRelPath = androidOpenXRPluginPath.Substring(androidOpenXRPluginBasePath.Length + 1); PluginImporter pi = PluginImporter.GetAtPath(androidOpenXRPluginRelPath) as PluginImporter; if (pi != null) { pi.SetCompatibleWithPlatform(BuildTarget.Android, true); AssetDatabase.ImportAsset(androidOpenXRPluginRelPath, ImportAssetOptions.ForceUpdate); } else { UnityEngine.Debug.LogWarning("Unable to find PluginImporter: " + androidOpenXRPluginRelPath); } } } bool win64PluginUpdated = false; if (enabledUtilsPluginPkg.IsWin64OpenXRPresent() && !enabledUtilsPluginPkg.IsWin64OpenXREnabled()) { if (enabledUtilsPluginPkg.IsWin64Enabled()) { string win64PluginPath = enabledUtilsPluginPkg.Plugins[PluginPlatform.Win64]; string win64PluginBasePath = GetCurrentProjectPath(); string win64PluginRelPath = win64PluginPath.Substring(win64PluginBasePath.Length + 1); PluginImporter pi = PluginImporter.GetAtPath(win64PluginRelPath) as PluginImporter; if (pi != null) { pi.ClearSettings(); pi.SetCompatibleWithEditor(false); pi.SetCompatibleWithAnyPlatform(false); AssetDatabase.ImportAsset(win64PluginRelPath, ImportAssetOptions.ForceUpdate); } else { UnityEngine.Debug.LogWarning("Unable to find PluginImporter: " + win64PluginRelPath); } } { string win64OpenXRPluginPath = enabledUtilsPluginPkg.Plugins[PluginPlatform.Win64OpenXR]; string win64OpenXRPluginBasePath = GetCurrentProjectPath(); string win64OpenXRPluginRelPath = win64OpenXRPluginPath.Substring(win64OpenXRPluginBasePath.Length + 1); PluginImporter pi = PluginImporter.GetAtPath(win64OpenXRPluginRelPath) as PluginImporter; if (pi != null) { pi.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows64, true); pi.SetCompatibleWithEditor(true); pi.SetEditorData("CPU", "X86_64"); pi.SetEditorData("OS", "Windows"); pi.SetPlatformData("Editor", "CPU", "X86_64"); pi.SetPlatformData("Editor", "OS", "Windows"); AssetDatabase.ImportAsset(win64OpenXRPluginRelPath, ImportAssetOptions.ForceUpdate); } else { UnityEngine.Debug.LogWarning("Unable to find PluginImporter: " + win64OpenXRPluginRelPath); } } win64PluginUpdated = true; } AssetDatabase.Refresh(); AssetDatabase.SaveAssets(); if (!unityRunningInBatchmode) { EditorUtility.DisplayDialog("Activate OVRPlugin with OpenXR", "Oculus Utilities Plugin with OpenXR has been enabled on Android", "Ok"); if (win64PluginUpdated && EditorUtility.DisplayDialog("Restart Unity", "Win64 plugin updated. Do you want to restart Unity editor?", "Restart", "Not Now")) { RestartUnityEditor(); } } #endif // !USING_XR_SDK } public static bool IsOVRPluginLegacyAPIActivated() { PluginPackage enabledUtilsPluginPkg = GetEnabledUtilsPluginPkg(); if (enabledUtilsPluginPkg == null) { return false; } return enabledUtilsPluginPkg.IsAndroidUniversalEnabled(); } // Separate entry point needed since "-executeMethod" does not support parameters or default parameter values private static void BatchmodePluginUpdate() { OnDelayCall(); // manually invoke when running editor in batchmode AttemptPluginUpdate(false); } private static void AttemptPluginUpdate(bool triggeredByAutoUpdate) { OVRPlugin.SendEvent("attempt_plugin_update_auto", triggeredByAutoUpdate.ToString()); PluginPackage bundledPluginPkg = GetBundledPluginPackage(); List allUtilsPluginPkgs = GetAllUtilitiesPluginPackages(); PluginPackage enabledUtilsPluginPkg = null; PluginPackage newestUtilsPluginPkg = null; foreach (PluginPackage pluginPkg in allUtilsPluginPkgs) { if ((newestUtilsPluginPkg == null) || (pluginPkg.Version > newestUtilsPluginPkg.Version)) { newestUtilsPluginPkg = pluginPkg; } if (pluginPkg.IsEnabled()) { if ((enabledUtilsPluginPkg == null) || (pluginPkg.Version > enabledUtilsPluginPkg.Version)) { enabledUtilsPluginPkg = pluginPkg; } } } bool reenableCurrentPluginPkg = false; PluginPackage targetPluginPkg = null; if ((newestUtilsPluginPkg != null) && (newestUtilsPluginPkg.Version > bundledPluginPkg.Version)) { if ((enabledUtilsPluginPkg == null) || (enabledUtilsPluginPkg.Version != newestUtilsPluginPkg.Version)) { targetPluginPkg = newestUtilsPluginPkg; } } else if ((enabledUtilsPluginPkg != null) && (enabledUtilsPluginPkg.Version < bundledPluginPkg.Version)) { targetPluginPkg = bundledPluginPkg; } PluginPackage currentPluginPkg = (enabledUtilsPluginPkg != null) ? enabledUtilsPluginPkg : bundledPluginPkg; if ((targetPluginPkg == null) && !UnitySupportsEnabledAndroidPlugin()) { // Force reenabling the current package to configure the correct android plugin for this unity version. reenableCurrentPluginPkg = true; targetPluginPkg = currentPluginPkg; } if (targetPluginPkg == null) { if (!triggeredByAutoUpdate && !unityRunningInBatchmode) { EditorUtility.DisplayDialog("Update Oculus Utilities Plugin", "OVRPlugin is already up to date.\n\nCurrent version: " + GetVersionDescription(currentPluginPkg.Version), "Ok", ""); } return; // No update necessary. } System.Version targetVersion = targetPluginPkg.Version; bool userAcceptsUpdate = false; if (unityRunningInBatchmode) { userAcceptsUpdate = true; } else { string dialogBody = "Oculus Utilities has detected that a newer OVRPlugin is available." + " Using the newest version is recommended. Do you want to enable it?\n\n" + "Current version: " + GetVersionDescription(currentPluginPkg.Version) + "\nAvailable version: " + targetVersion; if (reenableCurrentPluginPkg) { dialogBody = "Oculus Utilities has detected a configuration change that requires re-enabling the current OVRPlugin." + " Do you want to proceed?\n\nCurrent version: " + GetVersionDescription(currentPluginPkg.Version); } if (IsVersionValid(currentPluginPkg.Version)) { int dialogResult = EditorUtility.DisplayDialogComplex("Update Oculus Utilities Plugin", dialogBody, "Yes", "No, Don't Ask Again", "No"); switch (dialogResult) { case 0: // "Yes" userAcceptsUpdate = true; break; case 1: // "No, Don't Ask Again" autoUpdateEnabled = false; EditorUtility.DisplayDialog("Oculus Utilities OVRPlugin", "To manually update in the future, use the following menu option:\n\n" + "[Oculus -> Tools -> Update OVR Utilities Plugin]", "Ok", ""); return; case 2: // "No" return; } } else { // if there's no current valid version, update it automatically userAcceptsUpdate = true; } } if (userAcceptsUpdate) { DisableAllUtilitiesPluginPackages(); if (!targetPluginPkg.IsBundledPluginPackage()) { EnablePluginPackage(targetPluginPkg); } if (unityRunningInBatchmode || EditorUtility.DisplayDialog("Restart Unity", "OVRPlugin has been updated to " + GetVersionDescription(targetPluginPkg.Version) + ".\n\nPlease restart the Unity Editor to complete the update process." , "Restart", "Not Now")) { RestartUnityEditor(); } } } private static bool UnitySupportsEnabledAndroidPlugin() { List allUtilsPluginPkgs = GetAllUtilitiesPluginPackages(); foreach (PluginPackage pluginPkg in allUtilsPluginPkgs) { if (pluginPkg.IsEnabled()) { if ((pluginPkg.IsAndroidUniversalEnabled() || pluginPkg.IsAndroidOpenXREnabled()) && !unityVersionSupportsAndroidUniversal) { // Android Universal should only be enabled on supported Unity versions since it can prevent app launch. return false; } else if (!pluginPkg.IsAndroidUniversalEnabled() && pluginPkg.IsAndroidUniversalPresent() && !pluginPkg.IsAndroidOpenXREnabled() && pluginPkg.IsAndroidOpenXRPresent() && unityVersionSupportsAndroidUniversal) { // Android Universal is present and should be enabled on supported Unity versions since ARM64 config will fail otherwise. return false; } } } return true; } private static void RestartUnityEditor() { if (unityRunningInBatchmode) { EditorApplication.Exit(0); } else { restartPending = true; EditorApplication.OpenProject(GetCurrentProjectPath()); } } #region IOVRPluginInfoSupplier Implementation // Test if the OVRPlugin/OpenXR plugin is currently activated, used by other editor utilities public bool IsOVRPluginOpenXRActivated() => IsOVRPluginOpenXRActivatedInternal(); private static bool IsOVRPluginOpenXRActivatedInternal() { if (!unityVersionSupportsAndroidUniversal) // sanity check { return false; } PluginPackage enabledUtilsPluginPkg = GetEnabledUtilsPluginPkg(); return enabledUtilsPluginPkg != null && enabledUtilsPluginPkg.IsAndroidOpenXREnabled(); } public bool IsOVRPluginUnityProvidedActivated() { PluginPackage enabledUtilsPluginPkg = GetEnabledUtilsPluginPkg(); return enabledUtilsPluginPkg != null && enabledUtilsPluginPkg.IsBundledPluginPackage(); } #endregion } #endif