[DesktopVRSwitch] Testing

This commit is contained in:
NotAKidoS 2023-06-19 19:44:23 -05:00
parent 03514305be
commit 61a45f97bc
30 changed files with 957 additions and 524 deletions

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk"/>
<Project Sdk="Microsoft.NET.Sdk" />

View file

@ -1,4 +1,6 @@
using NAK.DesktopVRSwitch.Patches;
/**
using NAK.DesktopVRSwitch.Patches;
using System.Collections;
using UnityEngine;
using UnityEngine.XR;
@ -16,7 +18,7 @@ using ABI_RC.Core;
QualitySettings.vSyncCount = 0;
Time.fixedDeltaTime = Time.timeScale / hmd_DisplayFrequency;
**/
**
namespace NAK.DesktopVRSwitch;
@ -130,35 +132,36 @@ public class DesktopVRSwitcher : MonoBehaviour
public void PostVRModeSwitch(bool enableVR)
{
if (_softVRSwitch) return;
//close the menus
TryCatchHell.CloseCohtmlMenus();
//the base of VR checks
TryCatchHell.SetCheckVR(enableVR);
TryCatchHell.SetMetaPort(enableVR);
//game basics for functional gameplay post switch
TryCatchHell.RepositionCohtmlHud(enableVR);
TryCatchHell.UpdateHudOperations(enableVR);
TryCatchHell.DisableMirrorCanvas();
TryCatchHell.SwitchActiveCameraRigs(enableVR);
TryCatchHell.ResetCVRInputManager();
TryCatchHell.UpdateRichPresence();
TryCatchHell.UpdateGestureReconizerCam();
TryCatchHell.UpdateMenuCoreData(enableVR);
//let tracked objects know we switched
VRModeSwitchTracker.PostVRModeSwitch(enableVR);
//reload avatar by default, optional for debugging
if (_reloadLocalAvatar)
{
TryCatchHell.ReloadLocalAvatar();
}
SetupVR(enableVR);
_switchInProgress = false;
}
public void SetupVR(bool intoVR)
{
List<TryCatchHell.TryAction> actions = new List<TryCatchHell.TryAction>
{
TryCatchHell.SetCheckVR,
TryCatchHell.SetMetaPort,
TryCatchHell.RepositionCohtmlHud,
TryCatchHell.UpdateHudOperations,
TryCatchHell.DisableMirrorCanvas,
TryCatchHell.SwitchActiveCameraRigs,
TryCatchHell.ResetCVRInputManager,
TryCatchHell.UpdateRichPresence,
TryCatchHell.UpdateGestureReconizerCam,
TryCatchHell.UpdateMenuCoreData,
};
foreach (var action in actions)
{
TryCatchHell.TryExecute(action, intoVR);
}
TryCatchHell.TryExecute(VRModeSwitchTracker.PostVRModeSwitch, intoVR);
}
public void ResetSteamVROverrides()
{
// Reset physics time to Desktop default
@ -193,3 +196,6 @@ public class DesktopVRSwitcher : MonoBehaviour
}
}
**/

View file

@ -1,12 +1,11 @@
using ABI.CCK.Components;
using ABI_RC.Core.Player;
using ABI_RC.Core.Savior;
using ABI_RC.Core.Util.Object_Behaviour;
using ABI_RC.Systems.IK;
using ABI_RC.Systems.IK.TrackingModules;
using ABI_RC.Systems.MovementSystem;
using HarmonyLib;
using NAK.DesktopVRSwitch.Patches;
using NAK.DesktopVRSwitch.VRModeTrackers;
using UnityEngine;
namespace NAK.DesktopVRSwitch.HarmonyPatches;
@ -15,87 +14,24 @@ class CheckVRPatches
{
[HarmonyPostfix]
[HarmonyPatch(typeof(CheckVR), nameof(CheckVR.Start))]
private static void Postfix_CheckVR_Start(ref CheckVR __instance)
static void Postfix_CheckVR_Start(ref CheckVR __instance)
{
__instance.gameObject.AddComponent<DesktopVRSwitcher>();
}
}
class MovementSystemPatches
{
[HarmonyPostfix]
[HarmonyPatch(typeof(MovementSystem), nameof(MovementSystem.Start))]
private static void Postfix_MovementSystem_Start(ref MovementSystem __instance)
{
__instance.gameObject.AddComponent<MovementSystemTracker>();
}
}
class CVRPickupObjectPatches
{
[HarmonyPrefix]
[HarmonyPatch(typeof(CVRPickupObject), nameof(CVRPickupObject.Start))]
private static void Prefix_CVRPickupObject_Start(ref CVRPickupObject __instance)
{
if (__instance.gripType == CVRPickupObject.GripType.Free) return;
Transform vrOrigin = __instance.gripOrigin;
Transform desktopOrigin = __instance.gripOrigin.Find("[Desktop]");
if (vrOrigin != null && desktopOrigin != null)
{
var tracker = __instance.gameObject.AddComponent<CVRPickupObjectTracker>();
tracker.pickupObject = __instance;
tracker.storedGripOrigin = (!MetaPort.Instance.isUsingVr ? vrOrigin : desktopOrigin);
}
}
}
class CVRWorldPatches
{
[HarmonyPostfix]
[HarmonyPatch(typeof(CVRWorld), nameof(CVRWorld.SetDefaultCamValues))]
private static void Postfix_CVRWorld_SetDefaultCamValues()
{
ReferenceCameraPatch.OnWorldLoad();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(CVRWorld), nameof(CVRWorld.CopyRefCamValues))]
private static void Postfix_CVRWorld_CopyRefCamValues()
{
ReferenceCameraPatch.OnWorldLoad();
}
}
class CameraFacingObjectPatches
{
[HarmonyPostfix]
[HarmonyPatch(typeof(CameraFacingObject), nameof(CameraFacingObject.Start))]
private static void Postfix_CameraFacingObject_Start(ref CameraFacingObject __instance)
{
__instance.gameObject.AddComponent<CameraFacingObjectTracker>();
__instance.gameObject.AddComponent<VRModeSwitchManager>();
}
}
class IKSystemPatches
{
[HarmonyPostfix]
[HarmonyPatch(typeof(IKSystem), nameof(IKSystem.Start))]
private static void Postfix_IKSystem_Start(ref IKSystem __instance)
{
__instance.gameObject.AddComponent<IKSystemTracker>();
}
[HarmonyPostfix] //lazy fix so i dont need to wait few frames
[HarmonyPatch(typeof(TrackingPoint), nameof(TrackingPoint.Initialize))]
private static void Postfix_TrackingPoint_Initialize(ref TrackingPoint __instance)
static void Postfix_TrackingPoint_Initialize(ref TrackingPoint __instance)
{
__instance.referenceTransform.localScale = Vector3.one;
}
[HarmonyPostfix] //lazy fix so device indecies can change properly
[HarmonyPatch(typeof(SteamVRTrackingModule), nameof(SteamVRTrackingModule.ModuleDestroy))]
private static void Postfix_SteamVRTrackingModule_ModuleDestroy(ref SteamVRTrackingModule __instance)
static void Postfix_SteamVRTrackingModule_ModuleDestroy(ref SteamVRTrackingModule __instance)
{
for (int i = 0; i < __instance.TrackingPoints.Count; i++)
{
@ -105,12 +41,29 @@ class IKSystemPatches
}
}
class VRTrackerManagerPatches
class CVRWorldPatches
{
[HarmonyPostfix]
[HarmonyPatch(typeof(VRTrackerManager), nameof(VRTrackerManager.Start))]
private static void Postfix_VRTrackerManager_Start(ref VRTrackerManager __instance)
[HarmonyPatch(typeof(CVRWorld), nameof(CVRWorld.SetDefaultCamValues))]
static void Postfix_CVRWorld_SetDefaultCamValues()
{
__instance.gameObject.AddComponent<VRTrackerManagerTracker>();
ReferenceCameraPatch.OnWorldLoad();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(CVRWorld), nameof(CVRWorld.CopyRefCamValues))]
static void Postfix_CVRWorld_CopyRefCamValues()
{
ReferenceCameraPatch.OnWorldLoad();
}
}
class CameraFacingObjectPatches
{
[HarmonyPostfix]
[HarmonyPatch(typeof(CameraFacingObject), nameof(CameraFacingObject.Start))]
static void Postfix_CameraFacingObject_Start(ref CameraFacingObject __instance)
{
__instance.gameObject.AddComponent<CameraFacingObjectTracker>();
}
}

View file

@ -1,4 +1,6 @@
using MelonLoader;
using NAK.DesktopVRSwitch.VRModeTrackers;
using UnityEngine;
/**
I know the TryCatchHell thing might be a bit exessive, but it is
@ -18,23 +20,66 @@ 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 override void OnInitializeMelon()
{
Logger = LoggerInstance;
RegisterVRModeTrackers();
// main manager
ApplyPatches(typeof(HarmonyPatches.CheckVRPatches));
ApplyPatches(typeof(HarmonyPatches.CVRPickupObjectPatches));
ApplyPatches(typeof(HarmonyPatches.CVRWorldPatches));
// nameplate fixes
ApplyPatches(typeof(HarmonyPatches.CameraFacingObjectPatches));
// lazy fix to reset iksystem
ApplyPatches(typeof(HarmonyPatches.IKSystemPatches));
ApplyPatches(typeof(HarmonyPatches.MovementSystemPatches));
ApplyPatches(typeof(HarmonyPatches.VRTrackerManagerPatches));
// post processing fixes
ApplyPatches(typeof(HarmonyPatches.CVRWorldPatches));
}
public override void OnUpdate()
{
if (Input.GetKeyDown(KeyCode.F6) && Input.GetKey(KeyCode.LeftControl))
{
VRModeSwitchManager.Instance?.StartSwitch();
}
}
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());
}
void ApplyPatches(Type type)

View file

@ -1,31 +0,0 @@
using ABI.CCK.Components;
using UnityEngine;
//Thanks Ben! I was scared of transpiler so I reworked a bit...
namespace NAK.DesktopVRSwitch.Patches;
public class CVRPickupObjectTracker : MonoBehaviour
{
public CVRPickupObject pickupObject;
public Transform storedGripOrigin;
void Start()
{
VRModeSwitchTracker.OnPostVRModeSwitch += PostVRModeSwitch;
}
void OnDestroy()
{
VRModeSwitchTracker.OnPostVRModeSwitch -= PostVRModeSwitch;
}
public void PostVRModeSwitch(bool enableVR, Camera activeCamera)
{
if (pickupObject != null)
{
if (pickupObject._controllerRay != null) pickupObject._controllerRay.DropObject(true);
(storedGripOrigin, pickupObject.gripOrigin) = (pickupObject.gripOrigin, storedGripOrigin);
}
}
}

View file

@ -1,25 +0,0 @@
using ABI_RC.Core.Util.Object_Behaviour;
using UnityEngine;
namespace NAK.DesktopVRSwitch.Patches;
public class CameraFacingObjectTracker : MonoBehaviour
{
public CameraFacingObject cameraFacingObject;
void Start()
{
cameraFacingObject = GetComponent<CameraFacingObject>();
VRModeSwitchTracker.OnPostVRModeSwitch += PostVRModeSwitch;
}
void OnDestroy()
{
VRModeSwitchTracker.OnPostVRModeSwitch -= PostVRModeSwitch;
}
public void PostVRModeSwitch(bool enableVR, Camera activeCamera)
{
cameraFacingObject.m_Camera = activeCamera;
}
}

View file

@ -1,87 +0,0 @@
using ABI_RC.Systems.IK;
using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Systems.IK.TrackingModules;
using UnityEngine;
namespace NAK.DesktopVRSwitch.Patches;
public class IKSystemTracker : MonoBehaviour
{
public IKSystem ikSystem;
void Start()
{
ikSystem = GetComponent<IKSystem>();
VRModeSwitchTracker.OnPreVRModeSwitch += PreVRModeSwitch;
VRModeSwitchTracker.OnFailVRModeSwitch += FailedVRModeSwitch;
VRModeSwitchTracker.OnPostVRModeSwitch += PostVRModeSwitch;
}
void OnDestroy()
{
VRModeSwitchTracker.OnPreVRModeSwitch -= PreVRModeSwitch;
VRModeSwitchTracker.OnFailVRModeSwitch -= FailedVRModeSwitch;
VRModeSwitchTracker.OnPostVRModeSwitch -= PostVRModeSwitch;
}
public void PreVRModeSwitch(bool enableVR, Camera activeCamera)
{
BodySystem.TrackingEnabled = false;
BodySystem.TrackingPositionWeight = 0f;
BodySystem.TrackingLocomotionEnabled = false;
if (IKSystem.vrik != null)
IKSystem.vrik.enabled = false;
}
public void FailedVRModeSwitch(bool enableVR, Camera activeCamera)
{
BodySystem.TrackingEnabled = true;
BodySystem.TrackingPositionWeight = 1f;
BodySystem.TrackingLocomotionEnabled = true;
if (IKSystem.vrik != null)
IKSystem.vrik.enabled = true;
}
public void PostVRModeSwitch(bool enableVR, Camera activeCamera)
{
if (IKSystem.vrik != null)
DestroyImmediate(IKSystem.vrik);
//make sure you are fully tracking
BodySystem.TrackingEnabled = true;
BodySystem.TrackingPositionWeight = 1f;
BodySystem.TrackingLocomotionEnabled = true;
BodySystem.isCalibratedAsFullBody = false;
BodySystem.isCalibrating = false;
BodySystem.isRecalibration = false;
//make it so you dont instantly end up in FBT from Desktop
IKSystem.firstAvatarLoaded = DesktopVRSwitch.EntryEnterCalibrationOnSwitch.Value;
//turn of finger tracking just in case user switched controllers
ikSystem.FingerSystem.controlActive = false;
//vrik should be deleted by avatar switch
SetupSteamVRTrackingModule(enableVR);
}
void SetupSteamVRTrackingModule(bool enableVR)
{
var openVRModule = ikSystem._trackingModules.OfType<SteamVRTrackingModule>().FirstOrDefault();
if (openVRModule != null)
{
if (enableVR)
{
openVRModule.ModuleStart();
}
else
{
openVRModule.ModuleDestroy();
}
}
else if (enableVR)
{
var newVRModule = new SteamVRTrackingModule();
ikSystem.AddTrackingModule(newVRModule);
}
}
}

View file

@ -1,54 +0,0 @@
using ABI_RC.Systems.MovementSystem;
using UnityEngine;
namespace NAK.DesktopVRSwitch.Patches;
public class MovementSystemTracker : MonoBehaviour
{
public MovementSystem movementSystem;
public Vector3 preSwitchWorldPosition;
public Quaternion preSwitchWorldRotation;
void Start()
{
movementSystem = GetComponent<MovementSystem>();
VRModeSwitchTracker.OnPreVRModeSwitch += PreVRModeSwitch;
VRModeSwitchTracker.OnPostVRModeSwitch += PostVRModeSwitch;
}
void OnDestroy()
{
VRModeSwitchTracker.OnPreVRModeSwitch -= PreVRModeSwitch;
VRModeSwitchTracker.OnPostVRModeSwitch -= PostVRModeSwitch;
}
public void PreVRModeSwitch(bool enableVR, Camera activeCamera)
{
//correct rotationPivot y position, so we dont teleport up/down
Vector3 position = movementSystem.rotationPivot.transform.position;
position.y = movementSystem.transform.position.y;
preSwitchWorldPosition = position;
preSwitchWorldRotation = movementSystem.rotationPivot.transform.rotation;
//ChilloutVR does not use VRIK root right, so avatar root is VR player root.
//This causes desync between VR and Desktop positions & collision on switch.
//I correct for this in lazy way, but i use rotationPivot instead of avatar root,
//so the user can still switch even if avatar is null (if it failed to load for example).
movementSystem.ChangeCrouch(false);
movementSystem.ChangeProne(false);
}
public void PostVRModeSwitch(bool enableVR, Camera activeCamera)
{
//immediatly update camera to new camera transform
movementSystem.rotationPivot = activeCamera.transform;
//lazy way of correcting Desktop & VR offset issue (game does the maths)
movementSystem.TeleportToPosRot(preSwitchWorldPosition, preSwitchWorldRotation, false);
//recenter desktop collision to player object
if (!enableVR) movementSystem.UpdateColliderCenter(movementSystem.transform.position);
movementSystem.ChangeCrouch(false);
movementSystem.ChangeProne(false);
}
}

View file

@ -1,45 +0,0 @@
using ABI_RC.Core.Player;
using UnityEngine;
using UnityEngine.Events;
namespace NAK.DesktopVRSwitch.Patches;
public class VRModeSwitchTracker
{
public static event UnityAction<bool, Camera> OnPreVRModeSwitch;
public static event UnityAction<bool, Camera> OnPostVRModeSwitch;
public static event UnityAction<bool, Camera> OnFailVRModeSwitch;
public static void PreVRModeSwitch(bool enableVR)
{
TryCatchHell.TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Invoking VRModeSwitchTracker.OnPreVRModeSwitch.");
Camera activeCamera = PlayerSetup.Instance.GetActiveCamera().GetComponent<Camera>();
VRModeSwitchTracker.OnPreVRModeSwitch?.Invoke(enableVR, activeCamera);
},
"Error while invoking VRModeSwitchTracker.OnPreVRModeSwitch. Did someone do a fucky?");
}
public static void PostVRModeSwitch(bool enableVR)
{
TryCatchHell.TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Invoking VRModeSwitchTracker.OnPostVRModeSwitch.");
Camera activeCamera = PlayerSetup.Instance.GetActiveCamera().GetComponent<Camera>();
VRModeSwitchTracker.OnPostVRModeSwitch?.Invoke(enableVR, activeCamera);
},
"Error while invoking VRModeSwitchTracker.OnPostVRModeSwitch. Did someone do a fucky?");
}
public static void FailVRModeSwitch(bool enableVR)
{
TryCatchHell.TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Invoking VRModeSwitchTracker.OnFailVRModeSwitch.");
Camera activeCamera = PlayerSetup.Instance.GetActiveCamera().GetComponent<Camera>();
VRModeSwitchTracker.OnFailVRModeSwitch?.Invoke(enableVR, activeCamera);
},
"Error while invoking OnFailVRModeSwitch.OnPreVRModeSwitch. Did someone do a fucky?");
}
}

View file

@ -1,31 +0,0 @@
using ABI_RC.Core.Player;
using HarmonyLib;
using UnityEngine;
namespace NAK.DesktopVRSwitch.Patches;
public class VRTrackerManagerTracker : MonoBehaviour
{
public VRTrackerManager vrTrackerManager;
void Start()
{
vrTrackerManager = GetComponent<VRTrackerManager>();
VRModeSwitchTracker.OnPostVRModeSwitch += PostVRModeSwitch;
}
void OnDestroy()
{
VRModeSwitchTracker.OnPostVRModeSwitch -= PostVRModeSwitch;
}
public void PostVRModeSwitch(bool enableVR, Camera activeCamera)
{
//force the VRTrackerManager to reset anything its stored
//this makes it get correct Left/Right hand if entering VR with different controllers
//or if you restarted SteamVR and controllers are now in swapped index
vrTrackerManager.poses = null;
vrTrackerManager.leftHand = null;
vrTrackerManager.rightHand = null;
vrTrackerManager.hasCheckedForKnuckles = false;
}
}

View file

@ -1,188 +1,67 @@
using ABI_RC.Core;
using ABI_RC.Core.EventSystem;
using ABI_RC.Core.InteractionSystem;
using ABI_RC.Core.Player;
using ABI_RC.Core.Savior;
using ABI_RC.Core.UI;
using ABI_RC.Systems.Camera;
using UnityEngine;
using UnityEngine;
namespace NAK.DesktopVRSwitch;
internal class TryCatchHell
{
internal static void TryCatchWrapper(Action action, string errorMsg, params object[] msgArgs)
public delegate void TryAction(bool intoVR);
public static void TryExecute(TryAction action, bool intoVR)
{
try
{
action();
action(intoVR);
}
catch (Exception ex)
{
DesktopVRSwitch.Logger.Error(string.Format(errorMsg, msgArgs));
DesktopVRSwitch.Logger.Msg(ex.Message);
Debug.LogError($"Error executing action: {ex.Message}");
}
}
internal static void CloseCohtmlMenus()
internal static void CloseCohtmlMenus(bool intoVR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Closing ViewManager & CVR_MenuManager menus.");
ViewManager.Instance.UiStateToggle(false);
CVR_MenuManager.Instance.ToggleQuickMenu(false);
},
"Setting CheckVR hasVrDeviceLoaded failed.");
}
internal static void SetCheckVR(bool enableVR)
internal static void RepositionCohtmlHud(bool intoVR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg($"Setting CheckVR hasVrDeviceLoaded to {enableVR}.");
CheckVR.Instance.hasVrDeviceLoaded = enableVR;
},
"Setting CheckVR hasVrDeviceLoaded failed.");
}
internal static void SetMetaPort(bool enableVR)
internal static void UpdateHudOperations(bool intoVR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg($"Setting MetaPort isUsingVr to {enableVR}.");
MetaPort.Instance.isUsingVr = enableVR;
},
"Setting MetaPort isUsingVr failed.");
}
internal static void RepositionCohtmlHud(bool enableVR)
internal static void DisableMirrorCanvas(bool intoVR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Configuring new hud affinity for CohtmlHud.");
CohtmlHud.Instance.gameObject.transform.parent = enableVR ? PlayerSetup.Instance.vrCamera.transform : PlayerSetup.Instance.desktopCamera.transform;
CVRTools.ConfigureHudAffinity();
CohtmlHud.Instance.gameObject.transform.localScale = new Vector3(1.2f, 1f, 1.2f);
},
"Error parenting CohtmlHud to active camera.");
}
internal static void UpdateHudOperations(bool enableVR)
internal static void SwitchActiveCameraRigs(bool intoVR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Switching HudOperations worldLoadingItem & worldLoadStatus.");
HudOperations.Instance.worldLoadingItem = enableVR ? HudOperations.Instance.worldLoadingItemVr : HudOperations.Instance.worldLoadingItemDesktop;
HudOperations.Instance.worldLoadStatus = enableVR ? HudOperations.Instance.worldLoadStatusVr : HudOperations.Instance.worldLoadStatusDesktop;
},
"Failed switching HudOperations objects.");
}
internal static void DisableMirrorCanvas()
internal static void PauseInputInteractions(bool intoVR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Forcing PortableCamera canvas mirroring off.");
//tell the game we are in mirror mode so itll disable it (if enabled)
PortableCamera.Instance.mode = MirroringMode.Mirror;
PortableCamera.Instance.ChangeMirroring();
},
"Failed to disable PortableCamera canvas mirroring.");
}
internal static void SwitchActiveCameraRigs(bool enableVR)
internal static void ReloadLocalAvatar(bool intoVR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Switching active PlayerSetup camera rigs. Updating Desktop camera FOV.");
PlayerSetup.Instance.desktopCameraRig.SetActive(!enableVR);
PlayerSetup.Instance.vrCameraRig.SetActive(enableVR);
CVR_DesktopCameraController.UpdateFov();
//uicamera has script that copies fov from desktop cam
//toggling the cameras on/off resets aspect ratio
//so when rigs switch, that is already handled
},
"Failed to switch active camera rigs or update Desktop camera FOV.");
}
internal static void PauseInputInteractions(bool toggle)
internal static void UpdateGestureReconizerCam(bool intoVR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg($"Setting CVRInputManager inputEnabled & CVR_InteractableManager enableInteractions to {!toggle}");
CVRInputManager.Instance.inputEnabled = !toggle;
CVR_InteractableManager.enableInteractions = !toggle;
},
"Failed to toggle CVRInputManager inputEnabled & CVR_InteractableManager enableInteractions.");
}
internal static void ResetCVRInputManager()
internal static void UpdateMenuCoreData(bool intoVR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Resetting CVRInputManager inputs.");
//just in case
CVRInputManager.Instance.blockedByUi = false;
//sometimes head can get stuck, so just in case
CVRInputManager.Instance.independentHeadToggle = false;
//just nice to load into desktop with idle gesture
CVRInputManager.Instance.gestureLeft = 0f;
CVRInputManager.Instance.gestureLeftRaw = 0f;
CVRInputManager.Instance.gestureRight = 0f;
CVRInputManager.Instance.gestureRightRaw = 0f;
//turn off finger tracking input
CVRInputManager.Instance.individualFingerTracking = false;
},
"Failed to reset CVRInputManager inputs.");
}
internal static void ReloadLocalAvatar()
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Attempting to reload current local avatar from GUID.");
AssetManagement.Instance.LoadLocalAvatar(MetaPort.Instance.currentAvatarGuid);
},
"Failed to reload local avatar.");
}
internal static void UpdateRichPresence()
{
TryCatchWrapper(() =>
{
if (MetaPort.Instance.settings.GetSettingsBool("ImplementationRichPresenceDiscordEnabled", true))
{
DesktopVRSwitch.Logger.Msg("Forcing Discord Rich Presence update.");
MetaPort.Instance.settings.SetSettingsBool("ImplementationRichPresenceDiscordEnabled", false);
MetaPort.Instance.settings.SetSettingsBool("ImplementationRichPresenceDiscordEnabled", true);
}
if (MetaPort.Instance.settings.GetSettingsBool("ImplementationRichPresenceSteamEnabled", true))
{
DesktopVRSwitch.Logger.Msg("Forcing Steam Rich Presence update.");
MetaPort.Instance.settings.SetSettingsBool("ImplementationRichPresenceSteamEnabled", false);
MetaPort.Instance.settings.SetSettingsBool("ImplementationRichPresenceSteamEnabled", true);
}
},
"Failed to update Discord & Steam Rich Presence.");
}
internal static void UpdateGestureReconizerCam()
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Updating CVRGestureRecognizer _camera to active camera.");
CVRGestureRecognizer.Instance._camera = PlayerSetup.Instance.GetActiveCamera().GetComponent<Camera>();
},
"Failed to update CVRGestureRecognizer camera.");
}
internal static void UpdateMenuCoreData(bool enableVR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Updating CVR_Menu_Data core data.");
CVR_MenuManager.Instance.coreData.core.inVr = enableVR;
},
"Failed to update CVR_Menu_Data core data.");
}
}

24
DesktopVRSwitch/Utils.cs Normal file
View file

@ -0,0 +1,24 @@
using ABI_RC.Core.EventSystem;
using ABI_RC.Core.Player;
using ABI_RC.Core.Savior;
using UnityEngine;
namespace NAK.DesktopVRSwitch;
internal static class Utils
{
internal static GameObject GetPlayerCameraObject(bool intoVR)
{
if (intoVR)
{
return PlayerSetup.Instance.vrCamera;
}
return PlayerSetup.Instance.desktopCamera;
}
internal static void ReloadLocalAvatar()
{
DesktopVRSwitch.Logger.Msg("Attempting to reload current local avatar from GUID.");
AssetManagement.Instance.LoadLocalAvatar(MetaPort.Instance.currentAvatarGuid);
}
}

View file

@ -0,0 +1,30 @@
using ABI_RC.Core.Savior;
using UnityEngine;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class CVRGestureRecognizerTracker : VRModeTracker
{
public override void TrackerInit()
{
VRModeSwitchManager.OnPostVRModeSwitch += OnPostSwitch;
}
public override void TrackerDestroy()
{
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
{
CVRGestureRecognizer _cvrGestureRecognizer = CVRGestureRecognizer.Instance;
if (_cvrGestureRecognizer == null)
{
DesktopVRSwitch.Logger.Error("Error while getting CVRGestureRecognizer!");
return;
}
DesktopVRSwitch.Logger.Msg("Updating CVRGestureRecognizer _camera to active camera.");
_cvrGestureRecognizer._camera = Utils.GetPlayerCameraObject(intoVR).GetComponent<Camera>();
}
}

View file

@ -0,0 +1,41 @@
using ABI_RC.Core.Savior;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class CVRInputManagerTracker : VRModeTracker
{
public override void TrackerInit()
{
VRModeSwitchManager.OnPostVRModeSwitch += OnPostSwitch;
}
public override void TrackerDestroy()
{
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
void OnPostSwitch(bool intoVR)
{
CVRInputManager _cvrInputManager = CVRInputManager.Instance;
if (_cvrInputManager == null)
{
DesktopVRSwitch.Logger.Error("Error while getting CVRInputManager!");
return;
}
DesktopVRSwitch.Logger.Msg("Resetting CVRInputManager inputs.");
_cvrInputManager.inputEnabled = true;
//just in case
_cvrInputManager.blockedByUi = false;
//sometimes head can get stuck, so just in case
_cvrInputManager.independentHeadToggle = false;
//just nice to load into desktop with idle gesture
_cvrInputManager.gestureLeft = 0f;
_cvrInputManager.gestureLeftRaw = 0f;
_cvrInputManager.gestureRight = 0f;
_cvrInputManager.gestureRightRaw = 0f;
//turn off finger tracking input
_cvrInputManager.individualFingerTracking = false;
}
}

View file

@ -0,0 +1,34 @@
using ABI.CCK.Components;
using UnityEngine;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class CVRPickupObjectTracker : MonoBehaviour
{
private CVRPickupObject _pickupObject;
private Transform _storedGripOrigin;
public CVRPickupObjectTracker(CVRPickupObject pickupObject, Transform storedGripOrigin)
{
this._pickupObject = pickupObject;
this._storedGripOrigin = storedGripOrigin;
}
private void OnDestroy()
{
}
public void OnPostSwitch(bool intoVR)
{
if (_pickupObject != null)
{
// Drop the object if it is being held locally
if (_pickupObject._controllerRay != null)
_pickupObject._controllerRay.DropObject(true);
// Swap the grip origins
(_storedGripOrigin, _pickupObject.gripOrigin) = (_pickupObject.gripOrigin, _storedGripOrigin);
}
}
}

View file

@ -0,0 +1,29 @@
using ABI_RC.Core.InteractionSystem;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class CVR_InteractableManagerTracker : VRModeTracker
{
public override void TrackerInit()
{
VRModeSwitchManager.OnPostVRModeSwitch += OnPostSwitch;
}
public override void TrackerDestroy()
{
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
{
CVR_InteractableManager _cvrInteractableManager = CVR_InteractableManager.Instance;
if (_cvrInteractableManager == null)
{
DesktopVRSwitch.Logger.Error("Error while getting CVR_InteractableManager!");
return;
}
DesktopVRSwitch.Logger.Msg($"Setting CVRInputManager inputEnabled & CVR_InteractableManager enableInteractions to {!intoVR}");
CVR_InteractableManager.enableInteractions = !intoVR;
}
}

View file

@ -0,0 +1,44 @@
using ABI_RC.Core.InteractionSystem;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class CVR_MenuManagerTracker : VRModeTracker
{
public override void TrackerInit()
{
VRModeSwitchManager.OnPreVRModeSwitch += OnPreSwitch;
VRModeSwitchManager.OnPostVRModeSwitch += OnPostSwitch;
}
public override void TrackerDestroy()
{
VRModeSwitchManager.OnPreVRModeSwitch -= OnPreSwitch;
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPreSwitch(bool intoVR)
{
CVR_MenuManager _cvrMenuManager = CVR_MenuManager.Instance;
if (_cvrMenuManager == null)
{
DesktopVRSwitch.Logger.Error("Error while getting CVR_MenuManager!");
return;
}
DesktopVRSwitch.Logger.Msg("Closing CVR_MenuManager - Quick Menu.");
_cvrMenuManager.ToggleQuickMenu(false);
}
private void OnPostSwitch(bool intoVR)
{
CVR_MenuManager _cvrMenuManager = CVR_MenuManager.Instance;
if (_cvrMenuManager == null)
{
DesktopVRSwitch.Logger.Error("Error while getting CVR_MenuManager!");
return;
}
DesktopVRSwitch.Logger.Msg("Updating CVR_Menu_Data core data.");
_cvrMenuManager.coreData.core.inVr = intoVR;
}
}

View file

@ -0,0 +1,27 @@
using ABI_RC.Core.Util.Object_Behaviour;
using UnityEngine;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class CameraFacingObjectTracker : MonoBehaviour
{
private CameraFacingObject _cameraFacingObject;
public CameraFacingObjectTracker(CameraFacingObject cameraFacingObject)
{
this._cameraFacingObject = cameraFacingObject;
}
private void OnDestroy()
{
}
public void OnPreSwitch(bool intoVR) { }
public void OnFailedSwitch(bool intoVR) { }
public void OnPostSwitch(bool intoVR)
{
_cameraFacingObject.m_Camera = Utils.GetPlayerCameraObject(intoVR).GetComponent<Camera>();
}
}

View file

@ -0,0 +1,29 @@
using ABI_RC.Core.Savior;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class CheckVRTracker : VRModeTracker
{
public override void TrackerInit()
{
VRModeSwitchManager.OnPostVRModeSwitch += OnPostSwitch;
}
public override void TrackerDestroy()
{
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
{
CheckVR _checkVR = CheckVR.Instance;
if (_checkVR == null)
{
DesktopVRSwitch.Logger.Error("Error while getting CheckVR!");
return;
}
DesktopVRSwitch.Logger.Msg($"Setting CheckVR hasVrDeviceLoaded to {intoVR}.");
_checkVR.hasVrDeviceLoaded = intoVR;
}
}

View file

@ -0,0 +1,34 @@
using ABI_RC.Core.Player;
using ABI_RC.Core.UI;
using UnityEngine;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class CohtmlHudTracker : VRModeTracker
{
public override void TrackerInit()
{
VRModeSwitchManager.OnPostVRModeSwitch += OnPostSwitch;
}
public override void TrackerDestroy()
{
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
{
CohtmlHud _cohtmlHud = CohtmlHud.Instance;
if (_cohtmlHud == null)
{
DesktopVRSwitch.Logger.Error("Error while getting CohtmlHud!");
return;
}
DesktopVRSwitch.Logger.Msg("Configuring new hud affinity for CohtmlHud.");
_cohtmlHud.gameObject.transform.parent = intoVR ? PlayerSetup.Instance.vrCamera.transform : PlayerSetup.Instance.desktopCamera.transform;
// This handles rotation and position
ABI_RC.Core.CVRTools.ConfigureHudAffinity();
_cohtmlHud.gameObject.transform.localScale = new Vector3(1.2f, 1f, 1.2f);
}
}

View file

@ -0,0 +1,30 @@
using ABI_RC.Core.Player;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class HudOperationsTracker : VRModeTracker
{
public override void TrackerInit()
{
VRModeSwitchManager.OnPostVRModeSwitch += OnPostSwitch;
}
public override void TrackerDestroy()
{
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
{
HudOperations _hudOperations = HudOperations.Instance;
if (_hudOperations == null)
{
DesktopVRSwitch.Logger.Error("Error while getting HudOperations!");
return;
}
DesktopVRSwitch.Logger.Msg("Switching HudOperations worldLoadingItem & worldLoadStatus.");
_hudOperations.worldLoadingItem = intoVR ? _hudOperations.worldLoadingItemVr : _hudOperations.worldLoadingItemDesktop;
_hudOperations.worldLoadStatus = intoVR ? _hudOperations.worldLoadStatusVr : _hudOperations.worldLoadStatusDesktop;
}
}

View file

@ -0,0 +1,87 @@
using ABI_RC.Systems.IK;
using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Systems.IK.TrackingModules;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class IKSystemTracker : VRModeTracker
{
public override void TrackerInit()
{
VRModeSwitchManager.OnPreVRModeSwitch += OnPreSwitch;
VRModeSwitchManager.OnFailVRModeSwitch += OnFailedSwitch;
VRModeSwitchManager.OnPostVRModeSwitch += OnPostSwitch;
}
public override void TrackerDestroy()
{
VRModeSwitchManager.OnPreVRModeSwitch -= OnPreSwitch;
VRModeSwitchManager.OnFailVRModeSwitch -= OnFailedSwitch;
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPreSwitch(bool intoVR)
{
BodySystem.TrackingEnabled = false;
BodySystem.TrackingPositionWeight = 0f;
BodySystem.TrackingLocomotionEnabled = false;
if (IKSystem.vrik != null)
IKSystem.vrik.enabled = false;
}
private void OnFailedSwitch(bool intoVR)
{
BodySystem.TrackingEnabled = true;
BodySystem.TrackingPositionWeight = 1f;
BodySystem.TrackingLocomotionEnabled = true;
if (IKSystem.vrik != null)
IKSystem.vrik.enabled = true;
}
private void OnPostSwitch(bool intoVR)
{
if (IKSystem.vrik != null)
UnityEngine.Object.DestroyImmediate(IKSystem.vrik);
// Make sure you are fully tracking
BodySystem.TrackingEnabled = true;
BodySystem.TrackingPositionWeight = 1f;
BodySystem.TrackingLocomotionEnabled = true;
BodySystem.isCalibratedAsFullBody = false;
BodySystem.isCalibrating = false;
BodySystem.isRecalibration = false;
// Make it so you don't instantly end up in FBT from Desktop
IKSystem.firstAvatarLoaded = DesktopVRSwitch.EntryEnterCalibrationOnSwitch.Value;
// Turn off finger tracking just in case the user switched controllers
if (IKSystem.Instance != null)
IKSystem.Instance.FingerSystem.controlActive = false;
SetupSteamVRTrackingModule(intoVR);
}
private void SetupSteamVRTrackingModule(bool enableVR)
{
var openVRModule = IKSystem.Instance._trackingModules.OfType<SteamVRTrackingModule>().FirstOrDefault();
if (openVRModule != null)
{
if (enableVR)
{
openVRModule.ModuleStart();
}
else
{
openVRModule.ModuleDestroy();
}
}
else if (enableVR)
{
var newVRModule = new SteamVRTrackingModule();
IKSystem.Instance.AddTrackingModule(newVRModule);
}
}
}

View file

@ -0,0 +1,44 @@
using ABI_RC.Core.Savior;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class MetaPortTracker : VRModeTracker
{
public override void TrackerInit()
{
VRModeSwitchManager.OnPostVRModeSwitch += OnPostSwitch;
}
public override void TrackerDestroy()
{
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
{
MetaPort _metaPort = MetaPort.Instance;
if (_metaPort == null)
{
DesktopVRSwitch.Logger.Error("Error while getting MetaPort!");
return;
}
DesktopVRSwitch.Logger.Msg($"Setting MetaPort isUsingVr to {intoVR}.");
// Main thing most of the game checks for if using VR
_metaPort.isUsingVr = intoVR;
// Hacky way of updating rich presence
if (_metaPort.settings.GetSettingsBool("ImplementationRichPresenceDiscordEnabled", true))
{
DesktopVRSwitch.Logger.Msg("Forcing Discord Rich Presence update.");
_metaPort.settings.SetSettingsBool("ImplementationRichPresenceDiscordEnabled", false);
_metaPort.settings.SetSettingsBool("ImplementationRichPresenceDiscordEnabled", true);
}
if (_metaPort.settings.GetSettingsBool("ImplementationRichPresenceSteamEnabled", true))
{
DesktopVRSwitch.Logger.Msg("Forcing Steam Rich Presence update.");
_metaPort.settings.SetSettingsBool("ImplementationRichPresenceSteamEnabled", false);
_metaPort.settings.SetSettingsBool("ImplementationRichPresenceSteamEnabled", true);
}
}
}

View file

@ -0,0 +1,48 @@
using ABI_RC.Systems.MovementSystem;
using UnityEngine;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class MovementSystemTracker : VRModeTracker
{
private MovementSystem _movementSystem;
private Vector3 preSwitchWorldPosition;
private Quaternion preSwitchWorldRotation;
public override void TrackerInit()
{
VRModeSwitchManager.OnPreVRModeSwitch += OnPreSwitch;
VRModeSwitchManager.OnPostVRModeSwitch += OnPostSwitch;
}
public override void TrackerDestroy()
{
VRModeSwitchManager.OnPreVRModeSwitch -= OnPreSwitch;
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPreSwitch(bool intoVR)
{
_movementSystem = MovementSystem.Instance;
Vector3 position = _movementSystem.rotationPivot.transform.position;
position.y = _movementSystem.transform.position.y;
preSwitchWorldPosition = position;
preSwitchWorldRotation = _movementSystem.rotationPivot.transform.rotation;
_movementSystem.ChangeCrouch(false);
_movementSystem.ChangeProne(false);
}
private void OnPostSwitch(bool intoVR)
{
_movementSystem.rotationPivot = Utils.GetPlayerCameraObject(intoVR).transform;
_movementSystem.TeleportToPosRot(preSwitchWorldPosition, preSwitchWorldRotation, false);
if (!intoVR)
_movementSystem.UpdateColliderCenter(_movementSystem.transform.position);
_movementSystem.ChangeCrouch(false);
_movementSystem.ChangeProne(false);
}
}

View file

@ -0,0 +1,38 @@
using ABI_RC.Core.Player;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class PlayerSetupTracker : VRModeTracker
{
public override void TrackerInit()
{
VRModeSwitchManager.OnPostVRModeSwitch += OnPostSwitch;
}
public override void TrackerDestroy()
{
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
{
PlayerSetup _playerSetup = PlayerSetup.Instance;
if (_playerSetup == null)
{
DesktopVRSwitch.Logger.Error("Error while getting PlayerSetup!");
return;
}
DesktopVRSwitch.Logger.Msg("Switching active PlayerSetup camera rigs. Updating Desktop camera FOV.");
_playerSetup.desktopCameraRig.SetActive(!intoVR);
_playerSetup.vrCameraRig.SetActive(intoVR);
// This might error if we started in VR.
// '_cam' is not set until Start().
CVR_DesktopCameraController.UpdateFov();
// UICamera has a script that copies the FOV from the desktop cam.
// Toggling the cameras on/off resets the aspect ratio,
// so when rigs switch, that is already handled.
}
}

View file

@ -0,0 +1,31 @@
using ABI_RC.Systems.Camera;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class PortableCameraTracker : VRModeTracker
{
public override void TrackerInit()
{
VRModeSwitchManager.OnPostVRModeSwitch += OnPostSwitch;
}
public override void TrackerDestroy()
{
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
{
PortableCamera _portableCamera = PortableCamera.Instance;
if (_portableCamera == null)
{
DesktopVRSwitch.Logger.Error("Error while getting PortableCamera!");
return;
}
DesktopVRSwitch.Logger.Msg("Forcing PortableCamera canvas mirroring off.");
// Tell the game we are in mirror mode so it'll disable it (if enabled)
_portableCamera.mode = MirroringMode.Mirror;
_portableCamera.ChangeMirroring();
}
}

View file

@ -0,0 +1,185 @@
using ABI_RC.Systems.UI;
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.XR;
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.VRModeTrackers;
public class VRModeSwitchManager : MonoBehaviour
{
public static VRModeSwitchManager Instance { get; private set; }
// I don't think I *need* this. Only using cause I don't want stuff just floating off.
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;
public static void RegisterVRModeTracker(VRModeTracker observer)
{
_vrModeTrackers.Add(observer);
observer.TrackerInit();
}
public static void UnregisterVRModeTracker(VRModeTracker observer)
{
_vrModeTrackers.Remove(observer);
observer.TrackerDestroy();
}
// Settings
private bool _useWorldTransition = true;
private bool _reloadLocalAvatar = true;
// Internal
private bool _switchInProgress = false;
void Awake()
{
if (Instance != null)
{
DestroyImmediate(this);
return;
}
Instance = this;
}
public void StartSwitch()
{
StartCoroutine(StartSwitchCoroutine());
}
private IEnumerator StartSwitchCoroutine()
{
if (_switchInProgress)
{
yield break;
}
_switchInProgress = true;
yield return null;
if (_useWorldTransition) // start visual transition and wait for it to complete
yield return WorldTransitionSystem.Instance.StartTransitionCoroutine();
// Check if OpenVR is running
bool isUsingVr = IsInVR();
InvokeOnPreSwitch(isUsingVr);
// Start switch
if (!isUsingVr)
{
yield return StartCoroutine(StartOpenVR());
}
else
{
yield return StartCoroutine(StopOpenVR());
}
// Check for updated VR mode
if (isUsingVr != IsInVR())
{
InvokeOnPostSwitch(!isUsingVr);
// reload the local avatar
// only reload on success
if (_reloadLocalAvatar)
Utils.ReloadLocalAvatar();
}
else
{
InvokeOnFailedSwitch(!isUsingVr);
}
if (_useWorldTransition) // finish the visual transition and wait
yield return WorldTransitionSystem.Instance.ContinueTransitionCoroutine();
_switchInProgress = false;
yield break;
}
private void SafeInvokeUnityEvent(UnityAction<bool> switchEvent, bool isUsingVr)
{
try
{
switchEvent.Invoke(isUsingVr);
}
catch (Exception e)
{
Debug.Log($"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 IsInVR() => XRSettings.enabled;
private IEnumerator StartOpenVR()
{
XRSettings.LoadDeviceByName("OpenVR");
yield return null; //wait a frame before checking
if (!string.IsNullOrEmpty(XRSettings.loadedDeviceName))
{
DesktopVRSwitch.Logger.Msg("Starting SteamVR...");
XRSettings.enabled = true;
SteamVR_Input.Initialize(true);
yield return null;
yield break;
}
DesktopVRSwitch.Logger.Error("Initializing VR Failed. Is there no VR device connected?");
yield return null;
yield break;
}
private IEnumerator StopOpenVR()
{
SteamVR_Behaviour.instance.enabled = false;
yield return null;
if (!string.IsNullOrEmpty(XRSettings.loadedDeviceName))
{
SteamVR_Input.actionSets[0].Deactivate(SteamVR_Input_Sources.Any);
XRSettings.LoadDeviceByName("");
XRSettings.enabled = false;
yield return null;
yield break;
}
DesktopVRSwitch.Logger.Error("Attempted to exit VR without a VR device loaded.");
yield return null;
yield break;
}
}

View file

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

View file

@ -0,0 +1,32 @@
using ABI_RC.Core.Player;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class VRTrackerManagerTracker : VRModeTracker
{
public override void TrackerInit()
{
VRModeSwitchManager.OnPostVRModeSwitch += OnPostSwitch;
}
public override void TrackerDestroy()
{
VRModeSwitchManager.OnPostVRModeSwitch -= OnPostSwitch;
}
private void OnPostSwitch(bool intoVR)
{
VRTrackerManager _vrTrackerManager = VRTrackerManager.Instance;
if (_vrTrackerManager == null)
{
DesktopVRSwitch.Logger.Error("Error while getting VRTrackerManager!");
return;
}
DesktopVRSwitch.Logger.Msg($"Resetting VRTrackerManager.");
_vrTrackerManager.poses = null;
_vrTrackerManager.leftHand = null;
_vrTrackerManager.rightHand = null;
_vrTrackerManager.hasCheckedForKnuckles = false;
}
}

View file

@ -0,0 +1,29 @@
using ABI_RC.Core.InteractionSystem;
namespace NAK.DesktopVRSwitch.VRModeTrackers;
public class ViewManagerTracker : VRModeTracker
{
public override void TrackerInit()
{
VRModeSwitchManager.OnPreVRModeSwitch += OnPreSwitch;
}
public override void TrackerDestroy()
{
VRModeSwitchManager.OnPreVRModeSwitch -= OnPreSwitch;
}
public void OnPreSwitch(bool intoVR)
{
ViewManager _viewManager = ViewManager.Instance;
if (_viewManager == null)
{
DesktopVRSwitch.Logger.Error("Error while getting ViewManager!");
return;
}
DesktopVRSwitch.Logger.Msg("Closing ViewManager - Main Menu.");
_viewManager.UiStateToggle(false);
}
}