diff --git a/DesktopVRSwitch/DesktopVRSwitch.cs b/DesktopVRSwitch/DesktopVRSwitch.cs new file mode 100644 index 0000000..7da6495 --- /dev/null +++ b/DesktopVRSwitch/DesktopVRSwitch.cs @@ -0,0 +1,124 @@ +using NAK.Melons.DesktopVRSwitch.Patches; +using System.Collections; +using UnityEngine; +using UnityEngine.XR; +using Valve.VR; + +namespace NAK.Melons.DesktopVRSwitch; + +public class DesktopVRSwitch : MonoBehaviour +{ + //Settings + public bool _reloadLocalAvatar = true; + + //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() + { + BeforeVRModeSwitch(true); + XRSettings.LoadDeviceByName("OpenVR"); + yield return null; + if (string.IsNullOrEmpty(XRSettings.loadedDeviceName)) + { + DesktopVRSwitchMod.Logger.Error("Initializing VR Failed. Is there no VR device connected?"); + } + else + { + DesktopVRSwitchMod.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; + AfterVRModeSwitch(true); + } + yield break; + } + + private IEnumerator StopVR() + { + BeforeVRModeSwitch(false); + yield return null; + if (!string.IsNullOrEmpty(XRSettings.loadedDeviceName)) + { + //deactivate the action set so SteamVR_Input.Initialize can reactivate + SteamVR_Input.actionSets[0].Deactivate(SteamVR_Input_Sources.Any); + SteamVR.SafeDispose(); //idk + XRSettings.LoadDeviceByName(""); + XRSettings.enabled = false; + yield return null; + //reset physics time to Desktop default + Time.fixedDeltaTime = 0.02f; + AfterVRModeSwitch(false); + } + yield break; + } + + //one frame before switch attempt + public void BeforeVRModeSwitch(bool enterVR) + { + //let tracked objects know we are attempting to switch + VRModeSwitchTracker.PreVRModeSwitch(enterVR); + } + + //one frame after switch attempt + public void AfterVRModeSwitch(bool enterVR) + { + //these two must come first + TryCatchHell.SetCheckVR(enterVR); + TryCatchHell.SetMetaPort(enterVR); + + //the bulk of funni changes + TryCatchHell.RepositionCohtmlHud(enterVR); + TryCatchHell.UpdateHudOperations(enterVR); + TryCatchHell.DisableMirrorCanvas(); + TryCatchHell.SwitchActiveCameraRigs(enterVR); + TryCatchHell.ResetCVRInputManager(); + TryCatchHell.UpdateRichPresence(); + TryCatchHell.UpdateGestureReconizerCam(); + + //let tracked objects know we switched + VRModeSwitchTracker.PostVRModeSwitch(enterVR); + + //reload avatar by default, optional for debugging + if (_reloadLocalAvatar) + { + TryCatchHell.ReloadLocalAvatar(); + } + + _switchInProgress = false; + } +} + diff --git a/DesktopVRSwitch/DesktopVRSwitch.csproj b/DesktopVRSwitch/DesktopVRSwitch.csproj index adb74e4..0e61fd5 100644 --- a/DesktopVRSwitch/DesktopVRSwitch.csproj +++ b/DesktopVRSwitch/DesktopVRSwitch.csproj @@ -16,19 +16,16 @@ C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Aura2_Core.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Aura2_Core.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll - - - ..\..\Giamoz\Giamoz\bin\Debug\net472\Giamoz.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\MelonLoader.dll @@ -37,16 +34,16 @@ C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\SteamVR.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\UIExpansionKit.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\UIExpansionKit.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Unity.Postprocessing.Runtime.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Unity.Postprocessing.Runtime.dll - ..\..\..\DakyModsCVR\ManagedLibs\Unity.TextMeshPro.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Unity.TextMeshPro.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll @@ -55,13 +52,16 @@ C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.InputLegacyModule.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.VRModule.dll + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.VRModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.VRModule.dll - ..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.XRModule.dll + ..\..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.XRModule.dll diff --git a/DesktopVRSwitch/DesktopVRSwitchHelper.cs b/DesktopVRSwitch/DesktopVRSwitchHelper.cs deleted file mode 100644 index ee7949d..0000000 --- a/DesktopVRSwitch/DesktopVRSwitchHelper.cs +++ /dev/null @@ -1,434 +0,0 @@ -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.Core.Util.Object_Behaviour; -using ABI_RC.Systems.Camera; -using ABI_RC.Systems.IK.SubSystems; -using ABI_RC.Systems.MovementSystem; -using DesktopVRSwitch.Patches; -using HarmonyLib; -using MelonLoader; -using System.Collections; -using UnityEngine; -using UnityEngine.XR; -using Valve.VR; -using Object = UnityEngine.Object; - -namespace DesktopVRSwitch; - -public class DesktopVRSwitchHelper : MonoBehaviour -{ - public static DesktopVRSwitchHelper Instance; - - //settings - public bool SettingTimedErrorCatch = true; - public float SettingTimedErrorTimer = 10f; - - //internal shit - internal static bool isAttemptingSwitch = false; - internal static float timedSwitch = 0f; - internal static bool CurrentMode; - internal static Vector3 avatarWorldPos; - internal static Quaternion avatarWorldRot; - - public void SwitchMode(bool isTimedSwitch = false) - { - if (isAttemptingSwitch) return; - - isAttemptingSwitch = true; - MelonCoroutines.Start(AttemptPlatformSwitch()); - - //how long we wait until we assume an error occured - if (isTimedSwitch) - timedSwitch = Time.time + SettingTimedErrorTimer; - } - - public void Start() - { - Instance = this; - } - - public void Update() - { - // assuming CVRInputManager.switchMode button was originally for desktop/vr switching before being left to do literally nothing in rootlogic - if (Input.GetKeyDown(KeyCode.F6) && (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) && !isAttemptingSwitch) - { - SwitchMode(true); - } - - if (!isAttemptingSwitch) return; - - //catch if coroutine just decided to not finish... which happens? - if (Time.time > timedSwitch) - { - MelonLogger.Error("Timer exceeded. Something is wrong and coroutine failed partway."); - isAttemptingSwitch = false; - if (SettingTimedErrorCatch) - SwitchMode(); - } - } - - //disables VRIK if it was on the current avatar during switch - //absolutely bruteforcing the stupid vr playspace offset issue - public void LateUpdate() - { - if (!isAttemptingSwitch) return; - - if (!PlayerSetup.Instance.avatarIsLoading && PlayerSetup.Instance._avatar != null) - { - BodySystem.TrackingEnabled = false; - BodySystem.TrackingPositionWeight = 0f; - PlayerSetup.Instance._avatar.transform.position = avatarWorldPos; - PlayerSetup.Instance._avatar.transform.rotation = avatarWorldRot; - MovementSystem.Instance.TeleportToPosRot(avatarWorldPos, avatarWorldRot, false); - MovementSystem.Instance.UpdateColliderCenter(avatarWorldPos); - } - } - - internal static IEnumerator AttemptPlatformSwitch(bool forceMode = false) - { - //forceMode will attempt to backtrack to last working mode (if you dont like the mess, fix it yourself thx) - CurrentMode = forceMode ? CurrentMode : MetaPort.Instance.isUsingVr; - bool VRMode = forceMode ? CurrentMode : !CurrentMode; - - CloseMenuElements(VRMode); - ToggleInputInteractions(false); - DisableMirrorCanvas(); - - //store current player position/rotation to correct VR/Desktop offsets - avatarWorldPos = PlayerSetup.Instance._avatar.transform.position; - avatarWorldRot = PlayerSetup.Instance._avatar.transform.rotation; - - //exit all movement states - MovementSystem.Instance.ChangeCrouch(false); - MovementSystem.Instance.ChangeProne(false); - MovementSystem.Instance.canMove = false; - MovementSystem.Instance.canRot = false; - - //load SteamVR - InitializeSteamVR(VRMode); - - yield - return new WaitForEndOfFrame(); - - SetCheckVR(VRMode); - SetMetaPort(VRMode); - - //reset rich presence - if (MetaPort.Instance.settings.GetSettingsBool("ImplementationRichPresenceDiscordEnabled", true)) - { - MetaPort.Instance.settings.SetSettingsBool("ImplementationRichPresenceDiscordEnabled", false); - MetaPort.Instance.settings.SetSettingsBool("ImplementationRichPresenceDiscordEnabled", true); - } - if (MetaPort.Instance.settings.GetSettingsBool("ImplementationRichPresenceSteamEnabled", true)) - { - MetaPort.Instance.settings.SetSettingsBool("ImplementationRichPresenceSteamEnabled", false); - MetaPort.Instance.settings.SetSettingsBool("ImplementationRichPresenceSteamEnabled", true); - } - - yield - return new WaitForEndOfFrame(); - - SwitchActiveCameraRigs(VRMode); - UpdateCameraFacingObject(); - RepositionCohtmlHud(VRMode); - UpdateHudOperations(VRMode); - SwitchPickupOrigins(); - - yield - return new WaitForEndOfFrame(); - - //needs to come after SetMovementSystem - UpdateGestureReconizerCam(); - - ResetCVRInputManager(); - - //gonna try doing this last - DisposeSteamVR(VRMode); - - ToggleInputInteractions(true); - - //reload current avatar - AssetManagement.Instance.LoadLocalAvatar(MetaPort.Instance.currentAvatarGuid); - - yield return new WaitUntil(() => !PlayerSetup.Instance.avatarIsLoading); - - isAttemptingSwitch = false; - - BodySystem.TrackingEnabled = true; - BodySystem.TrackingPositionWeight = 1f; - MovementSystem.Instance.canMove = true; - MovementSystem.Instance.canRot = true; - - if (!VRMode) - //collision center is set to match headpos in VR, but desktop doesnt reset it - MovementSystem.Instance.UpdateColliderCenter(PlayerSetup.Instance._avatar.transform.position); - - yield - return new WaitForEndOfFrame(); - - //one last teleport to correct VR offset - MovementSystem.Instance.TeleportToPosRot(avatarWorldPos, avatarWorldRot, false); - - yield - return null; - } - - //shitton of try catch below - - internal static void InitializeSteamVR(bool isVR) - { - if (isVR) - { - //force SteamVR to fully initialize, this does all and more than what i did with LoadDevice() - SteamVR.Initialize(true); - - //Just to make sure. Game does this natively when entering VR. - SteamVR_Settings.instance.pauseGameWhenDashboardVisible = false; - - //TODO: something needs to be done to reinitialize SteamVR_Input or SteamVR_Actions - //If you restart SteamVR after already have been in VRMode, the steamvr action handles break - //ive tried: - //SteamVR_Input.Initialize(true) - //SteamVR_Actions.PreInitialize() - //Destroying SteamVR_Settings on DesktopMode - //Destroying SteamVR_Behavior on DesktopMode - //Destroying SteamVR_Render on DesktopMode - //Combinations of all of these.. - //Its probably really simple, but I just cannot figure out how. - } - } - - internal static void DisposeSteamVR(bool isVR) - { - if (!isVR) - { - //force SteamVR to let go of Chillout - XRSettings.LoadDeviceByName("None"); - XRSettings.enabled = false; - - //destroy [SteamVR] gameobject as next SteamVR.Initialize creates a new one - Object.Destroy(SteamVR_Behaviour.instance.gameObject); - - //what even does this do that is actually important? - SteamVR.SafeDispose(); - } - } - - // shouldn't be that important, right? - internal static void CloseMenuElements(bool isVR) - { - if (ViewManager.Instance != null) - { - MelonLogger.Msg("Closed MainMenu Instance."); - ViewManager.Instance.UiStateToggle(false); - } - else - { - MelonLogger.Msg("MainMenu Instance not found!!!"); - } - if (ViewManager.Instance != null) - { - MelonLogger.Msg("Closed QuickMenu Instance."); - CVR_MenuManager.Instance.ToggleQuickMenu(false); - } - else - { - MelonLogger.Msg("QuickMenu Instance not found!!!"); - } - } - - internal static void ToggleInputInteractions(bool toggle) - { - //disable input during switch - try - { - MelonLogger.Msg($"Toggling input & interactions to " + toggle); - CVRInputManager.Instance.inputEnabled = toggle; - CVR_InteractableManager.enableInteractions = toggle; - } - catch - { - MelonLogger.Error("Toggling input & interactions failed. Is something invalid?"); - MelonLogger.Msg("CVRInputManager.Instance: " + CVRInputManager.Instance); - MelonLogger.Msg("CVR_InteractableManager: " + CVR_InteractableManager.enableInteractions); - throw; - } - } - - internal static void SetCheckVR(bool isVR) - { - try - { - MelonLogger.Msg($"Set CheckVR hasVrDeviceLoaded to {isVR}."); - CheckVR.Instance.hasVrDeviceLoaded = isVR; - } - catch - { - MelonLogger.Error("Setting CheckVR hasVrDeviceLoaded failed. Is CheckVR.Instance invalid?"); - MelonLogger.Msg("CheckVR.Instance: " + CheckVR.Instance); - throw; - } - } - - internal static void SetMetaPort(bool isVR) - { - try - { - MelonLogger.Msg($"Set MetaPort isUsingVr to {isVR}."); - MetaPort.Instance.isUsingVr = isVR; - } - catch - { - MelonLogger.Error("Setting MetaPort isUsingVr failed. Is MetaPort.Instance invalid?"); - MelonLogger.Msg("MetaPort.Instance: " + MetaPort.Instance); - throw; - } - } - - internal static void SwitchActiveCameraRigs(bool isVR) - { - try - { - MelonLogger.Msg("Switched active camera rigs."); - PlayerSetup.Instance.desktopCameraRig.SetActive(!isVR); - PlayerSetup.Instance.vrCameraRig.SetActive(isVR); - } - catch - { - MelonLogger.Error("Error switching active cameras. Are the camera rigs invalid?"); - MelonLogger.Msg("PlayerSetup.Instance.desktopCameraRig: " + PlayerSetup.Instance.desktopCameraRig); - MelonLogger.Msg("PlayerSetup.Instance.vrCameraRig: " + PlayerSetup.Instance.vrCameraRig); - throw; - } - } - - internal static void RepositionCohtmlHud(bool isVR) - { - try - { - MelonLogger.Msg("Parented CohtmlHud to active camera."); - CohtmlHud.Instance.gameObject.transform.parent = isVR ? PlayerSetup.Instance.vrCamera.transform : PlayerSetup.Instance.desktopCamera.transform; - - //sets hud position, rotation, ~~and scale~~ based on MetaPort isUsingVr - CVRTools.ConfigureHudAffinity(); - CohtmlHud.Instance.gameObject.transform.localScale = new Vector3(1.2f, 1f, 1.2f); - } - catch - { - MelonLogger.Error("Error parenting CohtmlHud to active camera. Is CohtmlHud.Instance invalid?"); - MelonLogger.Msg("CohtmlHud.Instance: " + CohtmlHud.Instance); - throw; - } - } - - internal static void ResetCVRInputManager() - { - try - { - MelonLogger.Msg("Enabling CVRInputManager inputEnabled & disabling blockedByUi!"); - //CVRInputManager.Instance.reload = true; - //just in case - CVRInputManager.Instance.inputEnabled = true; - 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; - } - catch - { - MelonLogger.Error("CVRInputManager reload failed. Is CVRInputManager.Instance invalid?"); - MelonLogger.Msg("CVRInputManager.Instance: " + CVRInputManager.Instance); - throw; - } - } - - //every nameplate canvas uses CameraFacingObject :stare: - internal static void UpdateCameraFacingObject() - { - try - { - MelonLogger.Msg("Updating all CameraFacingObject scripts to face new camera. (this fixes nameplates)"); - CameraFacingObject[] camfaceobjs = Object.FindObjectsOfType(); - - for (int i = 0; i < camfaceobjs.Count(); i++) - { - camfaceobjs[i].m_Camera = PlayerSetup.Instance.GetActiveCamera().GetComponent(); - } - } - catch - { - MelonLogger.Error("Error updating CameraFacingObject objects! Nameplates will be wonk..."); - throw; - } - } - - internal static void UpdateHudOperations(bool isVR) - { - try - { - MelonLogger.Msg("Set HudOperations worldLoadingItem and worldLoadStatus to their respective Desktop/Vr parent."); - HudOperations.Instance.worldLoadingItem = isVR ? HudOperations.Instance.worldLoadingItemVr : HudOperations.Instance.worldLoadingItemDesktop; - HudOperations.Instance.worldLoadStatus = isVR ? HudOperations.Instance.worldLoadStatusVr : HudOperations.Instance.worldLoadStatusDesktop; - } - catch - { - MelonLogger.Error("Error updating HudOperations LoadingItem & LoadStatus!"); - throw; - } - } - - internal static void DisableMirrorCanvas() - { - try - { - //tell the game we are in mirror mode so itll disable it (if enabled) - PortableCamera.Instance.mode = MirroringMode.Mirror; - PortableCamera.Instance.ChangeMirroring(); - } - catch - { - MelonLogger.Error("Error updating CVRGestureRecognizer camera!"); - throw; - } - } - - internal static void UpdateGestureReconizerCam() - { - try - { - MelonLogger.Msg("Set GestureReconizerCam camera to active camera."); - Traverse.Create(CVRGestureRecognizer.Instance).Field("_camera").SetValue(PlayerSetup.Instance.GetActiveCamera().GetComponent()); - } - catch - { - MelonLogger.Error("Error updating CVRGestureRecognizer camera!"); - throw; - } - } - - internal static void SwitchPickupOrigins() - { - try - { - MelonLogger.Msg("Switched pickup origins."); - CVRPickupObjectTracker[] pickups = Object.FindObjectsOfType(); - for (int i = 0; i < pickups.Count(); i++) - { - pickups[i].OnSwitch(); - } - } - catch - { - MelonLogger.Error("Error switching pickup origins!"); - throw; - } - } -} \ No newline at end of file diff --git a/DesktopVRSwitch/HarmonyPatches.cs b/DesktopVRSwitch/HarmonyPatches.cs new file mode 100644 index 0000000..6790699 --- /dev/null +++ b/DesktopVRSwitch/HarmonyPatches.cs @@ -0,0 +1,92 @@ +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.MovementSystem; +using HarmonyLib; +using NAK.Melons.DesktopVRSwitch.Patches; +using UnityEngine; + +namespace NAK.Melons.DesktopVRSwitch.HarmonyPatches; + +internal class PlayerSetupPatches +{ + [HarmonyPostfix] + [HarmonyPatch(typeof(PlayerSetup), "Start")] + private static void Postfix_PlayerSetup_Start(ref PlayerSetup __instance) + { + if (CheckVR.Instance != null) + { + CheckVR.Instance.gameObject.AddComponent(); + return; + } + __instance.gameObject.AddComponent(); + DesktopVRSwitchMod.Logger.Error("CheckVR not found. Reverting to fallback method. This should never happen!"); + } +} + +internal class MovementSystemPatches +{ + [HarmonyPostfix] + [HarmonyPatch(typeof(MovementSystem), "Start")] + private static void Postfix_MovementSystem_Start(ref MovementSystem __instance) + { + __instance.gameObject.AddComponent(); + } +} + +internal class CVRPickupObjectPatches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(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(); + tracker.pickupObject = __instance; + tracker.storedGripOrigin = (!MetaPort.Instance.isUsingVr ? vrOrigin : desktopOrigin); + } + } +} + +internal class CVRWorldPatches +{ + [HarmonyPostfix] + [HarmonyPatch(typeof(CVRWorld), "SetDefaultCamValues")] + private static void CVRWorld_SetDefaultCamValues_Postfix() + { + ReferenceCameraPatch.OnWorldLoad(); + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(CVRWorld), "CopyRefCamValues")] + private static void CVRWorld_CopyRefCamValues_Postfix() + { + ReferenceCameraPatch.OnWorldLoad(); + } +} + +internal class CameraFacingObjectPatches +{ + [HarmonyPostfix] + [HarmonyPatch(typeof(CameraFacingObject), "Start")] + private static void Postfix_CameraFacingObject_Start(ref CameraFacingObject __instance) + { + __instance.gameObject.AddComponent(); + } +} + +internal class IKSystemPatches +{ + [HarmonyPostfix] + [HarmonyPatch(typeof(IKSystem), "Start")] + private static void Postfix_IKSystem_Start(ref IKSystem __instance) + { + __instance.gameObject.AddComponent(); + } +} \ No newline at end of file diff --git a/DesktopVRSwitch/Main.cs b/DesktopVRSwitch/Main.cs index a6ca2f9..4e61e12 100644 --- a/DesktopVRSwitch/Main.cs +++ b/DesktopVRSwitch/Main.cs @@ -1,59 +1,36 @@ -using ABI_RC.Core.Player; -using MelonLoader; +using MelonLoader; -//tell the game to change VRMode/DesktopMode for Steam/Discord presence -//RichPresence.PopulatePresence(); +namespace NAK.Melons.DesktopVRSwitch; -//nvm that resets the RichPresence clock- i want people to know how long ive wasted staring at mirror - -namespace DesktopVRSwitch; - -public class DesktopVRSwitch : MelonMod +public class DesktopVRSwitchMod : MelonMod { internal const string SettingsCategory = "DesktopVRSwitch"; internal static MelonPreferences_Category m_categoryDesktopVRSwitch; - internal static MelonPreferences_Entry m_entryTimedErrorCatch; - internal static MelonPreferences_Entry m_entryTimedErrorTimer; + internal static MelonLogger.Instance Logger; public override void OnInitializeMelon() { + Logger = LoggerInstance; m_categoryDesktopVRSwitch = MelonPreferences.CreateCategory(SettingsCategory); - m_entryTimedErrorCatch = m_categoryDesktopVRSwitch.CreateEntry("Timed Error Catch", true, description: "Attempt to switch back if an error is found after n seconds."); - m_entryTimedErrorTimer = m_categoryDesktopVRSwitch.CreateEntry("Timed Error Timer", 10f, description: "Amount of seconds to wait before assuming there was an error."); - m_categoryDesktopVRSwitch.SaveToFile(false); - foreach (var setting in m_categoryDesktopVRSwitch.Entries) - { - setting.OnEntryValueChangedUntyped.Subscribe(OnUpdateSettings); - } - - //UIExpansionKit addon - if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "UI Expansion Kit")) - { - MelonLogger.Msg("Initializing UIExpansionKit support."); - UiExtensionsAddon.Init(); - } - MelonLoader.MelonCoroutines.Start(WaitForLocalPlayer()); + ApplyPatches(typeof(HarmonyPatches.PlayerSetupPatches)); + ApplyPatches(typeof(HarmonyPatches.CVRPickupObjectPatches)); + ApplyPatches(typeof(HarmonyPatches.CVRWorldPatches)); + ApplyPatches(typeof(HarmonyPatches.CameraFacingObjectPatches)); + ApplyPatches(typeof(HarmonyPatches.IKSystemPatches)); + ApplyPatches(typeof(HarmonyPatches.MovementSystemPatches)); } - System.Collections.IEnumerator WaitForLocalPlayer() + private void ApplyPatches(Type type) { - while (PlayerSetup.Instance == null) - yield return null; - - PlayerSetup.Instance.gameObject.AddComponent(); - - while (DesktopVRSwitchHelper.Instance == null) - yield return null; - - UpdateAllSettings(); - } - - private void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); - private void UpdateAllSettings() - { - if (!DesktopVRSwitchHelper.Instance) return; - DesktopVRSwitchHelper.Instance.SettingTimedErrorCatch = m_entryTimedErrorCatch.Value; - DesktopVRSwitchHelper.Instance.SettingTimedErrorTimer = m_entryTimedErrorTimer.Value; + try + { + HarmonyInstance.PatchAll(type); + } + catch (Exception e) + { + Logger.Msg($"Failed while patching {type.Name}!"); + Logger.Error(e); + } } } \ No newline at end of file diff --git a/DesktopVRSwitch/Patches/CVRPickupObjectTracker.cs b/DesktopVRSwitch/Patches/CVRPickupObjectTracker.cs index 5bb7943..3f73d51 100644 --- a/DesktopVRSwitch/Patches/CVRPickupObjectTracker.cs +++ b/DesktopVRSwitch/Patches/CVRPickupObjectTracker.cs @@ -1,61 +1,31 @@ using ABI.CCK.Components; -using ABI_RC.Core.Savior; -using HarmonyLib; -using MelonLoader; using UnityEngine; //Thanks Ben! I was scared of transpiler so I reworked a bit... -namespace DesktopVRSwitch.Patches; - -[HarmonyPatch] -internal class CVRPickupObject_Patch -{ - [HarmonyPrefix] - [HarmonyPatch(typeof(CVRPickupObject), "Start")] - private static void CVRPickupObject_Start_Prefix(ref CVRPickupObject __instance) - { - if (__instance.gripOrigin == null) return; - - Transform desktopOrigin = __instance.gripOrigin.Find("[Desktop]"); - if (desktopOrigin == null) return; - - var pickupTracker = __instance.GetComponent(); - if (pickupTracker != null) return; - - __instance.gameObject.AddComponent(); - - StorePreviousPosition(__instance, (!MetaPort.Instance.isUsingVr) ? __instance.gripOrigin : desktopOrigin); - } - - private static void StorePreviousPosition(CVRPickupObject pickupObject, Transform gripOrigin) - { - MelonLogger.Msg("Storing previous gripOrigin."); - CVRPickupObjectTracker.previousGripOrigin[pickupObject] = gripOrigin; - } -} +namespace NAK.Melons.DesktopVRSwitch.Patches; public class CVRPickupObjectTracker : MonoBehaviour { - //maybe i should store both transforms instead and getcomponent for CVRPickupObject..? - public static Dictionary previousGripOrigin = new(); + public CVRPickupObject pickupObject; + public Transform storedGripOrigin; - public void OnSwitch() + void Start() { - var pickupObject = GetComponent(); + VRModeSwitchTracker.OnPostVRModeSwitch += PostVRModeSwitch; + } + void OnDestroy() + { + VRModeSwitchTracker.OnPostVRModeSwitch -= PostVRModeSwitch; + } + + public void PostVRModeSwitch(bool enterVR, Camera activeCamera) + { if (pickupObject != null) { - if (pickupObject.IsGrabbedByMe() && pickupObject._controllerRay != null) pickupObject._controllerRay.DropObject(true); - (previousGripOrigin[pickupObject], pickupObject.gripOrigin) = (pickupObject.gripOrigin, previousGripOrigin[pickupObject]); + if (pickupObject._controllerRay != null) pickupObject._controllerRay.DropObject(true); + (storedGripOrigin, pickupObject.gripOrigin) = (pickupObject.gripOrigin, storedGripOrigin); } } - - private void OnDestroy() - { - var pickupObject = GetComponent(); - - if (pickupObject != null) - previousGripOrigin.Remove(pickupObject); - } } diff --git a/DesktopVRSwitch/Patches/CameraFacingObjectTracker.cs b/DesktopVRSwitch/Patches/CameraFacingObjectTracker.cs new file mode 100644 index 0000000..918e925 --- /dev/null +++ b/DesktopVRSwitch/Patches/CameraFacingObjectTracker.cs @@ -0,0 +1,24 @@ +using ABI_RC.Core.Util.Object_Behaviour; +using UnityEngine; + +namespace NAK.Melons.DesktopVRSwitch.Patches; + +public class CameraFacingObjectTracker : MonoBehaviour +{ + public CameraFacingObject cameraFacingObject; + void Start() + { + cameraFacingObject = GetComponent(); + VRModeSwitchTracker.OnPostVRModeSwitch += PostVRModeSwitch; + } + + void OnDestroy() + { + VRModeSwitchTracker.OnPostVRModeSwitch -= PostVRModeSwitch; + } + + public void PostVRModeSwitch(bool enterVR, Camera activeCamera) + { + cameraFacingObject.m_Camera = activeCamera; + } +} \ No newline at end of file diff --git a/DesktopVRSwitch/Patches/IKSystemTracker.cs b/DesktopVRSwitch/Patches/IKSystemTracker.cs new file mode 100644 index 0000000..f64acea --- /dev/null +++ b/DesktopVRSwitch/Patches/IKSystemTracker.cs @@ -0,0 +1,57 @@ +using ABI_RC.Systems.IK; +using ABI_RC.Systems.IK.SubSystems; +using ABI_RC.Systems.IK.TrackingModules; +using HarmonyLib; +using UnityEngine; +using System.Reflection; + +namespace NAK.Melons.DesktopVRSwitch.Patches; + +public class IKSystemTracker : MonoBehaviour +{ + public IKSystem ikSystem; + public Traverse _traverseModules; + + void Start() + { + ikSystem = GetComponent(); + _traverseModules = Traverse.Create(ikSystem).Field("_trackingModules"); + VRModeSwitchTracker.OnPostVRModeSwitch += PostVRModeSwitch; + } + void OnDestroy() + { + VRModeSwitchTracker.OnPostVRModeSwitch -= PostVRModeSwitch; + } + + public void PostVRModeSwitch(bool enterVR, Camera activeCamera) + { + var _trackingModules = _traverseModules.GetValue>(); + SteamVRTrackingModule openVRTrackingModule = _trackingModules.FirstOrDefault(m => m is SteamVRTrackingModule) as SteamVRTrackingModule; + if (openVRTrackingModule != null) + { + if (enterVR) + { + openVRTrackingModule.ModuleStart(); + } + else + { + //why named destroy when it doesnt ? + openVRTrackingModule.ModuleDestroy(); + } + } + else + { + var steamVRTrackingModule = CreateSteamVRTrackingModule(); + ikSystem.AddTrackingModule(steamVRTrackingModule); + } + } + + //thanks for marking the constructor as internal + private SteamVRTrackingModule CreateSteamVRTrackingModule() + { + var steamVRTrackingModuleType = typeof(SteamVRTrackingModule); + var constructor = steamVRTrackingModuleType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null); + var instance = constructor.Invoke(null); + return (SteamVRTrackingModule)instance; + } +} \ No newline at end of file diff --git a/DesktopVRSwitch/Patches/MovementSystemTracker.cs b/DesktopVRSwitch/Patches/MovementSystemTracker.cs new file mode 100644 index 0000000..7aea4c9 --- /dev/null +++ b/DesktopVRSwitch/Patches/MovementSystemTracker.cs @@ -0,0 +1,39 @@ +using ABI_RC.Systems.MovementSystem; +using UnityEngine; + +namespace NAK.Melons.DesktopVRSwitch.Patches; + +public class MovementSystemTracker : MonoBehaviour +{ + public MovementSystem movementSystem; + + public Vector3 preSwitchWorldPosition; + public Quaternion preSwitchWorldRotation; + + void Start() + { + movementSystem = GetComponent(); + VRModeSwitchTracker.OnPostVRModeSwitch += PreVRModeSwitch; + VRModeSwitchTracker.OnPostVRModeSwitch += PostVRModeSwitch; + } + + void OnDestroy() + { + VRModeSwitchTracker.OnPostVRModeSwitch -= PreVRModeSwitch; + VRModeSwitchTracker.OnPostVRModeSwitch -= PostVRModeSwitch; + } + + public void PreVRModeSwitch(bool enterVR, Camera activeCamera) + { + preSwitchWorldPosition = movementSystem.rotationPivot.transform.position; + preSwitchWorldRotation = movementSystem.rotationPivot.transform.rotation; + } + + public void PostVRModeSwitch(bool enterVR, Camera activeCamera) + { + //lazy way of correcting Desktop & VR offset issue (game does the maths) + movementSystem.TeleportToPosRot(preSwitchWorldPosition, preSwitchWorldRotation, false); + //recenter desktop collision to player object + if (!enterVR) movementSystem.UpdateColliderCenter(movementSystem.transform.position); + } +} \ No newline at end of file diff --git a/DesktopVRSwitch/Patches/ReferenceCameraPatch.cs b/DesktopVRSwitch/Patches/ReferenceCameraPatch.cs new file mode 100644 index 0000000..9681873 --- /dev/null +++ b/DesktopVRSwitch/Patches/ReferenceCameraPatch.cs @@ -0,0 +1,91 @@ +using ABI_RC.Core.Base; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using Aura2API; +using BeautifyEffect; +using UnityEngine; +using UnityEngine.AzureSky; +using UnityEngine.Rendering.PostProcessing; +using Object = UnityEngine.Object; + +namespace NAK.Melons.DesktopVRSwitch.Patches; + +internal class ReferenceCameraPatch +{ + internal static void OnWorldLoad() + { + Camera activeCamera = (MetaPort.Instance.isUsingVr ? PlayerSetup.Instance.vrCamera : PlayerSetup.Instance.desktopCamera).GetComponent(); + Camera inactiveCamera = (MetaPort.Instance.isUsingVr ? PlayerSetup.Instance.desktopCamera : PlayerSetup.Instance.vrCamera).GetComponent(); + CopyToInactiveCam(activeCamera, inactiveCamera); + } + + internal static void CopyToInactiveCam(Camera activeCam, Camera inactiveCam) + { + DesktopVRSwitchMod.Logger.Msg("Copying active camera settings & components to inactive camera."); + + //steal basic settings + inactiveCam.farClipPlane = activeCam.farClipPlane; + inactiveCam.nearClipPlane = activeCam.nearClipPlane; + inactiveCam.cullingMask = activeCam.cullingMask; + inactiveCam.depthTextureMode = activeCam.depthTextureMode; + + //steal post processing if added + PostProcessLayer ppLayerActiveCam = activeCam.GetComponent(); + PostProcessLayer ppLayerInactiveCam = inactiveCam.AddComponentIfMissing(); + if (ppLayerActiveCam != null && ppLayerInactiveCam != null) + { + ppLayerInactiveCam.enabled = ppLayerActiveCam.enabled; + ppLayerInactiveCam.volumeLayer = ppLayerActiveCam.volumeLayer; + } + + //what even is this aura camera stuff + AuraCamera auraActiveCam = activeCam.GetComponent(); + AuraCamera auraInactiveCam = inactiveCam.AddComponentIfMissing(); + if (auraActiveCam != null && auraInactiveCam != null) + { + auraInactiveCam.enabled = auraActiveCam.enabled; + auraInactiveCam.frustumSettings = auraActiveCam.frustumSettings; + } + else + { + auraInactiveCam.enabled = false; + } + + //flare layer thing? the sun :_:_:_:_:_: + FlareLayer flareActiveCam = activeCam.GetComponent(); + FlareLayer flareInactiveCam = inactiveCam.AddComponentIfMissing(); + if (flareActiveCam != null && flareInactiveCam != null) + { + flareInactiveCam.enabled = flareActiveCam.enabled; + } + else + { + flareInactiveCam.enabled = false; + } + + //and now what the fuck is fog scattering + AzureFogScattering azureFogActiveCam = activeCam.GetComponent(); + AzureFogScattering azureFogInactiveCam = inactiveCam.AddComponentIfMissing(); + if (azureFogActiveCam != null && azureFogInactiveCam != null) + { + azureFogInactiveCam.fogScatteringMaterial = azureFogActiveCam.fogScatteringMaterial; + } + else + { + Object.Destroy(inactiveCam.GetComponent()); + } + + //why is there so many thingsssssssss + Beautify beautifyActiveCam = activeCam.GetComponent(); + Beautify beautifyInactiveCam = inactiveCam.AddComponentIfMissing(); + if (beautifyActiveCam != null && beautifyInactiveCam != null) + { + beautifyInactiveCam.quality = beautifyActiveCam.quality; + beautifyInactiveCam.profile = beautifyActiveCam.profile; + } + else + { + Object.Destroy(inactiveCam.gameObject.GetComponent()); + } + } +} \ No newline at end of file diff --git a/DesktopVRSwitch/Patches/VRModeSwitchTracker.cs b/DesktopVRSwitch/Patches/VRModeSwitchTracker.cs new file mode 100644 index 0000000..d6f20c3 --- /dev/null +++ b/DesktopVRSwitch/Patches/VRModeSwitchTracker.cs @@ -0,0 +1,33 @@ +using ABI_RC.Core.Player; +using UnityEngine; +using UnityEngine.Events; + +namespace NAK.Melons.DesktopVRSwitch.Patches; + +public class VRModeSwitchTracker +{ + public static event UnityAction OnPreVRModeSwitch; + public static event UnityAction OnPostVRModeSwitch; + + public static void PreVRModeSwitch(bool enterVR) + { + TryCatchHell.TryCatchWrapper(() => + { + DesktopVRSwitchMod.Logger.Msg("Invoking VRModeSwitchTracker.OnPreVRModeSwitch."); + Camera activeCamera = PlayerSetup.Instance.GetActiveCamera().GetComponent(); + VRModeSwitchTracker.OnPreVRModeSwitch?.Invoke(enterVR, activeCamera); + }, + "Error while invoking VRModeSwitchTracker.OnPreVRModeSwitch. Did someone do a fucky?"); + } + + public static void PostVRModeSwitch(bool enterVR) + { + TryCatchHell.TryCatchWrapper(() => + { + DesktopVRSwitchMod.Logger.Msg("Invoking VRModeSwitchTracker.OnPostVRModeSwitch."); + Camera activeCamera = PlayerSetup.Instance.GetActiveCamera().GetComponent(); + VRModeSwitchTracker.OnPostVRModeSwitch?.Invoke(enterVR, activeCamera); + }, + "Error while invoking VRModeSwitchTracker.OnPostVRModeSwitch. Did someone do a fucky?"); + } +} \ No newline at end of file diff --git a/DesktopVRSwitch/Properties/AssemblyInfo.cs b/DesktopVRSwitch/Properties/AssemblyInfo.cs index 743b703..35df6ca 100644 --- a/DesktopVRSwitch/Properties/AssemblyInfo.cs +++ b/DesktopVRSwitch/Properties/AssemblyInfo.cs @@ -1,18 +1,17 @@ -using DesktopVRSwitch.Properties; -using MelonLoader; +using MelonLoader; +using NAK.Melons.DesktopVRSwitch.Properties; using System.Reflection; - [assembly: AssemblyVersion(AssemblyInfoParams.Version)] [assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] [assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] -[assembly: AssemblyTitle(nameof(DesktopVRSwitch))] +[assembly: AssemblyTitle(nameof(NAK.Melons.DesktopVRSwitch))] [assembly: AssemblyCompany(AssemblyInfoParams.Author)] -[assembly: AssemblyProduct(nameof(DesktopVRSwitch))] +[assembly: AssemblyProduct(nameof(NAK.Melons.DesktopVRSwitch))] [assembly: MelonInfo( - typeof(DesktopVRSwitch.DesktopVRSwitch), - nameof(DesktopVRSwitch), + typeof(NAK.Melons.DesktopVRSwitch.DesktopVRSwitchMod), + nameof(NAK.Melons.DesktopVRSwitch), AssemblyInfoParams.Version, AssemblyInfoParams.Author, downloadLink: "https://github.com/NotAKidOnSteam/DesktopVRSwitch" @@ -21,10 +20,11 @@ using System.Reflection; [assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] [assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: HarmonyDontPatchAll] -namespace DesktopVRSwitch.Properties; +namespace NAK.Melons.DesktopVRSwitch.Properties; internal static class AssemblyInfoParams { - public const string Version = "3.0.5"; + public const string Version = "4.2.4"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/DesktopVRSwitch/TryCatchHell.cs b/DesktopVRSwitch/TryCatchHell.cs new file mode 100644 index 0000000..ad3313b --- /dev/null +++ b/DesktopVRSwitch/TryCatchHell.cs @@ -0,0 +1,167 @@ +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 HarmonyLib; +using UnityEngine; + +namespace NAK.Melons.DesktopVRSwitch; + +internal class TryCatchHell +{ + internal static void TryCatchWrapper(Action action, string errorMsg, params object[] msgArgs) + { + try + { + action(); + } + catch (Exception ex) + { + DesktopVRSwitchMod.Logger.Error(string.Format(errorMsg, msgArgs)); + DesktopVRSwitchMod.Logger.Msg(ex.Message); + } + } + + internal static void SetCheckVR(bool isVR) + { + TryCatchWrapper(() => + { + DesktopVRSwitchMod.Logger.Msg($"Setting CheckVR hasVrDeviceLoaded to {isVR}."); + CheckVR.Instance.hasVrDeviceLoaded = isVR; + }, + "Setting CheckVR hasVrDeviceLoaded failed."); + } + + internal static void SetMetaPort(bool isVR) + { + TryCatchWrapper(() => + { + DesktopVRSwitchMod.Logger.Msg($"Setting MetaPort isUsingVr to {isVR}."); + MetaPort.Instance.isUsingVr = isVR; + }, + "Setting MetaPort isUsingVr failed."); + } + + internal static void RepositionCohtmlHud(bool isVR) + { + TryCatchWrapper(() => + { + DesktopVRSwitchMod.Logger.Msg("Configuring new hud affinity for CohtmlHud."); + CohtmlHud.Instance.gameObject.transform.parent = isVR ? 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 isVR) + { + TryCatchWrapper(() => + { + DesktopVRSwitchMod.Logger.Msg("Switching HudOperations worldLoadingItem & worldLoadStatus."); + HudOperations.Instance.worldLoadingItem = isVR ? HudOperations.Instance.worldLoadingItemVr : HudOperations.Instance.worldLoadingItemDesktop; + HudOperations.Instance.worldLoadStatus = isVR ? HudOperations.Instance.worldLoadStatusVr : HudOperations.Instance.worldLoadStatusDesktop; + }, + "Failed switching HudOperations objects."); + } + + internal static void DisableMirrorCanvas() + { + TryCatchWrapper(() => + { + DesktopVRSwitchMod.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 isVR) + { + TryCatchWrapper(() => + { + DesktopVRSwitchMod.Logger.Msg("Switching active PlayerSetup camera rigs. Updating Desktop camera FOV."); + PlayerSetup.Instance.desktopCameraRig.SetActive(!isVR); + PlayerSetup.Instance.vrCameraRig.SetActive(isVR); + 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) + { + TryCatchWrapper(() => + { + DesktopVRSwitchMod.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() + { + TryCatchWrapper(() => + { + DesktopVRSwitchMod.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; + }, + "Failed to reset CVRInputManager inputs."); + } + + internal static void ReloadLocalAvatar() + { + TryCatchWrapper(() => + { + DesktopVRSwitchMod.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)) + { + DesktopVRSwitchMod.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)) + { + DesktopVRSwitchMod.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(() => + { + DesktopVRSwitchMod.Logger.Msg("Updating CVRGestureRecognizer _camera to active camera."); + Traverse.Create(CVRGestureRecognizer.Instance).Field("_camera").SetValue(PlayerSetup.Instance.GetActiveCamera().GetComponent()); + }, + "Failed to update CVRGestureRecognizer camera."); + } +} + diff --git a/DesktopVRSwitch/UIExpansionKitAddon.cs b/DesktopVRSwitch/UIExpansionKitAddon.cs deleted file mode 100644 index de9e9d7..0000000 --- a/DesktopVRSwitch/UIExpansionKitAddon.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Runtime.CompilerServices; -using UIExpansionKit.API; - -namespace DesktopVRSwitch; -public static class UiExtensionsAddon -{ - [MethodImpl(MethodImplOptions.NoInlining)] - public static void Init() - { - var settings = ExpansionKitApi.GetSettingsCategory(DesktopVRSwitch.SettingsCategory); - settings.AddSimpleButton("Switch VRMode", SwitchModeButton); - } - internal static void SwitchModeButton() => DesktopVRSwitchHelper.Instance.SwitchMode(true); -} \ No newline at end of file