From 72c9f123768d1dd067ca7a042ef857391c16c5dd Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Tue, 3 Jan 2023 01:20:05 -0600 Subject: [PATCH] overcomplicated shit --- MenuScalePatch/HarmonyPatches.cs | 108 +++++++++++++++ MenuScalePatch/MSP_Menus.cs | 25 ++++ MenuScalePatch/Main.cs | 104 +++----------- MenuScalePatch/MainMenuHelper.cs | 159 ++++++++++++++++++++++ MenuScalePatch/Properties/AssemblyInfo.cs | 4 +- MenuScalePatch/QuickMenuHelper.cs | 148 ++++++++++++++++++++ 6 files changed, 458 insertions(+), 90 deletions(-) create mode 100644 MenuScalePatch/HarmonyPatches.cs create mode 100644 MenuScalePatch/MSP_Menus.cs create mode 100644 MenuScalePatch/MainMenuHelper.cs create mode 100644 MenuScalePatch/QuickMenuHelper.cs diff --git a/MenuScalePatch/HarmonyPatches.cs b/MenuScalePatch/HarmonyPatches.cs new file mode 100644 index 0000000..3d24450 --- /dev/null +++ b/MenuScalePatch/HarmonyPatches.cs @@ -0,0 +1,108 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Core; +using cohtml; +using HarmonyLib; +using NAK.Melons.MenuScalePatch.Helpers; +using UnityEngine; + +namespace NAK.Melons.MenuScalePatch.HarmonyPatches; + +[HarmonyPatch] +internal class HarmonyPatches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(CVR_MenuManager), "SetScale")] + private static void SetQMScale(float avatarHeight, ref float ____scaleFactor, out bool __runOriginal) + { + ____scaleFactor = avatarHeight / 1.8f; + if (MetaPort.Instance.isUsingVr) + { + ____scaleFactor *= 0.5f; + } + MSP_MenuInfo.ScaleFactor = ____scaleFactor; + __runOriginal = false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(ViewManager), "SetScale")] + private static void CheckMMScale(out bool __runOriginal) + { + /** + ViewManager.SetScale runs once a second when it should only run when aspect ratio changes- CVR bug + assuming its caused by cast from int to float getting the screen size, something floating point bleh + i dont need it so i will nuke it >:) + **/ + __runOriginal = false; + } + + //nuke UpdateMenuPosition methods + //there are 2 Jobs calling this each second, which is fucking my shit + [HarmonyPrefix] + [HarmonyPatch(typeof(CVR_MenuManager), "UpdateMenuPosition")] + private static void Prefix_CVR_MenuManager_UpdateMenuPosition(out bool __runOriginal) + { + __runOriginal = false; + } + [HarmonyPrefix] + [HarmonyPatch(typeof(ViewManager), "UpdateMenuPosition")] + private static void Prefix_ViewManager_UpdateMenuPosition(out bool __runOriginal) + { + __runOriginal = false; + } + + //Set QM stuff + [HarmonyPostfix] + [HarmonyPatch(typeof(CVR_MenuManager), "Start")] + private static void SetupQMHelper(ref CVR_MenuManager __instance, ref GameObject ____leftVrAnchor) + { + QuickMenuHelper helper = __instance.quickMenu.gameObject.AddComponent(); + helper.handAnchor = ____leftVrAnchor.transform; + } + + //Set MM stuff + [HarmonyPostfix] + [HarmonyPatch(typeof(ViewManager), "Start")] + private static void SetupMMHelper(ref ViewManager __instance) + { + __instance.gameObject.AddComponent(); + } + + //hook quickmenu open/close + [HarmonyPostfix] + [HarmonyPatch(typeof(CVR_MenuManager), "ToggleQuickMenu", new Type[] { typeof(bool) })] + private static void Postfix_CVR_MenuManager_ToggleQuickMenu(bool show) + { + if (QuickMenuHelper.Instance == null) return; + QuickMenuHelper.Instance.UpdateWorldAnchors(); + QuickMenuHelper.Instance.ToggleDesktopInputMethod(show); + QuickMenuHelper.Instance.enabled = show; + } + + //add independent head movement to important input + [HarmonyPostfix] + [HarmonyPatch(typeof(InputModuleMouseKeyboard), "UpdateImportantInput")] + private static void Postfix_InputModuleMouseKeyboard_UpdateImportantInput(ref CVRInputManager ____inputManager) + { + ____inputManager.independentHeadTurn |= Input.GetKey(KeyCode.LeftAlt); + } + + //hook menu open/close + [HarmonyPostfix] + [HarmonyPatch(typeof(ViewManager), "UiStateToggle", new Type[] { typeof(bool) })] + private static void Postfix_ViewManager_UiStateToggle(bool show) + { + if (MainMenuHelper.Instance == null) return; + MainMenuHelper.Instance.UpdateWorldAnchors(); + MainMenuHelper.Instance.enabled = show; + } + + //Support for changing VRMode during runtime. + [HarmonyPostfix] + [HarmonyPatch(typeof(PlayerSetup), "CalibrateAvatar")] + private static void CheckVRModeOnSwitch() + { + MSP_MenuInfo.CameraTransform = PlayerSetup.Instance.GetActiveCamera().transform; + } +} \ No newline at end of file diff --git a/MenuScalePatch/MSP_Menus.cs b/MenuScalePatch/MSP_Menus.cs new file mode 100644 index 0000000..341c3c3 --- /dev/null +++ b/MenuScalePatch/MSP_Menus.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using ABI_RC.Core.Savior; + +namespace NAK.Melons.MenuScalePatch.Helpers; + +public class MSP_MenuInfo +{ + //Shared Info + public static float ScaleFactor = 1f; + public static Transform CameraTransform; + + //Settings...? + public static bool WorldAnchorQM; + + //if other mods need to disable? + public static bool DisableQMHelper; + public static bool DisableQMHelper_VR; + public static bool DisableMMHelper; + public static bool DisableMMHelper_VR; +} \ No newline at end of file diff --git a/MenuScalePatch/Main.cs b/MenuScalePatch/Main.cs index e8da0bd..812989b 100644 --- a/MenuScalePatch/Main.cs +++ b/MenuScalePatch/Main.cs @@ -5,100 +5,28 @@ using cohtml; using HarmonyLib; using MelonLoader; using UnityEngine; +using NAK.Melons.MenuScalePatch.Helpers; -namespace MenuScalePatch; +namespace NAK.Melons.MenuScalePatch; public class MenuScalePatch : MelonMod { - [HarmonyPatch] - private class HarmonyPatches + private static MelonPreferences_Category m_categoryMenuScalePatch; + private static MelonPreferences_Entry m_entryWorldAnchorVRQM; + public override void OnInitializeMelon() { - internal static bool adjustedMenuPosition = false; - internal static void SetMenuPosition(Transform menuTransform, float scale) + m_categoryMenuScalePatch = MelonPreferences.CreateCategory(nameof(MenuScalePatch)); + m_entryWorldAnchorVRQM = m_categoryMenuScalePatch.CreateEntry("World Anchor VR QM", false, description: "Should place QM in World Space while VR."); + + foreach (var setting in m_categoryMenuScalePatch.Entries) { - Transform rotationPivot = PlayerSetup.Instance._movementSystem.rotationPivot; - if (!MetaPort.Instance.isUsingVr) - { - menuTransform.eulerAngles = rotationPivot.eulerAngles; - } - menuTransform.position = rotationPivot.position + rotationPivot.forward * 1f * scale; - adjustedMenuPosition = true; - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(CVR_MenuManager), "SetScale")] - private static void SetQMScale(ref CohtmlView ___quickMenu, ref bool ___needsQuickmenuPositionUpdate, ref float ____scaleFactor, ref GameObject ____leftVrAnchor) - { - if (MetaPort.Instance.isUsingVr) - { - ___quickMenu.transform.position = ____leftVrAnchor.transform.position; - ___quickMenu.transform.rotation = ____leftVrAnchor.transform.rotation; - ___needsQuickmenuPositionUpdate = false; - return; - } - PlayerSetup.Instance.HandleDesktopCameraPosition(true); - SetMenuPosition(___quickMenu.transform, ____scaleFactor); - ___needsQuickmenuPositionUpdate = false; - } - - /** - ViewManager.SetScale runs once a second when it should only run when aspect ratio changes- CVR bug - assuming its caused by cast from int to float getting the screen size, something floating point bleh - attempting to ignore that call if there wasnt actually a change - **/ - - [HarmonyPrefix] - [HarmonyPatch(typeof(ViewManager), "SetScale")] - private static void CheckMMScale(float avatarHeight, ref float ___cachedAvatarHeight, out bool __state) - { - if (___cachedAvatarHeight == avatarHeight) - { - __state = false; - return; - } - __state = true; - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(ViewManager), "SetScale")] - private static void SetMMScale(ref ViewManager __instance, ref bool ___needsMenuPositionUpdate, ref float ___scaleFactor, bool __state) - { - if (!__state) return; - - PlayerSetup.Instance.HandleDesktopCameraPosition(true); - SetMenuPosition(__instance.transform, ___scaleFactor); - ___needsMenuPositionUpdate = false; - } - - /** - Following code resets the menu position on LateUpdate so you can use the menu while moving/falling. - It is Desktop only. QM inputs still don't work because they do their input checks in LateUpdate??? - **/ - - [HarmonyPrefix] - [HarmonyPatch(typeof(CVR_MenuManager), "LateUpdate")] - private static void DesktopQMFix(ref CohtmlView ___quickMenu, ref bool ___needsQuickmenuPositionUpdate, ref float ____scaleFactor, ref bool ____quickMenuOpen) - { - if (MetaPort.Instance.isUsingVr) return; - if (____quickMenuOpen && !adjustedMenuPosition) - { - SetMenuPosition(___quickMenu.transform, ____scaleFactor); - ___needsQuickmenuPositionUpdate = false; - } - adjustedMenuPosition = false; - } - - [HarmonyPrefix] - [HarmonyPatch(typeof(ViewManager), "LateUpdate")] - private static void DesktopMMFix(ref ViewManager __instance, ref bool ___needsMenuPositionUpdate, ref float ___scaleFactor, bool __state, ref bool ____gameMenuOpen) - { - if (MetaPort.Instance.isUsingVr) return; - if (____gameMenuOpen && !adjustedMenuPosition) - { - SetMenuPosition(__instance.transform, ___scaleFactor); - ___needsMenuPositionUpdate = false; - } - adjustedMenuPosition = false; + setting.OnEntryValueChangedUntyped.Subscribe(OnUpdateSettings); } } + + private void UpdateAllSettings() + { + MSP_MenuInfo.WorldAnchorQM = m_entryWorldAnchorVRQM.Value; + } + private void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); } \ No newline at end of file diff --git a/MenuScalePatch/MainMenuHelper.cs b/MenuScalePatch/MainMenuHelper.cs new file mode 100644 index 0000000..ba3f83d --- /dev/null +++ b/MenuScalePatch/MainMenuHelper.cs @@ -0,0 +1,159 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Core; +using ABI_RC.Systems.MovementSystem; +using cohtml; +using HarmonyLib; +using MelonLoader; +using UnityEngine; +using System.Reflection; + +namespace NAK.Melons.MenuScalePatch.Helpers; + +//TODO: Implement desktop ratio scaling back to MM + +/** + + This helper is assigned to the MainMenu object. + The DefaultExecutionOrder attribute saves me from needing + to use OnPreRender() callback... yay. + +**/ + +[DefaultExecutionOrder(999999)] +public class MainMenuHelper : MonoBehaviour +{ + public static MainMenuHelper Instance; + public Transform worldAnchor; + + static readonly FieldInfo ms_followAngleY = typeof(MovementSystem).GetField("_followAngleY", BindingFlags.NonPublic | BindingFlags.Instance); + private bool independentHeadTurn = false; + private bool returnIndependentHeadTurn = false; + private bool prevIndependentHeadTurn = false; + + void Start() + { + Instance = this; + CreateWorldAnchors(); + } + + void LateUpdate() + { + UpdateMenuPosition(); + } + + void OnDisable() + { + independentHeadTurn = false; + returnIndependentHeadTurn = false; + prevIndependentHeadTurn = false; + } + + public void ToggleDesktopInputMethod(bool flag) + { + PlayerSetup.Instance._movementSystem.disableCameraControl = flag; + CVRInputManager.Instance.inputEnabled = !flag; + RootLogic.Instance.ToggleMouse(flag); + CVR_MenuManager.Instance.desktopControllerRay.enabled = !flag; + Traverse.Create(CVR_MenuManager.Instance).Field("_desktopMouseMode").SetValue(flag); + } + + public void CreateWorldAnchors() + { + //VR specific anchor + GameObject vrAnchor = new GameObject("MSP_MMVR_Anchor"); + vrAnchor.transform.parent = PlayerSetup.Instance.vrCameraRig.transform; + vrAnchor.transform.localPosition = Vector3.zero; + this.worldAnchor = vrAnchor.transform; + } + + public void UpdateWorldAnchors() + { + if (this.worldAnchor == null || MSP_MenuInfo.CameraTransform == null) return; + + if (MetaPort.Instance.isUsingVr) + { + float zRotation = Mathf.Abs(MSP_MenuInfo.CameraTransform.localRotation.eulerAngles.z); + float minTilt = MetaPort.Instance.settings.GetSettingsFloat("GeneralMinimumMenuTilt", 0f); + if (zRotation <= minTilt || zRotation >= 360f - minTilt) + { + this.worldAnchor.rotation = Quaternion.LookRotation(MSP_MenuInfo.CameraTransform.forward, Vector3.up); + } + else + { + this.worldAnchor.eulerAngles = MSP_MenuInfo.CameraTransform.eulerAngles; + } + this.worldAnchor.position = MSP_MenuInfo.CameraTransform.position + MSP_MenuInfo.CameraTransform.forward * 2f * MSP_MenuInfo.ScaleFactor; + } + else + { + this.worldAnchor.eulerAngles = MSP_MenuInfo.CameraTransform.eulerAngles; + this.worldAnchor.position = MSP_MenuInfo.CameraTransform.position; + } + } + + public void UpdateMenuPosition() + { + if (MetaPort.Instance.isUsingVr) + { + HandleVRPosition(); + return; + } + + bool independentHeadTurnChanged = CVRInputManager.Instance.independentHeadTurn != prevIndependentHeadTurn; + if (independentHeadTurnChanged) + { + prevIndependentHeadTurn = CVRInputManager.Instance.independentHeadTurn; + //if pressing but not already enabled + if (prevIndependentHeadTurn) + { + if (!independentHeadTurn) + { + UpdateWorldAnchors(); + ToggleDesktopInputMethod(!prevIndependentHeadTurn); + independentHeadTurn = true; + } + returnIndependentHeadTurn = false; + } + else + { + returnIndependentHeadTurn = true; + } + } + + if (returnIndependentHeadTurn) + { + float angle = (float)ms_followAngleY.GetValue(MovementSystem.Instance); + if (angle == 0f) + { + independentHeadTurn = false; + returnIndependentHeadTurn = false; + ToggleDesktopInputMethod(!prevIndependentHeadTurn); + } + } + + HandleDesktopPosition(); + } + + //Desktop Main Menu + public void HandleDesktopPosition() + { + if (MSP_MenuInfo.CameraTransform == null || MSP_MenuInfo.DisableMMHelper) return; + + Transform activeAnchor = independentHeadTurn ? this.worldAnchor : MSP_MenuInfo.CameraTransform; + this.transform.localScale = new Vector3(1.6f * MSP_MenuInfo.ScaleFactor, 0.9f * MSP_MenuInfo.ScaleFactor, 1f); + this.transform.eulerAngles = activeAnchor.eulerAngles; + this.transform.position = activeAnchor.position + activeAnchor.forward * 1f * MSP_MenuInfo.ScaleFactor; + } + + //VR Main Menu + public void HandleVRPosition() + { + if (this.worldAnchor == null || MSP_MenuInfo.DisableMMHelper_VR) return; + this.transform.localScale = new Vector3(1.6f * MSP_MenuInfo.ScaleFactor * 1.8f, 0.9f * MSP_MenuInfo.ScaleFactor * 1.8f, 1f); + this.transform.position = this.worldAnchor.position; + this.transform.eulerAngles = this.worldAnchor.eulerAngles; + } +} + diff --git a/MenuScalePatch/Properties/AssemblyInfo.cs b/MenuScalePatch/Properties/AssemblyInfo.cs index a007473..34cef9b 100644 --- a/MenuScalePatch/Properties/AssemblyInfo.cs +++ b/MenuScalePatch/Properties/AssemblyInfo.cs @@ -11,7 +11,7 @@ using System.Reflection; [assembly: AssemblyProduct(nameof(MenuScalePatch))] [assembly: MelonInfo( - typeof(MenuScalePatch.MenuScalePatch), + typeof(NAK.Melons.MenuScalePatch.MenuScalePatch), nameof(MenuScalePatch), AssemblyInfoParams.Version, AssemblyInfoParams.Author, @@ -25,6 +25,6 @@ using System.Reflection; namespace MenuScalePatch.Properties; internal static class AssemblyInfoParams { - public const string Version = "3.0.0"; + public const string Version = "4.0.0"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/MenuScalePatch/QuickMenuHelper.cs b/MenuScalePatch/QuickMenuHelper.cs new file mode 100644 index 0000000..82e5791 --- /dev/null +++ b/MenuScalePatch/QuickMenuHelper.cs @@ -0,0 +1,148 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.Player; +using ABI_RC.Core.Savior; +using ABI_RC.Core; +using ABI_RC.Systems.MovementSystem; +using cohtml; +using HarmonyLib; +using MelonLoader; +using UnityEngine; +using System.Reflection; + +namespace NAK.Melons.MenuScalePatch.Helpers; + +/** + + This helper is assigned to the QuickMenu object. + The DefaultExecutionOrder attribute saves me from needing + to use OnPreRender() callback... yay. + +**/ + +[DefaultExecutionOrder(999999)] +public class QuickMenuHelper : MonoBehaviour +{ + public static QuickMenuHelper Instance; + public Transform worldAnchor; + public Transform handAnchor; + + static readonly FieldInfo ms_followAngleY = typeof(MovementSystem).GetField("_followAngleY", BindingFlags.NonPublic | BindingFlags.Instance); + private bool independentHeadTurn = false; + private bool returnIndependentHeadTurn = false; + private bool prevIndependentHeadTurn = false; + + void Start() + { + Instance = this; + CreateWorldAnchors(); + } + + void LateUpdate() + { + UpdateMenuPosition(); + } + + void OnDisable() + { + independentHeadTurn = false; + returnIndependentHeadTurn = false; + prevIndependentHeadTurn = false; + } + + public void ToggleDesktopInputMethod(bool flag) + { + PlayerSetup.Instance._movementSystem.disableCameraControl = flag; + CVRInputManager.Instance.inputEnabled = !flag; + RootLogic.Instance.ToggleMouse(flag); + CVR_MenuManager.Instance.desktopControllerRay.enabled = !flag; + Traverse.Create(CVR_MenuManager.Instance).Field("_desktopMouseMode").SetValue(flag); + } + + public void CreateWorldAnchors() + { + //VR specific anchor + GameObject vrAnchor = new GameObject("MSP_QMVR_Anchor"); + vrAnchor.transform.parent = PlayerSetup.Instance.vrCameraRig.transform; + vrAnchor.transform.localPosition = Vector3.zero; + this.worldAnchor = vrAnchor.transform; + } + + public void UpdateWorldAnchors() + { + if (this.worldAnchor == null || MSP_MenuInfo.CameraTransform == null) return; + + this.worldAnchor.eulerAngles = MSP_MenuInfo.CameraTransform.eulerAngles; + this.worldAnchor.position = MSP_MenuInfo.CameraTransform.position; + } + + public void UpdateMenuPosition() + { + if (MetaPort.Instance.isUsingVr) + { + HandleVRPosition(); + return; + } + + bool independentHeadTurnChanged = CVRInputManager.Instance.independentHeadTurn != prevIndependentHeadTurn; + if (independentHeadTurnChanged) + { + prevIndependentHeadTurn = CVRInputManager.Instance.independentHeadTurn; + //if pressing but not already enabled + if (prevIndependentHeadTurn) + { + if (!independentHeadTurn) + { + UpdateWorldAnchors(); + ToggleDesktopInputMethod(!prevIndependentHeadTurn); + independentHeadTurn = true; + } + returnIndependentHeadTurn = false; + } + else + { + returnIndependentHeadTurn = true; + } + } + + if (returnIndependentHeadTurn) + { + float angle = (float)ms_followAngleY.GetValue(MovementSystem.Instance); + if (angle == 0f) + { + independentHeadTurn = false; + returnIndependentHeadTurn = false; + ToggleDesktopInputMethod(!prevIndependentHeadTurn); + } + } + + HandleDesktopPosition(); + } + + //Desktop Quick Menu + public void HandleDesktopPosition() + { + if (MSP_MenuInfo.CameraTransform == null || MSP_MenuInfo.DisableQMHelper) return; + + Transform activeAnchor = independentHeadTurn ? this.worldAnchor : MSP_MenuInfo.CameraTransform; + this.transform.localScale = new Vector3(1f * MSP_MenuInfo.ScaleFactor, 1f * MSP_MenuInfo.ScaleFactor, 1f); + this.transform.eulerAngles = activeAnchor.eulerAngles; + this.transform.position = activeAnchor.position + activeAnchor.transform.forward * 1f * MSP_MenuInfo.ScaleFactor; + } + + //VR Quick Menu + public void HandleVRPosition() + { + if (this.handAnchor == null || MSP_MenuInfo.DisableQMHelper_VR) return; + + if (MSP_MenuInfo.WorldAnchorQM) + { + this.transform.localScale = new Vector3(1f * MSP_MenuInfo.ScaleFactor, 1f * MSP_MenuInfo.ScaleFactor, 1f); + this.transform.eulerAngles = this.worldAnchor.eulerAngles; + this.transform.position = this.worldAnchor.position + this.worldAnchor.transform.forward * 1f * MSP_MenuInfo.ScaleFactor; + return; + } + this.transform.localScale = new Vector3(1f * MSP_MenuInfo.ScaleFactor, 1f * MSP_MenuInfo.ScaleFactor, 1f); + this.transform.position = this.handAnchor.position; + this.transform.rotation = this.handAnchor.rotation; + } +} \ No newline at end of file