//======= Copyright (c) Valve Corporation, All rights reserved. =============== // // Purpose: Prompt developers to use settings most compatible with SteamVR. // //============================================================================= using UnityEngine; using UnityEditor; using System.IO; using System.Collections.Generic; using System.Linq; using System; using System.Reflection; using Valve.VR.InteractionSystem; #if OPENVR_XR_API using UnityEditor.XR.Management.Metadata; using UnityEngine.XR.Management; #endif #if UNITY_2018_2_OR_NEWER #pragma warning disable CS0618 #pragma warning disable CS0219 #pragma warning disable CS0414 #endif namespace Valve.VR { [InitializeOnLoad] public class SteamVR_AutoEnableVR { static SteamVR_AutoEnableVR() { EditorApplication.update += Update; } protected const string openVRString = "OpenVR"; protected const string unityOpenVRPackageString = "com.unity.xr.openvr.standalone"; protected const string valveOpenVRPackageString = "com.valvesoftware.unity.openvr"; #if UNITY_2020_1_OR_NEWER || OPENVR_XR_API protected const string valveEnabledLoaderKeyTemplate = "valve.enablexddrloader.{0}"; protected const string valveOpenVRLoaderType = "Unity.XR.OpenVR.OpenVRLoader"; #endif #if UNITY_2018_2_OR_NEWER private enum PackageStates { None, WaitingForList, WaitingForAdd, WaitingForAddConfirm, Installed, Failed, } private static UnityEditor.PackageManager.Requests.ListRequest listRequest; private static UnityEditor.PackageManager.Requests.AddRequest addRequest; private static PackageStates packageState = PackageStates.None; private static System.Diagnostics.Stopwatch addingPackageTime = new System.Diagnostics.Stopwatch(); private static System.Diagnostics.Stopwatch addingPackageTimeTotal = new System.Diagnostics.Stopwatch(); private static float estimatedTimeToInstall = 80; private static int addTryCount = 0; private static string enabledLoaderKey = null; private static MethodInfo isLoaderAssigned; private static MethodInfo installPackageAndAssignLoaderForBuildTarget; private static Type[] isLoaderAssignedMethodParameters; private static object[] isLoaderAssignedCallParameters; #endif public static void Update() { if (SteamVR_Settings.instance.autoEnableVR) { bool enabledVR = false; #if UNITY_2020_1_OR_NEWER || OPENVR_XR_API #if !UNITY_2020_2_OR_NEWER if (UnityEditor.PlayerSettings.virtualRealitySupported == true) { UnityEditor.PlayerSettings.virtualRealitySupported = false; enabledVR = true; Debug.Log("[SteamVR Setup] Disabled virtual reality support in Player Settings. Because you're using XR Manager. Make sure OpenVR Loader is enabled in XR Manager UI. (you can disable this by unchecking Assets/SteamVR/SteamVR_Settings.autoEnableVR)"); } #endif #if OPENVR_XR_API //little hacky, but the public methods weren't working. if (isLoaderAssignedMethodParameters == null) isLoaderAssignedMethodParameters = new Type[] { typeof(string), typeof(BuildTargetGroup) }; if (isLoaderAssignedCallParameters == null) isLoaderAssignedCallParameters = new object[] { valveOpenVRLoaderType, BuildTargetGroup.Standalone }; if (isLoaderAssigned == null) isLoaderAssigned = GetMethod("IsLoaderAssigned", isLoaderAssignedMethodParameters); if (installPackageAndAssignLoaderForBuildTarget == null) installPackageAndAssignLoaderForBuildTarget = GetMethod("InstallPackageAndAssignLoaderForBuildTarget"); if (isLoaderAssigned != null && installPackageAndAssignLoaderForBuildTarget != null) { bool isAssigned = (bool)isLoaderAssigned.Invoke(null, isLoaderAssignedCallParameters); if (isAssigned == false) { if (enabledLoaderKey == null) enabledLoaderKey = string.Format(valveEnabledLoaderKeyTemplate, SteamVR_Settings.instance.editorAppKey); if (EditorPrefs.HasKey(enabledLoaderKey) == false) { installPackageAndAssignLoaderForBuildTarget.Invoke(null, new object[] { valveOpenVRPackageString, valveOpenVRLoaderType, BuildTargetGroup.Standalone }); isAssigned = (bool)isLoaderAssigned.Invoke(null, isLoaderAssignedCallParameters); if (isAssigned) { EditorPrefs.SetBool(enabledLoaderKey, true); Debug.Log("[SteamVR Setup] Enabled OpenVR Loader in XR Management"); UnityEditor.EditorApplication.update -= Update; } } else { UnityEditor.EditorApplication.update -= Update; } } else { UnityEditor.EditorApplication.update -= Update; } } #elif UNITY_2020_1_OR_NEWER StartAutoUpdater(); #endif #else if (UnityEditor.PlayerSettings.virtualRealitySupported == false) { UnityEditor.PlayerSettings.virtualRealitySupported = true; enabledVR = true; Debug.Log("[SteamVR Setup] Enabled virtual reality support in Player Settings. (you can disable this by unchecking Assets/SteamVR/SteamVR_Settings.autoEnableVR)"); } UnityEditor.BuildTargetGroup currentTarget = UnityEditor.EditorUserBuildSettings.selectedBuildTargetGroup; #if (UNITY_5_4 || UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0) string[] devices = UnityEditorInternal.VR.VREditor.GetVREnabledDevices(currentTarget); #else string[] devices = UnityEditorInternal.VR.VREditor.GetVREnabledDevicesOnTargetGroup(currentTarget); #endif bool hasOpenVR = devices.Any(device => string.Equals(device, openVRString, System.StringComparison.CurrentCultureIgnoreCase)); if (hasOpenVR == false || enabledVR) { string[] newDevices; if (enabledVR && hasOpenVR == false) { newDevices = new string[] { openVRString }; //only list openvr if we enabled it } else { List devicesList = new List(devices); //list openvr as the first option if it wasn't in the list. if (hasOpenVR) devicesList.Remove(openVRString); devicesList.Insert(0, openVRString); newDevices = devicesList.ToArray(); } #if (UNITY_5_6 || UNITY_5_4 || UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0) UnityEditorInternal.VR.VREditor.SetVREnabledDevices(currentTarget, newDevices); #else UnityEditorInternal.VR.VREditor.SetVREnabledDevicesOnTargetGroup(currentTarget, newDevices); #endif Debug.Log("[SteamVR Setup] Added OpenVR to supported VR SDKs list."); } #if UNITY_2018_2_OR_NEWER //2018+ requires us to manually add the OpenVR package //2020.1+ has a separate script that does installs switch (packageState) { case PackageStates.None: //see if we have the package listRequest = UnityEditor.PackageManager.Client.List(true); packageState = PackageStates.WaitingForList; break; case PackageStates.WaitingForList: if (listRequest.IsCompleted) { if (listRequest.Error != null || listRequest.Status == UnityEditor.PackageManager.StatusCode.Failure) { packageState = PackageStates.Failed; break; } string packageName = null; packageName = unityOpenVRPackageString; bool hasPackage = listRequest.Result.Any(package => package.name == packageName); if (hasPackage == false) { //if we don't have the package - then install it addRequest = UnityEditor.PackageManager.Client.Add(packageName); packageState = PackageStates.WaitingForAdd; addTryCount++; Debug.Log("[SteamVR Setup] Installing OpenVR package..."); addingPackageTime.Start(); addingPackageTimeTotal.Start(); } else { //if we do have the package, do nothing packageState = PackageStates.Installed; //already installed } } break; case PackageStates.WaitingForAdd: if (addRequest.IsCompleted) { if (addRequest.Error != null || addRequest.Status == UnityEditor.PackageManager.StatusCode.Failure) { packageState = PackageStates.Failed; break; } else { //if the package manager says we added it then confirm that with the list listRequest = UnityEditor.PackageManager.Client.List(true); packageState = PackageStates.WaitingForAddConfirm; } } else { if (addingPackageTimeTotal.Elapsed.TotalSeconds > estimatedTimeToInstall) estimatedTimeToInstall *= 2; // :) string dialogText; if (addTryCount == 1) dialogText = "Installing OpenVR from Unity Package Manager..."; else dialogText = "Retrying OpenVR install from Unity Package Manager..."; bool cancel = UnityEditor.EditorUtility.DisplayCancelableProgressBar("SteamVR", dialogText, (float)addingPackageTimeTotal.Elapsed.TotalSeconds / estimatedTimeToInstall); if (cancel) packageState = PackageStates.Failed; if (addingPackageTime.Elapsed.TotalSeconds > 10) { Debug.Log("[SteamVR Setup] Waiting for package manager to install OpenVR package..."); addingPackageTime.Stop(); addingPackageTime.Reset(); addingPackageTime.Start(); } } break; case PackageStates.WaitingForAddConfirm: if (listRequest.IsCompleted) { if (listRequest.Error != null) { packageState = PackageStates.Failed; break; } string packageName = unityOpenVRPackageString; bool hasPackage = listRequest.Result.Any(package => package.name == packageName); if (hasPackage == false) { if (addTryCount == 1) { addRequest = UnityEditor.PackageManager.Client.Add(packageName); packageState = PackageStates.WaitingForAdd; addTryCount++; Debug.Log("[SteamVR Setup] Retrying OpenVR package install..."); } else { packageState = PackageStates.Failed; } } else { packageState = PackageStates.Installed; //installed successfully Debug.Log("[SteamVR Setup] Successfully installed OpenVR package."); } } break; } if (packageState == PackageStates.Failed || packageState == PackageStates.Installed) { addingPackageTime.Stop(); addingPackageTimeTotal.Stop(); UnityEditor.EditorUtility.ClearProgressBar(); UnityEditor.EditorApplication.update -= Update; //we're done trying to auto-enable vr if (packageState == PackageStates.Failed) { string failtext = "The Unity Package Manager failed to automatically install the OpenVR package. Please open the Package Manager Window and try to install it manually."; UnityEditor.EditorUtility.DisplayDialog("SteamVR", failtext, "Ok"); Debug.Log("[SteamVR Setup] " + failtext); } } #else UnityEditor.EditorApplication.update -= Update; #endif #endif } } private static void StartAutoUpdater() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int assemblyIndex = 0; assemblyIndex < assemblies.Length; assemblyIndex++) { Assembly assembly = assemblies[assemblyIndex]; Type type = assembly.GetType("Unity.XR.OpenVR.OpenVRAutoUpdater"); if (type != null) { MethodInfo preinitMethodInfo = type.GetMethod("Start"); if (preinitMethodInfo != null) { preinitMethodInfo.Invoke(null, null); return; } } } } private static Type xrMetadataStoreType; private static MethodInfo GetMethod(string methodName, Type[] parameters = null) { if (xrMetadataStoreType == null) xrMetadataStoreType = SteamVR_Utils.FindType("UnityEditor.XR.Management.Metadata.XRPackageMetadataStore"); if (parameters == null) return xrMetadataStoreType.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic); else return xrMetadataStoreType.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic, null, parameters, null); } } }