diff --git a/IPA.Loader/Loader/PluginInitInjector.cs b/IPA.Loader/Loader/PluginInitInjector.cs index 89556778..06196c33 100644 --- a/IPA.Loader/Loader/PluginInitInjector.cs +++ b/IPA.Loader/Loader/PluginInitInjector.cs @@ -13,7 +13,7 @@ using Net3_Proxy; namespace IPA.Loader { /// - /// The type that handles value injecting into a plugin's Init. + /// The type that handles value injecting into a plugin's initialization methods. /// public static class PluginInitInjector { diff --git a/IPA.Loader/Loader/PluginLoader.cs b/IPA.Loader/Loader/PluginLoader.cs index 7cfa36c0..c1aa84fd 100644 --- a/IPA.Loader/Loader/PluginLoader.cs +++ b/IPA.Loader/Loader/PluginLoader.cs @@ -29,7 +29,7 @@ namespace IPA.Loader /// /// A type to manage the loading of plugins. /// - public class PluginLoader + internal class PluginLoader { internal static Task LoadTask() => TaskEx.Run(() => @@ -201,7 +201,7 @@ namespace IPA.Loader if (type.HasInterface(typeof(IPlugin).FullName)) { Logger.loader.Warn("Interface-based plugin found"); - meta.RuntimeOptions = RuntimeOptions.SingleDynamicInit; + meta.IsAttributePlugin = false; meta.PluginType = type; return; } diff --git a/IPA.Loader/Loader/PluginManager.cs b/IPA.Loader/Loader/PluginManager.cs index 8dc54a24..2c4e4488 100644 --- a/IPA.Loader/Loader/PluginManager.cs +++ b/IPA.Loader/Loader/PluginManager.cs @@ -30,9 +30,6 @@ namespace IPA.Loader { #pragma warning disable CS0618 // Type or member is obsolete (IPlugin) - /// - /// An of new Beat Saber plugins - /// private static List _bsPlugins; internal static IEnumerable BSMetas => _bsPlugins; @@ -40,23 +37,15 @@ namespace IPA.Loader /// Gets info about the plugin with the specified name. /// /// the name of the plugin to get (must be an exact match) - /// the plugin info for the requested plugin or null + /// the plugin metadata for the requested plugin or if it doesn't exist or is disabled public static PluginMetadata GetPlugin(string name) => BSMetas.Select(p => p.Metadata).FirstOrDefault(p => p.Name == name); - /// - /// Gets info about the plugin with the specified ModSaber name. - /// - /// the ModSaber name of the plugin to get (must be an exact match) - /// the plugin info for the requested plugin or null - [Obsolete("Old name. Use GetPluginFromId instead.")] - public static PluginMetadata GetPluginFromModSaberName(string name) => GetPluginFromId(name); - /// /// Gets info about the plugin with the specified ID. /// /// the ID name of the plugin to get (must be an exact match) - /// the plugin info for the requested plugin or null + /// the plugin metadata for the requested plugin or if it doesn't exist or is disabled public static PluginMetadata GetPluginFromId(string name) => BSMetas.Select(p => p.Metadata).FirstOrDefault(p => p.Id == name); @@ -245,7 +234,7 @@ namespace IPA.Loader /// /// the plugin that was enabled /// whether it needs a restart to take effect - public delegate void PluginEnableDelegate(PluginInfo plugin, bool needsRestart); + public delegate void PluginEnableDelegate(PluginMetadata plugin, bool needsRestart); /// /// An invoker for the event. /// @@ -265,7 +254,7 @@ namespace IPA.Loader /// /// Gets a list of all BSIPA plugins. /// - /// a collection of all enabled plugins as s + /// a collection of all enabled plugins as s public static IEnumerable AllPlugins => BSMetas.Select(p => p.Metadata); /* @@ -284,7 +273,7 @@ namespace IPA.Loader */ /// - /// An of old IPA plugins. + /// An of old IPA plugins. /// /// all legacy plugin instances [Obsolete("I mean, IPlugin shouldn't be used, so why should this? Not renaming to extend support for old plugins.")] diff --git a/IPA.Loader/Loader/PluginMetadata.cs b/IPA.Loader/Loader/PluginMetadata.cs index 71259d83..c6a4f2fa 100644 --- a/IPA.Loader/Loader/PluginMetadata.cs +++ b/IPA.Loader/Loader/PluginMetadata.cs @@ -82,7 +82,14 @@ namespace IPA.Loader } } + /// + /// The that the plugin specified in its . + /// public RuntimeOptions RuntimeOptions { get; internal set; } + /// + /// Whether the plugin referred to by this metadata object is a BSIPA 4 attribute plugin. + /// + /// if the plugin is a BSIPA 4 plugin, if it is a BSIPA 3 plugin. public bool IsAttributePlugin { get; internal set; } = false; /// diff --git a/IPA.Loader/PluginInterfaces/Attributes/LifecycleAttributes.cs b/IPA.Loader/PluginInterfaces/Attributes/LifecycleAttributes.cs index cb577c36..59ec24b5 100644 --- a/IPA.Loader/PluginInterfaces/Attributes/LifecycleAttributes.cs +++ b/IPA.Loader/PluginInterfaces/Attributes/LifecycleAttributes.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace IPA { @@ -18,24 +14,84 @@ namespace IPA // TODO: is there a better way to manage this mess? + /// + /// Indicates that the target method should be called when the plugin is enabled. + /// + /// + /// + /// This attribute is interchangable with , and is treated identically. + /// They are seperate to allow plugin code to more clearly describe the intent of the methods. + /// + /// + /// Typically, this will be used when the parameter of the plugins's + /// is . + /// + /// + /// + /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public sealed class OnEnableAttribute : Attribute, IEdgeLifecycleAttribute { EdgeLifecycleType IEdgeLifecycleAttribute.Type => EdgeLifecycleType.Enable; } + /// + /// Indicates that the target method should be called when the game starts. + /// + /// + /// + /// This attribute is interchangable with , and is treated identically. + /// They are seperate to allow plugin code to more clearly describe the intent of the methods. + /// + /// + /// Typically, this will be used when the parameter of the plugins's + /// is . + /// + /// + /// + /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public sealed class OnStartAttribute : Attribute, IEdgeLifecycleAttribute { EdgeLifecycleType IEdgeLifecycleAttribute.Type => EdgeLifecycleType.Enable; } + /// + /// Indicates that the target method should be called when the plugin is disabled. + /// + /// + /// + /// This attribute is interchangable with , and is treated identically. + /// They are seperate to allow plugin code to more clearly describe the intent of the methods. + /// + /// + /// Typically, this will be used when the parameter of the plugins's + /// is . + /// + /// + /// + /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public sealed class OnDisableAttribute : Attribute, IEdgeLifecycleAttribute { EdgeLifecycleType IEdgeLifecycleAttribute.Type => EdgeLifecycleType.Disable; } + /// + /// Indicates that the target method should be called when the game exits. + /// + /// + /// + /// This attribute is interchangable with , and is treated identically. + /// They are seperate to allow plugin code to more clearly describe the intent of the methods. + /// + /// + /// Typically, this will be used when the parameter of the plugins's + /// is . + /// + /// + /// + /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public sealed class OnExitAttribute : Attribute, IEdgeLifecycleAttribute { diff --git a/IPA.Loader/PluginInterfaces/Attributes/PluginAttribute.cs b/IPA.Loader/PluginInterfaces/Attributes/PluginAttribute.cs index 44caf8f6..b39ceb22 100644 --- a/IPA.Loader/PluginInterfaces/Attributes/PluginAttribute.cs +++ b/IPA.Loader/PluginInterfaces/Attributes/PluginAttribute.cs @@ -1,32 +1,88 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using IPA.Loader; +using System; namespace IPA { + /// + /// Marks a class as being a BSIPA plugin. + /// + /// + /// + /// + /// + /// [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public sealed class PluginAttribute : Attribute { + /// + /// The passed into the constructor of this attribute. + /// // whenever this changes, PluginLoader.LoadMetadata must also change public RuntimeOptions RuntimeOptions { get; } + /// + /// Initializes a with the given + /// to indicate the runtime capabilities of the plugin. + /// + /// the options to use for this plugin public PluginAttribute(RuntimeOptions runtimeOptions) { RuntimeOptions = runtimeOptions; } } + /// + /// Options that a plugin must specify to describe how it expects to be run. + /// + /// + /// + /// + /// + /// + /// // TODO: figure out a better name for this public enum RuntimeOptions { + /// + /// Indicates that this plugin expects to be initialized and enabled with the game, and disabled with the game. + /// + /// + /// With this option set, whether or not the plugin is disabled during a given run is constant for that entire run. + /// SingleStartInit, - DynamicInit, - - // TODO: do I want this? - SingleDynamicInit + /// + /// Indicates that this plugin supports runtime enabling and disabling. + /// + /// + /// + /// When this is set, the plugin may be disabled at reasonable points during runtime. As with , + /// it will be initialized and enabled with the game if it is enabled on startup, and disabled with the game if it is enabled + /// on shutdown. + /// + /// + /// When a plugin with this set is enabled mid-game, the first time it is enabled, its initialization methods will be called, + /// then its enable methods. All subsequent enables will NOT re-initialize, however the enable methods will be called. + /// + /// + /// When a plugin with this set is disabled mid-game, the plugin instance will NOT be destroyed, and will instead be + /// re-used for subsequent enables. The plugin is expected to handle this gracefully, and behave in a way that makes sense. + /// + /// + DynamicInit } + /// + /// Marks a method or a constructor as an inialization method. + /// + /// + /// + /// If more than one constructor is marked with this attribute, the one with the most parameters, whether or not they can be injected, will be used. + /// + /// + /// Parameter injection is done with . + /// + /// + /// + /// [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] public sealed class InitAttribute : Attribute { } }