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)