diff --git a/MiraAPI/GameOptions/IModdedOption.cs b/MiraAPI/GameOptions/IModdedOption.cs
index e002912..ecffc1a 100644
--- a/MiraAPI/GameOptions/IModdedOption.cs
+++ b/MiraAPI/GameOptions/IModdedOption.cs
@@ -83,4 +83,11 @@ public interface IModdedOption
///
/// >The byte array representing the network data.
void HandleNetData(byte[] data);
+
+ ///
+ /// Saves the option to a preset configuration file.
+ ///
+ /// The ConfigFile representing the preset configuration.
+ /// Indicates whether to save the default value instead of the current value.
+ void SaveToPreset(ConfigFile presetConfig, bool saveDefault = false);
}
diff --git a/MiraAPI/GameOptions/ModdedOptionsManager.cs b/MiraAPI/GameOptions/ModdedOptionsManager.cs
index 7aaa154..4f7c583 100644
--- a/MiraAPI/GameOptions/ModdedOptionsManager.cs
+++ b/MiraAPI/GameOptions/ModdedOptionsManager.cs
@@ -42,7 +42,7 @@ public static class ModdedOptionsManager
Groups.Add(group);
TypeToGroup.Add(type, group);
- pluginInfo.OptionGroups.Add(group);
+ pluginInfo.InternalOptionGroups.Add(group);
typeof(OptionGroupSingleton<>).MakeGenericType(type)
.GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)!
@@ -119,7 +119,7 @@ public static class ModdedOptionsManager
option.ConfigDefinition = new ConfigDefinition(groupName, propertyName);
option.ParentMod = pluginInfo.MiraPlugin;
- pluginInfo.Options.Add(option);
+ pluginInfo.InternalOptions.Add(option);
ModdedOptions.Add(option.Id, option);
group.Options.Add(option);
}
@@ -140,7 +140,7 @@ public static class ModdedOptionsManager
// we dont know how other plugins handle their configs
// this way, all the options are saved at once, instead of one by one
var oldConfigSetting = new Dictionary();
- foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins())
+ foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins)
{
oldConfigSetting.Add(plugin, plugin.PluginConfig.SaveOnConfigSet);
plugin.PluginConfig.SaveOnConfigSet = false;
@@ -156,7 +156,7 @@ public static class ModdedOptionsManager
option.HandleNetData(netData.Data);
}
- foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins())
+ foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins)
{
plugin.PluginConfig.Save();
plugin.PluginConfig.SaveOnConfigSet = oldConfigSetting[plugin];
@@ -173,6 +173,7 @@ public static class ModdedOptionsManager
///
/// The original setter method.
/// The new object value.
+ // ReSharper disable once InconsistentNaming
public static void PropertySetterPatch(MethodBase __originalMethod, object value)
{
var attribute = OptionAttributes.First(pair => pair.Key.GetSetMethod() == __originalMethod).Value;
@@ -185,6 +186,7 @@ public static class ModdedOptionsManager
/// The original getter method.
/// The result of the property getter.
/// False so the original getter gets skipped.
+ // ReSharper disable InconsistentNaming
public static bool PropertyGetterPatch(MethodBase __originalMethod, ref object __result)
{
var attribute = OptionAttributes.First(pair => pair.Key.GetGetMethod() == __originalMethod).Value;
diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs
index 2b61e2b..442f66b 100644
--- a/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs
+++ b/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs
@@ -4,6 +4,7 @@ using MiraAPI.Networking;
using MiraAPI.PluginLoading;
using Reactor.Localization.Utilities;
using Reactor.Networking.Rpc;
+using Reactor.Utilities;
using UnityEngine;
namespace MiraAPI.GameOptions.OptionTypes;
@@ -127,6 +128,24 @@ public abstract class ModdedOption : IModdedOption
OnValueChanged(newValue);
}
+ ///
+ public void SaveToPreset(ConfigFile presetConfig, bool saveDefault=false)
+ {
+ if (ConfigDefinition is null)
+ {
+ Logger.Error($"Attempted to save {Title} to preset, but ConfigDefinition is null.");
+ return;
+ }
+ var value = saveDefault ? DefaultValue : Value;
+
+ if (!presetConfig.ContainsKey(ConfigDefinition))
+ {
+ presetConfig.Bind(ConfigDefinition, DefaultValue);
+ }
+
+ presetConfig[ConfigDefinition].BoxedValue = value;
+ }
+
///
public abstract float GetFloatData();
diff --git a/MiraAPI/Hud/CustomButtonManager.cs b/MiraAPI/Hud/CustomButtonManager.cs
index dd10f6c..9b176d2 100644
--- a/MiraAPI/Hud/CustomButtonManager.cs
+++ b/MiraAPI/Hud/CustomButtonManager.cs
@@ -29,7 +29,7 @@ public static class CustomButtonManager
}
CustomButtons.Add(button);
- pluginInfo.Buttons.Add(button);
+ pluginInfo.InternalButtons.Add(button);
typeof(CustomButtonSingleton<>).MakeGenericType(buttonType)
.GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)!
.SetValue(null, button);
diff --git a/MiraAPI/Modifiers/BaseModifier.cs b/MiraAPI/Modifiers/BaseModifier.cs
index 7b3dc3f..cd870eb 100644
--- a/MiraAPI/Modifiers/BaseModifier.cs
+++ b/MiraAPI/Modifiers/BaseModifier.cs
@@ -38,8 +38,8 @@ public abstract class BaseModifier : IOptionable
/// Gets the parent mod of the modifier.
///
public MiraPluginInfo ParentMod => Array.Find(
- MiraPluginManager.Instance.RegisteredPlugins(),
- x => x.Modifiers.Exists(y => y.TypeId == TypeId)
+ MiraPluginManager.Instance.RegisteredPlugins,
+ x => x.InternalModifiers.Exists(y => y.TypeId == TypeId)
) ?? throw new InvalidOperationException("Modifier is not registered.");
///
diff --git a/MiraAPI/Modifiers/ModifierManager.cs b/MiraAPI/Modifiers/ModifierManager.cs
index 5f6bbff..4aeee68 100644
--- a/MiraAPI/Modifiers/ModifierManager.cs
+++ b/MiraAPI/Modifiers/ModifierManager.cs
@@ -75,7 +75,7 @@ public static class ModifierManager
modifier = (BaseModifier)FormatterServices.GetUninitializedObject(modifierType);
}
- info.Modifiers.Add(modifier);
+ info.InternalModifiers.Add(modifier);
if (modifier is not GameModifier gameModifier)
{
diff --git a/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs b/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs
index 666a1ea..136934e 100644
--- a/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs
+++ b/MiraAPI/Patches/Freeplay/TaskAdderPatches.cs
@@ -67,9 +67,9 @@ internal static class TaskAdderPatches
modifiersFolder.FolderName = "Modifiers";
modifiersFolder.name = "ModifiersFolder";
- foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins())
+ foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins)
{
- if (plugin.CustomRoles.Any(x => x.Value is ICustomRole { Configuration.ShowInFreeplay: true }))
+ if (plugin.InternalRoles.Any(x => x.Value is ICustomRole { Configuration.ShowInFreeplay: true }))
{
var newFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
newFolder.name = plugin.PluginId+":Roles";
@@ -78,7 +78,7 @@ internal static class TaskAdderPatches
rolesFolder.SubFolders.Add(newFolder);
}
- if (plugin.Modifiers.Exists(x => x.ShowInFreeplay))
+ if (plugin.InternalModifiers.Exists(x => x.ShowInFreeplay))
{
var newFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
newFolder.name = plugin.PluginId+":Modifiers";
@@ -317,9 +317,9 @@ internal static class TaskAdderPatches
ref float num2,
ref float num3)
{
- for (var m = 0; m < plugin.Modifiers.Count; m++)
+ for (var m = 0; m < plugin.InternalModifiers.Count; m++)
{
- var modifier = plugin.Modifiers[m];
+ var modifier = plugin.InternalModifiers[m];
if (!modifier.ShowInFreeplay)
{
continue;
@@ -368,9 +368,9 @@ internal static class TaskAdderPatches
private static void PluginRoles(TaskAdderGame instance, MiraPluginInfo plugin, ref float num, ref float num2, ref float num3)
{
- for (var m = 0; m < plugin.CustomRoles.Count; m++)
+ for (var m = 0; m < plugin.InternalRoles.Count; m++)
{
- var roleBehaviour = plugin.CustomRoles.ElementAt(m).Value;
+ var roleBehaviour = plugin.InternalRoles.ElementAt(m).Value;
if (roleBehaviour.Role == RoleTypes.ImpostorGhost || roleBehaviour.Role == RoleTypes.CrewmateGhost ||
roleBehaviour is ICustomRole { Configuration.ShowInFreeplay: false })
{
diff --git a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs
index 8034eff..0d88920 100644
--- a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs
+++ b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs
@@ -14,18 +14,12 @@ using Object = UnityEngine.Object;
namespace MiraAPI.Patches.Options;
-///
-/// Patches the GameOptionsMenu to add custom options.
-///
[HarmonyPatch(typeof(GameOptionsMenu))]
-public static class GameOptionsMenuPatch
+internal static class GameOptionsMenuPatch
{
- ///
- /// Update patch for the GameOptionsMenu.
- ///
- /// The GameOptionsMenu instance.
[HarmonyPostfix]
[HarmonyPatch(nameof(GameOptionsMenu.Update))]
+ // ReSharper disable once InconsistentNaming
public static void UpdatePatch(GameOptionsMenu __instance)
{
if (GameSettingMenuPatches.SelectedModIdx == 0)
@@ -41,7 +35,7 @@ public static class GameOptionsMenuPatch
else
{
var filteredGroups =
- GameSettingMenuPatches.SelectedMod?.OptionGroups
+ GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
.Where(x => x.OptionableType == null && !x.ShowInModifiersMenu) ?? [];
foreach (var group in filteredGroups)
@@ -107,7 +101,7 @@ public static class GameOptionsMenuPatch
private static void ModifiersUpdate(ref float num)
{
- var groups = GameSettingMenuPatches.SelectedMod?.OptionGroups
+ var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
.Where(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true) ?? [];
foreach (var modGroup in groups)
@@ -118,7 +112,7 @@ public static class GameOptionsMenuPatch
private static void ModifiersCreate(GameOptionsMenu menu)
{
- var groups = GameSettingMenuPatches.SelectedMod?.OptionGroups
+ var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
.Where(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true) ?? [];
foreach (var group in groups)
{
@@ -128,6 +122,7 @@ public static class GameOptionsMenuPatch
[HarmonyPrefix]
[HarmonyPatch(nameof(GameOptionsMenu.CreateSettings))]
+ // ReSharper disable once InconsistentNaming
public static bool SettingsPatch(GameOptionsMenu __instance)
{
if (GameSettingMenuPatches.SelectedModIdx == 0)
@@ -143,7 +138,7 @@ public static class GameOptionsMenuPatch
return false;
}
- var filteredGroups = GameSettingMenuPatches.SelectedMod?.OptionGroups
+ var filteredGroups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
.Where(x => x.OptionableType == null && !x.ShowInModifiersMenu) ?? [];
foreach (var group in filteredGroups)
@@ -156,6 +151,7 @@ public static class GameOptionsMenuPatch
[HarmonyPrefix]
[HarmonyPatch(nameof(GameOptionsMenu.Initialize))]
+ // ReSharper disable once InconsistentNaming
public static bool InitPatch(GameOptionsMenu __instance)
{
if (__instance.Children != null && __instance.Children.Count != 0)
diff --git a/MiraAPI/Patches/Options/GamePresetsTabPatches.cs b/MiraAPI/Patches/Options/GamePresetsTabPatches.cs
index ca8f4ae..c068a52 100644
--- a/MiraAPI/Patches/Options/GamePresetsTabPatches.cs
+++ b/MiraAPI/Patches/Options/GamePresetsTabPatches.cs
@@ -1,26 +1,101 @@
using System.Linq;
using HarmonyLib;
-using MiraAPI.Presets;
+using MiraAPI.PluginLoading;
+using Reactor.Utilities;
+using Reactor.Utilities.Extensions;
+using UnityEngine;
+using UnityEngine.Events;
+using UnityEngine.UI;
namespace MiraAPI.Patches.Options;
internal static class GamePresetsTabPatches
{
- [HarmonyPatch(typeof(GamePresetsTab), nameof(GamePresetsTab.OpenMenu))]
- public static class GamePresetsTabOnEnablePatch
+ [HarmonyPatch(typeof(GamePresetsTab), nameof(GamePresetsTab.Start))]
+ public static class GamePresetsTabStartPatch
{
+ // ReSharper disable once InconsistentNaming
public static void Postfix(GamePresetsTab __instance)
{
- if (GameSettingMenuPatches.SelectedModIdx == 0)
+ var prefab = GameSettingMenu.Instance.GameSettingsButton;
+ if (prefab == null)
{
+ Logger.Error("GameSettingsButton prefab is null");
return;
}
- __instance.StandardPresetButton.gameObject.SetActive(false);
- __instance.SecondPresetButton.gameObject.SetActive(false);
+ var holder = new GameObject("PresetHolder");
+ holder.transform.SetParent(__instance.transform, false);
+ holder.transform.localPosition = new Vector3(-1.7f, 1.7f, 0);
+ var arrange = holder.AddComponent();
- foreach (var preset in PresetManager.Presets.Where(x=>x.Plugin==GameSettingMenuPatches.SelectedMod))
+ foreach (var preset in MiraPluginManager.Instance.RegisteredPlugins.SelectMany(x=>x.Presets))
{
+ var button = Object.Instantiate(prefab, holder.transform);
+ button.buttonText.text = preset.Name;
+ if (button.buttonText.TryGetComponent(out var tmp))
+ {
+ tmp.DestroyImmediate();
+ }
+
+ button.OnClick = new Button.ButtonClickedEvent();
+ button.OnClick.AddListener(
+ (UnityAction)(() =>
+ {
+ Logger.Error($"Loading preset {preset.Name}");
+ preset.LoadPreset();
+ }));
+ button.gameObject.SetActive(false);
+ preset.PresetButton = button.gameObject;
+ }
+
+ arrange.Alignment = GridArrange.StartAlign.Right;
+ arrange.CellSize = new Vector2(2.5f, -.55f);
+ arrange.Start();
+ arrange.ArrangeChilds();
+ }
+ }
+
+ [HarmonyPatch(typeof(GamePresetsTab), nameof(GamePresetsTab.OnEnable))]
+ public static class GamePresetsOnEnablePatch
+ {
+ // ReSharper disable once InconsistentNaming
+ public static void Postfix(GamePresetsTab __instance)
+ {
+ Logger.Error("OnEnable called");
+ __instance.StandardPresetButton.gameObject.SetActive(GameSettingMenuPatches.SelectedModIdx == 0);
+ __instance.SecondPresetButton.gameObject.SetActive(GameSettingMenuPatches.SelectedModIdx == 0);
+
+ foreach (var mod in MiraPluginManager.Instance.RegisteredPlugins)
+ {
+ foreach (var button in mod.Presets.Select(x=>x.PresetButton))
+ {
+ if (button != null)
+ {
+ button.SetActive(mod == GameSettingMenuPatches.SelectedMod);
+ }
+ }
+ }
+ }
+ }
+
+ [HarmonyPatch(typeof(GamePresetsTab), nameof(GamePresetsTab.OnDisable))]
+ public static class GamePresetsOnDisablePatch
+ {
+ // ReSharper disable once InconsistentNaming
+ public static void Postfix()
+ {
+ Logger.Error("OnDisable called");
+
+ foreach (var mod in MiraPluginManager.Instance.RegisteredPlugins)
+ {
+ foreach (var button in mod.Presets.Select(x=>x.PresetButton))
+ {
+ if (button != null)
+ {
+ button.SetActive(false);
+ }
+ }
}
}
}
diff --git a/MiraAPI/Patches/Options/GameSettingMenuPatches.cs b/MiraAPI/Patches/Options/GameSettingMenuPatches.cs
index 9e05f58..a6d3798 100644
--- a/MiraAPI/Patches/Options/GameSettingMenuPatches.cs
+++ b/MiraAPI/Patches/Options/GameSettingMenuPatches.cs
@@ -4,7 +4,6 @@ using HarmonyLib;
using MiraAPI.Modifiers;
using MiraAPI.PluginLoading;
using MiraAPI.Utilities.Assets;
-using Reactor.Utilities;
using Reactor.Utilities.Extensions;
using TMPro;
using UnityEngine;
@@ -33,6 +32,7 @@ internal static class GameSettingMenuPatches
[HarmonyPostfix]
[HarmonyPatch(nameof(GameSettingMenu.ChangeTab))]
+ // ReSharper disable once InconsistentNaming
public static void ChangeTabPostfix(GameSettingMenu __instance, int tabNum, bool previewOnly)
{
if ((previewOnly && Controller.currentTouchType == Controller.TouchType.Joystick) || !previewOnly)
@@ -79,6 +79,7 @@ internal static class GameSettingMenuPatches
/// The GameSettingMenu instance.
[HarmonyPrefix]
[HarmonyPatch(nameof(GameSettingMenu.Start))]
+ // ReSharper disable once InconsistentNaming
public static void StartPrefix(GameSettingMenu __instance)
{
_roleBtnOgPos = __instance.RoleSettingsButton.transform.localPosition;
@@ -112,7 +113,7 @@ internal static class GameSettingMenuPatches
(UnityAction)(() =>
{
SelectedModIdx += 1;
- if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins().Length)
+ if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins.Length)
{
SelectedModIdx = 0;
}
@@ -132,7 +133,7 @@ internal static class GameSettingMenuPatches
SelectedModIdx -= 1;
if (SelectedModIdx < 0)
{
- SelectedModIdx = MiraPluginManager.Instance.RegisteredPlugins().Length;
+ SelectedModIdx = MiraPluginManager.Instance.RegisteredPlugins.Length;
}
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
@@ -212,37 +213,37 @@ internal static class GameSettingMenuPatches
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
}
- private static void ChangeRoleSettingButton(bool replace, GameSettingMenu __instance)
+ private static void ChangeRoleSettingButton(bool replace, GameSettingMenu menu)
{
- __instance.RoleSettingsButton.OnClick = new ButtonClickedEvent();
- __instance.RoleSettingsButton.OnMouseOver = new UnityEvent();
+ menu.RoleSettingsButton.OnClick = new ButtonClickedEvent();
+ menu.RoleSettingsButton.OnMouseOver = new UnityEvent();
if (replace)
{
- __instance.RoleSettingsButton.buttonText.text = "Modifiers Settings";
- __instance.RoleSettingsButton.OnClick.AddListener(
+ menu.RoleSettingsButton.buttonText.text = "Modifiers Settings";
+ menu.RoleSettingsButton.OnClick.AddListener(
(UnityAction)(() =>
{
- __instance.ChangeTab(3, false);
+ menu.ChangeTab(3, false);
}));
- __instance.RoleSettingsButton.OnMouseOver.AddListener(
+ menu.RoleSettingsButton.OnMouseOver.AddListener(
(UnityAction)(() =>
{
- __instance.ChangeTab(3, true);
+ menu.ChangeTab(3, true);
}));
}
else
{
- __instance.RoleSettingsButton.buttonText.text = "Roles Settings";
- __instance.RoleSettingsButton.OnClick.AddListener(
+ menu.RoleSettingsButton.buttonText.text = "Roles Settings";
+ menu.RoleSettingsButton.OnClick.AddListener(
(UnityAction)(() =>
{
- __instance.ChangeTab(2, false);
+ menu.ChangeTab(2, false);
}));
- __instance.RoleSettingsButton.OnMouseOver.AddListener(
+ menu.RoleSettingsButton.OnMouseOver.AddListener(
(UnityAction)(() =>
{
- __instance.ChangeTab(2, true);
+ menu.ChangeTab(2, true);
}));
}
}
@@ -256,7 +257,7 @@ internal static class GameSettingMenuPatches
else if (_text is not null)
{
_text.fontSizeMax = 2.3f;
- SelectedMod = MiraPluginManager.Instance.RegisteredPlugins()[SelectedModIdx - 1];
+ SelectedMod = MiraPluginManager.Instance.RegisteredPlugins[SelectedModIdx - 1];
var name = SelectedMod.MiraPlugin.OptionsTitleText;
_text.text = name[..Math.Min(name.Length, 25)];
@@ -269,9 +270,9 @@ internal static class GameSettingMenuPatches
if (SelectedModIdx != 0)
{
- var modHasRoles = SelectedMod!.CustomRoles.Count != 0;
- var modHasModifiers = SelectedMod.OptionGroups.Exists(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true);
- var modHasOptions = SelectedMod.OptionGroups.Exists(x => x.OptionableType == null && !x.ShowInModifiersMenu);
+ var modHasRoles = SelectedMod!.InternalRoles.Count != 0;
+ var modHasModifiers = SelectedMod.InternalOptionGroups.Exists(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true);
+ var modHasOptions = SelectedMod.InternalOptionGroups.Exists(x => x.OptionableType == null && !x.ShowInModifiersMenu);
_modifiersButton.gameObject.SetActive(true);
_smallRolesButton.gameObject.SetActive(true);
@@ -367,6 +368,11 @@ internal static class GameSettingMenuPatches
ChangeRoleSettingButton(replaceWithModifiers, menu);
}
+ if (menu.PresetsTab.gameObject.active)
+ {
+ menu.ChangeTab(0, false);
+ }
+
CleanupTab(settings, roles);
}
@@ -385,6 +391,34 @@ internal static class GameSettingMenuPatches
private static void CleanupTab(GameOptionsMenu settings, RolesSettingsMenu roles)
{
+ if (roles.roleChances != null && SelectedMod?.InternalRoles.Count > 0)
+ {
+ CleanupRoleSettings(roles);
+ }
+
+ if (settings.Children != null && SelectedMod?.InternalOptionGroups.Count > 0)
+ {
+ CleanupSettings(settings);
+ }
+
+ if (_modifiersTab?.Children?.Count > 0)
+ {
+ CleanupSettings(_modifiersTab);
+ }
+ void CleanupSettings(GameOptionsMenu gameOptMenu)
+ {
+ ClearOptions(gameOptMenu.Children);
+ gameOptMenu.Children = null;
+
+ gameOptMenu.settingsContainer
+ .GetComponentsInChildren()
+ .ToList()
+ .ForEach(header => header.gameObject.DestroyImmediate());
+
+ gameOptMenu.Initialize();
+ gameOptMenu.scrollBar.ScrollToTop();
+ }
+
void CleanupRoleSettings(RolesSettingsMenu rolesMenu)
{
if (rolesMenu.advancedSettingChildren != null)
@@ -410,34 +444,5 @@ internal static class GameSettingMenuPatches
rolesMenu.SetQuotaTab();
rolesMenu.scrollBar.ScrollToTop();
}
-
- void CleanupSettings(GameOptionsMenu gameOptMenu)
- {
- ClearOptions(gameOptMenu.Children);
- gameOptMenu.Children = null;
-
- gameOptMenu.settingsContainer
- .GetComponentsInChildren()
- .ToList()
- .ForEach(header => header.gameObject.DestroyImmediate());
-
- gameOptMenu.Initialize();
- gameOptMenu.scrollBar.ScrollToTop();
- }
-
- if (roles.roleChances != null && SelectedMod?.CustomRoles.Count > 0)
- {
- CleanupRoleSettings(roles);
- }
-
- if (settings.Children != null && SelectedMod?.OptionGroups.Count > 0)
- {
- CleanupSettings(settings);
- }
-
- if (_modifiersTab?.Children?.Count > 0)
- {
- CleanupSettings(_modifiersTab);
- }
}
}
diff --git a/MiraAPI/Patches/Options/LobbyViewPanePatches.cs b/MiraAPI/Patches/Options/LobbyViewPanePatches.cs
index 43c5719..7c7979d 100644
--- a/MiraAPI/Patches/Options/LobbyViewPanePatches.cs
+++ b/MiraAPI/Patches/Options/LobbyViewPanePatches.cs
@@ -24,7 +24,7 @@ public static class LobbyViewPanePatches
private static MiraPluginInfo? SelectedMod => SelectedModIdx == 0
? null
- : MiraPluginManager.Instance.RegisteredPlugins()[SelectedModIdx - 1];
+ : MiraPluginManager.Instance.RegisteredPlugins[SelectedModIdx - 1];
private static PassiveButton? ModifiersTabButton { get; set; }
@@ -74,7 +74,7 @@ public static class LobbyViewPanePatches
(UnityAction)(() =>
{
SelectedModIdx += 1;
- if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins().Length)
+ if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins.Length)
{
SelectedModIdx = 0;
}
@@ -98,7 +98,7 @@ public static class LobbyViewPanePatches
SelectedModIdx -= 1;
if (SelectedModIdx < 0)
{
- SelectedModIdx = MiraPluginManager.Instance.RegisteredPlugins().Length;
+ SelectedModIdx = MiraPluginManager.Instance.RegisteredPlugins.Length;
}
Refresh(__instance);
@@ -127,7 +127,7 @@ public static class LobbyViewPanePatches
__instance.rolesTabButton.SelectButton(false);
ModifiersTabButton?.SelectButton(true);
- var filteredGroups = SelectedMod.OptionGroups
+ var filteredGroups = SelectedMod.InternalOptionGroups
.Where(x => x.GroupVisible() && (x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true));
DrawOptions(__instance, filteredGroups);
return false;
@@ -142,7 +142,7 @@ public static class LobbyViewPanePatches
return true;
}
- var filteredGroups = SelectedMod.OptionGroups
+ var filteredGroups = SelectedMod.InternalOptionGroups
.Where(x => x.OptionableType == null && x.GroupVisible.Invoke());
DrawOptions(__instance, filteredGroups);
return false;
@@ -250,7 +250,7 @@ public static class LobbyViewPanePatches
var list = new List();
- var roleGroups = GameSettingMenuPatches.SelectedMod?.CustomRoles.Values.OfType()
+ var roleGroups = GameSettingMenuPatches.SelectedMod?.InternalRoles.Values.OfType()
.ToLookup(x => x.RoleOptionsGroup);
if (roleGroups is null)
@@ -315,7 +315,7 @@ public static class LobbyViewPanePatches
viewSettingsInfoPanelRoleVariant.transform.localScale = Vector3.one;
viewSettingsInfoPanelRoleVariant.transform.localPosition = new Vector3(num2, num, -2f);
- var advancedRoleOptions = SelectedMod.OptionGroups
+ var advancedRoleOptions = SelectedMod.InternalOptionGroups
.Where(x => x.OptionableType == customRole.GetType())
.SelectMany(x => x.Options)
.ToList();
@@ -402,7 +402,7 @@ public static class LobbyViewPanePatches
return 0;
}
- var role = SelectedMod.CustomRoles.Values.FirstOrDefault(x => x.GetType() == roleType);
+ var role = SelectedMod.InternalRoles.Values.FirstOrDefault(x => x.GetType() == roleType);
if (role == null)
{
@@ -425,7 +425,7 @@ public static class LobbyViewPanePatches
var num = viewPanel.yPosStart;
var num2 = 1.08f;
- var filteredOptions = SelectedMod.OptionGroups
+ var filteredOptions = SelectedMod.InternalOptionGroups
.Where(x => x.OptionableType == roleType)
.SelectMany(x=>x.Options)
.ToList();
diff --git a/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs b/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs
index 9fe48d7..791391d 100644
--- a/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs
+++ b/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs
@@ -67,7 +67,7 @@ public static class RoleSettingMenuPatches
var num3 = 0;
- var roleGroups = GameSettingMenuPatches.SelectedMod?.CustomRoles.Values.OfType()
+ var roleGroups = GameSettingMenuPatches.SelectedMod?.InternalRoles.Values.OfType()
.ToLookup(x => x.RoleOptionsGroup);
if (roleGroups is null)
@@ -310,7 +310,7 @@ public static class RoleSettingMenuPatches
var num = hasImage ? -0.872f : -1;
// TODO: create sub groups under the role settings.
- var filteredOptions = GameSettingMenuPatches.SelectedMod?.OptionGroups
+ var filteredOptions = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
.Where(x=> x.OptionableType == role.GetType())
.SelectMany(x=>x.Options)
.ToList() ?? [];
@@ -474,7 +474,7 @@ public static class RoleSettingMenuPatches
roleOptionSetting.titleText.horizontalAlignment = HorizontalAlignmentOptions.Left;
if (GameSettingMenuPatches.SelectedMod is null ||
- GameSettingMenuPatches.SelectedMod.OptionGroups
+ GameSettingMenuPatches.SelectedMod.InternalOptionGroups
.Exists(x => x.OptionableType == role.GetType()))
{
var newButton = Object.Instantiate(roleOptionSetting.buttons[0], roleOptionSetting.transform);
@@ -506,7 +506,7 @@ public static class RoleSettingMenuPatches
roleOptionSetting.ChancePlusBtn.gameObject.SetActive(false);
}
- if (index < GameSettingMenuPatches.SelectedMod?.CustomRoles.Count - 1)
+ if (index < GameSettingMenuPatches.SelectedMod?.InternalRoles.Count - 1)
{
ScrollerNum -= 0.43f;
}
diff --git a/MiraAPI/PluginLoading/MiraPluginInfo.cs b/MiraAPI/PluginLoading/MiraPluginInfo.cs
index 68d3ff0..4a454a6 100644
--- a/MiraAPI/PluginLoading/MiraPluginInfo.cs
+++ b/MiraAPI/PluginLoading/MiraPluginInfo.cs
@@ -6,7 +6,9 @@ using MiraAPI.GameModes;
using MiraAPI.GameOptions;
using MiraAPI.Hud;
using MiraAPI.Modifiers;
+using MiraAPI.Presets;
+// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace MiraAPI.PluginLoading;
///
@@ -23,61 +25,58 @@ public class MiraPluginInfo
}
///
- /// Get a read only collection of this plugin's modifiers. This is probably not safe because they are uninitialized.
+ /// Gets a read only collection of this plugin's modifiers. This is not safe for modifiers with constructors.
///
- /// Readonly collection of modifiers.
- public IReadOnlyCollection GetModifiers()
- {
- return Modifiers.AsReadOnly();
- }
+ public IReadOnlyCollection Modifiers { get; private set; } = null!;
///
- /// Get a read only collection of this plugin's Option Groups.
+ /// Gets a read only collection of this plugin's Option Groups.
///
- /// Readonly collection of option groups.
- public IReadOnlyCollection GetOptionGroups()
- {
- return OptionGroups.AsReadOnly();
- }
+ public IReadOnlyCollection OptionGroups { get; private set; } = null!;
///
/// Gets a read only collection of this plugin's options.
///
- /// Read only collection of options.
- public IReadOnlyCollection GetOptions()
- {
- return Options.AsReadOnly();
- }
+ public IReadOnlyCollection Options { get; private set; } = null!;
///
/// Gets a read only dictionary of Role IDs and the RoleBehaviour object they are associated with.
///
- /// Read only dictionary of IDs and Roles.
- public ReadOnlyDictionary GetRoles()
- {
- return new ReadOnlyDictionary(CustomRoles);
- }
+ public ReadOnlyDictionary Roles { get; private set; } = null!;
///
/// Gets a read only collection of this plugin's custom buttons.
///
- /// Read only collection of buttons.
- public IReadOnlyCollection GetButtons()
+ public IReadOnlyCollection Buttons { get; private set; } = null!;
+
+ ///
+ /// Gets a read only dictionary of this plugin's custom game modes.
+ ///
+ public IReadOnlyCollection Presets { get; internal set; } = null!;
+
+ internal void SavePublicCollections()
{
- return Buttons.AsReadOnly();
+ Presets = [..InternalPresets];
+ Modifiers = [..InternalModifiers];
+ OptionGroups = [..InternalOptionGroups];
+ Options = [..InternalOptions];
+ Roles = new ReadOnlyDictionary(InternalRoles);
+ Buttons = [..InternalButtons];
}
- internal List OptionGroups { get; } = [];
+ internal List InternalPresets { get; } = [];
- internal List Options { get; } = [];
+ internal List InternalOptionGroups { get; } = [];
- internal List Modifiers { get; } = [];
+ internal List InternalOptions { get; } = [];
- internal Dictionary CustomRoles { get; } = [];
+ internal List InternalModifiers { get; } = [];
- internal Dictionary GameModes { get; } = [];
+ internal Dictionary InternalRoles { get; } = [];
- internal List Buttons { get; } = [];
+ internal Dictionary InternalGameModes { get; } = [];
+
+ internal List InternalButtons { get; } = [];
///
/// Gets the plugin's ID, as defined in the plugin's BepInEx metadata.
diff --git a/MiraAPI/PluginLoading/MiraPluginManager.cs b/MiraAPI/PluginLoading/MiraPluginManager.cs
index 885414d..e1f3f4b 100644
--- a/MiraAPI/PluginLoading/MiraPluginManager.cs
+++ b/MiraAPI/PluginLoading/MiraPluginManager.cs
@@ -12,6 +12,7 @@ using MiraAPI.GameOptions;
using MiraAPI.GameOptions.Attributes;
using MiraAPI.Hud;
using MiraAPI.Modifiers;
+using MiraAPI.Presets;
using MiraAPI.Roles;
using MiraAPI.Utilities;
using Reactor.Networking;
@@ -26,8 +27,9 @@ public sealed class MiraPluginManager
{
private readonly Dictionary _registeredPlugins = [];
- internal MiraPluginInfo[] RegisteredPlugins() => [.. _registeredPlugins.Values];
- internal Dictionary> QueuedRoleRegistrations { get; } = new();
+ internal MiraPluginInfo[] RegisteredPlugins { get; private set; } = null!;
+
+ internal Dictionary> QueuedRoleRegistrations { get; } = [];
internal static MiraPluginManager Instance { get; private set; } = new();
internal void Initialize()
@@ -96,17 +98,25 @@ public sealed class MiraPluginManager
RegisterColorClasses(type);
}
- info.OptionGroups.Sort((x, y) => x.GroupPriority.CompareTo(y.GroupPriority));
+ info.InternalOptionGroups.Sort((x, y) => x.GroupPriority.CompareTo(y.GroupPriority));
QueuedRoleRegistrations.Add(info, roles);
_registeredPlugins.Add(assembly, info);
+
+ info.SavePublicCollections();
+ PresetManager.CreateDefaultPreset(info);
+ PresetManager.LoadPresets(info);
Logger.Info($"Registering mod {pluginInfo.Metadata.GUID} with Mira API.");
};
IL2CPPChainloader.Instance.Finished += PaletteManager.RegisterAllColors;
IL2CPPChainloader.Instance.Finished += MiraEventManager.SortAllHandlers;
IL2CPPChainloader.Instance.Finished += () =>
{
+ // Save all buttons into a read-only collection for easy access
CustomButtonManager.Buttons = new ReadOnlyCollection(CustomButtonManager.CustomButtons);
+
+ // Cache all the registered plugins into an array for easy access
+ RegisteredPlugins = [.._registeredPlugins.Values];
};
}
diff --git a/MiraAPI/Presets/OptionPreset.cs b/MiraAPI/Presets/OptionPreset.cs
index d16f5f0..7ba935e 100644
--- a/MiraAPI/Presets/OptionPreset.cs
+++ b/MiraAPI/Presets/OptionPreset.cs
@@ -1,6 +1,7 @@
using System.Linq;
using BepInEx.Configuration;
using MiraAPI.PluginLoading;
+using UnityEngine;
namespace MiraAPI.Presets;
@@ -29,6 +30,11 @@ public class OptionPreset
///
public ConfigFile PresetConfig { get; }
+ ///
+ /// Gets or sets the button associated with the preset in the UI.
+ ///
+ public GameObject? PresetButton { get; set; }
+
///
/// Initializes a new instance of the class with the specified name and configuration file.
///
diff --git a/MiraAPI/Presets/PresetManager.cs b/MiraAPI/Presets/PresetManager.cs
index 7a8dc2b..a711127 100644
--- a/MiraAPI/Presets/PresetManager.cs
+++ b/MiraAPI/Presets/PresetManager.cs
@@ -1,5 +1,5 @@
-using System.Collections.Generic;
-using System.IO;
+using System.IO;
+using System.Linq;
using BepInEx.Configuration;
using MiraAPI.PluginLoading;
using UnityEngine;
@@ -16,10 +16,23 @@ public static class PresetManager
///
public static string PresetDirectory { get; } = Path.Join(Application.persistentDataPath, "mira_presets");
- ///
- /// Gets the list of available presets for the game options.
- ///
- public static List Presets { get; } = [];
+ internal static void CreateDefaultPreset(MiraPluginInfo plugin)
+ {
+ var presetPath = Path.Join(PresetManager.PresetDirectory, plugin.PluginId);
+ if (!Directory.Exists(presetPath))
+ {
+ Directory.CreateDirectory(presetPath);
+ }
+
+ var presetConfig = new ConfigFile(Path.Join(presetPath, "Default.cfg"), true);
+
+ foreach (var option in plugin.InternalOptions.Where(x => x.IncludeInPreset))
+ {
+ option.SaveToPreset(presetConfig, true);
+ }
+
+ presetConfig.Save();
+ }
///
/// Loads the presets for the specified plugin by reading the configuration files from the preset directory.
@@ -27,7 +40,7 @@ public static class PresetManager
/// >The plugin for which the presets should be loaded.
public static void LoadPresets(MiraPluginInfo plugin)
{
- Presets.Clear();
+ plugin.InternalPresets.Clear();
if (!Directory.Exists(PresetDirectory))
{
Directory.CreateDirectory(PresetDirectory);
@@ -43,7 +56,8 @@ public static class PresetManager
{
var presetName = Path.GetFileNameWithoutExtension(file);
var presetConfig = new ConfigFile(file, true);
- Presets.Add(new OptionPreset(presetName, plugin, presetConfig));
+ plugin.InternalPresets.Add(new OptionPreset(presetName, plugin, presetConfig));
}
+ plugin.Presets = [.. plugin.InternalPresets];
}
}
diff --git a/MiraAPI/Roles/CustomRoleManager.cs b/MiraAPI/Roles/CustomRoleManager.cs
index 6552641..01b3289 100644
--- a/MiraAPI/Roles/CustomRoleManager.cs
+++ b/MiraAPI/Roles/CustomRoleManager.cs
@@ -70,7 +70,7 @@ public static class CustomRoleManager
continue;
}
- pluginInfo.CustomRoles.Add((ushort)role.Role, role);
+ pluginInfo.InternalRoles.Add((ushort)role.Role, role);
}
}
@@ -156,7 +156,7 @@ public static class CustomRoleManager
/// A MiraPluginInfo object representing the parent mod of the role.
public static MiraPluginInfo FindParentMod(ICustomRole role)
{
- return MiraPluginManager.Instance.RegisteredPlugins().First(plugin => plugin.CustomRoles.ContainsValue(role as RoleBehaviour ?? throw new InvalidOperationException()));
+ return MiraPluginManager.Instance.RegisteredPlugins.First(plugin => plugin.InternalRoles.ContainsValue(role as RoleBehaviour ?? throw new InvalidOperationException()));
}
///
@@ -231,7 +231,7 @@ public static class CustomRoleManager
// we dont know how other plugins handle their configs
// this way, all the options are saved at once, instead of one by one
var oldConfigSetting = new Dictionary();
- foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins())
+ foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins)
{
oldConfigSetting.Add(plugin, plugin.PluginConfig.SaveOnConfigSet);
plugin.PluginConfig.SaveOnConfigSet = false;
@@ -266,7 +266,7 @@ public static class CustomRoleManager
}
}
- foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins())
+ foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins)
{
plugin.PluginConfig.Save();
plugin.PluginConfig.SaveOnConfigSet = oldConfigSetting[plugin];