diff --git a/IPA.Loader/IPA.Loader.csproj b/IPA.Loader/IPA.Loader.csproj index 0c83a962..15272b25 100644 --- a/IPA.Loader/IPA.Loader.csproj +++ b/IPA.Loader/IPA.Loader.csproj @@ -64,6 +64,7 @@ + diff --git a/IPA.Loader/Loader/Features/DefineFeature.cs b/IPA.Loader/Loader/Features/DefineFeature.cs index 15fffad0..092c90e4 100644 --- a/IPA.Loader/Loader/Features/DefineFeature.cs +++ b/IPA.Loader/Loader/Features/DefineFeature.cs @@ -7,7 +7,7 @@ namespace IPA.Loader.Features { public static bool NewFeature = true; - internal override bool StoreOnPlugin => false; + protected internal override bool StoreOnPlugin => false; public override bool Initialize(PluginLoader.PluginMetadata meta, string[] parameters) { // parameters should be (name, fully qualified type) diff --git a/IPA.Loader/Loader/Features/Feature.cs b/IPA.Loader/Loader/Features/Feature.cs index ec84ec20..4b103b1b 100644 --- a/IPA.Loader/Loader/Features/Feature.cs +++ b/IPA.Loader/Loader/Features/Feature.cs @@ -69,7 +69,10 @@ namespace IPA.Loader.Features /// the plugin to ensure is loaded. protected void RequireLoaded(PluginLoader.PluginMetadata plugin) => PluginLoader.Load(plugin); - internal virtual bool StoreOnPlugin => true; + /// + /// Defines whether or not this feature will be accessible from the plugin metadata once loaded. + /// + protected internal virtual bool StoreOnPlugin => true; private static readonly Dictionary featureTypes = new Dictionary { diff --git a/IPA.Loader/Loader/Features/InitInjectorFeature.cs b/IPA.Loader/Loader/Features/InitInjectorFeature.cs new file mode 100644 index 00000000..d4f069dc --- /dev/null +++ b/IPA.Loader/Loader/Features/InitInjectorFeature.cs @@ -0,0 +1,102 @@ +using System; +using System.IO; +using System.Reflection; + +namespace IPA.Loader.Features +{ + internal class InitInjectorFeature : Feature + { + protected internal override bool StoreOnPlugin => false; + + public override bool Initialize(PluginLoader.PluginMetadata meta, string[] parameters) + { // parameters should be (assembly qualified lookup type, [fully qualified type]:[method name]) + // method should be static + if (parameters.Length != 2) + { + InvalidMessage = "Incorrect number of parameters"; + return false; + } + + RequireLoaded(meta); + + var methodParts = parameters[1].Split(':'); + + var type = Type.GetType(parameters[0], false); + if (type == null) + { + InvalidMessage = $"Could not find type {parameters[0]}"; + return false; + } + + Type getType; + try + { + getType = meta.Assembly.GetType(methodParts[0]); + } + catch (ArgumentException) + { + InvalidMessage = $"Invalid type name {methodParts[0]}"; + return false; + } + catch (Exception e) when (e is FileNotFoundException || e is FileLoadException || e is BadImageFormatException) + { + string filename; + + switch (e) + { + case FileNotFoundException fn: + filename = fn.FileName; + goto hasFilename; + case FileLoadException fl: + filename = fl.FileName; + goto hasFilename; + case BadImageFormatException bi: + filename = bi.FileName; + hasFilename: + InvalidMessage = $"Could not find {filename} while loading type"; + break; + default: + InvalidMessage = $"Error while loading type: {e}"; + break; + } + + return false; + } + + MethodInfo method; + try + { + method = getType.GetMethod(methodParts[1], BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, + null, new[] + { + typeof(object), + typeof(ParameterInfo), + typeof(PluginLoader.PluginMetadata) + }, new ParameterModifier[0]); + } + catch (Exception e) + { + InvalidMessage = $"Error while loading type: {e}"; + return false; + } + + if (method == null) + { + InvalidMessage = $"Could not find method {methodParts[1]} in type {methodParts[0]}"; + return false; + } + + try + { + var del = (PluginInitInjector.InjectParameter)Delegate.CreateDelegate(typeof(PluginInitInjector.InjectParameter), null, method); + PluginInitInjector.AddInjector(type, del); + return true; + } + catch (Exception e) + { + InvalidMessage = $"Error generated while creating delegate: {e}"; + return false; + } + } + } +} diff --git a/IPA.Loader/Loader/manifest.json b/IPA.Loader/Loader/manifest.json index 75855794..d754a56c 100644 --- a/IPA.Loader/Loader/manifest.json +++ b/IPA.Loader/Loader/manifest.json @@ -11,6 +11,7 @@ "define-feature(debug, IPA.Loader.Features.DebugFeature)", "define-feature(warn, IPA.Loader.Features.WarnFeature)", "define-feature(no-update, IPA.Loader.Features.NoUpdateFeature)", - "define-feature(add-in, IPA.Loader.Features.AddInFeature)" + "define-feature(add-in, IPA.Loader.Features.AddInFeature)", + "define-feature(init-injector, IPA.Loader.Features.InitInjectorFeature)" ] } \ No newline at end of file