[DesktopVRSwitch] Minor changes

This commit is contained in:
NotAKidoS 2023-08-03 00:05:45 -05:00
parent 6d17085f21
commit 4c09f9bd57
25 changed files with 359 additions and 205 deletions

View file

@ -1,2 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk" />
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<Reference Include="BTKUILib">
<HintPath>$(MsBuildThisFileDirectory)\..\.ManagedLibs\BTKUILib.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
</Project>

View file

@ -3,6 +3,8 @@ 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;
using cohtml.Net;
using HarmonyLib;
using NAK.DesktopVRSwitch.Patches;
using NAK.DesktopVRSwitch.VRModeTrackers;
@ -117,13 +119,36 @@ internal class CVRPickupObjectPatches
}
}
internal class CohtmlUISystemPatches
{
[HarmonyPrefix]
[HarmonyPatch(typeof(UISystem), nameof(UISystem.RegisterGamepad))]
[HarmonyPatch(typeof(UISystem), nameof(UISystem.UnregisterGamepad))]
[HarmonyPatch(typeof(UISystem), nameof(UISystem.UpdateGamepadState))]
private static bool Prefix_UISystem_FuckOff()
{
/**
GameFace Version 1.34.0.4 released 10 Nov 2022
Fixed a crash when registering and unregistering gamepads
Fix Fixed setting a gamepad object when creating GamepadEvent from JavaScript
Fix Fixed a crash when unregistering a gamepad twice
Fix Fixed a GamepadEvent related crash during garbage collector tracing
it is not fixed you fucking piece of shit
**/
// dont
return false;
}
}
internal class SteamVRBehaviourPatches
{
[HarmonyPrefix]
[HarmonyPatch(typeof(SteamVR_Behaviour), nameof(SteamVR_Behaviour.OnQuit))]
private static bool Prefix_SteamVR_Behaviour_OnQuit()
{
if (!DesktopVRSwitch.EntrySwitchToDesktopOnExit.Value)
if (!ModSettings.EntrySwitchToDesktopOnExit.Value)
return true;
// If we don't switch fast enough, SteamVR will force close.

View file

@ -0,0 +1,64 @@
using BTKUILib;
using BTKUILib.UIObjects;
using System.Runtime.CompilerServices;
using ABI_RC.Core.Base;
namespace NAK.DesktopVRSwitch.Integrations;
public static class BTKUIAddon
{
#region Initialization
[MethodImpl(MethodImplOptions.NoInlining)]
public static void Initialize()
{
// Add mod to the Misc Menu
Page miscPage = QuickMenuAPI.MiscTabPage;
Category vrSwitchMiscCategory = miscPage.AddCategory(ModSettings.SettingsCategory);
vrSwitchMiscCategory.AddButton("Switch VR Mode", "", "Switch to Desktop/VR.").OnPress +=
() =>
{
QuickMenuAPI.ShowConfirm(
title: "Switch VR Mode",
content: "Are you sure you want to switch to Desktop/VR?",
onYes: () => VRModeSwitchManager.Instance.AttemptSwitch()
);
};
SetupSwitchConfigurationPage(ref vrSwitchMiscCategory);
}
#endregion
#region Pages Setup
private static void SetupSwitchConfigurationPage(ref Category parentCategory)
{
Page vrSwitchPage = parentCategory.AddPage("DesktopVRSwitch Settings", "", "Configure the settings for DesktopVRSwitch.", ModSettings.SettingsCategory);
vrSwitchPage.MenuTitle = "DesktopVRSwitch Settings";
Category vrSwitchCategory = vrSwitchPage.AddCategory(vrSwitchPage.MenuTitle);
AddMelonToggle(ref vrSwitchCategory, ModSettings.EntryEnterCalibrationOnSwitch);
AddMelonToggle(ref vrSwitchCategory, ModSettings.EntryUseTransitionOnSwitch);
AddMelonToggle(ref vrSwitchCategory, ModSettings.EntrySwitchToDesktopOnExit);
}
#endregion
#region Melon Pref Helpers
private static void AddMelonToggle(ref Category category, MelonLoader.MelonPreferences_Entry<bool> entry)
{
category.AddToggle(entry.DisplayName, entry.Description, entry.Value).OnValueUpdated += b => entry.Value = b;
}
private static void AddMelonSlider(ref Page page, MelonLoader.MelonPreferences_Entry<float> entry, float min, float max, int decimalPlaces = 2)
{
page.AddSlider(entry.DisplayName, entry.Description, entry.Value, min, max, decimalPlaces).OnValueUpdated += f => entry.Value = f;
}
#endregion
}

View file

@ -8,22 +8,7 @@ namespace NAK.DesktopVRSwitch;
public class DesktopVRSwitch : MelonMod
{
internal static MelonLogger.Instance Logger;
public static readonly MelonPreferences_Category Category =
MelonPreferences.CreateCategory(nameof(DesktopVRSwitch));
public static readonly MelonPreferences_Entry<bool> EntryEnterCalibrationOnSwitch =
Category.CreateEntry("Enter Calibration on Switch", true, description: "Should you automatically be placed into calibration after switch if FBT is available? Overridden by Save Calibration IK setting.");
public static readonly MelonPreferences_Entry<bool> EntryUseTransitionOnSwitch =
Category.CreateEntry("Use Transition on Switch", true, description: "Should the world transition play on VRMode switch?");
//public static readonly MelonPreferences_Entry<bool> EntryRenderVRGameView =
// Category.CreateEntry("Render VR Game View", true, description: "Should the VR view be displayed in the game window after VRMode switch?");
public static readonly MelonPreferences_Entry<bool> EntrySwitchToDesktopOnExit =
Category.CreateEntry("Switch to Desktop on SteamVR Exit", false, description: "Should the game switch to Desktop when SteamVR quits?");
public override void OnInitializeMelon()
{
Logger = LoggerInstance;
@ -40,9 +25,14 @@ public class DesktopVRSwitch : MelonMod
ApplyPatches(typeof(HarmonyPatches.IKSystemPatches));
// post processing fixes
ApplyPatches(typeof(HarmonyPatches.CVRWorldPatches));
// fuck you
ApplyPatches(typeof(HarmonyPatches.CohtmlUISystemPatches));
// prevent steamvr behaviour from closing game
ApplyPatches(typeof(HarmonyPatches.SteamVRBehaviourPatches));
InitializeIntegration("BTKUILib", Integrations.BTKUIAddon.Initialize);
}
public override void OnUpdate()
@ -83,6 +73,15 @@ public class DesktopVRSwitch : MelonMod
// 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();
}
private void ApplyPatches(Type type)
{

View file

@ -0,0 +1,20 @@
using MelonLoader;
namespace NAK.DesktopVRSwitch;
public static class ModSettings
{
internal const string SettingsCategory = nameof(DesktopVRSwitch);
public static readonly MelonPreferences_Category Category =
MelonPreferences.CreateCategory(SettingsCategory);
public static readonly MelonPreferences_Entry<bool> EntryEnterCalibrationOnSwitch =
Category.CreateEntry("Enter Calibration on Switch", true, description: "Should you automatically be placed into calibration after switch if FBT is available? Overridden by Save Calibration IK setting.");
public static readonly MelonPreferences_Entry<bool> EntryUseTransitionOnSwitch =
Category.CreateEntry("Use Transition on Switch", true, description: "Should the world transition play on VRMode switch?");
public static readonly MelonPreferences_Entry<bool> EntrySwitchToDesktopOnExit =
Category.CreateEntry("Switch to Desktop on SteamVR Exit", false, description: "Should the game switch to Desktop when SteamVR quits?");
}

View file

@ -9,7 +9,7 @@ using UnityEngine.Rendering.PostProcessing;
namespace NAK.DesktopVRSwitch.Patches;
internal class ReferenceCameraPatch
internal static class ReferenceCameraPatch
{
public static void OnWorldLoad()
{
@ -31,13 +31,15 @@ internal class ReferenceCameraPatch
inactiveCam.depthTextureMode = activeCam.depthTextureMode;
// We cant copy this because we set it to 0 with ThirdPerson
inactiveCam.cullingMask &= -32769;
inactiveCam.cullingMask |= 256;
inactiveCam.cullingMask |= 512;
inactiveCam.cullingMask |= 32;
inactiveCam.cullingMask &= -4097;
inactiveCam.cullingMask |= 1024;
inactiveCam.cullingMask |= 8192;
var cullingMask = inactiveCam.cullingMask;
cullingMask &= -32769;
cullingMask |= 256;
cullingMask |= 512;
cullingMask |= 32;
cullingMask &= -4097;
cullingMask |= 1024;
cullingMask |= 8192;
inactiveCam.cullingMask = cullingMask;
// Copy post processing if added
PostProcessLayer ppLayerActiveCam = activeCam.GetComponent<PostProcessLayer>();

View file

@ -2,47 +2,22 @@
using NAK.DesktopVRSwitch.VRModeTrackers;
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.XR;
using UnityEngine.XR.Management;
using Valve.VR;
/**
I am unsure about this observer approach as only a few things need OnPre and OnFailed switch.
Those wouldn't be needed if I can start OpenVR before all that anyways.
Or... I just start OpenVR and see if it worked. OnPreSwitch would only be needed by menus & transition.
I think I should just use Unity Events as they would allow easier mod support. Subscribe to what you need.
**/
namespace NAK.DesktopVRSwitch;
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
// I don't think I *need* this. Only using cause I don't want stuff just existing.
private static readonly List<VRModeTracker> _vrModeTrackers = new List<VRModeTracker>();
public static event UnityAction<bool> OnPreVRModeSwitch;
public static event UnityAction<bool> OnPostVRModeSwitch;
public static event UnityAction<bool> OnFailVRModeSwitch;
private const string XRSETTINGS_DEVICE = "OpenVR";
public static void RegisterVRModeTracker(VRModeTracker observer)
{
_vrModeTrackers.Add(observer);
observer.TrackerInit();
}
public static void UnregisterVRModeTracker(VRModeTracker observer)
{
_vrModeTrackers.Remove(observer);
observer.TrackerDestroy();
}
#region Variables
// Settings
public bool UseWorldTransition = true;
@ -50,6 +25,10 @@ public class VRModeSwitchManager : MonoBehaviour
public bool SwitchInProgress { get; private set; }
#endregion
#region Unity Methods
private void Awake()
{
if (Instance != null)
@ -60,125 +39,120 @@ public class VRModeSwitchManager : MonoBehaviour
Instance = this;
}
public void AttemptSwitch()
{
StartCoroutine(StartSwitchCoroutine());
}
#endregion
private IEnumerator StartSwitchCoroutine()
#region Public Methods
public static bool IsInXR() => XRGeneralSettings.Instance.Manager.activeLoader != null;
public void AttemptSwitch() => StartCoroutine(StartSwitchInternal());
#endregion
#region Private Methods
private IEnumerator StartSwitchInternal()
{
if (SwitchInProgress)
{
if (SwitchInProgress)
yield break;
}
SwitchInProgress = true;
yield return null;
if (UseWorldTransition)
{ // start visual transition and wait for it to complete
WorldTransitionSystem.Instance.StartTransition();
yield return new WaitForSeconds(WorldTransitionSystem.Instance.CurrentInLength);
}
yield return StartCoroutine(StartTransition());
// Check if OpenVR is running
bool isUsingVr = IsInXR();
InvokeOnPreSwitch(isUsingVr);
// Start switch
if (!isUsingVr)
yield return StartCoroutine(StartXR());
else
StopXR();
// Check for updated VR mode
if (isUsingVr != IsInXR())
{
// reload the local avatar
if (ReloadLocalAvatar)
{
Utils.ClearLocalAvatar();
Utils.ReloadLocalAvatar();
}
InvokeOnPostSwitch(!isUsingVr);
}
else
{
InvokeOnFailedSwitch(!isUsingVr);
}
yield return StartCoroutine(XRAndReloadAvatar(!isUsingVr));
if (UseWorldTransition)
{ // would be cool to have out length
WorldTransitionSystem.Instance.ContinueTransition();
yield return new WaitForSeconds(WorldTransitionSystem.Instance.CurrentInLength);
}
yield return StartCoroutine(ContinueTransition());
SwitchInProgress = false;
yield break;
}
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)
return;
Utils.ClearLocalAvatar();
Utils.ReloadLocalAvatar();
}
private void SafeInvokeUnityEvent(UnityAction<bool> switchEvent, bool isUsingVr)
#endregion
#region Transition Coroutines
private IEnumerator StartTransition()
{
if (WorldTransitionSystem.Instance == null) yield break;
WorldTransitionSystem.Instance.StartTransition();
yield return new WaitForSeconds(WorldTransitionSystem.Instance.CurrentInLength);
}
private IEnumerator ContinueTransition()
{
if (WorldTransitionSystem.Instance == null) yield break;
WorldTransitionSystem.Instance.ContinueTransition();
yield return new WaitForSeconds(WorldTransitionSystem.Instance.CurrentInLength);
}
#endregion
#region Event Handling
public class VRModeEventArgs : EventArgs
{
public bool IsUsingVr { get; }
public Camera PlayerCamera { get; }
public VRModeEventArgs(bool isUsingVr, Camera playerCamera)
{
IsUsingVr = isUsingVr;
PlayerCamera = 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)
{
try
{
switchEvent.Invoke(isUsingVr);
var playerCamera = Utils.GetPlayerCameraObject(isUsingVr).GetComponent<Camera>();
switchEvent?.Invoke(this, new VRModeEventArgs(isUsingVr, playerCamera));
}
catch (Exception e)
{
Debug.Log($"Error in event handler: {e}");
DesktopVRSwitch.Logger.Error($"Error in event handler: {e}");
}
}
private void InvokeOnPreSwitch(bool isUsingVr)
{
SafeInvokeUnityEvent(OnPreVRModeSwitch, isUsingVr);
}
private void InvokeOnPostSwitch(bool isUsingVr)
{
SafeInvokeUnityEvent(OnPostVRModeSwitch, isUsingVr);
}
private void InvokeOnFailedSwitch(bool isUsingVr)
{
SafeInvokeUnityEvent(OnFailVRModeSwitch, isUsingVr);
}
public bool IsInXR() => XRGeneralSettings.Instance.Manager.activeLoader != null;
private IEnumerator StartXR()
{
yield return null; // wait a frame before checking
yield return XRGeneralSettings.Instance.Manager.InitializeLoader();
if (XRGeneralSettings.Instance.Manager.activeLoader != null)
{
XRGeneralSettings.Instance.Manager.StartSubsystems();
}
yield return null;
yield break;
}
private void StopXR()
{
if (!XRGeneralSettings.Instance.Manager.isInitializationComplete)
return;
// Forces SteamVR to reinitialize SteamVR_Input next switch
SteamVR_ActionSet_Manager.DisableAllActionSets();
SteamVR_Input.initialized = false;
// Remove SteamVR behaviour & render
DestroyImmediate(SteamVR_Behaviour.instance.gameObject);
SteamVR.enabled = false; // disposes SteamVR
// Disable UnityXR
XRGeneralSettings.Instance.Manager.StopSubsystems();
XRGeneralSettings.Instance.Manager.DeinitializeLoader();
// We don't really need to wait a frame on Stop()
}
#endregion
}

View file

@ -15,10 +15,10 @@ public class CVRGestureRecognizerTracker : VRModeTracker
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
private void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
DesktopVRSwitch.Logger.Msg("Updating CVRGestureRecognizer _camera to active camera.");
CVRGestureRecognizer.Instance._camera = Utils.GetPlayerCameraObject(intoVR).GetComponent<Camera>();
CVRGestureRecognizer.Instance._camera = args.PlayerCamera;
}
}
}

View file

@ -16,14 +16,14 @@ public class CVRInputManagerTracker : VRModeTracker
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
private void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
DesktopVRSwitch.Logger.Msg("Resetting CVRInputManager inputs.");
CVRInputManager.Instance.inputEnabled = true;
// IM CRYING
CVRInputManager.Instance.reload = true;
//CVRInputManager.Instance.reload = true;
//just in case
CVRInputManager.Instance.textInputFocused = false;
@ -42,6 +42,6 @@ public class CVRInputManagerTracker : VRModeTracker
CVRInputManager.Instance.AddInputModule(CVRInputManager._moduleXR = new CVRInputModule_XR());
//enable xr input or whatnot
CVRInputManager._moduleXR.InputEnabled = intoVR;
CVRInputManager._moduleXR.InputEnabled = args.IsUsingVr;
}
}

View file

@ -18,7 +18,7 @@ public class CVRPickupObjectTracker : MonoBehaviour
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
public void OnPostSwitch(bool intoVR)
public void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
if (_pickupObject != null)
{
@ -30,4 +30,4 @@ public class CVRPickupObjectTracker : MonoBehaviour
(_storedGripOrigin, _pickupObject.gripOrigin) = (_pickupObject.gripOrigin, _storedGripOrigin);
}
}
}
}

View file

@ -17,7 +17,7 @@ public class CVRWorldTracker : VRModeTracker
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
private void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
DesktopVRSwitch.Logger.Msg("Configuring CVRWorld. Updating PostProcessing & DesktopCameraController FOV settings.");

View file

@ -14,10 +14,10 @@ public class CVR_InteractableManagerTracker : VRModeTracker
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
private void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
DesktopVRSwitch.Logger.Msg($"Setting CVRInputManager inputEnabled & CVR_InteractableManager enableInteractions to {!intoVR}");
DesktopVRSwitch.Logger.Msg($"Setting CVRInputManager inputEnabled & CVR_InteractableManager enableInteractions to {!args.IsUsingVr}");
CVR_InteractableManager.enableInteractions = !intoVR;
CVR_InteractableManager.enableInteractions = !args.IsUsingVr;
}
}

View file

@ -17,19 +17,19 @@ public class CVR_MenuManagerTracker : VRModeTracker
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPreSwitch(bool intoVR)
private void OnPreSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
DesktopVRSwitch.Logger.Msg("Closing CVR_MenuManager - Quick Menu.");
CVR_MenuManager.Instance.ToggleQuickMenu(false);
}
private void OnPostSwitch(bool intoVR)
private void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
DesktopVRSwitch.Logger.Msg("Updating CVR_Menu_Data core data.");
CVR_MenuManager.Instance.coreData.core.inVr = intoVR;
CVR_MenuManager.Instance.coreData.core.inVr = args.IsUsingVr;
CVR_MenuManager.Instance.quickMenu.transform.localPosition = Vector3.zero;
CVR_MenuManager.Instance.quickMenu.transform.localRotation = Quaternion.identity;
}
}
}

View file

@ -18,9 +18,8 @@ public class CameraFacingObjectTracker : MonoBehaviour
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
public void OnPostSwitch(bool intoVR)
public void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
// TODO: cache camera
_cameraFacingObject.m_Camera = Utils.GetPlayerCameraObject(intoVR).GetComponent<Camera>();
_cameraFacingObject.m_Camera = args.PlayerCamera;
}
}

View file

@ -14,8 +14,8 @@ public class CheckVRTracker : VRModeTracker
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
private void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
CheckVR.Instance.hasVrDeviceLoaded = intoVR;
CheckVR.Instance.hasVrDeviceLoaded = args.IsUsingVr;
}
}

View file

@ -16,11 +16,11 @@ public class CohtmlHudTracker : VRModeTracker
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
private void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
DesktopVRSwitch.Logger.Msg("Configuring new hud affinity for CohtmlHud.");
CohtmlHud.Instance.gameObject.transform.parent = Utils.GetPlayerCameraObject(intoVR).transform;
CohtmlHud.Instance.gameObject.transform.parent = Utils.GetPlayerCameraObject(args.IsUsingVr).transform;
// This handles rotation and position
CVRTools.ConfigureHudAffinity();
CohtmlHud.Instance.gameObject.transform.localScale = new Vector3(1.2f, 1f, 1.2f);

View file

@ -14,11 +14,11 @@ public class HudOperationsTracker : VRModeTracker
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
private void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
DesktopVRSwitch.Logger.Msg("Switching HudOperations worldLoadingItem & worldLoadStatus.");
HudOperations.Instance.worldLoadingItem = intoVR ? HudOperations.Instance.worldLoadingItemVr : HudOperations.Instance.worldLoadingItemDesktop;
HudOperations.Instance.worldLoadStatus = intoVR ? HudOperations.Instance.worldLoadStatusVr : HudOperations.Instance.worldLoadStatusDesktop;
HudOperations.Instance.worldLoadingItem = args.IsUsingVr ? HudOperations.Instance.worldLoadingItemVr : HudOperations.Instance.worldLoadingItemDesktop;
HudOperations.Instance.worldLoadStatus = args.IsUsingVr ? HudOperations.Instance.worldLoadStatusVr : HudOperations.Instance.worldLoadStatusDesktop;
}
}

View file

@ -20,7 +20,7 @@ public class IKSystemTracker : VRModeTracker
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPreSwitch(bool intoVR)
private void OnPreSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
BodySystem.TrackingEnabled = false;
BodySystem.TrackingPositionWeight = 0f;
@ -30,7 +30,7 @@ public class IKSystemTracker : VRModeTracker
IKSystem.vrik.enabled = false;
}
private void OnFailedSwitch(bool intoVR)
private void OnFailedSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
BodySystem.TrackingEnabled = true;
BodySystem.TrackingPositionWeight = 1f;
@ -40,7 +40,7 @@ public class IKSystemTracker : VRModeTracker
IKSystem.vrik.enabled = true;
}
private void OnPostSwitch(bool intoVR)
private void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
if (IKSystem.vrik != null)
UnityEngine.Object.DestroyImmediate(IKSystem.vrik);
@ -54,12 +54,12 @@ public class IKSystemTracker : VRModeTracker
BodySystem.isRecalibration = false;
// Make it so you don't instantly end up in FBT from Desktop
IKSystem.firstAvatarLoaded = DesktopVRSwitch.EntryEnterCalibrationOnSwitch.Value;
IKSystem.firstAvatarLoaded = ModSettings.EntryEnterCalibrationOnSwitch.Value;
// Turn off finger tracking just in case the user switched controllers
IKSystem.Instance.FingerSystem.controlActive = false;
SetupSteamVRTrackingModule(intoVR);
SetupSteamVRTrackingModule(args.IsUsingVr);
}
private void SetupSteamVRTrackingModule(bool enableVR)
@ -69,13 +69,9 @@ public class IKSystemTracker : VRModeTracker
if (openVRModule != null)
{
if (enableVR)
{
openVRModule.ModuleStart();
}
else
{
openVRModule.ModuleDestroy();
}
}
else if (enableVR)
{

View file

@ -17,16 +17,16 @@ public class MetaPortTracker : VRModeTracker
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
private void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
DesktopVRSwitch.Logger.Msg($"Setting MetaPort isUsingVr to {intoVR}.");
DesktopVRSwitch.Logger.Msg($"Setting MetaPort isUsingVr to {args.IsUsingVr}.");
// Main thing most of the game checks for if using VR
MetaPort.Instance.isUsingVr = intoVR;
MetaPort.Instance.isUsingVr = args.IsUsingVr;
// replace
UpdateRichPresence();
ResetSteamVROverrides(intoVR);
ResetSteamVROverrides(args.IsUsingVr);
}
private void UpdateRichPresence()

View file

@ -23,7 +23,7 @@ public class MovementSystemTracker : VRModeTracker
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPreSwitch(bool intoVR)
private void OnPreSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
DesktopVRSwitch.Logger.Msg("Storing player world position and rotation.");
@ -39,17 +39,17 @@ public class MovementSystemTracker : VRModeTracker
}
private void OnFailedSwitch(bool intoVR)
private void OnFailedSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
DesktopVRSwitch.Logger.Msg("Resetting MovementSystem mobility.");
MovementSystem.Instance.SetImmobilized(false);
}
private void OnPostSwitch(bool intoVR)
private void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
// Lazy
MelonLoader.MelonCoroutines.Start(TeleportFrameAfter(intoVR));
MelonLoader.MelonCoroutines.Start(TeleportFrameAfter(args.IsUsingVr));
}
private IEnumerator TeleportFrameAfter(bool intoVR)

View file

@ -14,11 +14,11 @@ public class PlayerSetupTracker : VRModeTracker
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
private void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
DesktopVRSwitch.Logger.Msg("Switching active PlayerSetup camera rigs. Updating Desktop camera FOV.");
PlayerSetup.Instance.desktopCameraRig.SetActive(!intoVR);
PlayerSetup.Instance.vrCameraRig.SetActive(intoVR);
PlayerSetup.Instance.desktopCameraRig.SetActive(!args.IsUsingVr);
PlayerSetup.Instance.vrCameraRig.SetActive(args.IsUsingVr);
}
}

View file

@ -14,7 +14,7 @@ public class PortableCameraTracker : VRModeTracker
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
private void OnPostSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
DesktopVRSwitch.Logger.Msg("Forcing PortableCamera canvas mirroring off.");

View file

@ -1,7 +1,7 @@
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class VRModeTracker
public abstract class VRModeTracker
{
public virtual void TrackerInit() { }
public virtual void TrackerDestroy() { }
}
}

View file

@ -14,7 +14,7 @@ public class ViewManagerTracker : VRModeTracker
VRModeSwitchManager.OnPreVRModeSwitch -= OnPreSwitch;
}
private void OnPreSwitch(bool intoVR)
private void OnPreSwitch(object sender, VRModeSwitchManager.VRModeEventArgs args)
{
DesktopVRSwitch.Logger.Msg("Closing ViewManager - Main Menu.");

View file

@ -0,0 +1,66 @@
using System.Collections;
using System.Reflection;
using ABI_RC.Core.Savior;
using Unity.XR.OpenVR;
using UnityEngine;
using UnityEngine.XR.Management;
using UnityEngine.XR.OpenXR;
using Valve.VR;
namespace NAK.DesktopVRSwitch;
internal static class XRHandler
{
internal static IEnumerator StartXR()
{
yield return XRGeneralSettings.Instance.Manager.InitializeLoader();
if (XRGeneralSettings.Instance.Manager.activeLoader != null)
XRGeneralSettings.Instance.Manager.StartSubsystems();
else
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
// 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)
{
item = ScriptableObject.CreateInstance<OpenVRLoader>();
DesktopVRSwitch.Logger.Msg("Using XR Loader: SteamVR");
}
else
{
item = ScriptableObject.CreateInstance<OpenXRLoader>();
DesktopVRSwitch.Logger.Msg("Using XR Loader: OpenXR");
}
typeof(XRManagerSettings)
.GetField("m_Loaders", BindingFlags.Instance | BindingFlags.NonPublic)
?.SetValue(XRGeneralSettings.Instance.Manager, new List<XRLoader> { item });
}
}