mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-02 06:19:22 +00:00
backport from experimental
This commit is contained in:
parent
8a3523539b
commit
5fd8e3d4d6
14 changed files with 686 additions and 560 deletions
124
DesktopVRSwitch/DesktopVRSwitch.cs
Normal file
124
DesktopVRSwitch/DesktopVRSwitch.cs
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -16,19 +16,16 @@
|
|||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp-firstpass">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Aura2_Core">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Aura2_Core.dll</HintPath>
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Aura2_Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="cohtml.Net">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll</HintPath>
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Cohtml.Runtime">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Giamoz">
|
||||
<HintPath>..\..\Giamoz\Giamoz\bin\Debug\net472\Giamoz.dll</HintPath>
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\MelonLoader.dll</HintPath>
|
||||
|
@ -37,16 +34,16 @@
|
|||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\SteamVR.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UIExpansionKit">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\UIExpansionKit.dll</HintPath>
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\Mods\UIExpansionKit.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Unity.Postprocessing.Runtime">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Unity.Postprocessing.Runtime.dll</HintPath>
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Unity.Postprocessing.Runtime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Unity.TextMeshPro">
|
||||
<HintPath>..\..\..\DakyModsCVR\ManagedLibs\Unity.TextMeshPro.dll</HintPath>
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Unity.TextMeshPro.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.AnimationModule">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
|
@ -55,13 +52,16 @@
|
|||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.PhysicsModule">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.VRModule">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.VRModule.dll</HintPath>
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.VRModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.VRModule">
|
||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.VRModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.XRModule">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.XRModule.dll</HintPath>
|
||||
<HintPath>..\..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.XRModule.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -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<CameraFacingObject>();
|
||||
|
||||
for (int i = 0; i < camfaceobjs.Count(); i++)
|
||||
{
|
||||
camfaceobjs[i].m_Camera = PlayerSetup.Instance.GetActiveCamera().GetComponent<Camera>();
|
||||
}
|
||||
}
|
||||
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<Camera>());
|
||||
}
|
||||
catch
|
||||
{
|
||||
MelonLogger.Error("Error updating CVRGestureRecognizer camera!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SwitchPickupOrigins()
|
||||
{
|
||||
try
|
||||
{
|
||||
MelonLogger.Msg("Switched pickup origins.");
|
||||
CVRPickupObjectTracker[] pickups = Object.FindObjectsOfType<CVRPickupObjectTracker>();
|
||||
for (int i = 0; i < pickups.Count(); i++)
|
||||
{
|
||||
pickups[i].OnSwitch();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
MelonLogger.Error("Error switching pickup origins!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
92
DesktopVRSwitch/HarmonyPatches.cs
Normal file
92
DesktopVRSwitch/HarmonyPatches.cs
Normal file
|
@ -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<DesktopVRSwitch>();
|
||||
return;
|
||||
}
|
||||
__instance.gameObject.AddComponent<DesktopVRSwitch>();
|
||||
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<MovementSystemTracker>();
|
||||
}
|
||||
}
|
||||
|
||||
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<CVRPickupObjectTracker>();
|
||||
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<CameraFacingObjectTracker>();
|
||||
}
|
||||
}
|
||||
|
||||
internal class IKSystemPatches
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(IKSystem), "Start")]
|
||||
private static void Postfix_IKSystem_Start(ref IKSystem __instance)
|
||||
{
|
||||
__instance.gameObject.AddComponent<IKSystemTracker>();
|
||||
}
|
||||
}
|
|
@ -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<bool> m_entryTimedErrorCatch;
|
||||
internal static MelonPreferences_Entry<float> m_entryTimedErrorTimer;
|
||||
internal static MelonLogger.Instance Logger;
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
Logger = LoggerInstance;
|
||||
m_categoryDesktopVRSwitch = MelonPreferences.CreateCategory(SettingsCategory);
|
||||
m_entryTimedErrorCatch = m_categoryDesktopVRSwitch.CreateEntry<bool>("Timed Error Catch", true, description: "Attempt to switch back if an error is found after n seconds.");
|
||||
m_entryTimedErrorTimer = m_categoryDesktopVRSwitch.CreateEntry<float>("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<DesktopVRSwitchHelper>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<CVRPickupObjectTracker>();
|
||||
if (pickupTracker != null) return;
|
||||
|
||||
__instance.gameObject.AddComponent<CVRPickupObjectTracker>();
|
||||
|
||||
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<CVRPickupObject, Transform> previousGripOrigin = new();
|
||||
public CVRPickupObject pickupObject;
|
||||
public Transform storedGripOrigin;
|
||||
|
||||
public void OnSwitch()
|
||||
void Start()
|
||||
{
|
||||
var pickupObject = GetComponent<CVRPickupObject>();
|
||||
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<CVRPickupObject>();
|
||||
|
||||
if (pickupObject != null)
|
||||
previousGripOrigin.Remove(pickupObject);
|
||||
}
|
||||
}
|
||||
|
|
24
DesktopVRSwitch/Patches/CameraFacingObjectTracker.cs
Normal file
24
DesktopVRSwitch/Patches/CameraFacingObjectTracker.cs
Normal file
|
@ -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<CameraFacingObject>();
|
||||
VRModeSwitchTracker.OnPostVRModeSwitch += PostVRModeSwitch;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
VRModeSwitchTracker.OnPostVRModeSwitch -= PostVRModeSwitch;
|
||||
}
|
||||
|
||||
public void PostVRModeSwitch(bool enterVR, Camera activeCamera)
|
||||
{
|
||||
cameraFacingObject.m_Camera = activeCamera;
|
||||
}
|
||||
}
|
57
DesktopVRSwitch/Patches/IKSystemTracker.cs
Normal file
57
DesktopVRSwitch/Patches/IKSystemTracker.cs
Normal file
|
@ -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<IKSystem>();
|
||||
_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<List<TrackingModule>>();
|
||||
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;
|
||||
}
|
||||
}
|
39
DesktopVRSwitch/Patches/MovementSystemTracker.cs
Normal file
39
DesktopVRSwitch/Patches/MovementSystemTracker.cs
Normal file
|
@ -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<MovementSystem>();
|
||||
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);
|
||||
}
|
||||
}
|
91
DesktopVRSwitch/Patches/ReferenceCameraPatch.cs
Normal file
91
DesktopVRSwitch/Patches/ReferenceCameraPatch.cs
Normal file
|
@ -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>();
|
||||
Camera inactiveCamera = (MetaPort.Instance.isUsingVr ? PlayerSetup.Instance.desktopCamera : PlayerSetup.Instance.vrCamera).GetComponent<Camera>();
|
||||
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>();
|
||||
PostProcessLayer ppLayerInactiveCam = inactiveCam.AddComponentIfMissing<PostProcessLayer>();
|
||||
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>();
|
||||
AuraCamera auraInactiveCam = inactiveCam.AddComponentIfMissing<AuraCamera>();
|
||||
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>();
|
||||
FlareLayer flareInactiveCam = inactiveCam.AddComponentIfMissing<FlareLayer>();
|
||||
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>();
|
||||
AzureFogScattering azureFogInactiveCam = inactiveCam.AddComponentIfMissing<AzureFogScattering>();
|
||||
if (azureFogActiveCam != null && azureFogInactiveCam != null)
|
||||
{
|
||||
azureFogInactiveCam.fogScatteringMaterial = azureFogActiveCam.fogScatteringMaterial;
|
||||
}
|
||||
else
|
||||
{
|
||||
Object.Destroy(inactiveCam.GetComponent<AzureFogScattering>());
|
||||
}
|
||||
|
||||
//why is there so many thingsssssssss
|
||||
Beautify beautifyActiveCam = activeCam.GetComponent<Beautify>();
|
||||
Beautify beautifyInactiveCam = inactiveCam.AddComponentIfMissing<Beautify>();
|
||||
if (beautifyActiveCam != null && beautifyInactiveCam != null)
|
||||
{
|
||||
beautifyInactiveCam.quality = beautifyActiveCam.quality;
|
||||
beautifyInactiveCam.profile = beautifyActiveCam.profile;
|
||||
}
|
||||
else
|
||||
{
|
||||
Object.Destroy(inactiveCam.gameObject.GetComponent<Beautify>());
|
||||
}
|
||||
}
|
||||
}
|
33
DesktopVRSwitch/Patches/VRModeSwitchTracker.cs
Normal file
33
DesktopVRSwitch/Patches/VRModeSwitchTracker.cs
Normal file
|
@ -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<bool, Camera> OnPreVRModeSwitch;
|
||||
public static event UnityAction<bool, Camera> OnPostVRModeSwitch;
|
||||
|
||||
public static void PreVRModeSwitch(bool enterVR)
|
||||
{
|
||||
TryCatchHell.TryCatchWrapper(() =>
|
||||
{
|
||||
DesktopVRSwitchMod.Logger.Msg("Invoking VRModeSwitchTracker.OnPreVRModeSwitch.");
|
||||
Camera activeCamera = PlayerSetup.Instance.GetActiveCamera().GetComponent<Camera>();
|
||||
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<Camera>();
|
||||
VRModeSwitchTracker.OnPostVRModeSwitch?.Invoke(enterVR, activeCamera);
|
||||
},
|
||||
"Error while invoking VRModeSwitchTracker.OnPostVRModeSwitch. Did someone do a fucky?");
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
167
DesktopVRSwitch/TryCatchHell.cs
Normal file
167
DesktopVRSwitch/TryCatchHell.cs
Normal file
|
@ -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<Camera>());
|
||||
},
|
||||
"Failed to update CVRGestureRecognizer camera.");
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue