diff --git a/MiraAPI/Events/MiraCancelableEvent.cs b/MiraAPI/Events/MiraCancelableEvent.cs index b4d3f05..fe772a9 100644 --- a/MiraAPI/Events/MiraCancelableEvent.cs +++ b/MiraAPI/Events/MiraCancelableEvent.cs @@ -1,8 +1,11 @@ -namespace MiraAPI.Events; +using MiraAPI.PluginLoading; + +namespace MiraAPI.Events; /// /// Abstract class for Mira Events that can be cancelled. /// +[MiraIgnore] public abstract class MiraCancelableEvent : MiraEvent { /// diff --git a/MiraAPI/Events/MiraEvent.cs b/MiraAPI/Events/MiraEvent.cs index f0f49bd..7fdca49 100644 --- a/MiraAPI/Events/MiraEvent.cs +++ b/MiraAPI/Events/MiraEvent.cs @@ -1,6 +1,9 @@ -namespace MiraAPI.Events; +using MiraAPI.PluginLoading; + +namespace MiraAPI.Events; /// /// Abstract class for Mira Events. /// +[MiraIgnore] public abstract class MiraEvent; diff --git a/MiraAPI/GameOptions/ModifierOptionGroup.cs b/MiraAPI/GameOptions/ModifierOptionGroup.cs index 3db6566..6309649 100644 --- a/MiraAPI/GameOptions/ModifierOptionGroup.cs +++ b/MiraAPI/GameOptions/ModifierOptionGroup.cs @@ -1,8 +1,10 @@ using System.Linq; +using MiraAPI.PluginLoading; namespace MiraAPI.GameOptions; #pragma warning disable CA1852 +[MiraIgnore] internal class ModifierOptionGroup : AbstractOptionGroup #pragma warning restore CA1852 { diff --git a/MiraAPI/LocalSettings/SettingTypes/LocalSettingBase.cs b/MiraAPI/LocalSettings/SettingTypes/LocalSettingBase.cs index c25f04e..48fd70d 100644 --- a/MiraAPI/LocalSettings/SettingTypes/LocalSettingBase.cs +++ b/MiraAPI/LocalSettings/SettingTypes/LocalSettingBase.cs @@ -1,11 +1,13 @@ using System; using System.Linq; using BepInEx.Configuration; +using MiraAPI.PluginLoading; using UnityEngine; namespace MiraAPI.LocalSettings.SettingTypes; /// +[MiraIgnore] public abstract class LocalSettingBase : ILocalSetting { /// diff --git a/MiraAPI/MiraApiPlugin.cs b/MiraAPI/MiraApiPlugin.cs index 594d927..f6364d9 100644 --- a/MiraAPI/MiraApiPlugin.cs +++ b/MiraAPI/MiraApiPlugin.cs @@ -1,6 +1,7 @@ global using static Reactor.Utilities.Logger; using System; using BepInEx; +using BepInEx.Configuration; using BepInEx.Unity.IL2CPP; using HarmonyLib; using MiraAPI.PluginLoading; @@ -20,8 +21,17 @@ namespace MiraAPI; [BepInDependency(ReactorPlugin.Id)] [BepInDependency(ModCompatibility.SubmergedId, BepInDependency.DependencyFlags.SoftDependency)] [ReactorModFlags(ModFlags.RequireOnAllClients)] -public partial class MiraApiPlugin : BasePlugin +public partial class MiraApiPlugin : BasePlugin, IMiraPlugin { + /// + public ConfigFile GetConfigFile() + { + return Config; + } + + /// + public string OptionsTitleText => "MiraAPI"; + /// /// Gets a value indicating whether the current device is running Starlight (on mobile). /// @@ -53,6 +63,6 @@ public partial class MiraApiPlugin : BasePlugin ReactorCredits.Register("Mira API", Version, IsDevBuild, ReactorCredits.AlwaysShow); PluginManager = new MiraPluginManager(); - PluginManager.Initialize(); + PluginManager.Initialize(this, this); } } diff --git a/MiraAPI/PluginLoading/MiraPluginManager.cs b/MiraAPI/PluginLoading/MiraPluginManager.cs index a99eae7..86247a1 100644 --- a/MiraAPI/PluginLoading/MiraPluginManager.cs +++ b/MiraAPI/PluginLoading/MiraPluginManager.cs @@ -39,12 +39,111 @@ public sealed class MiraPluginManager internal Dictionary> QueuedRoleRegistrations { get; } = []; internal static MiraPluginManager Instance { get; private set; } = new(); + public static ConfigFile MiraApiConfig { get; private set; } + public static MiraPluginInfo MiraApiPluginInfo { get; private set; } - internal void Initialize() + internal void Initialize(BasePlugin miraApiPlugin, IMiraPlugin apiPlugin) { Instance = this; CustomGameModeManager.RegisterDefaultMode(); CustomGameModeManager.GetAndSetGameMode(); + if (IL2CPPChainloader.Instance.Plugins.TryGetValue(MiraApiPlugin.Id, out var newPlugin)) + { + var assembly = Assembly.GetCallingAssembly(); + var info = new MiraPluginInfo(apiPlugin, newPlugin); + var roles = new List(); + + var oldConfigSetting = info.PluginConfig.SaveOnConfigSet; + info.PluginConfig.SaveOnConfigSet = false; + + foreach (var type in assembly.GetTypes()) + { + if (type.IsAbstract || type.GetCustomAttribute() != null) + { + continue; + } + + foreach (var method in AccessTools.GetDeclaredMethods(type)) + { + var eventAttribute = method.GetCustomAttribute(); + if (eventAttribute == null) + { + continue; + } + + if (!method.IsStatic) + { + Error($"Event method {method.Name} in {type.Name} must be static."); + continue; + } + + var parameters = method.GetParameters(); + if (parameters.Length != 1 || !parameters[0].ParameterType.IsSubclassOf(typeof(MiraEvent))) + { + Error($"Invalid event registration method {method.Name} in {type.Name}"); + continue; + } + + var paramType = parameters[0].ParameterType; + MiraEventManager.RegisterEventHandler(paramType, method, eventAttribute.Priority); + } + + if (RegisterModifier(type, info)) + { + continue; + } + + if (RegisterOptions(type, info)) + { + continue; + } + + if (RegisterLocalTabs(type, miraApiPlugin)) + { + continue; + } + + if (RegisterRole(type, info, out var role)) + { + roles.Add(role); + continue; + } + + if (RegisterButton(type, info)) + { + continue; + } + + if (RegisterGameOver(type)) + { + continue; + } + + if (RegisterGameModeAttribute(type, info)) + { + continue; + } + + RegisterColorClasses(type); + RegisterKeybinds(type, miraApiPlugin); + } + + info.PluginConfig.Save(); + info.PluginConfig.SaveOnConfigSet = oldConfigSetting; + MiraApiConfig = info.PluginConfig; + + info.InternalOptionGroups.Sort((x, y) => x.GroupPriority.CompareTo(y.GroupPriority)); + QueuedRoleRegistrations.Add(info, roles); + + _registeredPlugins.Add(assembly, info); + MiraApiPluginInfo = info; + + info.SavePublicCollections(); + PresetManager.CreateDefaultPreset(info); + PresetManager.LoadPresets(info); + Info($"Registering Mira API as mod."); + } + IL2CPPChainloader.Instance.PluginLoad += (pluginInfo, assembly, plugin) => { if (plugin is not IMiraPlugin miraPlugin)