diff --git a/IPA.Loader/Loader/Features/Feature.cs b/IPA.Loader/Loader/Features/Feature.cs
new file mode 100644
index 00000000..2c2d565a
--- /dev/null
+++ b/IPA.Loader/Loader/Features/Feature.cs
@@ -0,0 +1,38 @@
+namespace IPA.Loader.Features
+{
+ ///
+ /// The root interface for a mod Feature.
+ ///
+ public abstract class Feature
+ {
+ ///
+ /// Initializes the feature with the parameters provided in the definition.
+ ///
+ /// Note: When no parenthesis are provided, is null.
+ ///
+ /// the metadata of the plugin that is being prepared
+ /// the parameters passed to the feature definition, or null
+ /// if the feature is valid for the plugin, otherwise
+ public abstract bool Initialize(PluginLoader.PluginMetadata meta, string[] parameters);
+
+ ///
+ /// Called before a plugin is loaded.
+ ///
+ /// the plugin about to be loaded
+ /// whether or not the plugin should be loaded
+ public virtual bool BeforeLoad(PluginLoader.PluginMetadata plugin) => true;
+
+ ///
+ /// Called before a plugin's Init method is called.
+ ///
+ /// the plugin to be initialized
+ /// whether or not to call the Init method
+ public virtual bool BeforeInit(PluginLoader.PluginInfo plugin) => true;
+
+ ///
+ /// Called after a plugin has been fully initialized, whether or not there is an Init method.
+ ///
+ /// the plugin that was just initialized
+ public virtual void AfterInit(PluginLoader.PluginInfo plugin) { }
+ }
+}
\ No newline at end of file
diff --git a/IPA.Loader/Loader/PluginLoader.cs b/IPA.Loader/Loader/PluginLoader.cs
index 4e646cc7..3233d334 100644
--- a/IPA.Loader/Loader/PluginLoader.cs
+++ b/IPA.Loader/Loader/PluginLoader.cs
@@ -1,14 +1,15 @@
-using System;
+using IPA.Config;
+using IPA.Loader.Features;
+using IPA.Logging;
+using IPA.Utilities;
+using Mono.Cecil;
+using Newtonsoft.Json;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
-using IPA.Config;
-using IPA.Logging;
-using IPA.Utilities;
-using Mono.Cecil;
-using Newtonsoft.Json;
using Version = SemVer.Version;
namespace IPA.Loader
@@ -34,33 +35,42 @@ namespace IPA.Loader
/// The assembly the plugin was loaded from.
///
public Assembly Assembly { get; internal set; }
+
///
/// The TypeDefinition for the main type of the plugin.
///
public TypeDefinition PluginType { get; internal set; }
+
///
/// The human readable name of the plugin.
///
public string Name { get; internal set; }
+
///
/// The ModSaber ID of the plugin, or null if it doesn't have one.
///
public string Id { get; internal set; }
+
///
/// The version of the plugin.
///
public Version Version { get; internal set; }
+
///
/// The file the plugin was loaded from.
///
public FileInfo File { get; internal set; }
+
// ReSharper disable once UnusedAutoPropertyAccessor.Global
///
/// The features this plugin requests.
///
- public string[] Features { get; internal set; }
+ public IReadOnlyList Features => InternalFeatures;
+
+ internal List InternalFeatures = new List();
private PluginManifest manifest;
+
internal PluginManifest Manifest
{
get => manifest;
@@ -70,7 +80,6 @@ namespace IPA.Loader
Name = value.Name;
Version = value.Version;
Id = value.Id;
- Features = value.Features;
}
}
@@ -84,6 +93,7 @@ namespace IPA.Loader
public class PluginInfo
{
internal IBeatSaberPlugin Plugin { get; set; }
+
///
/// Metadata for the plugin.
///
@@ -133,8 +143,8 @@ namespace IPA.Loader
var pluginModule = AssemblyDefinition.ReadAssembly(plugin, new ReaderParameters
{
- ReadingMode = ReadingMode.Immediate,
- ReadWrite = false
+ ReadingMode = ReadingMode.Immediate,
+ ReadWrite = false
}).MainModule;
var iBeatSaberPlugin = pluginModule.ImportReference(typeof(IBeatSaberPlugin));
@@ -186,7 +196,7 @@ namespace IPA.Loader
internal static void Resolve()
{ // resolves duplicates and conflicts, etc
PluginsMetadata.Sort((a, b) => a.Version.CompareTo(b.Version));
-
+
var ids = new HashSet();
var ignore = new HashSet();
var resolved = new List(PluginsMetadata.Count);
@@ -284,7 +294,13 @@ namespace IPA.Loader
PluginsMetadata = metadata;
}
- internal static PluginInfo LoadPlugin(PluginMetadata meta)
+ internal static void Load(PluginMetadata meta)
+ {
+ if (meta.Assembly == null)
+ meta.Assembly = Assembly.LoadFrom(meta.File.FullName);
+ }
+
+ internal static PluginInfo InitPlugin(PluginMetadata meta)
{
if (meta.PluginType == null)
return new PluginInfo()
@@ -297,8 +313,7 @@ namespace IPA.Loader
try
{
- Logger.loader.Debug(meta.File.FullName);
- meta.Assembly = Assembly.LoadFrom(meta.File.FullName);
+ Load(meta);
var type = meta.Assembly.GetType(meta.PluginType.FullName);
var instance = (IBeatSaberPlugin)Activator.CreateInstance(type);
@@ -361,11 +376,6 @@ namespace IPA.Loader
return info;
}
- internal static List LoadPlugins()
- {
- var list = PluginsMetadata.Select(LoadPlugin).Where(p => p != null).ToList();
-
- return list;
- }
+ internal static List LoadPlugins() => PluginsMetadata.Select(InitPlugin).Where(p => p != null).ToList();
}
}
\ No newline at end of file