[DesktopVRSwitch] - > DesktopXRSwitch

This commit is contained in:
NotAKidoS 2023-05-17 12:06:48 -05:00
parent 37fcf6ece1
commit 05374459be
21 changed files with 441 additions and 352 deletions

View file

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

View file

@ -1,141 +0,0 @@
using NAK.DesktopVRSwitch.Patches;
using System.Collections;
using UnityEngine;
using UnityEngine.XR;
using Valve.VR;
namespace NAK.DesktopVRSwitch;
public class DesktopVRSwitcher : MonoBehaviour
{
//Debug Settings
public bool _reloadLocalAvatar = true;
public bool _softVRSwitch = false;
//Internal Stuff
private bool _switchInProgress = false;
void Start()
{
//do not pause game, this breaks dynbones & trackers
SteamVR_Settings.instance.pauseGameWhenDashboardVisible = false;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.F6) && Input.GetKey(KeyCode.LeftControl))
{
SwitchVRMode();
}
}
public void SwitchVRMode()
{
if (_switchInProgress) return;
if (!IsInVR())
{
StartCoroutine(StartVRSystem());
}
else
{
StartCoroutine(StopVR());
}
}
public bool IsInVR() => XRSettings.enabled;
private IEnumerator StartVRSystem()
{
PreVRModeSwitch(true);
XRSettings.LoadDeviceByName("OpenVR");
yield return null; //wait a frame before checking
if (!string.IsNullOrEmpty(XRSettings.loadedDeviceName))
{
DesktopVRSwitch.Logger.Msg("Starting SteamVR...");
XRSettings.enabled = true;
//force steamvr to reinitialize input
//this does SteamVR_Input.actionSets[0].Activate() for us (we deactivate in StopVR())
//but only if SteamVR_Settings.instance.activateFirstActionSetOnStart is enabled
//which in ChilloutVR, it is, because all those settings are default
SteamVR_Input.Initialize(true);
yield return null;
PostVRModeSwitch(true);
yield break;
}
DesktopVRSwitch.Logger.Error("Initializing VR Failed. Is there no VR device connected?");
FailedVRModeSwitch(true);
yield break;
}
private IEnumerator StopVR()
{
PreVRModeSwitch(false);
yield return null;
if (!string.IsNullOrEmpty(XRSettings.loadedDeviceName))
{
//SteamVR.SafeDispose(); //might fuck with SteamVRTrackingModule
//deactivate the action set so SteamVR_Input.Initialize can reactivate
SteamVR_Input.actionSets[0].Deactivate(SteamVR_Input_Sources.Any);
XRSettings.LoadDeviceByName("");
XRSettings.enabled = false;
yield return null;
Time.fixedDeltaTime = 0.02f; //reset physics time to Desktop default
PostVRModeSwitch(false);
yield break;
}
DesktopVRSwitch.Logger.Error("Attempted to exit VR without a VR device loaded.");
FailedVRModeSwitch(false);
yield break;
}
//one frame before switch attempt
public void PreVRModeSwitch(bool enableVR)
{
if (_softVRSwitch) return;
//let tracked objects know we are attempting to switch
VRModeSwitchTracker.PreVRModeSwitch(enableVR);
}
//one frame after switch attempt
public void FailedVRModeSwitch(bool enableVR)
{
if (_softVRSwitch) return;
//let tracked objects know a switch failed
VRModeSwitchTracker.FailVRModeSwitch(enableVR);
}
//one frame after switch attempt
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();
}
_switchInProgress = 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

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<Reference Include="Unity.XR.Management">
<HintPath>..\_ManagedLibs\Unity.XR.Management.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View file

@ -0,0 +1,135 @@
using NAK.Melons.DesktopXRSwitch.Patches;
using System.Collections;
using UnityEngine;
using UnityEngine.XR.Management;
using Valve.VR;
namespace NAK.Melons.DesktopXRSwitch;
public class DesktopXRSwitcher : MonoBehaviour
{
//Debug Settings
public bool _reloadLocalAvatar = true;
public bool _softVRSwitch = false;
//Internal Stuff
private bool _switchInProgress = false;
void Start()
{
//do not pause game, this breaks dynbones & trackers
SteamVR_Settings.instance.pauseGameWhenDashboardVisible = false;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.F6) && Input.GetKey(KeyCode.LeftControl))
{
SwitchXRMode();
}
}
public void SwitchXRMode()
{
if (_switchInProgress) return;
if (!IsInXR())
{
StartCoroutine(StartXRSystem());
}
else
{
StartCoroutine(StopXR());
}
}
public bool IsInXR() => XRGeneralSettings.Instance.Manager.activeLoader != null;
private IEnumerator StartXRSystem()
{
PreXRModeSwitch(true);
yield return null;
yield return XRGeneralSettings.Instance.Manager.InitializeLoader();
if (XRGeneralSettings.Instance.Manager.activeLoader != null)
{
DesktopXRSwitch.Logger.Msg("Starting OpenXR...");
XRGeneralSettings.Instance.Manager.StartSubsystems();
yield return null;
PostXRModeSwitch(true);
yield break;
}
DesktopXRSwitch.Logger.Error("Initializing XR Failed. Is there no XR device connected?");
FailedVRModeSwitch(true);
yield break;
}
private IEnumerator StopXR()
{
PreXRModeSwitch(false);
yield return null;
if (XRGeneralSettings.Instance.Manager.isInitializationComplete)
{
XRGeneralSettings.Instance.Manager.StopSubsystems();
XRGeneralSettings.Instance.Manager.DeinitializeLoader();
yield return null;
PostXRModeSwitch(false);
yield break;
}
DesktopXRSwitch.Logger.Error("Attempted to exit VR without a VR device loaded.");
FailedVRModeSwitch(false);
yield break;
}
//one frame after switch attempt
public void FailedVRModeSwitch(bool isXR)
{
if (_softVRSwitch) return;
//let tracked objects know a switch failed
XRModeSwitchTracker.FailXRModeSwitch(isXR);
}
//one frame before switch attempt
public void PreXRModeSwitch(bool isXR)
{
if (_softVRSwitch) return;
//let tracked objects know we are attempting to switch
XRModeSwitchTracker.PreXRModeSwitch(isXR);
}
//one frame after switch attempt
public void PostXRModeSwitch(bool isXR)
{
if (_softVRSwitch) return;
//close the menus
TryCatchHell.CloseCohtmlMenus();
//the base of VR checks
TryCatchHell.SetCheckVR(isXR);
TryCatchHell.SetMetaPort(isXR);
//game basics for functional gameplay post switch
TryCatchHell.RepositionCohtmlHud(isXR);
TryCatchHell.UpdateHudOperations(isXR);
TryCatchHell.DisableMirrorCanvas();
TryCatchHell.SwitchActiveCameraRigs(isXR);
TryCatchHell.SwitchCVRInputManager(isXR);
TryCatchHell.UpdateRichPresence();
TryCatchHell.UpdateGestureReconizerCam();
//let tracked objects know we switched
XRModeSwitchTracker.PostXRModeSwitch(isXR);
//reload avatar by default, optional for debugging
if (_reloadLocalAvatar)
{
TryCatchHell.ReloadLocalAvatar();
}
else
{
}
_switchInProgress = false;
}
}

View file

@ -3,13 +3,12 @@ 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.Melons.DesktopXRSwitch.Patches;
using UnityEngine;
namespace NAK.DesktopVRSwitch.HarmonyPatches;
namespace NAK.Melons.DesktopXRSwitch.HarmonyPatches;
internal class PlayerSetupPatches
{
@ -17,13 +16,14 @@ internal class PlayerSetupPatches
[HarmonyPatch(typeof(PlayerSetup), "Start")]
private static void Postfix_PlayerSetup_Start(ref PlayerSetup __instance)
{
__instance.gameObject.AddComponent<PlayerSetupTracker>();
if (CheckVR.Instance != null)
{
CheckVR.Instance.gameObject.AddComponent<DesktopVRSwitcher>();
CheckVR.Instance.gameObject.AddComponent<DesktopXRSwitcher>();
return;
}
__instance.gameObject.AddComponent<DesktopVRSwitcher>();
DesktopVRSwitch.Logger.Error("CheckVR not found. Reverting to fallback method. This should never happen!");
__instance.gameObject.AddComponent<DesktopXRSwitcher>();
DesktopXRSwitch.Logger.Error("CheckVR not found. Reverting to fallback method. This should never happen!");
}
}
@ -90,31 +90,4 @@ internal class IKSystemPatches
{
__instance.gameObject.AddComponent<IKSystemTracker>();
}
[HarmonyPostfix] //lazy fix so i dont need to wait few frames
[HarmonyPatch(typeof(TrackingPoint), "Initialize")]
private 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), "ModuleDestroy")]
private static void Postfix_SteamVRTrackingModule_ModuleDestroy(ref SteamVRTrackingModule __instance)
{
for (int i = 0; i < __instance.TrackingPoints.Count; i++)
{
UnityEngine.Object.Destroy(__instance.TrackingPoints[i].referenceGameObject);
}
__instance.TrackingPoints.Clear();
}
}
internal class VRTrackerManagerPatches
{
[HarmonyPostfix]
[HarmonyPatch(typeof(VRTrackerManager), "Start")]
private static void Postfix_VRTrackerManager_Start(ref VRTrackerManager __instance)
{
__instance.gameObject.AddComponent<VRTrackerManagerTracker>();
}
}

View file

@ -9,18 +9,18 @@
It is also just in case other mods break or tweak functionality that
could fuck with switching. Or if they try to detect switching and break...
The VRModeSwitchTracker system is also built so I can easily & quickly make adjustments to
The XRModeSwitchTracker system is also built so I can easily & quickly make adjustments to
components that may or may not change between builds without breaking the rest of the mod.
**/
namespace NAK.DesktopVRSwitch;
namespace NAK.Melons.DesktopXRSwitch;
public class DesktopVRSwitch : MelonMod
public class DesktopXRSwitch : MelonMod
{
internal static MelonLogger.Instance Logger;
public static readonly MelonPreferences_Category Category =
MelonPreferences.CreateCategory(nameof(DesktopVRSwitch));
MelonPreferences.CreateCategory(nameof(DesktopXRSwitch));
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.");
@ -34,7 +34,6 @@ public class DesktopVRSwitch : MelonMod
ApplyPatches(typeof(HarmonyPatches.CameraFacingObjectPatches));
ApplyPatches(typeof(HarmonyPatches.IKSystemPatches));
ApplyPatches(typeof(HarmonyPatches.MovementSystemPatches));
ApplyPatches(typeof(HarmonyPatches.VRTrackerManagerPatches));
}
private void ApplyPatches(Type type)

View file

@ -3,7 +3,7 @@ using UnityEngine;
//Thanks Ben! I was scared of transpiler so I reworked a bit...
namespace NAK.DesktopVRSwitch.Patches;
namespace NAK.Melons.DesktopXRSwitch.Patches;
public class CVRPickupObjectTracker : MonoBehaviour
{
@ -12,15 +12,15 @@ public class CVRPickupObjectTracker : MonoBehaviour
void Start()
{
VRModeSwitchTracker.OnPostVRModeSwitch += PostVRModeSwitch;
XRModeSwitchTracker.OnPostXRModeSwitch += PostXRModeSwitch;
}
void OnDestroy()
{
VRModeSwitchTracker.OnPostVRModeSwitch -= PostVRModeSwitch;
XRModeSwitchTracker.OnPostXRModeSwitch -= PostXRModeSwitch;
}
public void PostVRModeSwitch(bool enableVR, Camera activeCamera)
public void PostXRModeSwitch(bool isXR, Camera activeCamera)
{
if (pickupObject != null)
{
@ -28,4 +28,4 @@ public class CVRPickupObjectTracker : MonoBehaviour
(storedGripOrigin, pickupObject.gripOrigin) = (pickupObject.gripOrigin, storedGripOrigin);
}
}
}
}

View file

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

View file

@ -3,7 +3,7 @@ using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Systems.IK.TrackingModules;
using UnityEngine;
namespace NAK.DesktopVRSwitch.Patches;
namespace NAK.Melons.DesktopXRSwitch.Patches;
public class IKSystemTracker : MonoBehaviour
{
@ -12,18 +12,18 @@ public class IKSystemTracker : MonoBehaviour
void Start()
{
ikSystem = GetComponent<IKSystem>();
VRModeSwitchTracker.OnPreVRModeSwitch += PreVRModeSwitch;
VRModeSwitchTracker.OnFailVRModeSwitch += FailedVRModeSwitch;
VRModeSwitchTracker.OnPostVRModeSwitch += PostVRModeSwitch;
XRModeSwitchTracker.OnPreXRModeSwitch += PreXRModeSwitch;
XRModeSwitchTracker.OnFailXRModeSwitch += FailedXRModeSwitch;
XRModeSwitchTracker.OnPostXRModeSwitch += PostXRModeSwitch;
}
void OnDestroy()
{
VRModeSwitchTracker.OnPreVRModeSwitch -= PreVRModeSwitch;
VRModeSwitchTracker.OnFailVRModeSwitch -= FailedVRModeSwitch;
VRModeSwitchTracker.OnPostVRModeSwitch -= PostVRModeSwitch;
XRModeSwitchTracker.OnPreXRModeSwitch -= PreXRModeSwitch;
XRModeSwitchTracker.OnFailXRModeSwitch -= FailedXRModeSwitch;
XRModeSwitchTracker.OnPostXRModeSwitch -= PostXRModeSwitch;
}
public void PreVRModeSwitch(bool enableVR, Camera activeCamera)
public void PreXRModeSwitch(bool inXR, Camera activeCamera)
{
BodySystem.TrackingEnabled = false;
BodySystem.TrackingPositionWeight = 0f;
@ -32,7 +32,7 @@ public class IKSystemTracker : MonoBehaviour
IKSystem.vrik.enabled = false;
}
public void FailedVRModeSwitch(bool enableVR, Camera activeCamera)
public void FailedXRModeSwitch(bool inXR, Camera activeCamera)
{
BodySystem.TrackingEnabled = true;
BodySystem.TrackingPositionWeight = 1f;
@ -41,7 +41,7 @@ public class IKSystemTracker : MonoBehaviour
IKSystem.vrik.enabled = true;
}
public void PostVRModeSwitch(bool enableVR, Camera activeCamera)
public void PostXRModeSwitch(bool inXR, Camera activeCamera)
{
if (IKSystem.vrik != null)
DestroyImmediate(IKSystem.vrik);
@ -54,33 +54,35 @@ public class IKSystemTracker : MonoBehaviour
BodySystem.isCalibrating = false;
BodySystem.isRecalibration = false;
//make it so you dont instantly end up in FBT from Desktop
IKSystem.firstAvatarLoaded = DesktopVRSwitch.EntryEnterCalibrationOnSwitch.Value;
IKSystem.firstAvatarLoaded = DesktopXRSwitch.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);
SetupOpenXRTrackingModule(inXR);
}
void SetupSteamVRTrackingModule(bool enableVR)
void SetupOpenXRTrackingModule(bool enableVR)
{
var openVRModule = ikSystem._trackingModules.OfType<SteamVRTrackingModule>().FirstOrDefault();
var openXRTrackingModule = ikSystem._trackingModules.OfType<OpenXRTrackingModule>().FirstOrDefault();
if (openVRModule != null)
if (openXRTrackingModule != null)
{
if (enableVR)
{
openVRModule.ModuleStart();
openXRTrackingModule.ModuleStart();
}
else
{
openVRModule.ModuleDestroy();
openXRTrackingModule.ModuleDestroy();
if (openXRTrackingModule != null)
ikSystem._trackingModules.Remove(openXRTrackingModule);
}
}
else if (enableVR)
{
var newVRModule = new SteamVRTrackingModule();
var newVRModule = new OpenXRTrackingModule();
ikSystem.AddTrackingModule(newVRModule);
}
}

View file

@ -1,7 +1,7 @@
using ABI_RC.Systems.MovementSystem;
using UnityEngine;
namespace NAK.DesktopVRSwitch.Patches;
namespace NAK.Melons.DesktopXRSwitch.Patches;
public class MovementSystemTracker : MonoBehaviour
{
@ -12,17 +12,17 @@ public class MovementSystemTracker : MonoBehaviour
void Start()
{
movementSystem = GetComponent<MovementSystem>();
VRModeSwitchTracker.OnPreVRModeSwitch += PreVRModeSwitch;
VRModeSwitchTracker.OnPostVRModeSwitch += PostVRModeSwitch;
XRModeSwitchTracker.OnPreXRModeSwitch += PreXRModeSwitch;
XRModeSwitchTracker.OnPostXRModeSwitch += PostXRModeSwitch;
}
void OnDestroy()
{
VRModeSwitchTracker.OnPreVRModeSwitch -= PreVRModeSwitch;
VRModeSwitchTracker.OnPostVRModeSwitch -= PostVRModeSwitch;
XRModeSwitchTracker.OnPreXRModeSwitch -= PreXRModeSwitch;
XRModeSwitchTracker.OnPostXRModeSwitch -= PostXRModeSwitch;
}
public void PreVRModeSwitch(bool enableVR, Camera activeCamera)
public void PreXRModeSwitch(bool isXR, Camera activeCamera)
{
//correct rotationPivot y position, so we dont teleport up/down
Vector3 position = movementSystem.rotationPivot.transform.position;
@ -39,14 +39,14 @@ public class MovementSystemTracker : MonoBehaviour
movementSystem.ChangeProne(false);
}
public void PostVRModeSwitch(bool enableVR, Camera activeCamera)
public void PostXRModeSwitch(bool isXR, 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);
if (!isXR) movementSystem.UpdateColliderCenter(movementSystem.transform.position);
movementSystem.ChangeCrouch(false);
movementSystem.ChangeProne(false);

View file

@ -0,0 +1,142 @@
using ABI.CCK.Components;
using ABI_RC.Core.Base;
using ABI_RC.Core.Player;
using ABI_RC.Systems.IK;
using HarmonyLib;
using RootMotion.FinalIK;
using System.Reflection;
using UnityEngine;
namespace NAK.Melons.DesktopXRSwitch.Patches;
public class PlayerSetupTracker : MonoBehaviour
{
public static PlayerSetupTracker Instance;
public PlayerSetup playerSetup;
public Traverse _initialCameraPosTraverse;
public Traverse _lookIKTraverse;
public Traverse _lastScaleTraverse;
public HumanPose avatarInitialHumanPose;
public HumanPoseHandler avatarHumanPoseHandler;
public GameObject avatarObject;
public CVRAvatar avatarDescriptor;
public Animator avatarAnimator;
public Vector3 initialPosition;
public Quaternion initialRotation;
void Start()
{
Instance = this;
playerSetup = GetComponent<PlayerSetup>();
_initialCameraPosTraverse = Traverse.Create(playerSetup).Field("initialCameraPos");
_lookIKTraverse = Traverse.Create(playerSetup).Field("lookIK");
_lastScaleTraverse = Traverse.Create(playerSetup).Field("lastScale");
}
public void OnSetupAvatar(GameObject avatar)
{
avatarObject = avatar;
avatarDescriptor = avatarObject.GetComponent<CVRAvatar>();
avatarAnimator = avatarObject.GetComponent<Animator>();
initialPosition = avatarObject.transform.localPosition;
initialRotation = avatarObject.transform.localRotation;
if (avatarHumanPoseHandler == null)
{
avatarHumanPoseHandler = new HumanPoseHandler(avatarAnimator.avatar, avatarAnimator.transform);
}
avatarHumanPoseHandler.GetHumanPose(ref avatarInitialHumanPose);
}
public void OnClearAvatar()
{
avatarObject = null;
avatarDescriptor = null;
avatarAnimator = null;
initialPosition = Vector3.one;
initialRotation = Quaternion.identity;
avatarHumanPoseHandler = null;
}
public void ConfigureAvatarIK(bool isVR)
{
bool StateOnDisable = avatarAnimator.keepAnimatorStateOnDisable;
avatarAnimator.keepAnimatorStateOnDisable = true;
avatarAnimator.enabled = false;
//reset avatar offsets
avatarObject.transform.localPosition = initialPosition;
avatarObject.transform.localRotation = initialRotation;
avatarHumanPoseHandler.SetHumanPose(ref avatarInitialHumanPose);
if (isVR)
{
SwitchAvatarVr();
}
else
{
SwitchAvatarDesktop();
}
//lazy fix
_lastScaleTraverse.SetValue(Vector3.zero);
MethodInfo setPlaySpaceScaleMethod = playerSetup.GetType().GetMethod("CheckUpdateAvatarScaleToPlaySpaceRelation", BindingFlags.NonPublic | BindingFlags.Instance);
setPlaySpaceScaleMethod.Invoke(playerSetup, null);
avatarAnimator.keepAnimatorStateOnDisable = StateOnDisable;
avatarAnimator.enabled = true;
}
private void SwitchAvatarVr()
{
if (avatarDescriptor == null) return;
//remove LookAtIK if found
LookAtIK avatarLookAtIK = avatarObject.GetComponent<LookAtIK>();
if (avatarLookAtIK != null) DestroyImmediate(avatarLookAtIK);
//have IKSystem set up avatar for VR
//a good chunk of IKSystem initialization checks for existing
//stuff & if it is set up, so game is ready to handle it
if (avatarAnimator != null && avatarAnimator.isHuman)
{
IKSystem.Instance.InitializeAvatar(avatarDescriptor);
}
}
private void SwitchAvatarDesktop()
{
if (avatarDescriptor == null) return;
//remove VRIK & VRIKRootController if found
VRIK avatarVRIK = avatarObject.GetComponent<VRIK>();
VRIKRootController avatarVRIKRootController = avatarObject.GetComponent<VRIKRootController>();
if (avatarVRIK != null) DestroyImmediate(avatarVRIK);
if (avatarVRIKRootController != null) DestroyImmediate(avatarVRIKRootController);
//remove all TwistRelaxer components
TwistRelaxer[] avatarTwistRelaxers = avatarObject.GetComponentsInChildren<TwistRelaxer>();
for (int i = 0; i < avatarTwistRelaxers.Length; i++)
{
DestroyImmediate(avatarTwistRelaxers[i]);
}
Transform headTransform = avatarAnimator.GetBoneTransform(HumanBodyBones.Head);
if (headTransform != null)
{
//set DesktopCameraRig to head bone pos
playerSetup.desktopCameraRig.transform.position = headTransform.position;
//add LookAtIK & Configure
LookAtIK lookAtIK = avatarObject.AddComponentIfMissing<LookAtIK>();
lookAtIK.solver.head = new IKSolverLookAt.LookAtBone(headTransform);
lookAtIK.solver.headWeight = 0.75f;
lookAtIK.solver.target = playerSetup.desktopCameraTarget.transform;
_lookIKTraverse.SetValue(lookAtIK);
}
//set camera position & initial position for headbob (both modes end up with same number)
playerSetup.desktopCamera.transform.localPosition = (Vector3)_initialCameraPosTraverse.GetValue();
}
}

View file

@ -8,7 +8,7 @@ using UnityEngine.AzureSky;
using UnityEngine.Rendering.PostProcessing;
using Object = UnityEngine.Object;
namespace NAK.DesktopVRSwitch.Patches;
namespace NAK.Melons.DesktopXRSwitch.Patches;
internal class ReferenceCameraPatch
{
@ -21,7 +21,7 @@ internal class ReferenceCameraPatch
internal static void CopyToInactiveCam(Camera activeCam, Camera inactiveCam)
{
DesktopVRSwitch.Logger.Msg("Copying active camera settings & components to inactive camera.");
DesktopXRSwitch.Logger.Msg("Copying active camera settings & components to inactive camera.");
//steal basic settings
inactiveCam.farClipPlane = activeCam.farClipPlane;

View file

@ -0,0 +1,45 @@
using ABI_RC.Core.Player;
using UnityEngine;
using UnityEngine.Events;
namespace NAK.Melons.DesktopXRSwitch.Patches;
public class XRModeSwitchTracker
{
public static event UnityAction<bool, Camera> OnPreXRModeSwitch;
public static event UnityAction<bool, Camera> OnPostXRModeSwitch;
public static event UnityAction<bool, Camera> OnFailXRModeSwitch;
public static void PreXRModeSwitch(bool isXR)
{
TryCatchHell.TryCatchWrapper(() =>
{
DesktopXRSwitch.Logger.Msg("Invoking XRModeSwitchTracker.OnPreXRModeSwitch.");
Camera activeCamera = PlayerSetup.Instance.GetActiveCamera().GetComponent<Camera>();
XRModeSwitchTracker.OnPreXRModeSwitch?.Invoke(isXR, activeCamera);
},
"Error while invoking XRModeSwitchTracker.OnPreXRModeSwitch. Did someone do a fucky?");
}
public static void PostXRModeSwitch(bool isXR)
{
TryCatchHell.TryCatchWrapper(() =>
{
DesktopXRSwitch.Logger.Msg("Invoking XRModeSwitchTracker.OnPostXRModeSwitch.");
Camera activeCamera = PlayerSetup.Instance.GetActiveCamera().GetComponent<Camera>();
XRModeSwitchTracker.OnPostXRModeSwitch?.Invoke(isXR, activeCamera);
},
"Error while invoking XRModeSwitchTracker.OnPostXRModeSwitch. Did someone do a fucky?");
}
public static void FailXRModeSwitch(bool isXR)
{
TryCatchHell.TryCatchWrapper(() =>
{
DesktopXRSwitch.Logger.Msg("Invoking XRModeSwitchTracker.OnFailXRModeSwitch.");
Camera activeCamera = PlayerSetup.Instance.GetActiveCamera().GetComponent<Camera>();
XRModeSwitchTracker.OnFailXRModeSwitch?.Invoke(isXR, activeCamera);
},
"Error while invoking OnFailXRModeSwitch.OnPreXRModeSwitch. Did someone do a fucky?");
}
}

View file

@ -1,31 +1,30 @@
using MelonLoader;
using NAK.DesktopVRSwitch.Properties;
using NAK.Melons.DesktopXRSwitch.Properties;
using System.Reflection;
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)]
[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)]
[assembly: AssemblyTitle(nameof(NAK.DesktopVRSwitch))]
[assembly: AssemblyTitle(nameof(NAK.Melons.DesktopXRSwitch))]
[assembly: AssemblyCompany(AssemblyInfoParams.Author)]
[assembly: AssemblyProduct(nameof(NAK.DesktopVRSwitch))]
[assembly: AssemblyProduct(nameof(NAK.Melons.DesktopXRSwitch))]
[assembly: MelonInfo(
typeof(NAK.DesktopVRSwitch.DesktopVRSwitch),
nameof(NAK.DesktopVRSwitch),
typeof(NAK.Melons.DesktopXRSwitch.DesktopXRSwitch),
nameof(NAK.Melons.DesktopXRSwitch),
AssemblyInfoParams.Version,
AssemblyInfoParams.Author,
downloadLink: "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/DesktopVRSwitch"
downloadLink: "https://github.com/NotAKidOnSteam/DesktopXRSwitch"
)]
[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")]
[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
[assembly: MelonColor(ConsoleColor.DarkCyan)]
[assembly: HarmonyDontPatchAll]
namespace NAK.DesktopVRSwitch.Properties;
namespace NAK.Melons.DesktopXRSwitch.Properties;
internal static class AssemblyInfoParams
{
public const string Version = "4.3.6";
public const string Version = "4.3.4";
public const string Author = "NotAKidoS";
}

View file

@ -5,9 +5,12 @@ using ABI_RC.Core.Player;
using ABI_RC.Core.Savior;
using ABI_RC.Core.UI;
using ABI_RC.Systems.Camera;
using ABI_RC.Systems.InputManagement;
using ABI_RC.Systems.InputManagement.InputModules;
using HarmonyLib;
using UnityEngine;
namespace NAK.DesktopVRSwitch;
namespace NAK.Melons.DesktopXRSwitch;
internal class TryCatchHell
{
@ -19,8 +22,8 @@ internal class TryCatchHell
}
catch (Exception ex)
{
DesktopVRSwitch.Logger.Error(string.Format(errorMsg, msgArgs));
DesktopVRSwitch.Logger.Msg(ex.Message);
DesktopXRSwitch.Logger.Error(string.Format(errorMsg, msgArgs));
DesktopXRSwitch.Logger.Msg(ex.Message);
}
}
@ -28,52 +31,52 @@ internal class TryCatchHell
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Closing ViewManager & CVR_MenuManager menus.");
DesktopXRSwitch.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 SetCheckVR(bool isXR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg($"Setting CheckVR hasVrDeviceLoaded to {enableVR}.");
CheckVR.Instance.hasVrDeviceLoaded = enableVR;
DesktopXRSwitch.Logger.Msg($"Setting CheckVR hasVrDeviceLoaded to {isXR}.");
CheckVR.Instance.hasVrDeviceLoaded = isXR;
},
"Setting CheckVR hasVrDeviceLoaded failed.");
}
internal static void SetMetaPort(bool enableVR)
internal static void SetMetaPort(bool isXR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg($"Setting MetaPort isUsingVr to {enableVR}.");
MetaPort.Instance.isUsingVr = enableVR;
DesktopXRSwitch.Logger.Msg($"Setting MetaPort isUsingVr to {isXR}.");
MetaPort.Instance.isUsingVr = isXR;
},
"Setting MetaPort isUsingVr failed.");
}
internal static void RepositionCohtmlHud(bool enableVR)
internal static void RepositionCohtmlHud(bool isXR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Configuring new hud affinity for CohtmlHud.");
CohtmlHud.Instance.gameObject.transform.parent = enableVR ? PlayerSetup.Instance.vrCamera.transform : PlayerSetup.Instance.desktopCamera.transform;
DesktopXRSwitch.Logger.Msg("Configuring new hud affinity for CohtmlHud.");
CohtmlHud.Instance.gameObject.transform.parent = isXR ? 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 UpdateHudOperations(bool isXR)
{
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;
DesktopXRSwitch.Logger.Msg("Switching HudOperations worldLoadingItem & worldLoadStatus.");
HudOperations.Instance.worldLoadingItem = isXR ? HudOperations.Instance.worldLoadingItemVr : HudOperations.Instance.worldLoadingItemDesktop;
HudOperations.Instance.worldLoadStatus = isXR ? HudOperations.Instance.worldLoadStatusVr : HudOperations.Instance.worldLoadStatusDesktop;
},
"Failed switching HudOperations objects.");
}
@ -82,7 +85,7 @@ internal class TryCatchHell
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Forcing PortableCamera canvas mirroring off.");
DesktopXRSwitch.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();
@ -90,13 +93,13 @@ internal class TryCatchHell
"Failed to disable PortableCamera canvas mirroring.");
}
internal static void SwitchActiveCameraRigs(bool enableVR)
internal static void SwitchActiveCameraRigs(bool isXR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Switching active PlayerSetup camera rigs. Updating Desktop camera FOV.");
PlayerSetup.Instance.desktopCameraRig.SetActive(!enableVR);
PlayerSetup.Instance.vrCameraRig.SetActive(enableVR);
DesktopXRSwitch.Logger.Msg("Switching active PlayerSetup camera rigs. Updating Desktop camera FOV.");
PlayerSetup.Instance.desktopCameraRig.SetActive(!isXR);
PlayerSetup.Instance.vrCameraRig.SetActive(isXR);
CVR_DesktopCameraController.UpdateFov();
//uicamera has script that copies fov from desktop cam
//toggling the cameras on/off resets aspect ratio
@ -109,18 +112,18 @@ internal class TryCatchHell
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg($"Setting CVRInputManager inputEnabled & CVR_InteractableManager enableInteractions to {!toggle}");
DesktopXRSwitch.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 SwitchCVRInputManager(bool isXR)
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Resetting CVRInputManager inputs.");
DesktopXRSwitch.Logger.Msg("Resetting CVRInputManager inputs.");
//just in case
CVRInputManager.Instance.blockedByUi = false;
//sometimes head can get stuck, so just in case
@ -132,6 +135,15 @@ internal class TryCatchHell
CVRInputManager.Instance.gestureRightRaw = 0f;
//turn off finger tracking input
CVRInputManager.Instance.individualFingerTracking = false;
//add input module if you started in desktop
if (CVRInputManager._moduleOpenXR == null)
{
CVRInputManager.Instance.AddInputModule(CVRInputManager._moduleOpenXR = new CVRInputModule_OpenXR());
}
//enable xr input or whatnot
CVRInputManager._moduleOpenXR.InputEnabled = isXR;
},
"Failed to reset CVRInputManager inputs.");
}
@ -140,7 +152,7 @@ internal class TryCatchHell
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Attempting to reload current local avatar from GUID.");
DesktopXRSwitch.Logger.Msg("Attempting to reload current local avatar from GUID.");
AssetManagement.Instance.LoadLocalAvatar(MetaPort.Instance.currentAvatarGuid);
},
"Failed to reload local avatar.");
@ -152,13 +164,13 @@ internal class TryCatchHell
{
if (MetaPort.Instance.settings.GetSettingsBool("ImplementationRichPresenceDiscordEnabled", true))
{
DesktopVRSwitch.Logger.Msg("Forcing Discord Rich Presence update.");
DesktopXRSwitch.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.");
DesktopXRSwitch.Logger.Msg("Forcing Steam Rich Presence update.");
MetaPort.Instance.settings.SetSettingsBool("ImplementationRichPresenceSteamEnabled", false);
MetaPort.Instance.settings.SetSettingsBool("ImplementationRichPresenceSteamEnabled", true);
}
@ -170,19 +182,9 @@ internal class TryCatchHell
{
TryCatchWrapper(() =>
{
DesktopVRSwitch.Logger.Msg("Updating CVRGestureRecognizer _camera to active camera.");
CVRGestureRecognizer.Instance._camera = PlayerSetup.Instance.GetActiveCamera().GetComponent<Camera>();
DesktopXRSwitch.Logger.Msg("Updating CVRGestureRecognizer _camera to active camera.");
Traverse.Create(CVRGestureRecognizer.Instance).Field("_camera").SetValue(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.");
}
}
}

View file

@ -1,7 +1,7 @@
{
"_id": 103,
"name": "DesktopVRSwitch",
"modversion": "4.3.5",
"modversion": "4.3.1",
"gameversion": "2022r170",
"loaderversion": "0.5.7",
"modtype": "Mod",
@ -16,8 +16,8 @@
"requirements": [
"None"
],
"downloadlink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/releases/download/r3/DesktopVRSwitch.dll",
"sourcelink": "https://github.com/NotAKidOnSteam/NAK_CVR_Mods/tree/main/DesktopVRSwitch/",
"changelog": "- Reinitialize SteamVR input on switch. Correct fixedDeltaTime when entering Desktop.\n- Tweak to initial switch position for correcting offsets.\n- Fixed FBT tracking point initial size.\n- Update core menu data so QM Recalibrate/SeatedPlay button works.",
"downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRSwitch/releases/download/v4.3.1/DesktopVRSwitch.dll",
"sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRSwitch/",
"changelog": "- Backported rewrite from Experimental & patched up to handle OpenVR.\n- Reinitialize SteamVR input on switch incase user restarted SteamVR or changed controllers. Correct fixedDeltaTime when entering Desktop.\n- Many tweaks to ensure everything in-game functions as expected.",
"embedcolor": "3498db"
}

View file

@ -444,6 +444,10 @@
<HintPath>$(MsBuildThisFileDirectory)\_ManagedLibs\Unity.Entities.Hybrid.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.InputSystem">
<HintPath>$(MsBuildThisFileDirectory)\_ManagedLibs\Unity.InputSystem.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.InternalAPIEngineBridge.003">
<HintPath>$(MsBuildThisFileDirectory)\_ManagedLibs\Unity.InternalAPIEngineBridge.003.dll</HintPath>
<Private>False</Private>

View file

@ -19,7 +19,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CVRGizmos", "CVRGizmos\CVRG
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DesktopVRIK", "DesktopVRIK\DesktopVRIK.csproj", "{CD33AB69-F9A4-4F32-B69A-473131F6393B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DesktopVRSwitch", "DesktopVRSwitch\DesktopVRSwitch.csproj", "{30F56FE1-1654-4213-A51C-4C0278FB43A6}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DesktopXRSwitch", "DesktopXRSwitch\DesktopXRSwitch.csproj", "{30F56FE1-1654-4213-A51C-4C0278FB43A6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FuckMetrics", "FuckMetrics\FuckMetrics.csproj", "{55E805A5-404C-4BB9-9AF1-A432443B1424}"
EndProject

View file

@ -121,7 +121,7 @@ else {
# Loop through each DLL file to strip and call NStrip.exe
foreach($dllFile in $dllsToStrip) {
$dllPath = Join-Path -Path $managedLibsFolder -ChildPath $dllFile
& $nStripPath -p -n $dllPath $dllPath
& $nStripPath -p -cg -n $dllPath $dllPath
}
Write-Host ""