mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-02 22:39:22 +00:00
i dont rememebr
This commit is contained in:
parent
374ab6c11e
commit
86828a94e2
48 changed files with 1637 additions and 841 deletions
|
@ -1,137 +1,26 @@
|
|||
using ABI.CCK.Components;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Core.Util.Object_Behaviour;
|
||||
using ABI_RC.Systems.IK;
|
||||
using ABI_RC.Systems.IK.TrackingModules;
|
||||
using cohtml.Net;
|
||||
using ABI_RC.Core;
|
||||
using ABI_RC.Systems.InputManagement;
|
||||
using HarmonyLib;
|
||||
using NAK.DesktopVRSwitch.Patches;
|
||||
using NAK.DesktopVRSwitch.VRModeTrackers;
|
||||
using UnityEngine;
|
||||
using Valve.VR;
|
||||
using NativeVRModeSwitchManager = ABI_RC.Systems.VRModeSwitch.VRModeSwitchManager;
|
||||
|
||||
namespace NAK.DesktopVRSwitch.HarmonyPatches;
|
||||
|
||||
internal class CheckVRPatches
|
||||
internal class CVRInputManagerPatches
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(CheckVR), nameof(CheckVR.Awake))]
|
||||
private static void Postfix_CheckVR_Start(ref CheckVR __instance)
|
||||
[HarmonyPatch(typeof(CVRInputManager), "OnPostVRModeSwitch")]
|
||||
private static void Postfix_CVRInputManager_OnPostVRModeSwitch(bool inVr, UnityEngine.Camera playerCamera)
|
||||
{
|
||||
try
|
||||
{
|
||||
__instance.gameObject.AddComponent<VRModeSwitchManager>();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DesktopVRSwitch.Logger.Error($"Error during the patched method {nameof(Postfix_CheckVR_Start)}");
|
||||
DesktopVRSwitch.Logger.Error(e);
|
||||
}
|
||||
RootLogic.Instance.ToggleMouse(inVr);
|
||||
}
|
||||
}
|
||||
|
||||
internal class IKSystemPatches
|
||||
{
|
||||
[HarmonyPostfix] //lazy fix so device indices can change properly
|
||||
[HarmonyPatch(typeof(SteamVRTrackingModule), nameof(SteamVRTrackingModule.ModuleDestroy))]
|
||||
private static void Postfix_SteamVRTrackingModule_ModuleDestroy(ref SteamVRTrackingModule __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (TrackingPoint t in __instance.TrackingPoints)
|
||||
{
|
||||
UnityEngine.Object.Destroy(t.referenceGameObject);
|
||||
}
|
||||
|
||||
__instance.TrackingPoints.Clear();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DesktopVRSwitch.Logger.Error($"Error during the patched method {nameof(Postfix_SteamVRTrackingModule_ModuleDestroy)}");
|
||||
DesktopVRSwitch.Logger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class CVRWorldPatches
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(CVRWorld), nameof(CVRWorld.SetDefaultCamValues))]
|
||||
[HarmonyPatch(typeof(CVRWorld), nameof(CVRWorld.CopyRefCamValues))]
|
||||
private static void Postfix_CVRWorld_HandleCamValues()
|
||||
{
|
||||
try
|
||||
{
|
||||
ReferenceCameraPatch.OnWorldLoad();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DesktopVRSwitch.Logger.Error($"Error during the patched method {nameof(Postfix_CVRWorld_HandleCamValues)}");
|
||||
DesktopVRSwitch.Logger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class CameraFacingObjectPatches
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(CameraFacingObject), nameof(CameraFacingObject.Start))]
|
||||
private static void Postfix_CameraFacingObject_Start(ref CameraFacingObject __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
__instance.gameObject.AddComponent<CameraFacingObjectTracker>();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DesktopVRSwitch.Logger.Error($"Error during the patched method {nameof(Postfix_CameraFacingObject_Start)}");
|
||||
DesktopVRSwitch.Logger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class CVRPickupObjectPatches
|
||||
internal class VRModeSwitchManagerPatches
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(CVRPickupObject), nameof(CVRPickupObject.Start))]
|
||||
private static void Prefix_CVRPickupObject_Start(ref CVRPickupObject __instance)
|
||||
[HarmonyPatch(typeof(NativeVRModeSwitchManager), "StartSwitchInternal")]
|
||||
private static void Postfix_CVRInputManager_OnPostVRModeSwitch()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (__instance.gripType == CVRPickupObject.GripType.Free)
|
||||
return;
|
||||
|
||||
Transform vrOrigin = __instance.gripOrigin;
|
||||
Transform desktopOrigin = vrOrigin != null ? vrOrigin.Find("[Desktop]") : null;
|
||||
if (vrOrigin != null && desktopOrigin != null)
|
||||
{
|
||||
CVRPickupObjectTracker tracker = __instance.gameObject.AddComponent<CVRPickupObjectTracker>();
|
||||
tracker._pickupObject = __instance;
|
||||
tracker._storedGripOrigin = (!MetaPort.Instance.isUsingVr ? vrOrigin : desktopOrigin);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DesktopVRSwitch.Logger.Error($"Error during the patched method {nameof(Prefix_CVRPickupObject_Start)}");
|
||||
DesktopVRSwitch.Logger.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class SteamVRBehaviourPatches
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(SteamVR_Behaviour), nameof(SteamVR_Behaviour.OnQuit))]
|
||||
private static bool Prefix_SteamVR_Behaviour_OnQuit()
|
||||
{
|
||||
if (!ModSettings.EntrySwitchToDesktopOnExit.Value)
|
||||
return true;
|
||||
|
||||
// If we don't switch fast enough, SteamVR will force close.
|
||||
// World Transition might cause issues. Might need to override.
|
||||
if (VRModeSwitchManager.Instance != null)
|
||||
VRModeSwitchManager.Instance.AttemptSwitch();
|
||||
|
||||
return false;
|
||||
CVRInputManager.Instance.inputEnabled = false;
|
||||
}
|
||||
}
|
|
@ -1,84 +1,14 @@
|
|||
|
||||
using System;
|
||||
using MelonLoader;
|
||||
using NAK.DesktopVRSwitch.VRModeTrackers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.DesktopVRSwitch;
|
||||
|
||||
public class DesktopVRSwitch : MelonMod
|
||||
{
|
||||
internal static MelonLogger.Instance Logger;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
Logger = LoggerInstance;
|
||||
|
||||
RegisterVRModeTrackers();
|
||||
|
||||
// main manager
|
||||
ApplyPatches(typeof(HarmonyPatches.CheckVRPatches));
|
||||
// nameplate fixes
|
||||
ApplyPatches(typeof(HarmonyPatches.CameraFacingObjectPatches));
|
||||
// pickup fixes
|
||||
ApplyPatches(typeof(HarmonyPatches.CVRPickupObjectPatches));
|
||||
// lazy fix to reset iksystem
|
||||
ApplyPatches(typeof(HarmonyPatches.IKSystemPatches));
|
||||
// post processing fixes
|
||||
ApplyPatches(typeof(HarmonyPatches.CVRWorldPatches));
|
||||
|
||||
// prevent steamvr behaviour from closing game
|
||||
ApplyPatches(typeof(HarmonyPatches.SteamVRBehaviourPatches));
|
||||
|
||||
InitializeIntegration("BTKUILib", Integrations.BTKUIAddon.Initialize);
|
||||
}
|
||||
|
||||
public override void OnUpdate()
|
||||
{
|
||||
if (!Input.GetKeyDown(KeyCode.F6) || !Input.GetKey(KeyCode.LeftControl))
|
||||
return;
|
||||
|
||||
if (VRModeSwitchManager.Instance != null)
|
||||
VRModeSwitchManager.Instance.AttemptSwitch();
|
||||
}
|
||||
|
||||
private static void RegisterVRModeTrackers()
|
||||
{
|
||||
// Core trackers
|
||||
VRModeSwitchManager.RegisterVRModeTracker(new CheckVRTracker());
|
||||
VRModeSwitchManager.RegisterVRModeTracker(new MetaPortTracker());
|
||||
|
||||
// HUD trackers
|
||||
VRModeSwitchManager.RegisterVRModeTracker(new CohtmlHudTracker());
|
||||
VRModeSwitchManager.RegisterVRModeTracker(new HudOperationsTracker());
|
||||
|
||||
// Player trackers
|
||||
VRModeSwitchManager.RegisterVRModeTracker(new PlayerSetupTracker());
|
||||
VRModeSwitchManager.RegisterVRModeTracker(new MovementSystemTracker());
|
||||
VRModeSwitchManager.RegisterVRModeTracker(new IKSystemTracker());
|
||||
|
||||
// Menu trackers
|
||||
VRModeSwitchManager.RegisterVRModeTracker(new CVR_MenuManagerTracker());
|
||||
VRModeSwitchManager.RegisterVRModeTracker(new ViewManagerTracker());
|
||||
|
||||
// Interaction trackers
|
||||
VRModeSwitchManager.RegisterVRModeTracker(new CVRInputManagerTracker());
|
||||
VRModeSwitchManager.RegisterVRModeTracker(new CVR_InteractableManagerTracker());
|
||||
VRModeSwitchManager.RegisterVRModeTracker(new CVRGestureRecognizerTracker());
|
||||
|
||||
// Portable camera tracker
|
||||
VRModeSwitchManager.RegisterVRModeTracker(new PortableCameraTracker());
|
||||
|
||||
// CVRWorld tracker - Must come after PlayerSetupTracker
|
||||
VRModeSwitchManager.RegisterVRModeTracker(new CVRWorldTracker());
|
||||
}
|
||||
|
||||
private static void InitializeIntegration(string modName, Action integrationAction)
|
||||
{
|
||||
if (RegisteredMelons.All(it => it.Info.Name != modName))
|
||||
return;
|
||||
|
||||
Logger.Msg($"Initializing {modName} integration.");
|
||||
integrationAction.Invoke();
|
||||
ApplyPatches(typeof(HarmonyPatches.CVRInputManagerPatches));
|
||||
ApplyPatches(typeof(HarmonyPatches.VRModeSwitchManagerPatches));
|
||||
}
|
||||
|
||||
private void ApplyPatches(Type type)
|
||||
|
|
|
@ -1,32 +1,34 @@
|
|||
using ABI_RC.Systems.UI;
|
||||
using NAK.DesktopVRSwitch.VRModeTrackers;
|
||||
using System.Collections;
|
||||
using ABI_RC.Core.EventSystem;
|
||||
using ABI_RC.Core.IO;
|
||||
using ABI_RC.Core.Player;
|
||||
using ABI_RC.Core.Savior;
|
||||
using ABI_RC.Core.UI;
|
||||
using ABI_RC.Systems.GameEventSystem;
|
||||
using ABI_RC.Systems.InputManagement;
|
||||
using ABI_RC.Systems.VRModeSwitch;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.XR.Management;
|
||||
|
||||
namespace NAK.DesktopVRSwitch;
|
||||
|
||||
public class VRModeSwitchManager : MonoBehaviour
|
||||
public class VRModeSwitchManager : MonoBehaviour
|
||||
{
|
||||
#region Static
|
||||
|
||||
public static VRModeSwitchManager Instance { get; private set; }
|
||||
|
||||
public static void RegisterVRModeTracker(VRModeTracker observer) => observer.TrackerInit();
|
||||
public static void UnregisterVRModeTracker(VRModeTracker observer) => observer.TrackerDestroy();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Variables
|
||||
|
||||
// Settings
|
||||
public bool DesktopVRSwitchEnabled;
|
||||
public bool UseWorldTransition = true;
|
||||
public bool ReloadLocalAvatar = true;
|
||||
|
||||
|
||||
public bool SwitchInProgress { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Unity Methods
|
||||
|
||||
private void Awake()
|
||||
|
@ -36,73 +38,125 @@ public class VRModeSwitchManager : MonoBehaviour
|
|||
DestroyImmediate(this);
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
|
||||
DesktopVRSwitchEnabled = MetaPort.Instance.settings.GetSettingsBool("ExperimentalDesktopVRSwitch");
|
||||
MetaPort.Instance.settings.settingBoolChanged.AddListener(OnSettingsBoolChanged);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!DesktopVRSwitchEnabled)
|
||||
return;
|
||||
|
||||
if (SwitchInProgress)
|
||||
return;
|
||||
|
||||
if (CVRInputManager.Instance.switchMode)
|
||||
AttemptSwitch();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
private static bool IsInXR() => XRGeneralSettings.Instance.Manager.activeLoader != null;
|
||||
|
||||
public void AttemptSwitch() => StartCoroutine(StartSwitchInternal());
|
||||
|
||||
public void AttemptSwitch()
|
||||
{
|
||||
if (SwitchInProgress)
|
||||
return;
|
||||
|
||||
// dont allow switching during world transfer, itll explode violently
|
||||
if (CVRObjectLoader.Instance.IsLoadingWorldToJoin())
|
||||
return;
|
||||
|
||||
StartCoroutine(StartSwitchInternal());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void OnSettingsBoolChanged(string settingName, bool val)
|
||||
{
|
||||
if (settingName == "ExperimentalDesktopVRSwitch")
|
||||
DesktopVRSwitchEnabled = val;
|
||||
}
|
||||
|
||||
private IEnumerator StartSwitchInternal()
|
||||
{
|
||||
if (SwitchInProgress)
|
||||
if (SwitchInProgress)
|
||||
yield break;
|
||||
|
||||
|
||||
NotifyOnPreSwitch();
|
||||
|
||||
bool useWorldTransition = UseWorldTransition;
|
||||
SwitchInProgress = true;
|
||||
|
||||
|
||||
yield return null;
|
||||
|
||||
|
||||
if (useWorldTransition)
|
||||
yield return StartCoroutine(StartTransition());
|
||||
|
||||
bool isUsingVr = IsInXR();
|
||||
var wasInXr = IsInXR();
|
||||
|
||||
InvokeOnPreSwitch(isUsingVr);
|
||||
InvokeOnPreSwitch(!wasInXr);
|
||||
|
||||
yield return StartCoroutine(XRAndReloadAvatar(!isUsingVr));
|
||||
// Note: this assumes that wasInXr has been correctly set earlier in your method.
|
||||
Task xrTask = wasInXr ? XRHandler.StopXR() : XRHandler.StartXR();
|
||||
|
||||
// Wait for the task to complete. This makes the coroutine wait here until the above thread is done.
|
||||
yield return new WaitUntil(() => xrTask.IsCompleted || xrTask.IsFaulted);
|
||||
|
||||
// Check task status, handle any fault that occurred during the execution of the task.
|
||||
if (xrTask.IsFaulted)
|
||||
{
|
||||
// Log and/or handle exceptions that occurred within the task.
|
||||
Exception innerException = xrTask.Exception.InnerException; // The Exception that caused the Task to enter the faulted state
|
||||
MelonLoader.MelonLogger.Error("Encountered an error while executing the XR task: " + innerException.Message);
|
||||
// Handle the exception appropriately.
|
||||
}
|
||||
|
||||
if (wasInXr != IsInXR())
|
||||
{
|
||||
ReloadAvatar();
|
||||
InvokeOnPostSwitch(!wasInXr);
|
||||
}
|
||||
else
|
||||
{
|
||||
NotifyOnFailedSwitch();
|
||||
InvokeOnFailedSwitch(!wasInXr);
|
||||
}
|
||||
|
||||
if (useWorldTransition)
|
||||
yield return StartCoroutine(ContinueTransition());
|
||||
|
||||
SwitchInProgress = false;
|
||||
}
|
||||
|
||||
private IEnumerator XRAndReloadAvatar(bool start)
|
||||
{
|
||||
yield return StartCoroutine(start ? XRHandler.StartXR() : XRHandler.StopXR());
|
||||
|
||||
bool isUsingVr = IsInXR();
|
||||
if (isUsingVr == start)
|
||||
{
|
||||
ReloadAvatar();
|
||||
InvokeOnPostSwitch(start);
|
||||
}
|
||||
else
|
||||
{
|
||||
InvokeOnFailedSwitch(start);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReloadAvatar()
|
||||
{
|
||||
if (!ReloadLocalAvatar)
|
||||
if (!ReloadLocalAvatar)
|
||||
return;
|
||||
|
||||
Utils.ClearLocalAvatar();
|
||||
Utils.ReloadLocalAvatar();
|
||||
|
||||
// TODO: Is there a better way to reload only locally?
|
||||
PlayerSetup.Instance.ClearAvatar();
|
||||
AssetManagement.Instance.LoadLocalAvatar(MetaPort.Instance.currentAvatarGuid);
|
||||
}
|
||||
|
||||
#endregion
|
||||
private bool IsInXR()
|
||||
{
|
||||
return XRGeneralSettings.Instance.Manager.activeLoader != null;
|
||||
}
|
||||
|
||||
private UnityEngine.Camera GetPlayerCamera(bool isVr)
|
||||
{
|
||||
return (isVr ? PlayerSetup.Instance.vrCamera : PlayerSetup.Instance.desktopCamera)
|
||||
.GetComponent<UnityEngine.Camera>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Transition Coroutines
|
||||
|
||||
private IEnumerator StartTransition()
|
||||
|
@ -123,38 +177,46 @@ public class VRModeSwitchManager : MonoBehaviour
|
|||
|
||||
#region Event Handling
|
||||
|
||||
public class VRModeEventArgs : EventArgs
|
||||
private void InvokeOnPreSwitch(bool isUsingVr)
|
||||
{
|
||||
public bool IsUsingVr { get; }
|
||||
public Camera PlayerCamera { get; }
|
||||
UnityEngine.Camera playerCamera = GetPlayerCamera(isUsingVr);
|
||||
|
||||
public VRModeEventArgs(bool isUsingVr, Camera playerCamera)
|
||||
{
|
||||
IsUsingVr = isUsingVr;
|
||||
PlayerCamera = playerCamera;
|
||||
}
|
||||
ABI_RC.Systems.VRModeSwitch.VRModeSwitchManager.OnPreSwitchInternal?.Invoke(isUsingVr, playerCamera);
|
||||
CVRGameEventSystem.VRModeSwitch.OnPreSwitch?.Invoke(isUsingVr, playerCamera);
|
||||
}
|
||||
|
||||
public static event EventHandler<VRModeEventArgs> OnPreVRModeSwitch;
|
||||
public static event EventHandler<VRModeEventArgs> OnPostVRModeSwitch;
|
||||
public static event EventHandler<VRModeEventArgs> OnFailVRModeSwitch;
|
||||
|
||||
private void InvokeOnPreSwitch(bool isUsingVr) => SafeInvokeUnityEvent(OnPreVRModeSwitch, isUsingVr);
|
||||
private void InvokeOnPostSwitch(bool isUsingVr) => SafeInvokeUnityEvent(OnPostVRModeSwitch, isUsingVr);
|
||||
private void InvokeOnFailedSwitch(bool isUsingVr) => SafeInvokeUnityEvent(OnFailVRModeSwitch, isUsingVr);
|
||||
|
||||
private void SafeInvokeUnityEvent(EventHandler<VRModeEventArgs> switchEvent, bool isUsingVr)
|
||||
private void InvokeOnPostSwitch(bool isUsingVr)
|
||||
{
|
||||
try
|
||||
{
|
||||
Camera playerCamera = Utils.GetPlayerCameraObject(isUsingVr).GetComponent<Camera>();
|
||||
switchEvent?.Invoke(this, new VRModeEventArgs(isUsingVr, playerCamera));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DesktopVRSwitch.Logger.Error($"Error in event handler: {e}");
|
||||
}
|
||||
UnityEngine.Camera playerCamera = GetPlayerCamera(isUsingVr);
|
||||
|
||||
ABI_RC.Systems.VRModeSwitch.VRModeSwitchManager.OnPostSwitchInternal?.Invoke(isUsingVr, playerCamera);
|
||||
CVRGameEventSystem.VRModeSwitch.OnPostSwitch?.Invoke(isUsingVr, playerCamera);
|
||||
}
|
||||
|
||||
|
||||
private void InvokeOnFailedSwitch(bool isUsingVr)
|
||||
{
|
||||
UnityEngine.Camera playerCamera = GetPlayerCamera(isUsingVr);
|
||||
|
||||
ABI_RC.Systems.VRModeSwitch.VRModeSwitchManager.OnFailedSwitchInternal?.Invoke(isUsingVr, playerCamera);
|
||||
CVRGameEventSystem.VRModeSwitch.OnFailedSwitch?.Invoke(isUsingVr, playerCamera);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region Notifications
|
||||
|
||||
private void NotifyOnPreSwitch()
|
||||
{
|
||||
CohtmlHud.Instance.ViewDropTextImmediate("(Local) Client",
|
||||
"VR Mode Switch", "Switching to " + (IsInXR() ? "Desktop" : "VR") + " Mode");
|
||||
}
|
||||
|
||||
private void NotifyOnFailedSwitch()
|
||||
{
|
||||
// TODO: Can we get reason it failed?
|
||||
CohtmlHud.Instance.ViewDropTextImmediate("(Local) Client",
|
||||
"VR Mode Switch", "Switch failed");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
using System.Collections;
|
||||
#if !PLATFORM_ANDROID
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using ABI_RC.Core.Savior;
|
||||
using Unity.XR.OpenVR;
|
||||
|
@ -6,62 +10,76 @@ using UnityEngine;
|
|||
using UnityEngine.XR.Management;
|
||||
using UnityEngine.XR.OpenXR;
|
||||
using Valve.VR;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace NAK.DesktopVRSwitch;
|
||||
|
||||
internal static class XRHandler
|
||||
namespace ABI_RC.Systems.VRModeSwitch
|
||||
{
|
||||
internal static IEnumerator StartXR()
|
||||
internal static class XRHandler
|
||||
{
|
||||
yield return XRGeneralSettings.Instance.Manager.InitializeLoader();
|
||||
|
||||
if (XRGeneralSettings.Instance.Manager.activeLoader != null)
|
||||
XRGeneralSettings.Instance.Manager.StartSubsystems();
|
||||
else
|
||||
yield return StopXR();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
internal static IEnumerator StopXR()
|
||||
{
|
||||
if (!XRGeneralSettings.Instance.Manager.isInitializationComplete)
|
||||
yield break;
|
||||
|
||||
// Forces SteamVR to reinitialize SteamVR_Input next switch
|
||||
SteamVR_ActionSet_Manager.DisableAllActionSets();
|
||||
SteamVR_Input.initialized = false;
|
||||
|
||||
// Remove SteamVR behaviour & render
|
||||
UnityEngine.Object.DestroyImmediate(SteamVR_Behaviour.instance.gameObject);
|
||||
SteamVR.enabled = false; // disposes SteamVR
|
||||
Patches.SteamVRNullReferencePatch.DestroySteamVRInstancesImmediate();
|
||||
|
||||
// Disable UnityXR
|
||||
XRGeneralSettings.Instance.Manager.StopSubsystems();
|
||||
XRGeneralSettings.Instance.Manager.DeinitializeLoader();
|
||||
|
||||
// We don't really need to wait a frame on Stop()
|
||||
yield return null;
|
||||
}
|
||||
|
||||
internal static void SwitchLoader()
|
||||
{
|
||||
XRLoader item;
|
||||
|
||||
if (!CheckVR.Instance.forceOpenXr)
|
||||
private static async Task InitializeXRLoader()
|
||||
{
|
||||
item = ScriptableObject.CreateInstance<OpenVRLoader>();
|
||||
DesktopVRSwitch.Logger.Msg("Using XR Loader: SteamVR");
|
||||
EnsureXRLoader();
|
||||
XRGeneralSettings.Instance.Manager.InitializeLoaderSync();
|
||||
await Task.Yield();
|
||||
}
|
||||
else
|
||||
|
||||
internal static async Task StartXR()
|
||||
{
|
||||
item = ScriptableObject.CreateInstance<OpenXRLoader>();
|
||||
DesktopVRSwitch.Logger.Msg("Using XR Loader: OpenXR");
|
||||
await InitializeXRLoader();
|
||||
|
||||
if (XRGeneralSettings.Instance.Manager.activeLoader != null)
|
||||
XRGeneralSettings.Instance.Manager.StartSubsystems();
|
||||
else
|
||||
await StopXR(); // assuming StopXR is now an async method.
|
||||
|
||||
// Await a delay or equivalent method to wait for a frame.
|
||||
await Task.Yield(); // This line is to simulate "waiting for the next frame" in an async way.
|
||||
}
|
||||
|
||||
typeof(XRManagerSettings)
|
||||
.GetField("m_Loaders", BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
?.SetValue(XRGeneralSettings.Instance.Manager, new List<XRLoader> { item });
|
||||
internal static Task StopXR()
|
||||
{
|
||||
if (!XRGeneralSettings.Instance.Manager.isInitializationComplete)
|
||||
return Task.CompletedTask;
|
||||
|
||||
// Forces SteamVR to reinitialize SteamVR_Input next switch
|
||||
SteamVR_ActionSet_Manager.DisableAllActionSets();
|
||||
SteamVR_Input.initialized = false;
|
||||
|
||||
// Remove SteamVR behaviour & render
|
||||
Object.DestroyImmediate(SteamVR_Behaviour.instance.gameObject);
|
||||
SteamVR.enabled = false; // disposes SteamVR
|
||||
|
||||
// Disable UnityXR
|
||||
XRGeneralSettings.Instance.Manager.StopSubsystems();
|
||||
XRGeneralSettings.Instance.Manager.DeinitializeLoader();
|
||||
return Task.CompletedTask;
|
||||
|
||||
// If we need to wait for something specific (like a frame), we use Task.Delay or equivalent.
|
||||
// In this case, it seems like you don't need to wait after stopping XR,
|
||||
// so we don't necessarily need an equivalent to 'yield return null' here.
|
||||
}
|
||||
|
||||
private static void EnsureXRLoader()
|
||||
{
|
||||
Type selectedLoaderType = !CheckVR.Instance.forceOpenXr ? typeof(OpenVRLoader) : typeof(OpenXRLoader);
|
||||
|
||||
// dont do anything if we already have the loader selected
|
||||
if (XRGeneralSettings.Instance.Manager.activeLoaders.Count > 0
|
||||
&& XRGeneralSettings.Instance.Manager.activeLoaders[0].GetType() == selectedLoaderType)
|
||||
return;
|
||||
|
||||
XRLoader newLoaderInstance = (XRLoader)ScriptableObject.CreateInstance(selectedLoaderType);
|
||||
FieldInfo field = typeof(XRManagerSettings).GetField("m_Loaders",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (field == null) return;
|
||||
|
||||
// destroy old loaders, set the new laoder
|
||||
// this should not happen normally, but changing loader during runtime sounds funni
|
||||
if (field.GetValue(XRGeneralSettings.Instance.Manager) is List<XRLoader> currentLoaders)
|
||||
foreach (XRLoader loader in currentLoaders.Where(loader => loader != null)) Object.Destroy(loader);
|
||||
|
||||
field.SetValue(XRGeneralSettings.Instance.Manager, new List<XRLoader> { newLoaderInstance });
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue