From a1219f06569716789b8f27ef174c62e0db5a67a3 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Fri, 23 Aug 2024 23:22:29 -0400 Subject: [PATCH] change IModdedOptionGroup to AbstractOptionGroup, update group singleton class, save options to config --- MiraAPI.Example/Options/ExampleOptions.cs | 6 ++-- MiraAPI.Example/Options/ExampleOptions2.cs | 4 +-- .../Options/Roles/CustomRole2Settings.cs | 6 ++-- .../Options/Roles/CustomRoleSettings.cs | 6 ++-- ...dOptionGroup.cs => AbstractOptionGroup.cs} | 13 +++++--- MiraAPI/GameOptions/IModdedOption.cs | 4 ++- MiraAPI/GameOptions/ModdedOptionsManager.cs | 22 ++++++------- ...upSingleton.cs => OptionGroupSingleton.cs} | 4 +-- .../GameOptions/OptionTypes/ModdedOption.cs | 31 ++++++++++++++----- .../Patches/Options/GameOptionsMenuPatch.cs | 4 +-- MiraAPI/PluginLoading/MiraPluginInfo.cs | 10 +++--- MiraAPI/PluginLoading/MiraPluginManager.cs | 2 +- 12 files changed, 64 insertions(+), 48 deletions(-) rename MiraAPI/GameOptions/{IModdedOptionGroup.cs => AbstractOptionGroup.cs} (61%) rename MiraAPI/GameOptions/{ModdedGroupSingleton.cs => OptionGroupSingleton.cs} (71%) diff --git a/MiraAPI.Example/Options/ExampleOptions.cs b/MiraAPI.Example/Options/ExampleOptions.cs index 6c674a6..09f615f 100644 --- a/MiraAPI.Example/Options/ExampleOptions.cs +++ b/MiraAPI.Example/Options/ExampleOptions.cs @@ -4,10 +4,10 @@ using UnityEngine; namespace MiraAPI.Example.Options; -public class ExampleOptions : IModdedOptionGroup +public class ExampleOptions : AbstractOptionGroup { - public string GroupName => "General Group"; - public Color GroupColor => Color.red; + public override string GroupName => "General Group"; + public override Color GroupColor => Color.red; [ModdedToggleOption("Use Thing")] public bool UseThing { get; set; } = false; diff --git a/MiraAPI.Example/Options/ExampleOptions2.cs b/MiraAPI.Example/Options/ExampleOptions2.cs index 42c316f..b17ff20 100644 --- a/MiraAPI.Example/Options/ExampleOptions2.cs +++ b/MiraAPI.Example/Options/ExampleOptions2.cs @@ -3,9 +3,9 @@ using MiraAPI.GameOptions.OptionTypes; namespace MiraAPI.Example.Options; -public class ExampleOptions2 : IModdedOptionGroup +public class ExampleOptions2 : AbstractOptionGroup { - public string GroupName => "Example 2"; + public override string GroupName => "Example 2"; public ModdedToggleOption UseThing { get; } = new("Use Thingy 5", false); diff --git a/MiraAPI.Example/Options/Roles/CustomRole2Settings.cs b/MiraAPI.Example/Options/Roles/CustomRole2Settings.cs index e0e9d1a..b925dcf 100644 --- a/MiraAPI.Example/Options/Roles/CustomRole2Settings.cs +++ b/MiraAPI.Example/Options/Roles/CustomRole2Settings.cs @@ -5,11 +5,11 @@ using MiraAPI.GameOptions.Attributes; namespace MiraAPI.Example.Options.Roles; -public class CustomRole2Settings : IModdedOptionGroup +public class CustomRole2Settings : AbstractOptionGroup { - public string GroupName => "Custom Role"; + public override string GroupName => "Custom Role"; - public Type AdvancedRole => typeof(CustomRole2); + public override Type AdvancedRole => typeof(CustomRole2); [ModdedToggleOption("Teleportation ability")] public bool Teleport { get; set; } = true; diff --git a/MiraAPI.Example/Options/Roles/CustomRoleSettings.cs b/MiraAPI.Example/Options/Roles/CustomRoleSettings.cs index 98882ae..26503c0 100644 --- a/MiraAPI.Example/Options/Roles/CustomRoleSettings.cs +++ b/MiraAPI.Example/Options/Roles/CustomRoleSettings.cs @@ -5,11 +5,11 @@ using MiraAPI.GameOptions.Attributes; namespace MiraAPI.Example.Options.Roles; -public class CustomRoleSettings : IModdedOptionGroup +public class CustomRoleSettings : AbstractOptionGroup { - public string GroupName => "Custom Role"; + public override string GroupName => "Custom Role"; - public Type AdvancedRole => typeof(CustomRole); + public override Type AdvancedRole => typeof(CustomRole); [ModdedNumberOption("Testing level", min: 3, max: 9)] public float TestingLevel { get; set; } = 4; diff --git a/MiraAPI/GameOptions/IModdedOptionGroup.cs b/MiraAPI/GameOptions/AbstractOptionGroup.cs similarity index 61% rename from MiraAPI/GameOptions/IModdedOptionGroup.cs rename to MiraAPI/GameOptions/AbstractOptionGroup.cs index 6297011..564bfa1 100644 --- a/MiraAPI/GameOptions/IModdedOptionGroup.cs +++ b/MiraAPI/GameOptions/AbstractOptionGroup.cs @@ -1,27 +1,30 @@ using System; +using System.Collections.Generic; using UnityEngine; namespace MiraAPI.GameOptions; -public interface IModdedOptionGroup +public abstract class AbstractOptionGroup { + public List Options { get; } = []; + /// /// The name of the group. Visible in options menu. /// - public string GroupName { get; } + public abstract string GroupName { get; } /// /// A function that returns whether the group should be visible or not. /// - public Func GroupVisible => () => true; + public virtual Func GroupVisible => () => true; /// /// The group color. This is used to color the group in the options menu. /// - public Color GroupColor => Color.clear; + public virtual Color GroupColor => Color.clear; /// /// The role the group is associated with. This is used for the advanced role options menu. /// - public Type AdvancedRole => null; + public virtual Type AdvancedRole => null; } \ No newline at end of file diff --git a/MiraAPI/GameOptions/IModdedOption.cs b/MiraAPI/GameOptions/IModdedOption.cs index eaa7add..b8f2227 100644 --- a/MiraAPI/GameOptions/IModdedOption.cs +++ b/MiraAPI/GameOptions/IModdedOption.cs @@ -1,5 +1,6 @@ using MiraAPI.PluginLoading; using System; +using BepInEx.Configuration; using MiraAPI.Networking; using UnityEngine; @@ -9,12 +10,13 @@ public interface IModdedOption { public uint Id { get; } public BaseGameSetting Data { get; } - public IMiraPlugin ParentMod { get; set; } + public IMiraPlugin ParentMod { get; init; } public Type AdvancedRole { get; set; } public OptionBehaviour OptionBehaviour { get; protected set; } public string Title { get; } public StringNames StringName { get; } public Func Visible { get; set; } + public ConfigDefinition ConfigDefinition { get; } public void ValueChanged(OptionBehaviour optionBehaviour); public OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container); public NetData GetNetData(); diff --git a/MiraAPI/GameOptions/ModdedOptionsManager.cs b/MiraAPI/GameOptions/ModdedOptionsManager.cs index 39a8532..0725fc6 100644 --- a/MiraAPI/GameOptions/ModdedOptionsManager.cs +++ b/MiraAPI/GameOptions/ModdedOptionsManager.cs @@ -14,20 +14,17 @@ namespace MiraAPI.GameOptions; public class ModdedOptionsManager { private static readonly Dictionary OptionAttributes = new(); - private static readonly Dictionary TypeToGroup = new(); + private static readonly Dictionary TypeToGroup = new(); public static readonly Dictionary ModdedOptions = new(); - public static readonly Dictionary> Groups = new(); - + public static readonly List Groups = []; public static uint NextId => _nextId++; private static uint _nextId = 1; internal static bool RegisterGroup(Type type, MiraPluginInfo pluginInfo) { - var group = (IModdedOptionGroup)Activator.CreateInstance(type); - - if (group == null) + if (Activator.CreateInstance(type) is not AbstractOptionGroup group) { Logger.Error($"Failed to create group from {type.Name}"); return false; @@ -39,7 +36,7 @@ public class ModdedOptionsManager return false; } - Groups.Add(group, []); + Groups.Add(group); TypeToGroup.Add(type, group); pluginInfo.OptionGroups.Add(group); @@ -53,10 +50,8 @@ public class ModdedOptionsManager Logger.Error($"Failed to get group for {type.Name}"); return; } - - var option = (IModdedOption) property.GetValue(group); - - if (option == null) + + if (property.GetValue(group) is not IModdedOption option) { Logger.Error($"Failed to get option for {property.Name}"); return; @@ -101,14 +96,15 @@ public class ModdedOptionsManager RegisterOption(option, group, pluginInfo); } - private static void RegisterOption(IModdedOption option, IModdedOptionGroup group, MiraPluginInfo pluginInfo) + private static void RegisterOption(IModdedOption option, AbstractOptionGroup group, MiraPluginInfo pluginInfo) { option.ParentMod = pluginInfo.MiraPlugin; option.AdvancedRole = group.AdvancedRole; + pluginInfo.Options.Add(option); ModdedOptions.Add(option.Id, option); - Groups[group].Add(option); + group.Options.Add(option); } internal static void SyncAllOptions(int targetId=-1) diff --git a/MiraAPI/GameOptions/ModdedGroupSingleton.cs b/MiraAPI/GameOptions/OptionGroupSingleton.cs similarity index 71% rename from MiraAPI/GameOptions/ModdedGroupSingleton.cs rename to MiraAPI/GameOptions/OptionGroupSingleton.cs index 265cc2a..d7678c6 100644 --- a/MiraAPI/GameOptions/ModdedGroupSingleton.cs +++ b/MiraAPI/GameOptions/OptionGroupSingleton.cs @@ -3,13 +3,13 @@ using System.Linq; namespace MiraAPI.GameOptions; -public class ModdedGroupSingleton where T : IModdedOptionGroup +public class OptionGroupSingleton where T : AbstractOptionGroup { private static T _instance; public static T Instance { - get => _instance ??= ModdedOptionsManager.Groups.Keys.OfType().Single(); + get => _instance ??= ModdedOptionsManager.Groups.OfType().Single(); set { if (_instance != null) diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs index f34754d..8d28277 100644 --- a/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs +++ b/MiraAPI/GameOptions/OptionTypes/ModdedOption.cs @@ -2,6 +2,7 @@ using MiraAPI.Roles; using Reactor.Localization.Utilities; using System; +using BepInEx.Configuration; using MiraAPI.Networking; using Reactor.Networking.Rpc; using UnityEngine; @@ -10,9 +11,20 @@ namespace MiraAPI.GameOptions.OptionTypes; public abstract class ModdedOption : IModdedOption { + private readonly IMiraPlugin _parentMod; + public uint Id { get; } public BaseGameSetting Data { get; protected init; } - public IMiraPlugin ParentMod { get; set; } = null; + public IMiraPlugin ParentMod + { + get => _parentMod; + init + { + _parentMod = value; + var entry = _parentMod.GetConfigFile().Bind(ConfigDefinition, DefaultValue); + Value = entry.Value; + } + } public T Value { get; protected set; } public T DefaultValue { get; init; } public Action ChangedEvent { get; set; } @@ -21,9 +33,11 @@ public abstract class ModdedOption : IModdedOption public Func Visible { get; set; } public Type AdvancedRole { get; set; } public OptionBehaviour OptionBehaviour { get; set; } + public ConfigDefinition ConfigDefinition => new ("Options", Title); - protected ModdedOption(string title, T defaultValue, Type roleType) : this() + protected ModdedOption(string title, T defaultValue, Type roleType) { + Id = ModdedOptionsManager.NextId; Title = title; DefaultValue = defaultValue; Value = defaultValue; @@ -36,11 +50,6 @@ public abstract class ModdedOption : IModdedOption } } - private ModdedOption() - { - Id = ModdedOptionsManager.NextId; - } - public void ValueChanged(OptionBehaviour optionBehaviour) { SetValue(GetValueFromOptionBehaviour(optionBehaviour)); @@ -59,7 +68,13 @@ public abstract class ModdedOption : IModdedOption { Rpc.Instance.Send(PlayerControl.LocalPlayer, [GetNetData()], true); } - + + if (ParentMod is not null && + ParentMod.GetConfigFile().TryGetEntry(ConfigDefinition, out var entry)) + { + entry.Value = Value; + } + OnValueChanged(newValue); } diff --git a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs index f0fb354..06b46e1 100644 --- a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs +++ b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs @@ -28,9 +28,9 @@ public static class GameOptionsMenuPatch var filteredGroups = GameSettingMenuPatches.SelectedMod.OptionGroups.Where(x => x.GroupVisible.Invoke() && x.AdvancedRole is null); - foreach (IModdedOptionGroup group in filteredGroups) + foreach (AbstractOptionGroup group in filteredGroups) { - var filteredOpts = ModdedOptionsManager.Groups[group].Where(x => x.Visible.Invoke()).ToList(); + var filteredOpts = group.Options.Where(x => x.Visible.Invoke()).ToList(); if (filteredOpts.Count == 0) { continue; diff --git a/MiraAPI/PluginLoading/MiraPluginInfo.cs b/MiraAPI/PluginLoading/MiraPluginInfo.cs index 8214316..2b58165 100644 --- a/MiraAPI/PluginLoading/MiraPluginInfo.cs +++ b/MiraAPI/PluginLoading/MiraPluginInfo.cs @@ -8,12 +8,12 @@ namespace MiraAPI.PluginLoading; public class MiraPluginInfo(string id, IMiraPlugin miraPlugin, PluginInfo info) { - public string PluginId { get; set; } = id; - public IMiraPlugin MiraPlugin { get; set; } = miraPlugin; - public PluginInfo PluginInfo { get; set; } = info; - public ConfigFile PluginConfig { get; set; } = miraPlugin.GetConfigFile(); + public string PluginId { get; } = id; + public IMiraPlugin MiraPlugin { get; } = miraPlugin; + public PluginInfo PluginInfo { get; } = info; + public ConfigFile PluginConfig { get; } = miraPlugin.GetConfigFile(); - public readonly List OptionGroups = []; + public readonly List OptionGroups = []; public readonly List Options = []; public readonly Dictionary CustomRoles = []; diff --git a/MiraAPI/PluginLoading/MiraPluginManager.cs b/MiraAPI/PluginLoading/MiraPluginManager.cs index 45dccb2..1124be9 100644 --- a/MiraAPI/PluginLoading/MiraPluginManager.cs +++ b/MiraAPI/PluginLoading/MiraPluginManager.cs @@ -55,7 +55,7 @@ internal class MiraPluginManager private static void RegisterAllOptions(Assembly assembly, MiraPluginInfo pluginInfo) { - var filteredTypes = assembly.GetTypes().Where(type => type.IsAssignableTo(typeof(IModdedOptionGroup))); + var filteredTypes = assembly.GetTypes().Where(type => type.IsAssignableTo(typeof(AbstractOptionGroup))); foreach (var type in filteredTypes) {