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.

154 lines
5.4 KiB

  1. using IllusionPlugin;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Runtime.CompilerServices;
  9. using System.Runtime.InteropServices;
  10. using System.Text;
  11. namespace IllusionInjector
  12. {
  13. public static class PluginManager
  14. {
  15. private static List<IPlugin> _Plugins = null;
  16. internal static readonly Logger debugLogger = new Logger("IllusionInjector");
  17. /// <summary>
  18. /// Gets the list of loaded plugins and loads them if necessary.
  19. /// </summary>
  20. public static IEnumerable<IPlugin> Plugins
  21. {
  22. get
  23. {
  24. if(_Plugins == null)
  25. {
  26. LoadPlugins();
  27. }
  28. return _Plugins;
  29. }
  30. }
  31. private static void LoadPlugins()
  32. {
  33. string pluginDirectory = Path.Combine(Environment.CurrentDirectory, "Plugins");
  34. // Process.GetCurrentProcess().MainModule crashes the game and Assembly.GetEntryAssembly() is NULL,
  35. // so we need to resort to P/Invoke
  36. string exeName = Path.GetFileNameWithoutExtension(AppInfo.StartupPath);
  37. debugLogger.Log(exeName);
  38. _Plugins = new List<IPlugin>();
  39. if (!Directory.Exists(pluginDirectory)) return;
  40. if (!Directory.Exists(Path.Combine(pluginDirectory, ".cache")))
  41. {
  42. Directory.CreateDirectory(Path.Combine(pluginDirectory, ".cache"));
  43. }
  44. else
  45. {
  46. foreach (string plugin in Directory.GetFiles(Path.Combine(pluginDirectory, ".cache"), "*"))
  47. {
  48. File.Delete(plugin);
  49. }
  50. }
  51. //Copy plugins to .cache
  52. string[] originalPlugins = Directory.GetFiles(pluginDirectory, "*.dll");
  53. foreach (string s in originalPlugins)
  54. {
  55. string pluginCopy = pluginDirectory + "\\.cache" + s.Substring(s.LastIndexOf('\\'));
  56. File.Copy(Path.Combine(pluginDirectory, s), pluginCopy);
  57. }
  58. //Load copied plugins
  59. string copiedPluginsDirectory = pluginDirectory + "\\.cache";
  60. string[] copiedPlugins = Directory.GetFiles(copiedPluginsDirectory, "*.dll");
  61. foreach (string s in copiedPlugins)
  62. {
  63. _Plugins.AddRange(LoadPluginsFromFile(s, exeName));
  64. }
  65. // DEBUG
  66. debugLogger.Log($"Running on Unity {UnityEngine.Application.unityVersion}");
  67. debugLogger.Log("-----------------------------");
  68. debugLogger.Log($"Loading plugins from {pluginDirectory} and found {_Plugins.Count}");
  69. debugLogger.Log("-----------------------------");
  70. foreach (var plugin in _Plugins)
  71. {
  72. debugLogger.Log($"{plugin.Name}: {plugin.Version}");
  73. if (!(plugin is IPluginNew)) {
  74. debugLogger.Warning($"{plugin.Name} uses a Deprecated Interface! This may cause errors!");
  75. }
  76. }
  77. debugLogger.Log("-----------------------------");
  78. }
  79. private static IEnumerable<IPlugin> LoadPluginsFromFile(string file, string exeName)
  80. {
  81. List<IPlugin> plugins = new List<IPlugin>();
  82. if (!File.Exists(file) || !file.EndsWith(".dll", true, null))
  83. return plugins;
  84. try
  85. {
  86. Assembly assembly = Assembly.LoadFrom(file);
  87. foreach (Type t in assembly.GetTypes())
  88. {
  89. if (t.GetInterface("IPlugin") != null)
  90. {
  91. try
  92. {
  93. IPlugin pluginInstance = Activator.CreateInstance(t) as IPlugin;
  94. string[] filter = null;
  95. if (pluginInstance is IEnhancedPlugin)
  96. {
  97. filter = ((IEnhancedPlugin)pluginInstance).Filter;
  98. }
  99. if(filter == null || filter.Contains(exeName, StringComparer.OrdinalIgnoreCase))
  100. plugins.Add(pluginInstance);
  101. }
  102. catch (Exception e)
  103. {
  104. debugLogger.Exception($"Could not load plugin {t.FullName} in {Path.GetFileName(file)}! {e}");
  105. }
  106. }
  107. }
  108. }
  109. catch (Exception e)
  110. {
  111. debugLogger.Error($"Could not load {Path.GetFileName(file)}! {e}");
  112. }
  113. return plugins;
  114. }
  115. public class AppInfo
  116. {
  117. [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false)]
  118. private static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);
  119. private static HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero);
  120. public static string StartupPath
  121. {
  122. get
  123. {
  124. StringBuilder stringBuilder = new StringBuilder(260);
  125. GetModuleFileName(NullHandleRef, stringBuilder, stringBuilder.Capacity);
  126. return stringBuilder.ToString();
  127. }
  128. }
  129. }
  130. }
  131. }