From e541840da997277ade8878ed4e628aece2360ce4 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Mon, 20 Jul 2026 16:35:52 -0400 Subject: [PATCH 1/5] improve lag issues in settings menu on 17.4 --- .../Patches/Options/GameOptionsMenuPatch.cs | 232 +++++++++--------- .../Patches/Options/RoleSettingMenuPatches.cs | 145 ++++++----- MiraAPI/Utilities/Extensions.cs | 40 +++ 3 files changed, 244 insertions(+), 173 deletions(-) diff --git a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs index cbc11aa..e8ad1a2 100644 --- a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs +++ b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs @@ -1,6 +1,10 @@ using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using AmongUs.GameOptions; +using BepInEx.Unity.IL2CPP.Utils.Collections; using HarmonyLib; using Il2CppInterop.Runtime.Attributes; using MiraAPI.GameOptions; @@ -178,7 +182,8 @@ internal static class GameOptionsMenuPatch private static void ModifiersUpdate(ref float num) { var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups - .Where(x => x.ParentMenu is MenuCategory.Modifiers || x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true) ?? []; + .Where(x => x.ParentMenu is MenuCategory.Modifiers || + x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true) ?? []; foreach (var modGroup in groups) { @@ -189,7 +194,8 @@ internal static class GameOptionsMenuPatch private static void ModifiersCreate(GameOptionsMenu menu) { var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups - .Where(x => x.ParentMenu is MenuCategory.Modifiers || x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true) ?? []; + .Where(x => x.ParentMenu is MenuCategory.Modifiers || + x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true) ?? []; foreach (var group in groups) { CreateGroup(menu, group); @@ -208,20 +214,17 @@ internal static class GameOptionsMenuPatch __instance.MapPicker.gameObject.SetActive(false); - if (__instance.name == "MODIFIERS TAB") + switch (__instance.name) { - ModifiersCreate(__instance); - return false; - } - else if (__instance.name == "CUSTOM TAB 1") - { - CustomMenuOneCreate(__instance); - return false; - } - else if (__instance.name == "CUSTOM TAB 2") - { - CustomMenuTwoCreate(__instance); - return false; + case "MODIFIERS TAB": + ModifiersCreate(__instance); + return false; + case "CUSTOM TAB 1": + CustomMenuOneCreate(__instance); + return false; + case "CUSTOM TAB 2": + CustomMenuTwoCreate(__instance); + return false; } var filteredGroups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups @@ -318,117 +321,120 @@ internal static class GameOptionsMenuPatch defaultPreset = preset; } - foreach (var newOpt in options) - { - newOpt.SetClickMask(menu.ButtonClickMask); - - SpriteRenderer[] componentsInChildren = newOpt.GetComponentsInChildren(true); - foreach (var renderer in componentsInChildren) + menu.StartCoroutine( + options.CoLoopWithBudget((newOpt) => { - if (group.GroupColor != MiraApiPlugin.DefaultHeaderColor) + newOpt.SetClickMask(menu.ButtonClickMask); + + SpriteRenderer[] componentsInChildren = newOpt.GetComponentsInChildren(true); + foreach (var renderer in componentsInChildren) { - renderer.color = group.GroupColor.FindAlternateColor(); - if (renderer.transform.parent.TryGetComponent(out var btn)) + if (group.GroupColor != MiraApiPlugin.DefaultHeaderColor) { - btn.interactableColor = group.GroupColor.FindAlternateColor(); - btn.interactableHoveredColor = Color.white; + renderer.color = group.GroupColor.FindAlternateColor(); + if (renderer.transform.parent.TryGetComponent(out var btn)) + { + btn.interactableColor = group.GroupColor.FindAlternateColor(); + btn.interactableHoveredColor = Color.white; + } } + + renderer.material.SetInt(PlayerMaterial.MaskLayer, 20); } - renderer.material.SetInt(PlayerMaterial.MaskLayer, 20); - } - - foreach (var textMeshPro in newOpt.GetComponentsInChildren(true)) - { - if (group.GroupColor != MiraApiPlugin.DefaultHeaderColor) + foreach (var textMeshPro in newOpt.GetComponentsInChildren(true)) { - textMeshPro.color = group.GroupColor; + if (group.GroupColor != MiraApiPlugin.DefaultHeaderColor) + { + textMeshPro.color = group.GroupColor; + } + + textMeshPro.fontMaterial.SetFloat(ShaderID.StencilComp, 3f); + textMeshPro.fontMaterial.SetFloat(ShaderID.Stencil, 20); } - textMeshPro.fontMaterial.SetFloat(ShaderID.StencilComp, 3f); - textMeshPro.fontMaterial.SetFloat(ShaderID.Stencil, 20); - } - - if (newOpt is ToggleOption toggle) - { - toggle.CheckMark.sprite = MiraAssets.Checkmark.LoadAsset(); - toggle.CheckMark.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor - ? group.GroupColor - : MiraAssets.AcceptedTeal; - var rend = toggle.CheckMark.transform.parent.FindChild("ActiveSprite") - .GetComponent(); - rend.sprite = MiraAssets.CheckmarkBox.LoadAsset(); - rend.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor - ? group.GroupColor - : MiraAssets.AcceptedTeal; - } - - menu.Children.Add(newOpt); - var resetBtn = new GameObject("ResetOption"); - resetBtn.transform.parent = newOpt.transform; - resetBtn.transform.localScale = new(.5f, .5f, 1); - resetBtn.layer = LayerMask.NameToLayer("UI"); - resetBtn.transform.localPosition = new Vector3(-3.1f, 0f, -2f); - var resetRend = resetBtn.AddComponent(); - resetRend.sprite = MiraAssets.ResetButton.LoadAsset(); - resetRend.maskInteraction = SpriteMaskInteraction.VisibleInsideMask; - resetRend.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor) - ? Color.white - : group.GroupColor.FindAlternateColor(); - var resetBoxCol = resetBtn.gameObject.AddComponent(); - resetBoxCol.size = new Vector2(1f, 1f); - resetBoxCol.offset = new Vector2(0, 0); - var passiveButton = resetBtn.AddComponent(); - passiveButton.OnClick = new Button.ButtonClickedEvent(); - passiveButton.ClickSound = menu.BackButton.GetComponent().ClickSound; - passiveButton.OnMouseOver = new UnityEvent(); - passiveButton.OnMouseOver.AddListener( - (UnityAction)(() => + if (newOpt is ToggleOption toggle) { - resetRend.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor + toggle.CheckMark.sprite = MiraAssets.Checkmark.LoadAsset(); + toggle.CheckMark.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor ? group.GroupColor : MiraAssets.AcceptedTeal; - })); - passiveButton.OnMouseOut = new UnityEvent(); - passiveButton.OnMouseOut.AddListener( - (UnityAction)(() => - { - resetRend.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor) - ? Color.white - : group.GroupColor.FindAlternateColor(); - })); - if (newOpt is ToggleOption toggleOpt) - { - passiveButton.OnClick.AddListener( - (UnityAction)(() => - { - defaultPreset!.ResetOption(toggleOpt); - })); - } - else if (newOpt is NumberOption numOpt) - { - passiveButton.OnClick.AddListener( - (UnityAction)(() => - { - defaultPreset!.ResetOption(numOpt); - })); - } - else if (newOpt is StringOption strOpt) - { - passiveButton.OnClick.AddListener( - (UnityAction)(() => - { - defaultPreset!.ResetOption(strOpt); - })); - } - if (!defaultPreset!.IsOptionInPreset(newOpt)) - { - resetBtn.Destroy(); - } + var rend = toggle.CheckMark.transform.parent.FindChild("ActiveSprite") + .GetComponent(); + rend.sprite = MiraAssets.CheckmarkBox.LoadAsset(); + rend.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor + ? group.GroupColor + : MiraAssets.AcceptedTeal; + } - newOpt.Initialize(); - newOpt.gameObject.SetActive(false); - } + menu.Children.Add(newOpt); + var resetBtn = new GameObject("ResetOption"); + resetBtn.transform.parent = newOpt.transform; + resetBtn.transform.localScale = new(.5f, .5f, 1); + resetBtn.layer = LayerMask.NameToLayer("UI"); + resetBtn.transform.localPosition = new Vector3(-3.1f, 0f, -2f); + var resetRend = resetBtn.AddComponent(); + resetRend.sprite = MiraAssets.ResetButton.LoadAsset(); + resetRend.maskInteraction = SpriteMaskInteraction.VisibleInsideMask; + resetRend.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor) + ? Color.white + : group.GroupColor.FindAlternateColor(); + var resetBoxCol = resetBtn.gameObject.AddComponent(); + resetBoxCol.size = new Vector2(1f, 1f); + resetBoxCol.offset = new Vector2(0, 0); + var passiveButton = resetBtn.AddComponent(); + passiveButton.OnClick = new Button.ButtonClickedEvent(); + passiveButton.ClickSound = menu.BackButton.GetComponent().ClickSound; + passiveButton.OnMouseOver = new UnityEvent(); + passiveButton.OnMouseOver.AddListener( + (UnityAction)(() => + { + resetRend.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor + ? group.GroupColor + : MiraAssets.AcceptedTeal; + })); + passiveButton.OnMouseOut = new UnityEvent(); + passiveButton.OnMouseOut.AddListener( + (UnityAction)(() => + { + resetRend.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor) + ? Color.white + : group.GroupColor.FindAlternateColor(); + })); + if (newOpt is ToggleOption toggleOpt) + { + passiveButton.OnClick.AddListener( + (UnityAction)(() => + { + defaultPreset!.ResetOption(toggleOpt); + })); + } + else if (newOpt is NumberOption numOpt) + { + passiveButton.OnClick.AddListener( + (UnityAction)(() => + { + defaultPreset!.ResetOption(numOpt); + })); + } + else if (newOpt is StringOption strOpt) + { + passiveButton.OnClick.AddListener( + (UnityAction)(() => + { + defaultPreset!.ResetOption(strOpt); + })); + } + + if (!defaultPreset!.IsOptionInPreset(newOpt)) + { + resetBtn.Destroy(); + } + + newOpt.Initialize(); + newOpt.gameObject.SetActive(false); + }).WrapToIl2Cpp() + ); var boxCol = categoryHeaderMasked.gameObject.AddComponent(); boxCol.size = new Vector2(7, 0.7f); diff --git a/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs b/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs index 55947c8..18daa7d 100644 --- a/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs +++ b/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs @@ -1,9 +1,10 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using AmongUs.GameOptions; +using BepInEx.Unity.IL2CPP.Utils.Collections; using HarmonyLib; -using Il2CppInterop.Runtime.InteropTypes.Arrays; using MiraAPI.GameOptions; using MiraAPI.Networking; using MiraAPI.Roles; @@ -11,7 +12,6 @@ using MiraAPI.Utilities; using MiraAPI.Utilities.Assets; using Reactor.Localization.Utilities; using Reactor.Networking.Rpc; -using Reactor.Utilities; using Reactor.Utilities.Extensions; using TMPro; using UnityEngine; @@ -49,9 +49,7 @@ public static class RoleSettingMenuPatches __instance.scrollBar.SetScrollBounds(__instance); } - [HarmonyPrefix] - [HarmonyPatch(nameof(RolesSettingsMenu.SetQuotaTab))] - public static bool SetQuotaTabPatch(RolesSettingsMenu __instance) + private static IEnumerator CoQuotaTabPatch(RolesSettingsMenu roleMenu) { foreach (var obj in Headers) { @@ -59,8 +57,10 @@ public static class RoleSettingMenuPatches { continue; } + obj.DeepDestroy(false); } + Headers.Clear(); foreach (var obj in RoleOptionSettings) { @@ -68,24 +68,26 @@ public static class RoleSettingMenuPatches { continue; } + obj.gameObject.DeepDestroy(false); } + RoleOptionSettings.Clear(); CurrentRole = null; CurrentRoleOptions = null; - __instance.roleChances = new Il2CppSystem.Collections.Generic.List(); - __instance.advancedSettingChildren = new Il2CppSystem.Collections.Generic.List(); + roleMenu.roleChances = new Il2CppSystem.Collections.Generic.List(); + roleMenu.advancedSettingChildren = new Il2CppSystem.Collections.Generic.List(); - var maskBg = __instance.scrollBar.transform.FindChild("MaskBg"); - var hitbox = __instance.scrollBar.transform.FindChild("Hitbox"); - var dividerImage = __instance.transform.FindChild("HeaderButtons/DividerImage"); + var maskBg = roleMenu.scrollBar.transform.FindChild("MaskBg"); + var hitbox = roleMenu.scrollBar.transform.FindChild("Hitbox"); + var dividerImage = roleMenu.transform.FindChild("HeaderButtons/DividerImage"); if (GameSettingMenuPatches.SelectedModIdx == 0) { - __instance.AllButton.transform.parent.gameObject.SetActive(true); - __instance.AllButton.gameObject.SetActive(true); - __instance.scrollBar.transform.localPosition = new Vector3(-1.4957f, 0.657f, -4); + roleMenu.AllButton.transform.parent.gameObject.SetActive(true); + roleMenu.AllButton.gameObject.SetActive(true); + roleMenu.scrollBar.transform.localPosition = new Vector3(-1.4957f, 0.657f, -4); maskBg.localPosition = new Vector3(1.5353f, -.5734f, -.1f); maskBg.localScale = new Vector3(6.6811f, 3.3563f, 0.5598f); hitbox.localPosition = new Vector3(0.3297f, -.2333f, 4f); @@ -94,67 +96,70 @@ public static class RoleSettingMenuPatches var num = 0.662f; - var list = CustomRoleManager.AllRoles.Where( - r => !r.IsCustomRole() && !r.IsRoleBlacklisted() && r.TeamType == RoleTeamTypes.Crewmate && r.Role != RoleTypes.Crewmate && - r.Role != RoleTypes.CrewmateGhost).ToList(); - var list2 = CustomRoleManager.AllRoles.Where( - r => !r.IsCustomRole() && !r.IsRoleBlacklisted() && r.TeamType == RoleTeamTypes.Impostor && r.Role != RoleTypes.Impostor && - r.Role != RoleTypes.ImpostorGhost).ToList(); + var list = CustomRoleManager.AllRoles.Where(r => + !r.IsCustomRole() && !r.IsRoleBlacklisted() && r.TeamType == RoleTeamTypes.Crewmate && + r.Role != RoleTypes.Crewmate && + r.Role != RoleTypes.CrewmateGhost).ToList(); + var list2 = CustomRoleManager.AllRoles.Where(r => + !r.IsCustomRole() && !r.IsRoleBlacklisted() && r.TeamType == RoleTeamTypes.Impostor && + r.Role != RoleTypes.Impostor && + r.Role != RoleTypes.ImpostorGhost).ToList(); - if (__instance.roleTabs == null || __instance.roleTabs.Count == 0) + if (roleMenu.roleTabs == null || roleMenu.roleTabs.Count == 0) { var num2 = -1.928f; - __instance.roleTabs = new(); - __instance.roleTabs.Add(__instance.AllButton); + roleMenu.roleTabs = new(); + roleMenu.roleTabs.Add(roleMenu.AllButton); foreach (var t in list) { - __instance.AddRoleTab(t, ref num2); + roleMenu.AddRoleTab(t, ref num2); } foreach (var t in list2) { - __instance.AddRoleTab(t, ref num2); + roleMenu.AddRoleTab(t, ref num2); } } var categoryHeaderEditRole = Object.Instantiate( - __instance.categoryHeaderEditRoleOrigin, + roleMenu.categoryHeaderEditRoleOrigin, Vector3.zero, Quaternion.identity, - __instance.RoleChancesSettings.transform); + roleMenu.RoleChancesSettings.transform); categoryHeaderEditRole.SetHeader(StringNames.CrewmateRolesHeader, 20); categoryHeaderEditRole.transform.localPosition = new Vector3(4.986f, num, -2f); num -= 0.522f; var num3 = 0; foreach (var t in list) { - __instance.CreateQuotaOption(t, ref num, num3); + roleMenu.CreateQuotaOption(t, ref num, num3); num3++; } num -= 0.22f; var categoryHeaderEditRole2 = Object.Instantiate( - __instance.categoryHeaderEditRoleOrigin, + roleMenu.categoryHeaderEditRoleOrigin, Vector3.zero, Quaternion.identity, - __instance.RoleChancesSettings.transform); + roleMenu.RoleChancesSettings.transform); categoryHeaderEditRole2.SetHeader(StringNames.ImpostorRolesHeader, 20); categoryHeaderEditRole2.transform.localPosition = new Vector3(4.986f, num, -2f); num -= 0.522f; foreach (var t in list2) { - __instance.CreateQuotaOption(t, ref num, num3); + roleMenu.CreateQuotaOption(t, ref num, num3); num3++; } - return false; + Info($"Created {num3} role options for the default game."); + yield return null; } ScrollerNum = 0.522f; - __instance.AllButton.transform.parent.gameObject.SetActive(false); - __instance.AllButton.gameObject.SetActive(false); - __instance.scrollBar.transform.localPosition = new Vector3(-1.4957f, 1.5261f, -4); + roleMenu.AllButton.transform.parent.gameObject.SetActive(false); + roleMenu.AllButton.gameObject.SetActive(false); + roleMenu.scrollBar.transform.localPosition = new Vector3(-1.4957f, 1.5261f, -4); maskBg.localPosition = new Vector3(1.5353f, -1.0607f, -.1f); maskBg.localScale = new Vector3(6.6811f, 4.1563f, 0.5598f); hitbox.localPosition = new Vector3(0.3297f, -.6333f, 4f); @@ -168,7 +173,8 @@ public static class RoleSettingMenuPatches if (roleGroups is null) { - return false; + Error("No role groups found for the selected mod."); + yield break; } // sort the groups by priority @@ -176,13 +182,14 @@ public static class RoleSettingMenuPatches .OrderBy(x => x.Key.Priority) .ThenBy(x => x.Key.Name); - var quotaThing = __instance.categoryHeaderEditRoleOrigin.transform.FindChild("QuotaHeader"); + var quotaThing = roleMenu.categoryHeaderEditRoleOrigin.transform.FindChild("QuotaHeader"); var usingNewQuota = false; - var template = __instance.transform.parent.parent.GetComponent().GameSettingsTab.categoryHeaderOrigin; + var template = roleMenu.transform.parent.parent.GetComponent().GameSettingsTab + .categoryHeaderOrigin; foreach (var grouping in sortedRoleGroups) { - if (!grouping.Any() || grouping.All(x=> x.Configuration.HideSettings || !x.VisibleInSettings())) + if (!grouping.Any() || grouping.All(x => x.Configuration.HideSettings || !x.VisibleInSettings())) { continue; } @@ -202,7 +209,7 @@ public static class RoleSettingMenuPatches template, Vector3.zero, Quaternion.identity, - __instance.RoleChancesSettings.transform); + roleMenu.RoleChancesSettings.transform); categoryHeaderMasked.SetHeader(name, 20); @@ -245,19 +252,23 @@ public static class RoleSettingMenuPatches categoryHeaderMasked.Background.color = Palette.ImpostorRoleHeaderRed; break; default: - categoryHeaderMasked.Title.color = group.Color.Equals(MiraApiPlugin.DefaultHeaderColor) ? Color.white : group.Color.FindAlternateColor(); + categoryHeaderMasked.Title.color = group.Color.Equals(MiraApiPlugin.DefaultHeaderColor) + ? Color.white + : group.Color.FindAlternateColor(); categoryHeaderMasked.Divider.color = group.Color; categoryHeaderMasked.Background.color = group.Color; break; } - categoryHeaderMasked.Title.fontStyle = __instance.categoryHeaderEditRoleOrigin.Title.fontStyle; - categoryHeaderMasked.Title.font = __instance.categoryHeaderEditRoleOrigin.Title.font; - categoryHeaderMasked.Title.fontMaterial = __instance.categoryHeaderEditRoleOrigin.Title.fontMaterial; + categoryHeaderMasked.Title.fontStyle = roleMenu.categoryHeaderEditRoleOrigin.Title.fontStyle; + categoryHeaderMasked.Title.font = roleMenu.categoryHeaderEditRoleOrigin.Title.font; + categoryHeaderMasked.Title.fontMaterial = roleMenu.categoryHeaderEditRoleOrigin.Title.fontMaterial; categoryHeaderMasked.Divider.color = categoryHeaderMasked.Background.color; categoryHeaderMasked.Background.transform.localPosition = new Vector3(0.55f, -0.1833f, 0); - categoryHeaderMasked.Background.size = new Vector2(categoryHeaderMasked.Background.size.x + 1.5f, categoryHeaderMasked.Background.size.y); + categoryHeaderMasked.Background.size = new Vector2( + categoryHeaderMasked.Background.size.x + 1.5f, + categoryHeaderMasked.Background.size.y); categoryHeaderMasked.transform.localScale = Vector3.one * 0.63f; categoryHeaderMasked.transform.localPosition = new Vector3(-0.44f, ScrollerNum, -2f); @@ -277,20 +288,21 @@ public static class RoleSettingMenuPatches if (!RoleGroupHidden[group]) { - foreach (var role in grouping) - { - if (role is not RoleBehaviour roleBehaviour) + yield return + grouping.CoLoopWithBudget(role => { - continue; - } + if (role is not RoleBehaviour roleBehaviour) + { + return; + } - var option = CreateQuotaOption(__instance, roleBehaviour, num4); - if (option is not null) - { - RoleOptionSettings.Add(option); - num4++; - } - } + var option = CreateQuotaOption(roleMenu, roleBehaviour, num4); + if (option is not null) + { + RoleOptionSettings.Add(option); + num4++; + } + }); } var boxCol = categoryHeaderMasked.gameObject.AddComponent(); @@ -298,25 +310,28 @@ public static class RoleSettingMenuPatches boxCol.offset = new Vector2(1.5f, -0.3f); var headerBtn = categoryHeaderMasked.gameObject.AddComponent(); - headerBtn.ClickSound = __instance.BackButton.GetComponent().ClickSound; + headerBtn.ClickSound = roleMenu.BackButton.GetComponent().ClickSound; headerBtn.OnMouseOver = new UnityEvent(); headerBtn.OnMouseOut = new UnityEvent(); headerBtn.OnClick.AddListener( (UnityAction)(() => { - RolePositions[GameSettingMenuPatches.SelectedModIdx] = __instance.scrollBar.Inner.localPosition; + RolePositions[GameSettingMenuPatches.SelectedModIdx] = roleMenu.scrollBar.Inner.localPosition; if (RoleGroupHidden.TryGetValue(group, out var groupHidden)) { RoleGroupHidden[group] = !groupHidden; } + foreach (var obj in Headers) { if (!obj) { continue; } + obj.DeepDestroy(false); } + Headers.Clear(); foreach (var obj in RoleOptionSettings) { @@ -324,10 +339,12 @@ public static class RoleSettingMenuPatches { continue; } + obj.gameObject.DeepDestroy(false); } + RoleOptionSettings.Clear(); - __instance.SetQuotaTab(); + roleMenu.SetQuotaTab(); })); headerBtn.SetButtonEnableState(true); @@ -337,7 +354,14 @@ public static class RoleSettingMenuPatches } } - __instance.scrollBar.SetScrollBounds(__instance); + roleMenu.scrollBar.SetScrollBounds(roleMenu); + } + + [HarmonyPrefix] + [HarmonyPatch(nameof(RolesSettingsMenu.SetQuotaTab))] + public static bool SetQuotaTabPatch(RolesSettingsMenu __instance) + { + __instance.StartCoroutine(CoQuotaTabPatch(__instance).WrapToIl2Cpp()); return false; } @@ -362,6 +386,7 @@ public static class RoleSettingMenuPatches } [HarmonyPrefix] + // TODO: turn this into a fixed update [HarmonyPatch(nameof(RolesSettingsMenu.Update))] public static bool UpdatePatch(RolesSettingsMenu __instance) { diff --git a/MiraAPI/Utilities/Extensions.cs b/MiraAPI/Utilities/Extensions.cs index 717f0b9..4590ad6 100644 --- a/MiraAPI/Utilities/Extensions.cs +++ b/MiraAPI/Utilities/Extensions.cs @@ -1,10 +1,12 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; +using System.Timers; using HarmonyLib; using MiraAPI.GameOptions; using MiraAPI.Networking; @@ -239,6 +241,44 @@ public static class Extensions } } + /// + /// Runs a given action in a loop with a frame budget based on the current target frame rate. Once the budget is hit, the loop continues on the next frame. + /// + /// The collection to iterate over. + /// The action to perform on each item. + /// The type of the collection. + /// Coroutine. + public static IEnumerator CoLoopWithBudget(this IEnumerable collection, Action action) + { + var fps = Application.targetFrameRate > 0 ? Application.targetFrameRate : 60; + long budget = 1 / (fps * 2); // default is half of current frame time. + yield return collection.CoLoopWithBudget(budget, action); + } + + /// + /// Runs a given action in a loop with a given frame budget. Once the budget is hit, the loop continues on the next frame. + /// + /// The collection to iterate over. + /// The # of milliseconds to spend in the loop. + /// The action to perform on each item. + /// The type of the collection. + /// Coroutine. + public static IEnumerator CoLoopWithBudget(this IEnumerable collection, long frameBudget, Action action) + { + var timer = new Stopwatch(); + timer.Start(); + foreach (var item in collection) + { + action(item); + + if (timer.ElapsedMilliseconds > frameBudget) + { + timer.Restart(); + yield return null; + } + } + } + private static IEnumerator Nuke(GameObject? go, bool clearGc) { if (go == null) From f9721a8d698c980b44a839368d36651e3b1cdab2 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Mon, 20 Jul 2026 19:06:52 -0400 Subject: [PATCH 2/5] improve stability and FPS on 17.4+ --- MiraAPI/GameOptions/AbstractOptionGroup.cs | 2 + .../ModifierDisplayComponent.cs | 4 +- MiraAPI/Patches/HudManagerPatches.cs | 2 +- MiraAPI/Patches/Menu/HatsTabPatches.cs | 2 +- MiraAPI/Patches/Menu/NameplatesTabPatches.cs | 2 +- MiraAPI/Patches/Menu/SkinsTabPatches.cs | 2 +- MiraAPI/Patches/Menu/VisorsTabPatches.cs | 2 +- .../Patches/Options/GameOptionsMenuPatch.cs | 206 +++++++++--------- .../Patches/Options/GamePresetsTabPatches.cs | 2 +- .../Patches/Options/RoleSettingMenuPatches.cs | 31 ++- MiraAPI/Patches/Roles/HudManagerPatches.cs | 2 +- MiraAPI/Presets/PresetManager.cs | 3 +- MiraAPI/Presets/SavePresetPopup.cs | 2 +- MiraAPI/Utilities/Extensions.cs | 11 +- 14 files changed, 143 insertions(+), 130 deletions(-) diff --git a/MiraAPI/GameOptions/AbstractOptionGroup.cs b/MiraAPI/GameOptions/AbstractOptionGroup.cs index 8be08c6..5ee95c2 100644 --- a/MiraAPI/GameOptions/AbstractOptionGroup.cs +++ b/MiraAPI/GameOptions/AbstractOptionGroup.cs @@ -70,6 +70,8 @@ public abstract class AbstractOptionGroup internal bool AllOptionsHidden { get; set; } internal CategoryHeaderMasked? Header { get; set; } + + internal Coroutine? CreationCoroutine { get; set; } } /// diff --git a/MiraAPI/Modifiers/ModifierDisplay/ModifierDisplayComponent.cs b/MiraAPI/Modifiers/ModifierDisplay/ModifierDisplayComponent.cs index 4a6411f..4b4c71e 100644 --- a/MiraAPI/Modifiers/ModifierDisplay/ModifierDisplayComponent.cs +++ b/MiraAPI/Modifiers/ModifierDisplay/ModifierDisplayComponent.cs @@ -138,7 +138,7 @@ public class ModifierDisplayComponent(nint cppPtr) : MonoBehaviour(cppPtr) internal void DestroyComponent(ModifierUiComponent component) { _modifiers.Remove(component.Modifier!); - component.gameObject.DeepDestroy(); + component.gameObject.Destroy(); RefreshModifiers(); } @@ -208,7 +208,7 @@ public class ModifierDisplayComponent(nint cppPtr) : MonoBehaviour(cppPtr) continue; } - mod.Value.gameObject.DeepDestroy(); + mod.Value.gameObject.Destroy(); _modifiers.Remove(mod.Key); } diff --git a/MiraAPI/Patches/HudManagerPatches.cs b/MiraAPI/Patches/HudManagerPatches.cs index a6cd68b..a508ccf 100644 --- a/MiraAPI/Patches/HudManagerPatches.cs +++ b/MiraAPI/Patches/HudManagerPatches.cs @@ -148,7 +148,7 @@ public static class HudManagerPatches foreach (var t in BottomLeft.GetComponentsInChildren(true)) { - t.gameObject.DeepDestroy(false); + t.gameObject.Destroy(); } Utilities.Extensions.ClearGarbageCollector(); diff --git a/MiraAPI/Patches/Menu/HatsTabPatches.cs b/MiraAPI/Patches/Menu/HatsTabPatches.cs index b06b11a..43d96c3 100644 --- a/MiraAPI/Patches/Menu/HatsTabPatches.cs +++ b/MiraAPI/Patches/Menu/HatsTabPatches.cs @@ -100,7 +100,7 @@ public static class HatsTabPatches if (loadRoutine != null) Coroutines.Stop(loadRoutine); hatIndex = 0; - foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.DeepDestroy(false); + foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.Destroy(); __instance.ColorChips.Clear(); __instance.scroller.Inner.GetComponentsInChildren().Do(x => x.gameObject.DeepDestroy(false)); diff --git a/MiraAPI/Patches/Menu/NameplatesTabPatches.cs b/MiraAPI/Patches/Menu/NameplatesTabPatches.cs index 4e9b693..6e96d5f 100644 --- a/MiraAPI/Patches/Menu/NameplatesTabPatches.cs +++ b/MiraAPI/Patches/Menu/NameplatesTabPatches.cs @@ -81,7 +81,7 @@ public static class NameplatesTabPatches private static void GenerateHats(NameplatesTab __instance, int page) { - foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.DeepDestroy(false); + foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.Destroy(); __instance.ColorChips.Clear(); __instance.scroller.Inner.GetComponentsInChildren().Do(x => x.gameObject.DeepDestroy(false)); diff --git a/MiraAPI/Patches/Menu/SkinsTabPatches.cs b/MiraAPI/Patches/Menu/SkinsTabPatches.cs index 44d08d5..e1c97a5 100644 --- a/MiraAPI/Patches/Menu/SkinsTabPatches.cs +++ b/MiraAPI/Patches/Menu/SkinsTabPatches.cs @@ -83,7 +83,7 @@ public static class SkinsTabPatches private static void GenerateHats(SkinsTab __instance, int page) { - foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.DeepDestroy(false); + foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.Destroy(); __instance.ColorChips.Clear(); __instance.scroller.Inner.GetComponentsInChildren().Do(x => x.gameObject.DeepDestroy(false)); diff --git a/MiraAPI/Patches/Menu/VisorsTabPatches.cs b/MiraAPI/Patches/Menu/VisorsTabPatches.cs index c5fe9a4..a1627cf 100644 --- a/MiraAPI/Patches/Menu/VisorsTabPatches.cs +++ b/MiraAPI/Patches/Menu/VisorsTabPatches.cs @@ -80,7 +80,7 @@ public static class VisorsTabPatches private static void GenerateHats(VisorsTab __instance, int page) { - foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.DeepDestroy(false); + foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.Destroy(); __instance.ColorChips.Clear(); __instance.scroller.Inner.GetComponentsInChildren().Do(x => x.gameObject.DeepDestroy(false)); diff --git a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs index e8ad1a2..3068a1b 100644 --- a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs +++ b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs @@ -85,9 +85,9 @@ internal static class GameOptionsMenuPatch __instance.scrollBar.SetYBoundsMax(-num - 1.65f); } - private static void UpdateGroup(AbstractOptionGroup group, ref float num) + private static void UpdateGroup(AbstractOptionGroup? group, ref float num) { - if (group.Options.Count == 0 || group.Header is null) + if (group is null || group.Options.Count == 0 || group.Header is null || group.CreationCoroutine is not null) { return; } @@ -113,7 +113,7 @@ internal static class GameOptionsMenuPatch { var newOpt = opt.OptionBehaviour; - if (newOpt is null) + if (!newOpt || newOpt == null) { continue; } @@ -274,7 +274,7 @@ internal static class GameOptionsMenuPatch return false; } - private static void CreateGroup(GameOptionsMenu menu, AbstractOptionGroup group) + private static IEnumerator CoCreateGroup(GameOptionsMenu menu, AbstractOptionGroup group) { var categoryHeaderMasked = Object.Instantiate( menu.categoryHeaderOrigin, @@ -321,120 +321,118 @@ internal static class GameOptionsMenuPatch defaultPreset = preset; } - menu.StartCoroutine( - options.CoLoopWithBudget((newOpt) => + yield return options.CoLoopWithBudget(newOpt => + { + newOpt.SetClickMask(menu.ButtonClickMask); + + SpriteRenderer[] componentsInChildren = newOpt.GetComponentsInChildren(true); + foreach (var renderer in componentsInChildren) { - newOpt.SetClickMask(menu.ButtonClickMask); - - SpriteRenderer[] componentsInChildren = newOpt.GetComponentsInChildren(true); - foreach (var renderer in componentsInChildren) + if (group.GroupColor != MiraApiPlugin.DefaultHeaderColor) { - if (group.GroupColor != MiraApiPlugin.DefaultHeaderColor) + renderer.color = group.GroupColor.FindAlternateColor(); + if (renderer.transform.parent.TryGetComponent(out var btn)) { - renderer.color = group.GroupColor.FindAlternateColor(); - if (renderer.transform.parent.TryGetComponent(out var btn)) - { - btn.interactableColor = group.GroupColor.FindAlternateColor(); - btn.interactableHoveredColor = Color.white; - } + btn.interactableColor = group.GroupColor.FindAlternateColor(); + btn.interactableHoveredColor = Color.white; } - - renderer.material.SetInt(PlayerMaterial.MaskLayer, 20); } - foreach (var textMeshPro in newOpt.GetComponentsInChildren(true)) - { - if (group.GroupColor != MiraApiPlugin.DefaultHeaderColor) - { - textMeshPro.color = group.GroupColor; - } + renderer.material.SetInt(PlayerMaterial.MaskLayer, 20); + } - textMeshPro.fontMaterial.SetFloat(ShaderID.StencilComp, 3f); - textMeshPro.fontMaterial.SetFloat(ShaderID.Stencil, 20); + foreach (var textMeshPro in newOpt.GetComponentsInChildren(true)) + { + if (group.GroupColor != MiraApiPlugin.DefaultHeaderColor) + { + textMeshPro.color = group.GroupColor; } - if (newOpt is ToggleOption toggle) + textMeshPro.fontMaterial.SetFloat(ShaderID.StencilComp, 3f); + textMeshPro.fontMaterial.SetFloat(ShaderID.Stencil, 20); + } + + if (newOpt is ToggleOption toggle) + { + toggle.CheckMark.sprite = MiraAssets.Checkmark.LoadAsset(); + toggle.CheckMark.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor + ? group.GroupColor + : MiraAssets.AcceptedTeal; + var rend = toggle.CheckMark.transform.parent.FindChild("ActiveSprite") + .GetComponent(); + rend.sprite = MiraAssets.CheckmarkBox.LoadAsset(); + rend.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor + ? group.GroupColor + : MiraAssets.AcceptedTeal; + } + + menu.Children.Add(newOpt); + var resetBtn = new GameObject("ResetOption"); + resetBtn.transform.parent = newOpt.transform; + resetBtn.transform.localScale = new(.5f, .5f, 1); + resetBtn.layer = LayerMask.NameToLayer("UI"); + resetBtn.transform.localPosition = new Vector3(-3.1f, 0f, -2f); + var resetRend = resetBtn.AddComponent(); + resetRend.sprite = MiraAssets.ResetButton.LoadAsset(); + resetRend.maskInteraction = SpriteMaskInteraction.VisibleInsideMask; + resetRend.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor) + ? Color.white + : group.GroupColor.FindAlternateColor(); + var resetBoxCol = resetBtn.gameObject.AddComponent(); + resetBoxCol.size = new Vector2(1f, 1f); + resetBoxCol.offset = new Vector2(0, 0); + var passiveButton = resetBtn.AddComponent(); + passiveButton.OnClick = new Button.ButtonClickedEvent(); + passiveButton.ClickSound = menu.BackButton.GetComponent().ClickSound; + passiveButton.OnMouseOver = new UnityEvent(); + passiveButton.OnMouseOver.AddListener( + (UnityAction)(() => { - toggle.CheckMark.sprite = MiraAssets.Checkmark.LoadAsset(); - toggle.CheckMark.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor + resetRend.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor ? group.GroupColor : MiraAssets.AcceptedTeal; - var rend = toggle.CheckMark.transform.parent.FindChild("ActiveSprite") - .GetComponent(); - rend.sprite = MiraAssets.CheckmarkBox.LoadAsset(); - rend.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor - ? group.GroupColor - : MiraAssets.AcceptedTeal; - } - - menu.Children.Add(newOpt); - var resetBtn = new GameObject("ResetOption"); - resetBtn.transform.parent = newOpt.transform; - resetBtn.transform.localScale = new(.5f, .5f, 1); - resetBtn.layer = LayerMask.NameToLayer("UI"); - resetBtn.transform.localPosition = new Vector3(-3.1f, 0f, -2f); - var resetRend = resetBtn.AddComponent(); - resetRend.sprite = MiraAssets.ResetButton.LoadAsset(); - resetRend.maskInteraction = SpriteMaskInteraction.VisibleInsideMask; - resetRend.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor) - ? Color.white - : group.GroupColor.FindAlternateColor(); - var resetBoxCol = resetBtn.gameObject.AddComponent(); - resetBoxCol.size = new Vector2(1f, 1f); - resetBoxCol.offset = new Vector2(0, 0); - var passiveButton = resetBtn.AddComponent(); - passiveButton.OnClick = new Button.ButtonClickedEvent(); - passiveButton.ClickSound = menu.BackButton.GetComponent().ClickSound; - passiveButton.OnMouseOver = new UnityEvent(); - passiveButton.OnMouseOver.AddListener( + })); + passiveButton.OnMouseOut = new UnityEvent(); + passiveButton.OnMouseOut.AddListener( + (UnityAction)(() => + { + resetRend.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor) + ? Color.white + : group.GroupColor.FindAlternateColor(); + })); + if (newOpt is ToggleOption toggleOpt) + { + passiveButton.OnClick.AddListener( (UnityAction)(() => { - resetRend.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor - ? group.GroupColor - : MiraAssets.AcceptedTeal; + defaultPreset!.ResetOption(toggleOpt); })); - passiveButton.OnMouseOut = new UnityEvent(); - passiveButton.OnMouseOut.AddListener( + } + else if (newOpt is NumberOption numOpt) + { + passiveButton.OnClick.AddListener( (UnityAction)(() => { - resetRend.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor) - ? Color.white - : group.GroupColor.FindAlternateColor(); + defaultPreset!.ResetOption(numOpt); })); - if (newOpt is ToggleOption toggleOpt) - { - passiveButton.OnClick.AddListener( - (UnityAction)(() => - { - defaultPreset!.ResetOption(toggleOpt); - })); - } - else if (newOpt is NumberOption numOpt) - { - passiveButton.OnClick.AddListener( - (UnityAction)(() => - { - defaultPreset!.ResetOption(numOpt); - })); - } - else if (newOpt is StringOption strOpt) - { - passiveButton.OnClick.AddListener( - (UnityAction)(() => - { - defaultPreset!.ResetOption(strOpt); - })); - } + } + else if (newOpt is StringOption strOpt) + { + passiveButton.OnClick.AddListener( + (UnityAction)(() => + { + defaultPreset!.ResetOption(strOpt); + })); + } - if (!defaultPreset!.IsOptionInPreset(newOpt)) - { - resetBtn.Destroy(); - } + if (!defaultPreset!.IsOptionInPreset(newOpt)) + { + resetBtn.Destroy(); + } - newOpt.Initialize(); - newOpt.gameObject.SetActive(false); - }).WrapToIl2Cpp() - ); + newOpt.Initialize(); + newOpt.gameObject.SetActive(false); + }).WrapToIl2Cpp(); var boxCol = categoryHeaderMasked.gameObject.AddComponent(); boxCol.size = new Vector2(7, 0.7f); @@ -453,5 +451,17 @@ internal static class GameOptionsMenuPatch : "(Click to close)"; })); headerBtn.SetButtonEnableState(true); + + group.CreationCoroutine = null; + } + + private static void CreateGroup(GameOptionsMenu menu, AbstractOptionGroup group) + { + if (group.CreationCoroutine != null) + { + GameSettingMenu.Instance.StopCoroutine(group.CreationCoroutine); + } + + group.CreationCoroutine = GameSettingMenu.Instance.StartCoroutine(CoCreateGroup(menu, group).WrapToIl2Cpp()); } } diff --git a/MiraAPI/Patches/Options/GamePresetsTabPatches.cs b/MiraAPI/Patches/Options/GamePresetsTabPatches.cs index a4b6cca..2c6cc68 100644 --- a/MiraAPI/Patches/Options/GamePresetsTabPatches.cs +++ b/MiraAPI/Patches/Options/GamePresetsTabPatches.cs @@ -262,7 +262,7 @@ internal static class GamePresetsTabPatches iconSpriteRend.sprite = MiraAssets.RefreshIcon.LoadAsset(); Helpers.DivideSize(refreshButton.gameObject, 2f); - refreshButton.buttonText.gameObject.DeepDestroy(); + refreshButton.buttonText.gameObject.Destroy(); refreshButton.OnClick = new Button.ButtonClickedEvent(); refreshButton.OnClick.AddListener((UnityAction)Refresh); diff --git a/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs b/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs index 18daa7d..b6f61c4 100644 --- a/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs +++ b/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs @@ -58,7 +58,7 @@ public static class RoleSettingMenuPatches continue; } - obj.DeepDestroy(false); + obj.Destroy(); } Headers.Clear(); @@ -69,7 +69,7 @@ public static class RoleSettingMenuPatches continue; } - obj.gameObject.DeepDestroy(false); + obj.gameObject.Destroy(); } RoleOptionSettings.Clear(); @@ -228,9 +228,9 @@ public static class RoleSettingMenuPatches var blankLabel = quotaInst.transform.FindChild("BlankLabel").gameObject; var chanceLabel = quotaInst.transform.FindChild("Chance Label").gameObject; var countLabel = quotaInst.transform.FindChild("# Label").gameObject; - blankLabel.DeepDestroy(false); - chanceLabel.DeepDestroy(false); - countLabel.DeepDestroy(false); + blankLabel.Destroy(); + chanceLabel.Destroy(); + countLabel.Destroy(); usingNewQuota = true; quotaThing = quotaInst; } @@ -329,7 +329,7 @@ public static class RoleSettingMenuPatches continue; } - obj.DeepDestroy(false); + obj.Destroy(); } Headers.Clear(); @@ -340,7 +340,7 @@ public static class RoleSettingMenuPatches continue; } - obj.gameObject.DeepDestroy(false); + obj.gameObject.Destroy(); } RoleOptionSettings.Clear(); @@ -355,13 +355,21 @@ public static class RoleSettingMenuPatches } roleMenu.scrollBar.SetScrollBounds(roleMenu); + _quotaTabCoroutine = null; } + private static Coroutine? _quotaTabCoroutine; + [HarmonyPrefix] [HarmonyPatch(nameof(RolesSettingsMenu.SetQuotaTab))] public static bool SetQuotaTabPatch(RolesSettingsMenu __instance) { - __instance.StartCoroutine(CoQuotaTabPatch(__instance).WrapToIl2Cpp()); + if (_quotaTabCoroutine != null) + { + GameSettingMenu.Instance.StopCoroutine(_quotaTabCoroutine); + } + + _quotaTabCoroutine = GameSettingMenu.Instance.StartCoroutine(CoQuotaTabPatch(__instance).WrapToIl2Cpp()); return false; } @@ -474,7 +482,7 @@ public static class RoleSettingMenuPatches { foreach (var optBehaviour in __instance.AdvancedRolesSettings.GetComponentsInChildren()) { - optBehaviour.gameObject.DeepDestroy(false); + optBehaviour.gameObject.Destroy(); } CurrentRole = role; @@ -486,8 +494,6 @@ public static class RoleSettingMenuPatches .SelectMany(x => x.Options) .ToList() ?? []; - CurrentRoleOptions = filteredOptions; - foreach (var option in filteredOptions) { var newOpt = option.CreateOption( @@ -518,6 +524,7 @@ public static class RoleSettingMenuPatches newOpt.Initialize(); } + CurrentRoleOptions = filteredOptions; __instance.scrollBar.ScrollToTop(); } @@ -670,7 +677,7 @@ public static class RoleSettingMenuPatches var newButton = Object.Instantiate(roleOptionSetting.buttons[0], roleOptionSetting.transform); newButton.name = "ConfigButton"; newButton.transform.localPosition = new Vector3(0.4473f, -0.3f, -2f); - newButton.transform.FindChild("Text_TMP").gameObject.DeepDestroy(); + newButton.transform.FindChild("Text_TMP").gameObject.Destroy(); newButton.activeSprites.Destroy(); var btnRend = newButton.transform.FindChild("ButtonSprite").GetComponent(); diff --git a/MiraAPI/Patches/Roles/HudManagerPatches.cs b/MiraAPI/Patches/Roles/HudManagerPatches.cs index 79c2306..6827341 100644 --- a/MiraAPI/Patches/Roles/HudManagerPatches.cs +++ b/MiraAPI/Patches/Roles/HudManagerPatches.cs @@ -73,7 +73,7 @@ public static class HudManagerPatches } else if (RoleTab != null) { - RoleTab.gameObject.DeepDestroy(); + RoleTab.gameObject.Destroy(); RoleTab = null; } } diff --git a/MiraAPI/Presets/PresetManager.cs b/MiraAPI/Presets/PresetManager.cs index bec1216..d346c52 100644 --- a/MiraAPI/Presets/PresetManager.cs +++ b/MiraAPI/Presets/PresetManager.cs @@ -6,6 +6,7 @@ using MiraAPI.PluginLoading; using MiraAPI.Roles; using MiraAPI.Utilities; using Reactor.Utilities; +using Reactor.Utilities.Extensions; using UnityEngine; namespace MiraAPI.Presets; @@ -62,7 +63,7 @@ public static class PresetManager { if (btn != null) { - btn.DeepDestroy(); + btn.Destroy(); } } diff --git a/MiraAPI/Presets/SavePresetPopup.cs b/MiraAPI/Presets/SavePresetPopup.cs index 23ce48b..87959e7 100644 --- a/MiraAPI/Presets/SavePresetPopup.cs +++ b/MiraAPI/Presets/SavePresetPopup.cs @@ -26,7 +26,7 @@ public class SavePresetPopup(nint cppPtr) : Minigame(cppPtr) // Cleanup holder object public void OnDestroy() { - transform.parent.gameObject.DeepDestroy(); + transform.parent.gameObject.Destroy(); } public override void Close() diff --git a/MiraAPI/Utilities/Extensions.cs b/MiraAPI/Utilities/Extensions.cs index 4590ad6..c4b9ef3 100644 --- a/MiraAPI/Utilities/Extensions.cs +++ b/MiraAPI/Utilities/Extensions.cs @@ -58,7 +58,7 @@ public static class Extensions bool isComplete; if (self.amClosing == Minigame.CloseState.Closing) { - self.gameObject.DeepDestroy(); + self.gameObject.Destroy(); return; } if (self.CloseSound && Constants.ShouldPlaySfx()) @@ -231,14 +231,7 @@ public static class Extensions /// Whether to run the garbage collector immediately. public static void DeepDestroy(this GameObject obj, bool clearGc = true) { - if (MainMenuManagerPatches.NeedsDeepDestroy) - { - Coroutines.Start(Nuke(obj, clearGc)); - } - else - { - obj?.Destroy(); - } + obj.Destroy(); } /// From 992bdbcbf8310ff03073994b96d6b3f10a427176 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Mon, 20 Jul 2026 19:10:06 -0400 Subject: [PATCH 3/5] cleanup usings --- MiraAPI.Example/ExamplePlugin.cs | 3 +-- MiraAPI.Example/Options/Roles/FreezerRoleSettings.cs | 2 -- MiraAPI/Events/MiraEventManager.cs | 1 - MiraAPI/Events/Vanilla/Meeting/Voting/AfterVoteEvent.cs | 4 +--- MiraAPI/Events/Vanilla/Meeting/Voting/BeforeVoteEvent.cs | 4 +--- MiraAPI/GameEnd/GameOverManager.cs | 1 - MiraAPI/GameModes/CustomGameModeManager.cs | 1 - MiraAPI/GameOptions/AbstractOptionGroup.cs | 2 -- MiraAPI/GameOptions/OptionTypes/ModdedOption.cs | 2 -- MiraAPI/Hud/CustomActionButton.cs | 1 - MiraAPI/Hud/CustomButtonManager.cs | 1 - MiraAPI/Hud/MultiTargetButton.cs | 1 - MiraAPI/Keybinds/KeybindManager.cs | 1 - MiraAPI/Keybinds/VanillaKeybind.cs | 1 - .../Attributes/LocalSettingsButtonAttribute.cs | 1 - MiraAPI/LocalSettings/LocalSettingsButton.cs | 1 - MiraAPI/LocalSettings/LocalSettingsManager.cs | 2 -- MiraAPI/Modifiers/ModifierComponent.cs | 1 - .../Modifiers/ModifierDisplay/ModifierDisplayComponent.cs | 1 - MiraAPI/Modifiers/ModifierExtensions.cs | 1 - MiraAPI/Modifiers/ModifierManager.cs | 1 - MiraAPI/Modifiers/Types/TimedModifier.cs | 1 - MiraAPI/Networking/CustomGameOverRpc.cs | 1 - MiraAPI/Networking/CustomMurderRpc.cs | 3 --- MiraAPI/Patches/Events/ReportBodyEventPatch.cs | 1 - MiraAPI/Patches/Events/VanillaButtonPatches.cs | 4 +--- MiraAPI/Patches/Hud/ButtonResetPatches.cs | 1 - MiraAPI/Patches/IntroCutscenePatches.cs | 4 +--- MiraAPI/Patches/Keybinds/ControlMapperPatches.cs | 5 ----- MiraAPI/Patches/Keybinds/KeybindsPatch.cs | 1 - MiraAPI/Patches/LocalSettings/OptionsMenuPatches.cs | 1 - MiraAPI/Patches/Options/GameOptionsMenuPatch.cs | 4 ---- MiraAPI/Patches/Options/GamePresetsTabPatches.cs | 1 - MiraAPI/Patches/Options/NotificationPopperPatch.cs | 2 -- MiraAPI/Patches/Options/OptionsPatches.cs | 5 +---- MiraAPI/Patches/Options/PlayerOptionPatches.cs | 6 +----- MiraAPI/Patches/PlayerControlPatches.cs | 1 - MiraAPI/Patches/Roles/HowToPlayPatch.cs | 3 +-- MiraAPI/Patches/Roles/HudManagerPatches.cs | 2 -- MiraAPI/Patches/Roles/RoleManagerPatches.cs | 1 - MiraAPI/Patches/Roles/RoleOptionsCollectionPatch.cs | 1 - MiraAPI/Patches/ServerDropdownPatch.cs | 1 - MiraAPI/Patches/TmpAwakePatch.cs | 1 - MiraAPI/Patches/Voting/DummyBehaviourPatch.cs | 1 - MiraAPI/PluginLoading/MiraPluginInfo.cs | 1 - MiraAPI/Presets/PresetManager.cs | 2 -- MiraAPI/Roles/CustomRoleManager.cs | 1 - MiraAPI/Roles/ICustomRole.cs | 2 -- MiraAPI/Utilities/Assets/LoadableAddressableAsset.cs | 1 - MiraAPI/Utilities/Assets/LoadableAddressableAssets.cs | 1 - MiraAPI/Utilities/Extensions.cs | 3 --- MiraAPI/Utilities/Helpers.cs | 2 -- MiraAPI/Voting/VotingUtils.cs | 1 - 53 files changed, 8 insertions(+), 90 deletions(-) diff --git a/MiraAPI.Example/ExamplePlugin.cs b/MiraAPI.Example/ExamplePlugin.cs index 0aed9c4..b20ec41 100644 --- a/MiraAPI.Example/ExamplePlugin.cs +++ b/MiraAPI.Example/ExamplePlugin.cs @@ -1,5 +1,4 @@ -using System.Linq; -using BepInEx; +using BepInEx; using BepInEx.Configuration; using BepInEx.Unity.IL2CPP; using HarmonyLib; diff --git a/MiraAPI.Example/Options/Roles/FreezerRoleSettings.cs b/MiraAPI.Example/Options/Roles/FreezerRoleSettings.cs index 1be3649..3c1fdeb 100644 --- a/MiraAPI.Example/Options/Roles/FreezerRoleSettings.cs +++ b/MiraAPI.Example/Options/Roles/FreezerRoleSettings.cs @@ -3,8 +3,6 @@ using MiraAPI.GameOptions; using MiraAPI.GameOptions.Attributes; using MiraAPI.Utilities; using MiraAPI.Utilities.Assets; -using TMPro; -using UnityEngine; namespace MiraAPI.Example.Options.Roles; diff --git a/MiraAPI/Events/MiraEventManager.cs b/MiraAPI/Events/MiraEventManager.cs index 005415b..30ffb74 100644 --- a/MiraAPI/Events/MiraEventManager.cs +++ b/MiraAPI/Events/MiraEventManager.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Reflection; -using Reactor.Utilities; namespace MiraAPI.Events; diff --git a/MiraAPI/Events/Vanilla/Meeting/Voting/AfterVoteEvent.cs b/MiraAPI/Events/Vanilla/Meeting/Voting/AfterVoteEvent.cs index 95583f3..60a3d36 100644 --- a/MiraAPI/Events/Vanilla/Meeting/Voting/AfterVoteEvent.cs +++ b/MiraAPI/Events/Vanilla/Meeting/Voting/AfterVoteEvent.cs @@ -1,6 +1,4 @@ -using MiraAPI.Voting; - -namespace MiraAPI.Events.Vanilla.Meeting.Voting; +namespace MiraAPI.Events.Vanilla.Meeting.Voting; /// /// Event that is invoked after the local player successfully votes a player or skips. This event is not cancelable. diff --git a/MiraAPI/Events/Vanilla/Meeting/Voting/BeforeVoteEvent.cs b/MiraAPI/Events/Vanilla/Meeting/Voting/BeforeVoteEvent.cs index 74fde38..e6b28f9 100644 --- a/MiraAPI/Events/Vanilla/Meeting/Voting/BeforeVoteEvent.cs +++ b/MiraAPI/Events/Vanilla/Meeting/Voting/BeforeVoteEvent.cs @@ -1,6 +1,4 @@ -using MiraAPI.Voting; - -namespace MiraAPI.Events.Vanilla.Meeting.Voting; +namespace MiraAPI.Events.Vanilla.Meeting.Voting; /// /// Event that is invoked before the local player confirms a vote on a player or when skipping. This event is cancelable. diff --git a/MiraAPI/GameEnd/GameOverManager.cs b/MiraAPI/GameEnd/GameOverManager.cs index eb39835..28d2f48 100644 --- a/MiraAPI/GameEnd/GameOverManager.cs +++ b/MiraAPI/GameEnd/GameOverManager.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using Reactor.Utilities; namespace MiraAPI.GameEnd; diff --git a/MiraAPI/GameModes/CustomGameModeManager.cs b/MiraAPI/GameModes/CustomGameModeManager.cs index 7e274c4..3edd028 100644 --- a/MiraAPI/GameModes/CustomGameModeManager.cs +++ b/MiraAPI/GameModes/CustomGameModeManager.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Reactor.Utilities; namespace MiraAPI.GameModes; diff --git a/MiraAPI/GameOptions/AbstractOptionGroup.cs b/MiraAPI/GameOptions/AbstractOptionGroup.cs index 5ee95c2..f8f0877 100644 --- a/MiraAPI/GameOptions/AbstractOptionGroup.cs +++ b/MiraAPI/GameOptions/AbstractOptionGroup.cs @@ -2,10 +2,8 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using Il2CppInterop.Runtime.Attributes; using MiraAPI.Modifiers; using MiraAPI.Roles; -using TMPro; using UnityEngine; namespace MiraAPI.GameOptions; diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs index 50457b6..4300c4f 100644 --- a/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs +++ b/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs @@ -1,11 +1,9 @@ using System; using BepInEx.Configuration; -using Il2CppInterop.Runtime.Attributes; using MiraAPI.Networking; using MiraAPI.PluginLoading; using Reactor.Localization.Utilities; using Reactor.Networking.Rpc; -using TMPro; using UnityEngine; namespace MiraAPI.GameOptions.OptionTypes; diff --git a/MiraAPI/Hud/CustomActionButton.cs b/MiraAPI/Hud/CustomActionButton.cs index f5cf521..4c5df0c 100644 --- a/MiraAPI/Hud/CustomActionButton.cs +++ b/MiraAPI/Hud/CustomActionButton.cs @@ -7,7 +7,6 @@ using MiraAPI.LocalSettings; using MiraAPI.Patches; using MiraAPI.Utilities; using MiraAPI.Utilities.Assets; -using Reactor.Utilities; using Rewired; using TMPro; using UnityEngine; diff --git a/MiraAPI/Hud/CustomButtonManager.cs b/MiraAPI/Hud/CustomButtonManager.cs index 5a1ba3b..70ca14b 100644 --- a/MiraAPI/Hud/CustomButtonManager.cs +++ b/MiraAPI/Hud/CustomButtonManager.cs @@ -4,7 +4,6 @@ using System.Collections.ObjectModel; using System.Reflection; using MiraAPI.Events.Mira; using MiraAPI.PluginLoading; -using UnityEngine; namespace MiraAPI.Hud; diff --git a/MiraAPI/Hud/MultiTargetButton.cs b/MiraAPI/Hud/MultiTargetButton.cs index 12458d4..d52d845 100644 --- a/MiraAPI/Hud/MultiTargetButton.cs +++ b/MiraAPI/Hud/MultiTargetButton.cs @@ -1,6 +1,5 @@ using System.Linq; using HarmonyLib; -using Reactor.Utilities.Extensions; using UnityEngine; namespace MiraAPI.Hud; diff --git a/MiraAPI/Keybinds/KeybindManager.cs b/MiraAPI/Keybinds/KeybindManager.cs index 207fab5..042322a 100644 --- a/MiraAPI/Keybinds/KeybindManager.cs +++ b/MiraAPI/Keybinds/KeybindManager.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using Il2CppInterop.Runtime.Attributes; using MiraAPI.Utilities; -using Reactor.Utilities; using Rewired; namespace MiraAPI.Keybinds; diff --git a/MiraAPI/Keybinds/VanillaKeybind.cs b/MiraAPI/Keybinds/VanillaKeybind.cs index 594e583..5f34288 100644 --- a/MiraAPI/Keybinds/VanillaKeybind.cs +++ b/MiraAPI/Keybinds/VanillaKeybind.cs @@ -1,5 +1,4 @@ using System.Globalization; -using Rewired; namespace MiraAPI.Keybinds; diff --git a/MiraAPI/LocalSettings/Attributes/LocalSettingsButtonAttribute.cs b/MiraAPI/LocalSettings/Attributes/LocalSettingsButtonAttribute.cs index 043a81d..83a3955 100644 --- a/MiraAPI/LocalSettings/Attributes/LocalSettingsButtonAttribute.cs +++ b/MiraAPI/LocalSettings/Attributes/LocalSettingsButtonAttribute.cs @@ -1,5 +1,4 @@ using System; -using BepInEx.Configuration; namespace MiraAPI.LocalSettings.Attributes; diff --git a/MiraAPI/LocalSettings/LocalSettingsButton.cs b/MiraAPI/LocalSettings/LocalSettingsButton.cs index 6f1fa57..5a1f371 100644 --- a/MiraAPI/LocalSettings/LocalSettingsButton.cs +++ b/MiraAPI/LocalSettings/LocalSettingsButton.cs @@ -1,6 +1,5 @@ using System; using MiraAPI.Utilities; -using Reactor.Localization.Utilities; using Reactor.Utilities.Extensions; using TMPro; using UnityEngine; diff --git a/MiraAPI/LocalSettings/LocalSettingsManager.cs b/MiraAPI/LocalSettings/LocalSettingsManager.cs index 2f6fc16..aa1c217 100644 --- a/MiraAPI/LocalSettings/LocalSettingsManager.cs +++ b/MiraAPI/LocalSettings/LocalSettingsManager.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.Reflection; using BepInEx.Unity.IL2CPP; -using MiraAPI.GameOptions; -using Reactor.Utilities; namespace MiraAPI.LocalSettings; diff --git a/MiraAPI/Modifiers/ModifierComponent.cs b/MiraAPI/Modifiers/ModifierComponent.cs index 09e411a..6432b18 100644 --- a/MiraAPI/Modifiers/ModifierComponent.cs +++ b/MiraAPI/Modifiers/ModifierComponent.cs @@ -8,7 +8,6 @@ using MiraAPI.LocalSettings; using MiraAPI.Modifiers.ModifierDisplay; using MiraAPI.Modifiers.Types; using MiraAPI.Patches.Roles; -using Reactor.Utilities; using Reactor.Utilities.Attributes; using UnityEngine; diff --git a/MiraAPI/Modifiers/ModifierDisplay/ModifierDisplayComponent.cs b/MiraAPI/Modifiers/ModifierDisplay/ModifierDisplayComponent.cs index 4b4c71e..e93f477 100644 --- a/MiraAPI/Modifiers/ModifierDisplay/ModifierDisplayComponent.cs +++ b/MiraAPI/Modifiers/ModifierDisplay/ModifierDisplayComponent.cs @@ -4,7 +4,6 @@ using System.Linq; using HarmonyLib; using Il2CppInterop.Runtime.Attributes; using MiraAPI.LocalSettings; -using MiraAPI.Utilities; using MiraAPI.Utilities.Assets; using Reactor.Utilities.Attributes; using Reactor.Utilities.Extensions; diff --git a/MiraAPI/Modifiers/ModifierExtensions.cs b/MiraAPI/Modifiers/ModifierExtensions.cs index 20f08be..e70a26a 100644 --- a/MiraAPI/Modifiers/ModifierExtensions.cs +++ b/MiraAPI/Modifiers/ModifierExtensions.cs @@ -5,7 +5,6 @@ using MiraAPI.Networking; using MiraAPI.Networking.Modifiers; using Reactor.Networking.Attributes; using Reactor.Networking.Rpc; -using Reactor.Utilities; namespace MiraAPI.Modifiers; diff --git a/MiraAPI/Modifiers/ModifierManager.cs b/MiraAPI/Modifiers/ModifierManager.cs index 877e43b..8d5621e 100644 --- a/MiraAPI/Modifiers/ModifierManager.cs +++ b/MiraAPI/Modifiers/ModifierManager.cs @@ -6,7 +6,6 @@ using MiraAPI.Modifiers.Types; using MiraAPI.PluginLoading; using MiraAPI.Roles; using MiraAPI.Utilities; -using Reactor.Utilities; using Reactor.Utilities.Extensions; using Random = System.Random; diff --git a/MiraAPI/Modifiers/Types/TimedModifier.cs b/MiraAPI/Modifiers/Types/TimedModifier.cs index 6fe1c1d..472b3cf 100644 --- a/MiraAPI/Modifiers/Types/TimedModifier.cs +++ b/MiraAPI/Modifiers/Types/TimedModifier.cs @@ -1,5 +1,4 @@ using System; -using Reactor.Utilities; using UnityEngine; namespace MiraAPI.Modifiers.Types; diff --git a/MiraAPI/Networking/CustomGameOverRpc.cs b/MiraAPI/Networking/CustomGameOverRpc.cs index f7df4a7..6475d6a 100644 --- a/MiraAPI/Networking/CustomGameOverRpc.cs +++ b/MiraAPI/Networking/CustomGameOverRpc.cs @@ -4,7 +4,6 @@ using InnerNet; using MiraAPI.GameEnd; using Reactor.Networking.Attributes; using Reactor.Networking.Rpc; -using Reactor.Utilities; namespace MiraAPI.Networking; diff --git a/MiraAPI/Networking/CustomMurderRpc.cs b/MiraAPI/Networking/CustomMurderRpc.cs index 9a6ff0b..7009819 100644 --- a/MiraAPI/Networking/CustomMurderRpc.cs +++ b/MiraAPI/Networking/CustomMurderRpc.cs @@ -10,9 +10,6 @@ using MiraAPI.Events.Vanilla.Gameplay; using MiraAPI.Utilities; using Reactor.Networking.Attributes; using Reactor.Networking.Rpc; -using Reactor.Utilities; -using Reactor.Utilities.Extensions; -using Rewired; using UnityEngine; using Object = UnityEngine.Object; diff --git a/MiraAPI/Patches/Events/ReportBodyEventPatch.cs b/MiraAPI/Patches/Events/ReportBodyEventPatch.cs index 305311e..3eb1c29 100644 --- a/MiraAPI/Patches/Events/ReportBodyEventPatch.cs +++ b/MiraAPI/Patches/Events/ReportBodyEventPatch.cs @@ -4,7 +4,6 @@ using InnerNet; using MiraAPI.Events; using MiraAPI.Events.Vanilla.Meeting; using MiraAPI.Utilities; -using Reactor.Utilities; namespace MiraAPI.Patches.Events; diff --git a/MiraAPI/Patches/Events/VanillaButtonPatches.cs b/MiraAPI/Patches/Events/VanillaButtonPatches.cs index 490e401..71df73f 100644 --- a/MiraAPI/Patches/Events/VanillaButtonPatches.cs +++ b/MiraAPI/Patches/Events/VanillaButtonPatches.cs @@ -1,9 +1,7 @@ -using System.Linq; -using AmongUs.GameOptions; +using AmongUs.GameOptions; using HarmonyLib; using MiraAPI.Events; using MiraAPI.Events.Vanilla.Gameplay; -using MiraAPI.Events.Vanilla.Usables; namespace MiraAPI.Patches.Events; diff --git a/MiraAPI/Patches/Hud/ButtonResetPatches.cs b/MiraAPI/Patches/Hud/ButtonResetPatches.cs index 5e46048..ab0dc32 100644 --- a/MiraAPI/Patches/Hud/ButtonResetPatches.cs +++ b/MiraAPI/Patches/Hud/ButtonResetPatches.cs @@ -1,6 +1,5 @@ using HarmonyLib; using MiraAPI.Hud; -using Reactor.Utilities; namespace MiraAPI.Patches.Hud; diff --git a/MiraAPI/Patches/IntroCutscenePatches.cs b/MiraAPI/Patches/IntroCutscenePatches.cs index 7d52287..4ee990c 100644 --- a/MiraAPI/Patches/IntroCutscenePatches.cs +++ b/MiraAPI/Patches/IntroCutscenePatches.cs @@ -1,12 +1,10 @@ -using System.Linq; -using System.Reflection; +using System.Reflection; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using MiraAPI.Events; using MiraAPI.Events.Vanilla.Gameplay; using MiraAPI.Roles; using MiraAPI.Utilities; -using Reactor.Utilities; namespace MiraAPI.Patches; diff --git a/MiraAPI/Patches/Keybinds/ControlMapperPatches.cs b/MiraAPI/Patches/Keybinds/ControlMapperPatches.cs index f0c51c0..6666a2c 100644 --- a/MiraAPI/Patches/Keybinds/ControlMapperPatches.cs +++ b/MiraAPI/Patches/Keybinds/ControlMapperPatches.cs @@ -1,13 +1,8 @@ using System.Linq; using HarmonyLib; using MiraAPI.Keybinds; -using MiraAPI.LocalSettings; -using Reactor.Utilities; -using Reactor.Utilities.Extensions; using Rewired.UI.ControlMapper; -using TMPro; using UnityEngine; -using UnityEngine.Events; using UnityEngine.UI; namespace MiraAPI.Patches.Keybinds; diff --git a/MiraAPI/Patches/Keybinds/KeybindsPatch.cs b/MiraAPI/Patches/Keybinds/KeybindsPatch.cs index c08a47f..9c1034f 100644 --- a/MiraAPI/Patches/Keybinds/KeybindsPatch.cs +++ b/MiraAPI/Patches/Keybinds/KeybindsPatch.cs @@ -1,6 +1,5 @@ using HarmonyLib; using MiraAPI.Keybinds; -using MonoMod.Utils; using Rewired; namespace MiraAPI.Patches.Keybinds; diff --git a/MiraAPI/Patches/LocalSettings/OptionsMenuPatches.cs b/MiraAPI/Patches/LocalSettings/OptionsMenuPatches.cs index ab8ed2c..10ab62d 100644 --- a/MiraAPI/Patches/LocalSettings/OptionsMenuPatches.cs +++ b/MiraAPI/Patches/LocalSettings/OptionsMenuPatches.cs @@ -3,7 +3,6 @@ using System.Linq; using HarmonyLib; using MiraAPI.LocalSettings; using MiraAPI.Utilities.Assets; -using Reactor.Utilities; using Reactor.Utilities.Extensions; using UnityEngine; using UnityEngine.Events; diff --git a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs index 3068a1b..b50b430 100644 --- a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs +++ b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs @@ -1,12 +1,8 @@ using System; using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; using System.Linq; -using AmongUs.GameOptions; using BepInEx.Unity.IL2CPP.Utils.Collections; using HarmonyLib; -using Il2CppInterop.Runtime.Attributes; using MiraAPI.GameOptions; using MiraAPI.Modifiers; using MiraAPI.Presets; diff --git a/MiraAPI/Patches/Options/GamePresetsTabPatches.cs b/MiraAPI/Patches/Options/GamePresetsTabPatches.cs index 2c6cc68..ff75606 100644 --- a/MiraAPI/Patches/Options/GamePresetsTabPatches.cs +++ b/MiraAPI/Patches/Options/GamePresetsTabPatches.cs @@ -8,7 +8,6 @@ using MiraAPI.Presets; using MiraAPI.Roles; using MiraAPI.Utilities; using MiraAPI.Utilities.Assets; -using Reactor.Utilities; using Reactor.Utilities.Extensions; using TMPro; using UnityEngine; diff --git a/MiraAPI/Patches/Options/NotificationPopperPatch.cs b/MiraAPI/Patches/Options/NotificationPopperPatch.cs index 349f103..8024ea4 100644 --- a/MiraAPI/Patches/Options/NotificationPopperPatch.cs +++ b/MiraAPI/Patches/Options/NotificationPopperPatch.cs @@ -1,8 +1,6 @@ using System.Linq; using HarmonyLib; -using Il2CppSystem; using MiraAPI.Roles; -using Object = Il2CppSystem.Object; namespace MiraAPI.Patches.Options; diff --git a/MiraAPI/Patches/Options/OptionsPatches.cs b/MiraAPI/Patches/Options/OptionsPatches.cs index 0f99691..36651f9 100644 --- a/MiraAPI/Patches/Options/OptionsPatches.cs +++ b/MiraAPI/Patches/Options/OptionsPatches.cs @@ -1,9 +1,6 @@ -using System.Collections.Generic; -using System.Linq; -using HarmonyLib; +using HarmonyLib; using Il2CppSystem; using MiraAPI.GameOptions; -using MiraAPI.GameOptions.OptionTypes; using MiraAPI.Roles; using MiraAPI.Utilities; using UnityEngine; diff --git a/MiraAPI/Patches/Options/PlayerOptionPatches.cs b/MiraAPI/Patches/Options/PlayerOptionPatches.cs index 2b77bc1..9cf0134 100644 --- a/MiraAPI/Patches/Options/PlayerOptionPatches.cs +++ b/MiraAPI/Patches/Options/PlayerOptionPatches.cs @@ -1,12 +1,8 @@ -using System; -using System.Linq; +using System.Linq; using HarmonyLib; using MiraAPI.GameOptions; -using MiraAPI.GameOptions.OptionTypes; using MiraAPI.Utilities; -using Reactor.Utilities; using UnityEngine; -using Object = Il2CppSystem.Object; namespace MiraAPI.Patches.Options; diff --git a/MiraAPI/Patches/PlayerControlPatches.cs b/MiraAPI/Patches/PlayerControlPatches.cs index 3c851b0..77b83c2 100644 --- a/MiraAPI/Patches/PlayerControlPatches.cs +++ b/MiraAPI/Patches/PlayerControlPatches.cs @@ -8,7 +8,6 @@ using MiraAPI.Hud; using MiraAPI.Modifiers; using MiraAPI.Utilities; using MiraAPI.Voting; -using Reactor.Utilities; using Reactor.Utilities.Extensions; namespace MiraAPI.Patches; diff --git a/MiraAPI/Patches/Roles/HowToPlayPatch.cs b/MiraAPI/Patches/Roles/HowToPlayPatch.cs index ee6e5ff..c7cc2e5 100644 --- a/MiraAPI/Patches/Roles/HowToPlayPatch.cs +++ b/MiraAPI/Patches/Roles/HowToPlayPatch.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Linq; +using System.Linq; using AmongUs.GameOptions; using HarmonyLib; using MiraAPI.Roles; diff --git a/MiraAPI/Patches/Roles/HudManagerPatches.cs b/MiraAPI/Patches/Roles/HudManagerPatches.cs index 6827341..3de9b71 100644 --- a/MiraAPI/Patches/Roles/HudManagerPatches.cs +++ b/MiraAPI/Patches/Roles/HudManagerPatches.cs @@ -1,9 +1,7 @@ using HarmonyLib; using InnerNet; using MiraAPI.Roles; -using MiraAPI.Utilities; using Reactor.Utilities.Extensions; -using UnityEngine; namespace MiraAPI.Patches.Roles; diff --git a/MiraAPI/Patches/Roles/RoleManagerPatches.cs b/MiraAPI/Patches/Roles/RoleManagerPatches.cs index 713ffdf..8d13595 100644 --- a/MiraAPI/Patches/Roles/RoleManagerPatches.cs +++ b/MiraAPI/Patches/Roles/RoleManagerPatches.cs @@ -1,7 +1,6 @@ using System.Linq; using AmongUs.GameOptions; using HarmonyLib; -using InnerNet; using MiraAPI.Events; using MiraAPI.Events.Vanilla.Gameplay; using MiraAPI.Modifiers; diff --git a/MiraAPI/Patches/Roles/RoleOptionsCollectionPatch.cs b/MiraAPI/Patches/Roles/RoleOptionsCollectionPatch.cs index ff57b37..d4d80d3 100644 --- a/MiraAPI/Patches/Roles/RoleOptionsCollectionPatch.cs +++ b/MiraAPI/Patches/Roles/RoleOptionsCollectionPatch.cs @@ -2,7 +2,6 @@ using HarmonyLib; using Il2CppSystem.Collections.Generic; using MiraAPI.Roles; -using Reactor.Utilities; namespace MiraAPI.Patches.Roles; diff --git a/MiraAPI/Patches/ServerDropdownPatch.cs b/MiraAPI/Patches/ServerDropdownPatch.cs index 6ff7e68..7749c9b 100644 --- a/MiraAPI/Patches/ServerDropdownPatch.cs +++ b/MiraAPI/Patches/ServerDropdownPatch.cs @@ -1,6 +1,5 @@ using System.Linq; using HarmonyLib; -using Reactor.Utilities; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; diff --git a/MiraAPI/Patches/TmpAwakePatch.cs b/MiraAPI/Patches/TmpAwakePatch.cs index 2d43d23..9405e01 100644 --- a/MiraAPI/Patches/TmpAwakePatch.cs +++ b/MiraAPI/Patches/TmpAwakePatch.cs @@ -1,4 +1,3 @@ -using System.Linq; using HarmonyLib; using MiraAPI.Utilities.Assets; using TMPro; diff --git a/MiraAPI/Patches/Voting/DummyBehaviourPatch.cs b/MiraAPI/Patches/Voting/DummyBehaviourPatch.cs index 9e5c8a4..1d8c1e9 100644 --- a/MiraAPI/Patches/Voting/DummyBehaviourPatch.cs +++ b/MiraAPI/Patches/Voting/DummyBehaviourPatch.cs @@ -7,7 +7,6 @@ using MiraAPI.Events; using MiraAPI.Events.Vanilla.Meeting.Voting; using MiraAPI.Utilities; using MiraAPI.Voting; -using Reactor.Utilities; using Reactor.Utilities.Extensions; using UnityEngine; diff --git a/MiraAPI/PluginLoading/MiraPluginInfo.cs b/MiraAPI/PluginLoading/MiraPluginInfo.cs index 0df7cb5..db030b0 100644 --- a/MiraAPI/PluginLoading/MiraPluginInfo.cs +++ b/MiraAPI/PluginLoading/MiraPluginInfo.cs @@ -5,7 +5,6 @@ using BepInEx.Configuration; using MiraAPI.GameModes; using MiraAPI.GameOptions; using MiraAPI.Hud; -using MiraAPI.LocalSettings; using MiraAPI.Modifiers; using MiraAPI.Presets; diff --git a/MiraAPI/Presets/PresetManager.cs b/MiraAPI/Presets/PresetManager.cs index d346c52..f753db5 100644 --- a/MiraAPI/Presets/PresetManager.cs +++ b/MiraAPI/Presets/PresetManager.cs @@ -4,8 +4,6 @@ using System.Linq; using BepInEx.Configuration; using MiraAPI.PluginLoading; using MiraAPI.Roles; -using MiraAPI.Utilities; -using Reactor.Utilities; using Reactor.Utilities.Extensions; using UnityEngine; diff --git a/MiraAPI/Roles/CustomRoleManager.cs b/MiraAPI/Roles/CustomRoleManager.cs index 9e6540f..d85ed19 100644 --- a/MiraAPI/Roles/CustomRoleManager.cs +++ b/MiraAPI/Roles/CustomRoleManager.cs @@ -11,7 +11,6 @@ using MiraAPI.Utilities; using MiraAPI.Utilities.Assets; using Reactor.Localization.Utilities; using Reactor.Networking.Rpc; -using Reactor.Utilities; using Reactor.Utilities.Extensions; using TMPro; using UnityEngine; diff --git a/MiraAPI/Roles/ICustomRole.cs b/MiraAPI/Roles/ICustomRole.cs index 1915949..c0c97be 100644 --- a/MiraAPI/Roles/ICustomRole.cs +++ b/MiraAPI/Roles/ICustomRole.cs @@ -4,8 +4,6 @@ using BepInEx.Configuration; using MiraAPI.GameOptions; using MiraAPI.Modifiers; using MiraAPI.PluginLoading; -using Reactor.Utilities; -using TMPro; using UnityEngine; namespace MiraAPI.Roles; diff --git a/MiraAPI/Utilities/Assets/LoadableAddressableAsset.cs b/MiraAPI/Utilities/Assets/LoadableAddressableAsset.cs index b9e8c55..144f608 100644 --- a/MiraAPI/Utilities/Assets/LoadableAddressableAsset.cs +++ b/MiraAPI/Utilities/Assets/LoadableAddressableAsset.cs @@ -1,5 +1,4 @@ using System; -using Reactor.Utilities; using UnityEngine.AddressableAssets; namespace MiraAPI.Utilities.Assets; diff --git a/MiraAPI/Utilities/Assets/LoadableAddressableAssets.cs b/MiraAPI/Utilities/Assets/LoadableAddressableAssets.cs index 9cabf83..c70100a 100644 --- a/MiraAPI/Utilities/Assets/LoadableAddressableAssets.cs +++ b/MiraAPI/Utilities/Assets/LoadableAddressableAssets.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using Reactor.Utilities; using UnityEngine.AddressableAssets; namespace MiraAPI.Utilities.Assets; diff --git a/MiraAPI/Utilities/Extensions.cs b/MiraAPI/Utilities/Extensions.cs index c4b9ef3..a16d1e1 100644 --- a/MiraAPI/Utilities/Extensions.cs +++ b/MiraAPI/Utilities/Extensions.cs @@ -6,14 +6,11 @@ using System.Globalization; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; -using System.Timers; using HarmonyLib; using MiraAPI.GameOptions; using MiraAPI.Networking; -using MiraAPI.Patches.Menu; using MiraAPI.Roles; using MiraAPI.Voting; -using Reactor.Utilities; using Reactor.Utilities.Extensions; using Rewired; using Rewired.Data; diff --git a/MiraAPI/Utilities/Helpers.cs b/MiraAPI/Utilities/Helpers.cs index c089e40..9f66817 100644 --- a/MiraAPI/Utilities/Helpers.cs +++ b/MiraAPI/Utilities/Helpers.cs @@ -2,12 +2,10 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using AmongUs.GameOptions; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes.Arrays; using MiraAPI.Roles; using MiraAPI.Utilities.Assets; -using Reactor.Utilities; using Rewired; using TMPro; using UnityEngine; diff --git a/MiraAPI/Voting/VotingUtils.cs b/MiraAPI/Voting/VotingUtils.cs index 130e4c4..fb117e4 100644 --- a/MiraAPI/Voting/VotingUtils.cs +++ b/MiraAPI/Voting/VotingUtils.cs @@ -5,7 +5,6 @@ using MiraAPI.Events.Vanilla.Meeting.Voting; using MiraAPI.Networking; using MiraAPI.Utilities; using Reactor.Networking.Attributes; -using Reactor.Utilities; namespace MiraAPI.Voting; From 0a0ad7441955a3928afb9fc7993d8db0950cde44 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Mon, 20 Jul 2026 20:02:29 -0400 Subject: [PATCH 4/5] improve GC collection --- MiraAPI/Utilities/Extensions.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MiraAPI/Utilities/Extensions.cs b/MiraAPI/Utilities/Extensions.cs index a16d1e1..9dd91e9 100644 --- a/MiraAPI/Utilities/Extensions.cs +++ b/MiraAPI/Utilities/Extensions.cs @@ -366,7 +366,8 @@ public static class Extensions public static void ClearGarbageCollector() { Resources.UnloadUnusedAssets(); - GC.Collect(); + Il2CppSystem.GC.Collect(0, Il2CppSystem.GCCollectionMode.Forced); + GC.Collect(0, GCCollectionMode.Forced); } /// From 1b40b1c5e43bb3a410078fbbd525c6be5521bbbe Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Mon, 20 Jul 2026 20:23:38 -0400 Subject: [PATCH 5/5] attempt to improve gc behavior --- MiraAPI/Patches/Options/GameSettingMenuPatches.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MiraAPI/Patches/Options/GameSettingMenuPatches.cs b/MiraAPI/Patches/Options/GameSettingMenuPatches.cs index 6e12c61..995da8e 100644 --- a/MiraAPI/Patches/Options/GameSettingMenuPatches.cs +++ b/MiraAPI/Patches/Options/GameSettingMenuPatches.cs @@ -419,6 +419,8 @@ internal static class GameSettingMenuPatches _customTwoButton!.transform.localPosition = _customTwoBtnOgPos; menu.RoleSettingsButton.transform.localPosition = _roleBtnOgPos; + CleanupTab(settings, roles); + if (SelectedModIdx != 0) { _customOneButton.buttonText.text = SelectedMod!.MiraPlugin.CustomOptionMenuNameOne; @@ -560,8 +562,6 @@ internal static class GameSettingMenuPatches { menu.ChangeTab(0, false); } - - CleanupTab(settings, roles); } private static void ClearOptions(Il2CppSystem.Collections.Generic.List options) @@ -606,6 +606,8 @@ internal static class GameSettingMenuPatches CleanupSettings(_customTwoTab, MenuCategory.CustomTwo); } + Utilities.Extensions.ClearGarbageCollector(); + void CleanupRoleSettings(RolesSettingsMenu rolesMenu) { if (rolesMenu.advancedSettingChildren != null)