Browse Source

Started work on Feature system

pull/1/head
Anairkoen Schno 5 years ago
parent
commit
4a41e618cf
2 changed files with 68 additions and 20 deletions
  1. +38
    -0
      IPA.Loader/Loader/Features/Feature.cs
  2. +30
    -20
      IPA.Loader/Loader/PluginLoader.cs

+ 38
- 0
IPA.Loader/Loader/Features/Feature.cs View File

@ -0,0 +1,38 @@
namespace IPA.Loader.Features
{
/// <summary>
/// The root interface for a mod Feature.
/// </summary>
public abstract class Feature
{
/// <summary>
/// Initializes the feature with the parameters provided in the definition.
///
/// Note: When no parenthesis are provided, <paramref name="parameters"/> is null.
/// </summary>
/// <param name="meta">the metadata of the plugin that is being prepared</param>
/// <param name="parameters">the parameters passed to the feature definition, or null</param>
/// <returns><see langword="true"/> if the feature is valid for the plugin, <see langword="false"/> otherwise</returns>
public abstract bool Initialize(PluginLoader.PluginMetadata meta, string[] parameters);
/// <summary>
/// Called before a plugin is loaded.
/// </summary>
/// <param name="plugin">the plugin about to be loaded</param>
/// <returns>whether or not the plugin should be loaded</returns>
public virtual bool BeforeLoad(PluginLoader.PluginMetadata plugin) => true;
/// <summary>
/// Called before a plugin's Init method is called.
/// </summary>
/// <param name="plugin">the plugin to be initialized</param>
/// <returns>whether or not to call the Init method</returns>
public virtual bool BeforeInit(PluginLoader.PluginInfo plugin) => true;
/// <summary>
/// Called after a plugin has been fully initialized, whether or not there is an Init method.
/// </summary>
/// <param name="plugin">the plugin that was just initialized</param>
public virtual void AfterInit(PluginLoader.PluginInfo plugin) { }
}
}

+ 30
- 20
IPA.Loader/Loader/PluginLoader.cs View File

@ -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.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using IPA.Config;
using IPA.Logging;
using IPA.Utilities;
using Mono.Cecil;
using Newtonsoft.Json;
using Version = SemVer.Version; using Version = SemVer.Version;
namespace IPA.Loader namespace IPA.Loader
@ -34,33 +35,42 @@ namespace IPA.Loader
/// The assembly the plugin was loaded from. /// The assembly the plugin was loaded from.
/// </summary> /// </summary>
public Assembly Assembly { get; internal set; } public Assembly Assembly { get; internal set; }
/// <summary> /// <summary>
/// The TypeDefinition for the main type of the plugin. /// The TypeDefinition for the main type of the plugin.
/// </summary> /// </summary>
public TypeDefinition PluginType { get; internal set; } public TypeDefinition PluginType { get; internal set; }
/// <summary> /// <summary>
/// The human readable name of the plugin. /// The human readable name of the plugin.
/// </summary> /// </summary>
public string Name { get; internal set; } public string Name { get; internal set; }
/// <summary> /// <summary>
/// The ModSaber ID of the plugin, or null if it doesn't have one. /// The ModSaber ID of the plugin, or null if it doesn't have one.
/// </summary> /// </summary>
public string Id { get; internal set; } public string Id { get; internal set; }
/// <summary> /// <summary>
/// The version of the plugin. /// The version of the plugin.
/// </summary> /// </summary>
public Version Version { get; internal set; } public Version Version { get; internal set; }
/// <summary> /// <summary>
/// The file the plugin was loaded from. /// The file the plugin was loaded from.
/// </summary> /// </summary>
public FileInfo File { get; internal set; } public FileInfo File { get; internal set; }
// ReSharper disable once UnusedAutoPropertyAccessor.Global // ReSharper disable once UnusedAutoPropertyAccessor.Global
/// <summary> /// <summary>
/// The features this plugin requests. /// The features this plugin requests.
/// </summary> /// </summary>
public string[] Features { get; internal set; }
public IReadOnlyList<Feature> Features => InternalFeatures;
internal List<Feature> InternalFeatures = new List<Feature>();
private PluginManifest manifest; private PluginManifest manifest;
internal PluginManifest Manifest internal PluginManifest Manifest
{ {
get => manifest; get => manifest;
@ -70,7 +80,6 @@ namespace IPA.Loader
Name = value.Name; Name = value.Name;
Version = value.Version; Version = value.Version;
Id = value.Id; Id = value.Id;
Features = value.Features;
} }
} }
@ -84,6 +93,7 @@ namespace IPA.Loader
public class PluginInfo public class PluginInfo
{ {
internal IBeatSaberPlugin Plugin { get; set; } internal IBeatSaberPlugin Plugin { get; set; }
/// <summary> /// <summary>
/// Metadata for the plugin. /// Metadata for the plugin.
/// </summary> /// </summary>
@ -133,8 +143,8 @@ namespace IPA.Loader
var pluginModule = AssemblyDefinition.ReadAssembly(plugin, new ReaderParameters var pluginModule = AssemblyDefinition.ReadAssembly(plugin, new ReaderParameters
{ {
ReadingMode = ReadingMode.Immediate,
ReadWrite = false
ReadingMode = ReadingMode.Immediate,
ReadWrite = false
}).MainModule; }).MainModule;
var iBeatSaberPlugin = pluginModule.ImportReference(typeof(IBeatSaberPlugin)); var iBeatSaberPlugin = pluginModule.ImportReference(typeof(IBeatSaberPlugin));
@ -186,7 +196,7 @@ namespace IPA.Loader
internal static void Resolve() internal static void Resolve()
{ // resolves duplicates and conflicts, etc { // resolves duplicates and conflicts, etc
PluginsMetadata.Sort((a, b) => a.Version.CompareTo(b.Version)); PluginsMetadata.Sort((a, b) => a.Version.CompareTo(b.Version));
var ids = new HashSet<string>(); var ids = new HashSet<string>();
var ignore = new HashSet<PluginMetadata>(); var ignore = new HashSet<PluginMetadata>();
var resolved = new List<PluginMetadata>(PluginsMetadata.Count); var resolved = new List<PluginMetadata>(PluginsMetadata.Count);
@ -284,7 +294,13 @@ namespace IPA.Loader
PluginsMetadata = metadata; 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) if (meta.PluginType == null)
return new PluginInfo() return new PluginInfo()
@ -297,8 +313,7 @@ namespace IPA.Loader
try 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 type = meta.Assembly.GetType(meta.PluginType.FullName);
var instance = (IBeatSaberPlugin)Activator.CreateInstance(type); var instance = (IBeatSaberPlugin)Activator.CreateInstance(type);
@ -361,11 +376,6 @@ namespace IPA.Loader
return info; return info;
} }
internal static List<PluginInfo> LoadPlugins()
{
var list = PluginsMetadata.Select(LoadPlugin).Where(p => p != null).ToList();
return list;
}
internal static List<PluginInfo> LoadPlugins() => PluginsMetadata.Select(InitPlugin).Where(p => p != null).ToList();
} }
} }

Loading…
Cancel
Save