using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using IPA.Config; using IPA.Logging; using IPA.Utilities; namespace IPA.Loader { /// /// The type that handles value injecting into a plugin's Init. /// public static class PluginInitInjector { /// /// A typed injector for a plugin's Init method. When registered, called for all associated types. If it returns null, the default for the type will be used. /// /// the previous return value of the function, or if never called for plugin. /// the of the parameter being injected. /// the for the plugin being loaded. /// the value to inject into that parameter. public delegate object InjectParameter(object previous, ParameterInfo param, PluginLoader.PluginMetadata meta); /// /// Adds an injector to be used when calling future plugins' Init methods. /// /// the type of the parameter. /// the function to call for injection. public static void AddInjector(Type type, InjectParameter injector) { injectors.Add(new Tuple(type, injector)); } private static readonly List> injectors = new List> { new Tuple(typeof(Logger), (prev, param, meta) => prev ?? new StandardLogger(meta.Name)), new Tuple(typeof(IModPrefs), (prev, param, meta) => prev ?? new ModPrefs(meta)), new Tuple(typeof(IConfigProvider), (prev, param, meta) => { if (prev != null) return prev; var cfgProvider = Config.Config.GetProviderFor(meta.Name, param); cfgProvider.Load(); return cfgProvider; }) }; internal static void Inject(MethodInfo init, PluginLoader.PluginInfo info) { var instance = info.Plugin; var meta = info.Metadata; var initArgs = new List(); var initParams = init.GetParameters(); Dictionary, object> previousValues = new Dictionary, object>(injectors.Count); foreach (var param in initParams) { var paramType = param.ParameterType; var value = paramType.GetDefault(); foreach (var pair in injectors.Where(t => paramType.IsAssignableFrom(t.Item1))) { object prev = null; if (previousValues.ContainsKey(pair)) prev = previousValues[pair]; var val = pair.Item2?.Invoke(prev, param, meta); if (previousValues.ContainsKey(pair)) previousValues[pair] = val; else previousValues.Add(pair, val); if (val == null) continue; value = val; break; } initArgs.Add(value); } init.Invoke(instance, initArgs.ToArray()); } } }