diff --git a/FuckMetrics/FuckMetrics.cs b/FuckMetrics/FuckMetrics.cs new file mode 100644 index 0000000..a37b17c --- /dev/null +++ b/FuckMetrics/FuckMetrics.cs @@ -0,0 +1,92 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.IO; +using cohtml; +using HarmonyLib; +using UnityEngine; + +namespace NAK.Melons.FuckMetrics; + +public static class FuckMetrics +{ + public enum SettingState + { + Always, + MenuOnly, + Disabled + } + + public static void ToggleMetrics(bool enable) + { + var job = SchedulerSystem.Instance.activeJobs.FirstOrDefault(pair => pair.Job.Method.Name == "UpdateMetrics").Job; + if (enable && job == null) + { + SchedulerSystem.AddJob(new SchedulerSystem.Job(ViewManager.Instance.UpdateMetrics), 0f, FuckMetricsMod.EntryMetricsUpdateRate.Value, -1); + } + else if (!enable && job != null) + { + SchedulerSystem.RemoveJob(job); + } + } + + public static void ToggleCoreUpdates(bool enable) + { + var job = SchedulerSystem.Instance.activeJobs.FirstOrDefault(pair => pair.Job.Method.Name == "SendCoreUpdate").Job; + if (enable && job == null) + { + SchedulerSystem.AddJob(new SchedulerSystem.Job(CVR_MenuManager.Instance.SendCoreUpdate), 0f, FuckMetricsMod.EntryCoreUpdateRate.Value, -1); + } + else if (!enable && job != null) + { + SchedulerSystem.RemoveJob(job); + } + } + + public static void ApplyMetricsSettings(bool show) + { + var disableMetrics = FuckMetricsMod.EntryDisableMetrics.Value; + if (disableMetrics == FuckMetrics.SettingState.Always) return; + + if (disableMetrics == FuckMetrics.SettingState.MenuOnly) + { + FuckMetrics.ToggleMetrics(show); + } + else if (disableMetrics == FuckMetrics.SettingState.Disabled && show) + { + ViewManager.Instance.UpdateMetrics(); + } + } + + public static void ApplyCoreUpdatesSettings(bool show) + { + var disableCoreUpdates = FuckMetricsMod.EntryDisableCoreUpdates.Value; + if (disableCoreUpdates == FuckMetrics.SettingState.Always) return; + + if (disableCoreUpdates == FuckMetrics.SettingState.MenuOnly) + { + FuckMetrics.ToggleCoreUpdates(show); + } + else if (disableCoreUpdates == FuckMetrics.SettingState.Disabled && show) + { + CVR_MenuManager.Instance.SendCoreUpdate(); + } + } + + public static void CohtmlAdvanceView(CohtmlView cohtmlView, Traverse menuOpenTraverse) + { + if (!FuckMetricsMod.EntryDisableCohtmlViewOnIdle.Value) return; + + if (cohtmlView != null && !menuOpenTraverse.GetValue()) + { + cohtmlView.enabled = false; + + try + { + cohtmlView.View.Advance(cohtmlView.m_UISystem?.Id ?? 0, (double)Time.unscaledTime * 1000.0); + } + catch (Exception e) + { + FuckMetricsMod.Logger.Error($"An exception was thrown while calling CohtmlView.Advance(). Error message: {e.Message}"); + } + } + } +} diff --git a/FuckMetrics/FuckMetrics.csproj b/FuckMetrics/FuckMetrics.csproj new file mode 100644 index 0000000..a930aa0 --- /dev/null +++ b/FuckMetrics/FuckMetrics.csproj @@ -0,0 +1,44 @@ + + + + + net472 + enable + latest + false + True + + + + + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\0Harmony.dll + + + ManagedLibs\Assembly-CSharp.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\cohtml.Net.dll + + + ManagedLibs\Cohtml.Runtime.dll + + + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\MelonLoader\MelonLoader.dll + + + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll + + + C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.InputLegacyModule.dll + + + + + + + + + diff --git a/FuckMetrics/FuckMetrics.sln b/FuckMetrics/FuckMetrics.sln new file mode 100644 index 0000000..b6c2e37 --- /dev/null +++ b/FuckMetrics/FuckMetrics.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32630.192 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FuckMetrics", "FuckMetrics.csproj", "{D2625DDC-48EA-4390-8B4C-69D1E4E9C5E5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D2625DDC-48EA-4390-8B4C-69D1E4E9C5E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2625DDC-48EA-4390-8B4C-69D1E4E9C5E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D2625DDC-48EA-4390-8B4C-69D1E4E9C5E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D2625DDC-48EA-4390-8B4C-69D1E4E9C5E5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {CE55D93A-682A-47F4-A971-65132B854210} + EndGlobalSection +EndGlobal diff --git a/FuckMetrics/HarmonyPatches.cs b/FuckMetrics/HarmonyPatches.cs new file mode 100644 index 0000000..476ee5b --- /dev/null +++ b/FuckMetrics/HarmonyPatches.cs @@ -0,0 +1,64 @@ +using ABI_RC.Core.InteractionSystem; +using ABI_RC.Core.IO; +using cohtml; +using HarmonyLib; + +namespace NAK.Melons.FuckMetrics.HarmonyPatches; + +public static class CVR_MenuManagerPatches +{ + [HarmonyPostfix] + [HarmonyPatch(typeof(CVR_MenuManager), "ToggleQuickMenu", new Type[] { typeof(bool) })] + private static void Postfix_CVR_MenuManager_ToggleQuickMenu(bool show) + { + FuckMetrics.ApplyMetricsSettings(show); + FuckMetrics.ApplyCoreUpdatesSettings(show); + } +} + +public static class ViewManagerPatches +{ + [HarmonyPostfix] + [HarmonyPatch(typeof(ViewManager), "UiStateToggle", new Type[] { typeof(bool) })] + private static void Postfix_ViewManager_UiStateToggle(bool show) + { + FuckMetrics.ApplyMetricsSettings(show); + FuckMetrics.ApplyCoreUpdatesSettings(show); + } +} + +public static class CohtmlViewPatches +{ + private static CohtmlView _quickMenuView; + private static CohtmlView _gameMenuView; + private static Traverse _quickMenuOpenTraverse; + private static Traverse _gameMenuOpenTraverse; + + [HarmonyPostfix] + [HarmonyPatch(typeof(CVR_MenuManager), "Start")] + private static void Postfix_CVRMenuManager_Start(ref CVR_MenuManager __instance, ref CohtmlView ___quickMenu) + { + _quickMenuView = ___quickMenu; + _quickMenuOpenTraverse = Traverse.Create(__instance).Field("_quickMenuOpen"); + SchedulerSystem.AddJob(() => FuckMetrics.CohtmlAdvanceView(_quickMenuView, _quickMenuOpenTraverse), 15f, 6f, -1); + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(ViewManager), "Start")] + private static void Postfix_ViewManager_Start(ref ViewManager __instance, ref CohtmlView ___gameMenuView) + { + _gameMenuView = ___gameMenuView; + _gameMenuOpenTraverse = Traverse.Create(__instance).Field("_gameMenuOpen"); + SchedulerSystem.AddJob(() => FuckMetrics.CohtmlAdvanceView(_gameMenuView, _gameMenuOpenTraverse), 12f, 6f, -1); + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(ViewManager), "OnMicrophoneStatusSwitched")] + private static void Postfix_ViewManager_OnMicrophoneStatusSwitched() + { + if (_quickMenuOpenTraverse.GetValue()) + { + CVR_MenuManager.Instance.SendCoreUpdate(); + } + } +} diff --git a/FuckMetrics/Main.cs b/FuckMetrics/Main.cs new file mode 100644 index 0000000..f01bcdc --- /dev/null +++ b/FuckMetrics/Main.cs @@ -0,0 +1,98 @@ +using ABI_RC.Core.Player; +using MelonLoader; +using System.Collections; + +namespace NAK.Melons.FuckMetrics; + +public class FuckMetricsMod : MelonMod +{ + public static MelonLogger.Instance Logger; + public const string SettingsCategory = "FuckMetrics"; + public static readonly MelonPreferences_Category CategoryFuckMetrics = MelonPreferences.CreateCategory(SettingsCategory); + + public static readonly MelonPreferences_Entry EntryDisableCohtmlViewOnIdle = + CategoryFuckMetrics.CreateEntry("Disable CohtmlView On Idle", false, description: "Disables CohtmlView on the menus when idle. Takes up to 6 seconds after menu exit. This can give a huge performance boost."); + + public static readonly MelonPreferences_Entry EntryDisableMetrics = + CategoryFuckMetrics.CreateEntry("Menu Metrics", FuckMetrics.SettingState.MenuOnly, description: "Disables menu metrics (FPS & Ping). Updates once on menu open if disabled."); + + public static readonly MelonPreferences_Entry EntryDisableCoreUpdates = + CategoryFuckMetrics.CreateEntry("Menu Core Updates", FuckMetrics.SettingState.MenuOnly, description: "Disables menu core updates (Gamerule Icons & Debug Status). Updates once on menu open if disabled."); + + public static readonly MelonPreferences_Entry EntryMetricsUpdateRate = + CategoryFuckMetrics.CreateEntry("Metrics Update Rate", 1f, description: "Sets the update rate for the menu metrics. Default is 0.5f. Recommended to be 1f or higher."); + + public static readonly MelonPreferences_Entry EntryCoreUpdateRate = + CategoryFuckMetrics.CreateEntry("Core Update Rate", 2f, description: "Sets the update rate for the menu core updates. Default is 0.1f. Recommended to be 2f or higher."); + + public override void OnInitializeMelon() + { + Logger = LoggerInstance; + + EntryDisableMetrics.OnEntryValueChangedUntyped.Subscribe(OnDisableMetrics); + EntryDisableCoreUpdates.OnEntryValueChangedUntyped.Subscribe(OnDisableCoreUpdates); + EntryMetricsUpdateRate.OnEntryValueChangedUntyped.Subscribe(OnChangeMetricsUpdateRate); + EntryCoreUpdateRate.OnEntryValueChangedUntyped.Subscribe(OnChangeCoreUpdateRate); + + ApplyPatches(typeof(HarmonyPatches.CVR_MenuManagerPatches)); + ApplyPatches(typeof(HarmonyPatches.ViewManagerPatches)); + ApplyPatches(typeof(HarmonyPatches.CohtmlViewPatches)); + MelonCoroutines.Start(WaitForLocalPlayer()); + } + + private IEnumerator WaitForLocalPlayer() + { + while (PlayerSetup.Instance == null) + yield return null; + InitializeSettings(); + } + + private void InitializeSettings() + { + FuckMetrics.ToggleMetrics(false); + FuckMetrics.ToggleCoreUpdates(false); + FuckMetrics.ToggleMetrics(EntryDisableMetrics.Value == FuckMetrics.SettingState.Always); + FuckMetrics.ToggleCoreUpdates(EntryDisableCoreUpdates.Value == FuckMetrics.SettingState.Always); + } + + private void OnDisableMetrics(object arg1, object arg2) + { + FuckMetrics.ToggleMetrics(EntryDisableMetrics.Value != FuckMetrics.SettingState.Disabled); + } + + private void OnDisableCoreUpdates(object arg1, object arg2) + { + FuckMetrics.ToggleCoreUpdates(EntryDisableCoreUpdates.Value != FuckMetrics.SettingState.Disabled); + } + + private void OnChangeMetricsUpdateRate(object arg1, object arg2) + { + if (EntryDisableMetrics.Value != FuckMetrics.SettingState.Disabled) + { + FuckMetrics.ToggleMetrics(false); + FuckMetrics.ToggleMetrics(true); + } + } + + private void OnChangeCoreUpdateRate(object arg1, object arg2) + { + if (EntryDisableCoreUpdates.Value != FuckMetrics.SettingState.Disabled) + { + FuckMetrics.ToggleCoreUpdates(false); + FuckMetrics.ToggleCoreUpdates(true); + } + } + + private void ApplyPatches(Type type) + { + 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/FuckMetrics/ManagedLibs/.keep b/FuckMetrics/ManagedLibs/.keep new file mode 100644 index 0000000..e69de29 diff --git a/FuckMetrics/Properties/AssemblyInfo.cs b/FuckMetrics/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..241d435 --- /dev/null +++ b/FuckMetrics/Properties/AssemblyInfo.cs @@ -0,0 +1,31 @@ +using MelonLoader; +using NAK.Melons.FuckMetrics.Properties; +using System.Reflection; + + +[assembly: AssemblyVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)] +[assembly: AssemblyTitle(nameof(NAK.Melons.FuckMetrics))] +[assembly: AssemblyCompany(AssemblyInfoParams.Author)] +[assembly: AssemblyProduct(nameof(NAK.Melons.FuckMetrics))] + +[assembly: MelonInfo( + typeof(NAK.Melons.FuckMetrics.FuckMetricsMod), + nameof(NAK.Melons.FuckMetrics), + AssemblyInfoParams.Version, + AssemblyInfoParams.Author, + downloadLink: "https://github.com/NotAKidOnSteam/FuckMetrics" +)] + +[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")] +[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] +[assembly: HarmonyDontPatchAll] + +namespace NAK.Melons.FuckMetrics.Properties; +internal static class AssemblyInfoParams +{ + public const string Version = "1.0.4"; + public const string Author = "NotAKidoS"; +} \ No newline at end of file diff --git a/FuckMetrics/format.json b/FuckMetrics/format.json new file mode 100644 index 0000000..e3d18e4 --- /dev/null +++ b/FuckMetrics/format.json @@ -0,0 +1,24 @@ +{ + "_id": 135, + "name": "FuckMetrics", + "modversion": "1.0.4", + "gameversion": "2022r170", + "loaderversion": "0.5.7", + "modtype": "Mod", + "author": "NotAKidoS", + "description": "This mod limits UpdateMetrics & SendCoreUpdate while the menus are closed. This helps to alleviate hitching and performance issues, particularly with FPS drops while unmuted in online instances and VRIK tapping in place.\n\nPlease view the Github README for more info.", + "searchtags": [ + "cohtml", + "menus", + "quick", + "fps", + "performance" + ], + "requirements": [ + "None" + ], + "downloadlink": "https://github.com/NotAKidOnSteam/FuckMetrics/releases/download/v1.0.4/FuckMetrics.dll", + "sourcelink": "https://github.com/NotAKidOnSteam/FuckMetrics/", + "changelog": "- Initial Release.\n- Renamed to FuckMetrics.\n- Add Update Rate settings.\n- Add back CohtmlView disabling as option.\n- Update CoreUpdate on mic toggle if QM is open.\n- Fix Cohtml disabling not using menu instance.", + "embedcolor": "#8ed6fb" +} \ No newline at end of file diff --git a/README.md b/README.md index 618b6f6..1d3c32e 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,40 @@ https://user-images.githubusercontent.com/37721153/221870123-fbe4f5e8-8d6e-4a43- https://feedback.abinteractive.net/p/desktop-feet-ik-for-avatars https://feedback.abinteractive.net/p/pivot-desktop-camera-with-head +# FuckMetrics + +This mod limits UpdateMetrics & SendCoreUpdate while the menus are closed. This helps to alleviate hitching and performance issues, particularly with FPS drops while unmuted in online instances and VRIK tapping in place. + +## Settings + +* Disable CohtmlView On Idle + - Disables CohtmlView on the menus when idle. Takes up to 6 seconds after menu exit. This can give a huge performance boost, but is disabled by default as Cohtml can be unpredictable. +* Menu Metrics + - Menu metrics settings (FPS & Ping). Always, Menu Only, or Disabled. Updates once on menu open if disabled. +* Menu Core Updates + - Menu core update settings (Gamerule icons & download debug status). Always, Menu Only, or Disabled. Updates once on menu open if disabled. +* Metrics Update Rate + - Sets the update rate for the menu metrics. CVR default is 0.5f. Recommended to be 1f or higher. +* Core Update Rate + - Sets the update rate for the menu core updates. CVR default is 0.1f. Recommended to be 2f or higher as it is intensive. + +In general, keeping Menu Metrics & Menu Core Updates to Menu Only with a high Update Rate (in seconds), should be enough for smooth gameplay. Only turn on Disable CohtmlView On Idle if you really wanna squeeze performance, as Cohtml can sometimes freak out when disabled. + +## Examples + +The following clips demonstrate the difference in performance with and without the FuckMetrics mod. While not a scientifically rigorous comparison, it is clear that there is a significant performance hit when unmuted, causing Dynamic Bones to jitter, in the clip without the mod: + +https://user-images.githubusercontent.com/37721153/225494880-7e06195c-6f0d-4a21-aaa8-5f9f4ba5e9dd.mp4 + +However, with the FuckMetrics mod enabled, the performance hit when unmuted is almost negligible, as shown in the clip below: + +https://user-images.githubusercontent.com/37721153/225495141-7abcb17b-60c7-487d-9de8-ef9818cbd6eb.mp4 + +While this mod is not directly fixing the performance hit while unmuted, it is likely freeing enough resources that unmuting does not cause a noticable performance hit while in online instances. This comes at the cost of Cohtml being a bit more fragile, as it is more likely to randomly error while disabled. + +## Relevant Feedback Posts: + +https://feedback.abinteractive.net/p/fps-drop-while-unmuted --- @@ -96,3 +130,7 @@ https://documentation.abinteractive.net/official/legal/tos/#7-modding-our-games > Use of this mod is done so at the user's own risk and the creator cannot be held responsible for any issues arising from its use. > To the best of my knowledge, I have adhered to the Modding Guidelines established by Alpha Blend Interactive. +<<<<<<< HEAD +======= + +>>>>>>> FuckMetrics/main