You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

95 lines
3.8 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using IPA.Config;
  6. using IPA.Logging;
  7. using IPA.Utilities;
  8. #if NET3
  9. using Net3_Proxy;
  10. #endif
  11. namespace IPA.Loader
  12. {
  13. /// <summary>
  14. /// The type that handles value injecting into a plugin's Init.
  15. /// </summary>
  16. public static class PluginInitInjector
  17. {
  18. /// <summary>
  19. /// 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.
  20. /// </summary>
  21. /// <param name="previous">the previous return value of the function, or <see langword="null"/> if never called for plugin.</param>
  22. /// <param name="param">the <see cref="ParameterInfo"/> of the parameter being injected.</param>
  23. /// <param name="meta">the <see cref="PluginLoader.PluginMetadata"/> for the plugin being loaded.</param>
  24. /// <returns>the value to inject into that parameter.</returns>
  25. public delegate object InjectParameter(object previous, ParameterInfo param, PluginLoader.PluginMetadata meta);
  26. /// <summary>
  27. /// Adds an injector to be used when calling future plugins' Init methods.
  28. /// </summary>
  29. /// <param name="type">the type of the parameter.</param>
  30. /// <param name="injector">the function to call for injection.</param>
  31. public static void AddInjector(Type type, InjectParameter injector)
  32. {
  33. injectors.Add(new Tuple<Type, InjectParameter>(type, injector));
  34. }
  35. private static readonly List<Tuple<Type, InjectParameter>> injectors = new List<Tuple<Type, InjectParameter>>
  36. {
  37. new Tuple<Type, InjectParameter>(typeof(Logger), (prev, param, meta) => prev ?? new StandardLogger(meta.Name)),
  38. #pragma warning disable CS0618 // Type or member is obsolete
  39. new Tuple<Type, InjectParameter>(typeof(IModPrefs), (prev, param, meta) => prev ?? new ModPrefs(meta)),
  40. #pragma warning restore CS0618 // Type or member is obsolete
  41. new Tuple<Type, InjectParameter>(typeof(PluginLoader.PluginMetadata), (prev, param, meta) => prev ?? meta),
  42. new Tuple<Type, InjectParameter>(typeof(IConfigProvider), (prev, param, meta) =>
  43. {
  44. if (prev != null) return prev;
  45. var cfgProvider = Config.Config.GetProviderFor(meta.Name, param);
  46. cfgProvider.Load();
  47. return cfgProvider;
  48. })
  49. };
  50. internal static void Inject(MethodInfo init, PluginLoader.PluginInfo info)
  51. {
  52. var instance = info.Plugin;
  53. var meta = info.Metadata;
  54. var initArgs = new List<object>();
  55. var initParams = init.GetParameters();
  56. Dictionary<Tuple<Type, InjectParameter>, object> previousValues =
  57. new Dictionary<Tuple<Type, InjectParameter>, object>(injectors.Count);
  58. foreach (var param in initParams)
  59. {
  60. var paramType = param.ParameterType;
  61. var value = paramType.GetDefault();
  62. foreach (var pair in injectors.Where(t => paramType.IsAssignableFrom(t.Item1)))
  63. {
  64. object prev = null;
  65. if (previousValues.ContainsKey(pair))
  66. prev = previousValues[pair];
  67. var val = pair.Item2?.Invoke(prev, param, meta);
  68. if (previousValues.ContainsKey(pair))
  69. previousValues[pair] = val;
  70. else
  71. previousValues.Add(pair, val);
  72. if (val == null) continue;
  73. value = val;
  74. break;
  75. }
  76. initArgs.Add(value);
  77. }
  78. init.Invoke(instance, initArgs.ToArray());
  79. }
  80. }
  81. }