diff --git a/MenuScalePatch/HarmonyPatches.cs b/MenuScalePatch/HarmonyPatches.cs index 8f601d8..999c87d 100644 --- a/MenuScalePatch/HarmonyPatches.cs +++ b/MenuScalePatch/HarmonyPatches.cs @@ -3,6 +3,8 @@ using ABI_RC.Core.Player; using ABI_RC.Core.Savior; using HarmonyLib; using NAK.Melons.MenuScalePatch.Helpers; +using System.Reflection; +using System.Reflection.Emit; using UnityEngine; namespace NAK.Melons.MenuScalePatch.HarmonyPatches; @@ -20,43 +22,64 @@ namespace NAK.Melons.MenuScalePatch.HarmonyPatches; [HarmonyPatch] internal class HarmonyPatches { + //stuff needed on start + [HarmonyPostfix] + [HarmonyPatch(typeof(PlayerSetup), "Start")] + private static void Postfix_PlayerSetup_Start() + { + try + { + MSP_MenuInfo.CameraTransform = PlayerSetup.Instance.GetActiveCamera().transform; + MenuScalePatch.UpdateAllSettings(); + QuickMenuHelper.Instance.CreateWorldAnchors(); + MainMenuHelper.Instance.CreateWorldAnchors(); + } + catch (System.Exception e) + { + MenuScalePatch.Logger.Error(e); + } + } + [HarmonyPrefix] [HarmonyPatch(typeof(CVR_MenuManager), "SetScale")] - private static void Prefix_CVR_MenuManager_SetScale(float avatarHeight, ref float ____scaleFactor, out bool __runOriginal) + private static bool Prefix_CVR_MenuManager_SetScale(float avatarHeight, ref float ____scaleFactor) { ____scaleFactor = avatarHeight / 1.8f; if (MetaPort.Instance.isUsingVr) ____scaleFactor *= 0.5f; MSP_MenuInfo.ScaleFactor = ____scaleFactor; - __runOriginal = false; + if (!MSP_MenuInfo.PlayerAnchorMenus) + { + QuickMenuHelper.Instance.NeedsPositionUpdate = true; + MainMenuHelper.Instance.NeedsPositionUpdate = true; + } + return false; } [HarmonyPrefix] [HarmonyPatch(typeof(ViewManager), "SetScale")] - private static void Prefix_ViewManager_SetScale(out bool __runOriginal) + private static bool Prefix_ViewManager_SetScale() { - //bitch - __runOriginal = false; + return 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) + private static bool Prefix_CVR_MenuManager_UpdateMenuPosition() { - //fuck u - __runOriginal = false; + return false; } [HarmonyPrefix] [HarmonyPatch(typeof(ViewManager), "UpdateMenuPosition")] - private static void Prefix_ViewManager_UpdateMenuPosition(ref float ___cachedScreenAspectRatio, out bool __runOriginal) + private static bool Prefix_ViewManager_UpdateMenuPosition(ref float ___cachedScreenAspectRatio) { //this is called once a second, so ill fix their dumb aspect ratio shit float ratio = (float)Screen.width / (float)Screen.height; float clamp = Mathf.Clamp(ratio, 0f, 1.8f); MSP_MenuInfo.AspectRatio = 1.7777779f / clamp; - __runOriginal = false; + return false; } //Set QM stuff @@ -64,8 +87,16 @@ internal class HarmonyPatches [HarmonyPatch(typeof(CVR_MenuManager), "Start")] private static void Postfix_CVR_MenuManager_Start(ref CVR_MenuManager __instance, ref GameObject ____leftVrAnchor) { - QuickMenuHelper helper = __instance.quickMenu.gameObject.AddComponent(); - helper.handAnchor = ____leftVrAnchor.transform; + try + { + QuickMenuHelper helper = __instance.quickMenu.gameObject.AddComponent(); + helper.handAnchor = ____leftVrAnchor.transform; + helper.enabled = false; + } + catch (System.Exception e) + { + MenuScalePatch.Logger.Error(e); + } } //Set MM stuff @@ -73,35 +104,71 @@ internal class HarmonyPatches [HarmonyPatch(typeof(ViewManager), "Start")] private static void Postfix_ViewManager_Start(ref ViewManager __instance) { - __instance.gameObject.AddComponent(); + try + { + MainMenuHelper helper = __instance.gameObject.AddComponent(); + helper.enabled = false; + } + catch (System.Exception e) + { + MenuScalePatch.Logger.Error(e); + } } //hook quickmenu open/close [HarmonyPrefix] [HarmonyPatch(typeof(CVR_MenuManager), "ToggleQuickMenu", new Type[] { typeof(bool) })] - private static void Prefix_CVR_MenuManager_ToggleQuickMenu(bool show, ref bool ____quickMenuOpen) + private static bool Prefix_CVR_MenuManager_ToggleQuickMenu(bool show, ref CVR_MenuManager __instance, ref bool ____quickMenuOpen) { - if (QuickMenuHelper.Instance == null) return; + if (QuickMenuHelper.Instance == null) return true; if (show != ____quickMenuOpen) { - QuickMenuHelper.Instance.UpdateWorldAnchors(); + ____quickMenuOpen = show; + __instance.quickMenu.enabled = show; + __instance.quickMenuAnimator.SetBool("Open", show); + QuickMenuHelper.Instance.enabled = show; + QuickMenuHelper.Instance.UpdateWorldAnchors(show); + //shouldnt run if switching menus on desktop + if (!MetaPort.Instance.isUsingVr) + { + if (!show && MainMenuHelper.Instance.enabled) + { + return false; + } + ViewManager.Instance.UiStateToggle(false); + } MSP_MenuInfo.ToggleDesktopInputMethod(show); + CVRPlayerManager.Instance.ReloadAllNameplates(); } - QuickMenuHelper.Instance.enabled = show; + return false; } //hook menu open/close [HarmonyPrefix] [HarmonyPatch(typeof(ViewManager), "UiStateToggle", new Type[] { typeof(bool) })] - private static void Postfix_ViewManager_UiStateToggle(bool show, ref bool ____gameMenuOpen) + private static bool Postfix_ViewManager_UiStateToggle(bool show, ref ViewManager __instance, ref bool ____gameMenuOpen) { - if (MainMenuHelper.Instance == null) return; + if (MainMenuHelper.Instance == null) return true; if (show != ____gameMenuOpen) { - MainMenuHelper.Instance.UpdateWorldAnchors(); + ____gameMenuOpen = show; + __instance.gameMenuView.enabled = show; + __instance.uiMenuAnimator.SetBool("Open", show); + MainMenuHelper.Instance.enabled = show; + MainMenuHelper.Instance.UpdateWorldAnchors(show); + //shouldnt run if switching menus on desktop + if (!MetaPort.Instance.isUsingVr) + { + if (!show && QuickMenuHelper.Instance.enabled) + { + return false; + } + CVR_MenuManager.Instance.ToggleQuickMenu(false); + } MSP_MenuInfo.ToggleDesktopInputMethod(show); + CVRPlayerManager.Instance.ReloadAllNameplates(); } - MainMenuHelper.Instance.enabled = show; + return false; } //add independent head movement to important input @@ -117,6 +184,57 @@ internal class HarmonyPatches [HarmonyPatch(typeof(PlayerSetup), "CalibrateAvatar")] private static void Postfix_PlayerSetup_CalibrateAvatar() { - MSP_MenuInfo.CameraTransform = PlayerSetup.Instance.GetActiveCamera().transform; + try + { + MSP_MenuInfo.CameraTransform = PlayerSetup.Instance.GetActiveCamera().transform; + } + catch (System.Exception e) + { + MenuScalePatch.Logger.Error(e); + } + } + + //[HarmonyTranspiler] + //[HarmonyPatch(typeof(ControllerRay), "LateUpdate")] + private static IEnumerable Transpiler_ControllerRay_UpdateInput( + IEnumerable instructions, ILGenerator il) + { + + // Stop calling move mouse events on the menus, the ones that instantiate and the send the event (easy) + // Makes this: "component.View.MouseEvent(mouseEventData1);" go POOF + instructions = new CodeMatcher(instructions) + .MatchForward(false, + new CodeMatch(OpCodes.Ldloc_S), + new CodeMatch(i => i.opcode == OpCodes.Callvirt && i.operand is MethodInfo { Name: "get_View" }), + new CodeMatch(OpCodes.Ldloc_S), + new CodeMatch(i => i.opcode == OpCodes.Callvirt && i.operand is MethodInfo { Name: "MouseEvent" })) + .Repeat(matcher => matcher + .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Nop)) + .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Nop)) + .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Nop)) + .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Nop)) + ) + .InstructionEnumeration(); + + // Look for the if flag2 and replace flag 2 with false, for the ones that create the event and send inline (hard ;_;) + // Makes this: "if (flag2 && this._mouseDownOnMenu != ControllerRay.Menu.None || ..." into: + // this: "if (false && this._mouseDownOnMenu != ControllerRay.Menu.None || ..." + instructions = new CodeMatcher(instructions) + .MatchForward(false, + new CodeMatch(OpCodes.Ldloc_2), + new CodeMatch(OpCodes.Brfalse), + new CodeMatch(OpCodes.Ldarg_0), + new CodeMatch(i => + i.opcode == OpCodes.Ldfld && i.operand is FieldInfo { Name: "_mouseDownOnMenu" }), + new CodeMatch(OpCodes.Brtrue), + new CodeMatch(OpCodes.Ldarg_0), + new CodeMatch(i => + i.opcode == OpCodes.Ldfld && i.operand is FieldInfo { Name: "_mouseDownOnMenu" }), + new CodeMatch(OpCodes.Ldc_I4_1), + new CodeMatch(OpCodes.Bne_Un)) + .SetOpcodeAndAdvance(OpCodes.Ldc_I4_0) // replace flag2 with false + .InstructionEnumeration(); + + return instructions; } } \ No newline at end of file diff --git a/MenuScalePatch/Helpers/MainMenuHelper.cs b/MenuScalePatch/Helpers/MainMenuHelper.cs index 2df6d1b..6930cf6 100644 --- a/MenuScalePatch/Helpers/MainMenuHelper.cs +++ b/MenuScalePatch/Helpers/MainMenuHelper.cs @@ -2,6 +2,7 @@ using ABI_RC.Core.Savior; using UnityEngine; + namespace NAK.Melons.MenuScalePatch.Helpers; //TODO: Implement desktop ratio scaling back to MM @@ -14,22 +15,25 @@ namespace NAK.Melons.MenuScalePatch.Helpers; **/ -[DefaultExecutionOrder(999999)] +[DefaultExecutionOrder(20000)] public class MainMenuHelper : MonoBehaviour { public static MainMenuHelper Instance; public Transform worldAnchor; + public bool NeedsPositionUpdate; - void Start() + void Awake() { Instance = this; - CreateWorldAnchors(); } void LateUpdate() { - MSP_MenuInfo.HandleIndependentLookInput(); - UpdateMenuPosition(); + if (MSP_MenuInfo.UseIndependentHeadTurn) + MSP_MenuInfo.HandleIndependentLookInput(); + if (MSP_MenuInfo.PlayerAnchorMenus) + UpdateMenuPosition(); + if (NeedsPositionUpdate) UpdateMenuPosition(); } public void CreateWorldAnchors() @@ -41,7 +45,7 @@ public class MainMenuHelper : MonoBehaviour worldAnchor = vrAnchor.transform; } - public void UpdateWorldAnchors() + public void UpdateWorldAnchors(bool updateMenuPos = false) { if (worldAnchor == null || MSP_MenuInfo.CameraTransform == null) return; @@ -64,10 +68,12 @@ public class MainMenuHelper : MonoBehaviour worldAnchor.eulerAngles = MSP_MenuInfo.CameraTransform.eulerAngles; worldAnchor.position = MSP_MenuInfo.CameraTransform.position; } + if (updateMenuPos) UpdateMenuPosition(); } public void UpdateMenuPosition() { + NeedsPositionUpdate = false; if (MetaPort.Instance.isUsingVr) { HandleVRPosition(); @@ -94,4 +100,4 @@ public class MainMenuHelper : MonoBehaviour transform.position = worldAnchor.position; transform.eulerAngles = worldAnchor.eulerAngles; } -} \ No newline at end of file +} diff --git a/MenuScalePatch/Helpers/QuickMenuHelper.cs b/MenuScalePatch/Helpers/QuickMenuHelper.cs index 834251f..1c713b9 100644 --- a/MenuScalePatch/Helpers/QuickMenuHelper.cs +++ b/MenuScalePatch/Helpers/QuickMenuHelper.cs @@ -12,23 +12,26 @@ namespace NAK.Melons.MenuScalePatch.Helpers; **/ -[DefaultExecutionOrder(999999)] +[DefaultExecutionOrder(20000)] public class QuickMenuHelper : MonoBehaviour { public static QuickMenuHelper Instance; public Transform worldAnchor; public Transform handAnchor; + public bool NeedsPositionUpdate; - void Start() + void Awake() { Instance = this; - CreateWorldAnchors(); } void LateUpdate() { - MSP_MenuInfo.HandleIndependentLookInput(); - UpdateMenuPosition(); + if (MSP_MenuInfo.UseIndependentHeadTurn) + MSP_MenuInfo.HandleIndependentLookInput(); + if (MSP_MenuInfo.PlayerAnchorMenus || MetaPort.Instance.isUsingVr) + UpdateMenuPosition(); + if (NeedsPositionUpdate) UpdateMenuPosition(); } public void CreateWorldAnchors() @@ -40,15 +43,17 @@ public class QuickMenuHelper : MonoBehaviour worldAnchor = vrAnchor.transform; } - public void UpdateWorldAnchors() + public void UpdateWorldAnchors(bool updateMenuPos = false) { if (worldAnchor == null || MSP_MenuInfo.CameraTransform == null) return; worldAnchor.eulerAngles = MSP_MenuInfo.CameraTransform.eulerAngles; worldAnchor.position = MSP_MenuInfo.CameraTransform.position; + if (updateMenuPos) UpdateMenuPosition(); } public void UpdateMenuPosition() { + NeedsPositionUpdate = false; if (MetaPort.Instance.isUsingVr) { HandleVRPosition(); diff --git a/MenuScalePatch/MSP_Menus.cs b/MenuScalePatch/MSP_Menus.cs index 290781c..facd5e0 100644 --- a/MenuScalePatch/MSP_Menus.cs +++ b/MenuScalePatch/MSP_Menus.cs @@ -12,33 +12,38 @@ namespace NAK.Melons.MenuScalePatch.Helpers; public class MSP_MenuInfo { //Shared Info - public static float ScaleFactor = 1f; - public static float AspectRatio = 1f; - public static Transform CameraTransform; + internal static float ScaleFactor = 1f; + internal static float AspectRatio = 1f; + internal static Transform CameraTransform; //Settings...? - public static bool WorldAnchorQM; + internal static bool WorldAnchorQM = false; + internal static bool UseIndependentHeadTurn = true; + internal static bool PlayerAnchorMenus = true; //if other mods need to disable? - public static bool DisableQMHelper; - public static bool DisableQMHelper_VR; - public static bool DisableMMHelper; - public static bool DisableMMHelper_VR; + internal static bool DisableQMHelper; + internal static bool DisableQMHelper_VR; + internal static bool DisableMMHelper; + internal static bool DisableMMHelper_VR; - public static void ToggleDesktopInputMethod(bool flag) + //reflection (traverse sucks ass) + private static readonly FieldInfo _desktopMouseMode = typeof(CVR_MenuManager).GetField("_desktopMouseMode", BindingFlags.NonPublic | BindingFlags.Instance); + + internal static void ToggleDesktopInputMethod(bool flag) { if (MetaPort.Instance.isUsingVr) return; 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); + _desktopMouseMode.SetValue(CVR_MenuManager.Instance, flag); } - static readonly FieldInfo ms_followAngleY = typeof(MovementSystem).GetField("_followAngleY", BindingFlags.NonPublic | BindingFlags.Instance); - public static bool independentHeadTurn = false; + internal static readonly FieldInfo ms_followAngleY = typeof(MovementSystem).GetField("_followAngleY", BindingFlags.NonPublic | BindingFlags.Instance); + internal static bool independentHeadTurn = false; - public static void HandleIndependentLookInput() + internal static void HandleIndependentLookInput() { //angle of independent look axis bool isPressed = CVRInputManager.Instance.independentHeadTurn || CVRInputManager.Instance.independentHeadToggle; diff --git a/MenuScalePatch/Main.cs b/MenuScalePatch/Main.cs index 72a78d2..72eae7d 100644 --- a/MenuScalePatch/Main.cs +++ b/MenuScalePatch/Main.cs @@ -5,22 +5,31 @@ namespace NAK.Melons.MenuScalePatch; public class MenuScalePatch : MelonMod { - private static MelonPreferences_Category m_categoryMenuScalePatch; - private static MelonPreferences_Entry m_entryWorldAnchorVRQM; + internal static MelonLogger.Instance Logger; + internal static MelonPreferences_Category m_categoryMenuScalePatch; + internal static MelonPreferences_Entry + m_entryWorldAnchorVRQM, + m_entryUseIndependentHeadTurn, + m_entryPlayerAnchorMenus; public override void OnInitializeMelon() { 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."); - + //m_entryWorldAnchorVRQM = m_categoryMenuScalePatch.CreateEntry("World Anchor VR QM", false, description: "Should place QM in World Space while VR."); + m_entryUseIndependentHeadTurn = m_categoryMenuScalePatch.CreateEntry("Use Independent Head Turn", true, description: "Should you be able to use independent head turn in a menu while in Desktop?"); + m_entryPlayerAnchorMenus = m_categoryMenuScalePatch.CreateEntry("Player Anchor Menus", true, description: "Should the menus be anchored to & constantly follow the player?"); + foreach (var setting in m_categoryMenuScalePatch.Entries) { setting.OnEntryValueChangedUntyped.Subscribe(OnUpdateSettings); } - } - private void UpdateAllSettings() - { - MSP_MenuInfo.WorldAnchorQM = m_entryWorldAnchorVRQM.Value; + Logger = LoggerInstance; } - private void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); + internal static void UpdateAllSettings() + { + //MSP_MenuInfo.WorldAnchorQM = m_entryWorldAnchorVRQM.Value; + MSP_MenuInfo.UseIndependentHeadTurn = m_entryUseIndependentHeadTurn.Value; + MSP_MenuInfo.PlayerAnchorMenus = m_entryPlayerAnchorMenus.Value; + } + private static void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); } \ No newline at end of file diff --git a/MenuScalePatch/MenuScalePatch.csproj b/MenuScalePatch/MenuScalePatch.csproj index 655b3bd..7293ed3 100644 --- a/MenuScalePatch/MenuScalePatch.csproj +++ b/MenuScalePatch/MenuScalePatch.csproj @@ -21,6 +21,9 @@ C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\MelonLoader.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.CoreModule.dll diff --git a/MenuScalePatch/Properties/AssemblyInfo.cs b/MenuScalePatch/Properties/AssemblyInfo.cs index 64804cf..34cef9b 100644 --- a/MenuScalePatch/Properties/AssemblyInfo.cs +++ b/MenuScalePatch/Properties/AssemblyInfo.cs @@ -25,6 +25,6 @@ using System.Reflection; namespace MenuScalePatch.Properties; internal static class AssemblyInfoParams { - public const string Version = "4.1.1"; + public const string Version = "4.0.0"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/MenuScalePatch/format.json b/MenuScalePatch/format.json index 02f7943..d91654b 100644 --- a/MenuScalePatch/format.json +++ b/MenuScalePatch/format.json @@ -1,12 +1,12 @@ { "_id": 95, "name": "MenuScalePatch", - "modversion": "3.0.0", + "modversion": "4.0.0", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", "author": "NotAKidoS", - "description": "Corrects MM and QM position when avatar is being scaled.\n\nDesktop menus will now always follow camera while open.", + "description": "Corrects MM and QM position when avatar is being scaled.\n\nOptional setting to enable Independent Head Turn while in menus.\nOptional setting to force menus to always follow player.", "searchtags": [ "menu", "scale", @@ -16,8 +16,8 @@ "requirements": [ "None" ], - "downloadlink": "https://github.com/NotAKidOnSteam/MenuScalePatch/releases/download/v3.0.0/MenuScalePatch.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/MenuScalePatch/releases/download/v4.0.0/MenuScalePatch.dll", "sourcelink": "https://github.com/NotAKidOnSteam/MenuScalePatch/", - "changelog": "Removed collision scaling feature as it is now native.\nAdjusted QM scaling for VR.\nAdded menu correction for Desktop so you can use menus while moving.\nImmediate viewpoint correction for Desktop during scaling.", + "changelog": "- Added option for menus to be attached to you in Desktop and VR.\n- Added option to use independent head movement while in a menu.", "embedcolor": "804221" } \ No newline at end of file