From 5cccc192b1b43539c95b1e0e87df4233b4dc3026 Mon Sep 17 00:00:00 2001 From: Atony <75191600+AtonyGit@users.noreply.github.com> Date: Fri, 17 Jul 2026 15:07:40 -0500 Subject: [PATCH] Add support for better option notfs --- .../Options/Roles/FreezerRoleSettings.cs | 8 +++ MiraAPI/GameOptions/AbstractOptionGroup.cs | 7 +++ MiraAPI/GameOptions/IModdedOption.cs | 10 ++++ MiraAPI/GameOptions/ModdedOptionsManager.cs | 33 ++++++++++++ .../GameOptions/OptionNotifConfiguration.cs | 53 +++++++++++++++++++ .../OptionTypes/ModdedEnumOption.cs | 16 +++++- .../OptionTypes/ModdedNumberOption.cs | 7 ++- .../GameOptions/OptionTypes/ModdedOption.cs | 9 +++- .../OptionTypes/ModdedPlayerOption.cs | 8 ++- .../OptionTypes/ModdedToggleOption.cs | 8 ++- .../Options/NotificationPopperPatch.cs | 2 +- 11 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 MiraAPI/GameOptions/OptionNotifConfiguration.cs diff --git a/MiraAPI.Example/Options/Roles/FreezerRoleSettings.cs b/MiraAPI.Example/Options/Roles/FreezerRoleSettings.cs index 1473068..1be3649 100644 --- a/MiraAPI.Example/Options/Roles/FreezerRoleSettings.cs +++ b/MiraAPI.Example/Options/Roles/FreezerRoleSettings.cs @@ -2,11 +2,19 @@ using MiraAPI.GameOptions; using MiraAPI.GameOptions.Attributes; using MiraAPI.Utilities; +using MiraAPI.Utilities.Assets; +using TMPro; +using UnityEngine; namespace MiraAPI.Example.Options.Roles; public class FreezerRoleSettings : AbstractOptionGroup { + public override OptionNotifConfiguration Configuration => new( + Palette.Blue, + TmpSpriteUtils.CreateSpriteAsset( + MiraAssets.ImpostorFile.LoadAsset(), + "ApiExample.Role.Impostor.FreezerRole")); public override string GroupName => "Custom Role"; [ModdedNumberOption("Freeze Duration", 1, 15, 1, MiraNumberSuffixes.Seconds)] diff --git a/MiraAPI/GameOptions/AbstractOptionGroup.cs b/MiraAPI/GameOptions/AbstractOptionGroup.cs index cb82e1c..07d008a 100644 --- a/MiraAPI/GameOptions/AbstractOptionGroup.cs +++ b/MiraAPI/GameOptions/AbstractOptionGroup.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using Il2CppInterop.Runtime.Attributes; using MiraAPI.Modifiers; +using TMPro; using UnityEngine; namespace MiraAPI.GameOptions; @@ -58,6 +60,11 @@ public abstract class AbstractOptionGroup /// public virtual uint GroupPriority => uint.MaxValue; + /// + /// Gets the default notification settings for the group. + /// + public virtual OptionNotifConfiguration Configuration => new(new Color(0.7333f, 0.7333f, 0.7333f, 1)); + internal bool AllOptionsHidden { get; set; } internal CategoryHeaderMasked? Header { get; set; } diff --git a/MiraAPI/GameOptions/IModdedOption.cs b/MiraAPI/GameOptions/IModdedOption.cs index 907ab7d..646c22b 100644 --- a/MiraAPI/GameOptions/IModdedOption.cs +++ b/MiraAPI/GameOptions/IModdedOption.cs @@ -21,6 +21,16 @@ public interface IModdedOption /// string Title { get; set; } + /// + /// Gets or sets the parent of the option. + /// + AbstractOptionGroup ParentGroup { get; set; } + + /// + /// Gets the notification settings for the option. + /// + OptionNotifConfiguration Configuration { get; } + /// /// Gets the for the option, used for localization. /// diff --git a/MiraAPI/GameOptions/ModdedOptionsManager.cs b/MiraAPI/GameOptions/ModdedOptionsManager.cs index 3e6e04e..7dd26ee 100644 --- a/MiraAPI/GameOptions/ModdedOptionsManager.cs +++ b/MiraAPI/GameOptions/ModdedOptionsManager.cs @@ -12,6 +12,8 @@ using MiraAPI.PluginLoading; using MiraAPI.Utilities; using Reactor.Networking.Rpc; using Reactor.Utilities; +using TMPro; +using UnityEngine; namespace MiraAPI.GameOptions; @@ -30,6 +32,36 @@ public static class ModdedOptionsManager internal static uint NextId => _nextId++; private static uint _nextId = 1; + public static void AddSettingsChangeMessage(NotificationPopper notif, StringNames key, string value, Color textColor, TMP_SpriteAsset? sprite, bool playSound = true) + { + var item = string.Empty; + var text = textColor.ToTextColor(); + if (sprite != null) + { + item = TranslationController.Instance.GetString( + StringNames.LobbyChangeSettingNotification, + string.Concat( + "", + text, + TranslationController.Instance.GetString(key), + ""), + "" + value + "" + ); + } + else + { + item = TranslationController.Instance.GetString( + StringNames.LobbyChangeSettingNotification, + "" + + text + + TranslationController.Instance.GetString(key) + "", + "" + value + ""); + } + notif.SettingsChangeMessageLogic(key, item, playSound); + } + internal static bool RegisterGroup(Type type, MiraPluginInfo pluginInfo) { if (Activator.CreateInstance(type) is not AbstractOptionGroup group) @@ -123,6 +155,7 @@ public static class ModdedOptionsManager option.ConfigDefinition = new ConfigDefinition(groupName, propertyName); + option.ParentGroup = group; option.ParentMod = pluginInfo.MiraPlugin; pluginInfo.InternalOptions.Add(option); ModdedOptions.Add(option.Id, option); diff --git a/MiraAPI/GameOptions/OptionNotifConfiguration.cs b/MiraAPI/GameOptions/OptionNotifConfiguration.cs new file mode 100644 index 0000000..e16106f --- /dev/null +++ b/MiraAPI/GameOptions/OptionNotifConfiguration.cs @@ -0,0 +1,53 @@ +using System; +using Il2CppInterop.Runtime.Attributes; +using TMPro; +using UnityEngine; +namespace MiraAPI.GameOptions; + +/// +/// Used to configure the specific visuals for option notifications. +/// +public record struct OptionNotifConfiguration +{ +#pragma warning disable S1133 + [Obsolete("Default constructor is not supported")] +#pragma warning restore S1133 +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + public OptionNotifConfiguration() +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + { + throw new NotImplementedException("Default constructor is not supported."); + } + + /// + /// Initializes a new instance of the struct based on a group. + /// + /// The in which you are configuring. + public OptionNotifConfiguration(AbstractOptionGroup group) + { + PopUpIconTmp = group.Configuration.PopUpIconTmp; + PopUpTextColor = group.Configuration.PopUpTextColor; + } + + /// + /// Initializes a new instance of the struct from scratch. + /// + /// The text for the configuration. + /// The icon for the configuration. + public OptionNotifConfiguration(Color color, TMP_SpriteAsset asset = null!) + { + PopUpIconTmp = asset; + PopUpTextColor = color; + } + + /// + /// Gets or sets the for the icon on the options pop-up. + /// + public TMP_SpriteAsset PopUpIconTmp { get; set; } + + /// + /// Gets or sets the for the text on the options pop-up. + /// + [HideFromIl2Cpp] + public Color PopUpTextColor { get; set; } +} diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs index 1f92418..30809bd 100644 --- a/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs +++ b/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs @@ -90,7 +90,13 @@ public class ModdedEnumOption : ModdedOption /// protected override void OnValueChanged(int newValue) { - HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(newValue), false); + ModdedOptionsManager.AddSettingsChangeMessage( + HudManager.Instance.Notifier, + StringName, + Data.GetValueString(newValue), + Configuration.PopUpTextColor, + Configuration.PopUpIconTmp, + false); if (!OptionBehaviour) { return; @@ -183,7 +189,13 @@ public class ModdedEnumOption : ModdedOption where T : Enum /// protected override void OnValueChanged(T newValue) { - HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(Convert.ToInt32(newValue, NumberFormatInfo.InvariantInfo)), false); + ModdedOptionsManager.AddSettingsChangeMessage( + HudManager.Instance.Notifier, + StringName, + Data.GetValueString(Convert.ToInt32(newValue, NumberFormatInfo.InvariantInfo)), + Configuration.PopUpTextColor, + Configuration.PopUpIconTmp, + false); if (!OptionBehaviour) { return; diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedNumberOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedNumberOption.cs index 1a5ef33..87f4ca9 100644 --- a/MiraAPI/GameOptions/OptionTypes/ModdedNumberOption.cs +++ b/MiraAPI/GameOptions/OptionTypes/ModdedNumberOption.cs @@ -225,9 +225,12 @@ public class ModdedNumberOption : ModdedOption protected override void OnValueChanged(float newValue) { Value = Mathf.Clamp(newValue, Min, Max); - HudManager.Instance.Notifier.AddSettingsChangeMessage( + ModdedOptionsManager.AddSettingsChangeMessage( + HudManager.Instance.Notifier, StringName, - Data.GetValueString(Value), + Data.GetValueString(newValue), + Configuration.PopUpTextColor, + Configuration.PopUpIconTmp, false); if (OptionBehaviour is NumberOption opt) diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs index 206894d..a023bac 100644 --- a/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs +++ b/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs @@ -1,10 +1,11 @@ using System; using BepInEx.Configuration; +using Il2CppInterop.Runtime.Attributes; using MiraAPI.Networking; using MiraAPI.PluginLoading; using Reactor.Localization.Utilities; using Reactor.Networking.Rpc; -using Reactor.Utilities; +using TMPro; using UnityEngine; namespace MiraAPI.GameOptions.OptionTypes; @@ -190,4 +191,10 @@ public abstract class ModdedOption : IModdedOption { return option.Value; } + + /// + public AbstractOptionGroup ParentGroup { get; set; } + + /// + public OptionNotifConfiguration Configuration => new(ParentGroup); } diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedPlayerOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedPlayerOption.cs index f6516cd..db397bd 100644 --- a/MiraAPI/GameOptions/OptionTypes/ModdedPlayerOption.cs +++ b/MiraAPI/GameOptions/OptionTypes/ModdedPlayerOption.cs @@ -126,7 +126,13 @@ public class ModdedPlayerOption : ModdedOption /// protected override void OnValueChanged(int newValue) { - HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(newValue), false); + ModdedOptionsManager.AddSettingsChangeMessage( + HudManager.Instance.Notifier, + StringName, + Data.GetValueString(newValue), + Configuration.PopUpTextColor, + Configuration.PopUpIconTmp, + false); if (!OptionBehaviour) { return; diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedToggleOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedToggleOption.cs index 0b13f97..55b69b9 100644 --- a/MiraAPI/GameOptions/OptionTypes/ModdedToggleOption.cs +++ b/MiraAPI/GameOptions/OptionTypes/ModdedToggleOption.cs @@ -71,7 +71,13 @@ public class ModdedToggleOption : ModdedOption /// protected override void OnValueChanged(bool newValue) { - HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, newValue ? "On" : "Off", false); + ModdedOptionsManager.AddSettingsChangeMessage( + HudManager.Instance.Notifier, + StringName, + newValue ? "On" : "Off", + Configuration.PopUpTextColor, + Configuration.PopUpIconTmp, + false); if (!OptionBehaviour) { return; diff --git a/MiraAPI/Patches/Options/NotificationPopperPatch.cs b/MiraAPI/Patches/Options/NotificationPopperPatch.cs index 0ba8605..349f103 100644 --- a/MiraAPI/Patches/Options/NotificationPopperPatch.cs +++ b/MiraAPI/Patches/Options/NotificationPopperPatch.cs @@ -33,7 +33,7 @@ public static class NotificationPopperPatch icon, "", textColor, - TranslationController.Instance.GetString(key, Array.Empty()), + TranslationController.Instance.GetString(key), "" ), "" + roleCount + "",