From ba0ee49255658f017b3fa97057e921f4f4c97fe5 Mon Sep 17 00:00:00 2001 From: Atony <75191600+AtonyGit@users.noreply.github.com> Date: Mon, 19 Jan 2026 20:10:21 -0600 Subject: [PATCH] Add reset button for game options --- .../Patches/Options/GameOptionsMenuPatch.cs | 103 ++++++++++++++++-- MiraAPI/Presets/OptionPreset.cs | 22 ++++ MiraAPI/Presets/PresetManager.cs | 2 + MiraAPI/Resources/ResetButton.png | Bin 0 -> 3195 bytes MiraAPI/Utilities/Assets/MiraAssets.cs | 5 + 5 files changed, 120 insertions(+), 12 deletions(-) create mode 100644 MiraAPI/Resources/ResetButton.png diff --git a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs index fd6704e..dee3fa3 100644 --- a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs +++ b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs @@ -1,8 +1,11 @@ using System; using System.Linq; +using AmongUs.GameOptions; using HarmonyLib; +using Il2CppInterop.Runtime.Attributes; using MiraAPI.GameOptions; using MiraAPI.Modifiers; +using MiraAPI.Presets; using MiraAPI.Utilities; using MiraAPI.Utilities.Assets; using Reactor.Localization.Utilities; @@ -10,6 +13,7 @@ using Reactor.Utilities.Extensions; using TMPro; using UnityEngine; using UnityEngine.Events; +using UnityEngine.UI; using Object = UnityEngine.Object; namespace MiraAPI.Patches.Options; @@ -23,6 +27,7 @@ internal static class GameOptionsMenuPatch { HudManager.Instance.PlayerCam.OverrideScreenShakeEnabled = false; } + [HarmonyPostfix] [HarmonyPatch(nameof(GameOptionsMenu.OnDisable))] public static void ClosePatch(GameOptionsMenu __instance) @@ -166,7 +171,7 @@ internal static class GameOptionsMenuPatch private static void ModifiersUpdate(ref float num) { var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups - .Where(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true) ?? []; + .Where(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true) ?? []; foreach (var modGroup in groups) { @@ -177,7 +182,7 @@ internal static class GameOptionsMenuPatch private static void ModifiersCreate(GameOptionsMenu menu) { var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups - .Where(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true) ?? []; + .Where(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true) ?? []; foreach (var group in groups) { CreateGroup(menu, group); @@ -270,7 +275,9 @@ internal static class GameOptionsMenuPatch categoryHeaderMasked.SetHeader(CustomStringName.CreateAndRegister(group.GroupName), 20); categoryHeaderMasked.Background.color = group.GroupColor; categoryHeaderMasked.Divider.color = group.GroupColor; - categoryHeaderMasked.Title.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor) ? Color.white : group.GroupColor.FindAlternateColor(); + categoryHeaderMasked.Title.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor) + ? Color.white + : group.GroupColor.FindAlternateColor(); categoryHeaderMasked.Background.sprite = MiraAssets.CategoryHeader.LoadAsset(); categoryHeaderMasked.Background.sprite.texture.filterMode = FilterMode.Bilinear; @@ -289,13 +296,20 @@ internal static class GameOptionsMenuPatch newText.transform.localPosition = new Vector3(2.6249f, -0.165f, 0f); newText.gameObject.GetComponent().Destroy(); - var options = group.Options.Select( - opt => opt.CreateOption( - menu.checkboxOrigin, - menu.numberOptionOrigin, - menu.stringOptionOrigin, - menu.playerOptionOrigin, - menu.settingsContainer)); + var options = group.Options.Select(opt => opt.CreateOption( + menu.checkboxOrigin, + menu.numberOptionOrigin, + menu.stringOptionOrigin, + menu.playerOptionOrigin, + menu.settingsContainer)); + + OptionPreset? defaultPreset = null; + if (GameSettingMenuPatches.SelectedMod != null && PresetManager.DefaultPresets.TryGetValue( + GameSettingMenuPatches.SelectedMod, + out var preset)) + { + defaultPreset = preset; + } foreach (var newOpt in options) { @@ -331,14 +345,79 @@ internal static class GameOptionsMenuPatch if (newOpt is ToggleOption toggle) { toggle.CheckMark.sprite = MiraAssets.Checkmark.LoadAsset(); - toggle.CheckMark.color = group.GroupColor != MiraApiPlugin.DefaultHeaderColor ? group.GroupColor : MiraAssets.AcceptedTeal; + 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; + 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)(() => + { + 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); diff --git a/MiraAPI/Presets/OptionPreset.cs b/MiraAPI/Presets/OptionPreset.cs index 06e3f8a..89786e4 100644 --- a/MiraAPI/Presets/OptionPreset.cs +++ b/MiraAPI/Presets/OptionPreset.cs @@ -71,4 +71,26 @@ public class OptionPreset CustomRoleManager.SyncAllRoleSettings(); } + + /// + /// Resets the specified option with the preset provided. + /// + public void ResetOption(OptionBehaviour baseOption) + { + var selectedOpt = Plugin.InternalOptions.First(x => x.OptionBehaviour == baseOption); + selectedOpt.LoadFromPreset(PresetConfig); + /*ModdedOptionsManager.SyncAllOptions(); + + CustomRoleManager.SyncAllRoleSettings();*/ + } + + /// + /// Gets whether the specified option is included in the preset. + /// + /// >The value of whether the option is in the preset. + public bool IsOptionInPreset(OptionBehaviour baseOption) + { + var selectedOpt = Plugin.InternalOptions.First(x => x.OptionBehaviour == baseOption); + return selectedOpt.ConfigDefinition != null && PresetConfig.ContainsKey(selectedOpt.ConfigDefinition); + } } diff --git a/MiraAPI/Presets/PresetManager.cs b/MiraAPI/Presets/PresetManager.cs index 9204e42..ba4289f 100644 --- a/MiraAPI/Presets/PresetManager.cs +++ b/MiraAPI/Presets/PresetManager.cs @@ -19,6 +19,7 @@ public static class PresetManager /// public static string PresetDirectory { get; } = Path.GetFullPath("mira_presets", Application.persistentDataPath); + internal static Dictionary DefaultPresets { get; } = []; internal static List InternalMasterPresets { get; } = []; /// @@ -47,6 +48,7 @@ public static class PresetManager } presetConfig.Save(); + DefaultPresets.Add(plugin, new OptionPreset("Default", plugin, presetConfig)); } /// diff --git a/MiraAPI/Resources/ResetButton.png b/MiraAPI/Resources/ResetButton.png new file mode 100644 index 0000000000000000000000000000000000000000..9856c85f0d59c5a5f2465a2101ac20da8104b689 GIT binary patch literal 3195 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 literal 0 HcmV?d00001 diff --git a/MiraAPI/Utilities/Assets/MiraAssets.cs b/MiraAPI/Utilities/Assets/MiraAssets.cs index bccb204..bb91416 100644 --- a/MiraAPI/Utilities/Assets/MiraAssets.cs +++ b/MiraAPI/Utilities/Assets/MiraAssets.cs @@ -90,6 +90,11 @@ public static class MiraAssets /// public static LoadableResourceAsset CheckmarkBox { get; } = new("MiraAPI.Resources.CheckMarkBox.png"); + /// + /// Gets the Reset Box used in the Settings Menu. + /// + public static LoadableResourceAsset ResetButton { get; } = new("MiraAPI.Resources.ResetButton.png"); + /// /// Gets the Checkmark used in the Settings Menu. ///