A fork of Eusth's IPA
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.

165 lines
5.7KB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Runtime.InteropServices;
  7. using System.Text;
  8. using IllusionPlugin;
  9. namespace IllusionInjector
  10. {
  11. public static class PluginManager
  12. {
  13. private static List<IPlugin> _Plugins = null;
  14. /// <summary>
  15. /// Gets the list of loaded plugins and loads them if necessary.
  16. /// </summary>
  17. public static IEnumerable<IPlugin> Plugins
  18. {
  19. get
  20. {
  21. if (_Plugins == null)
  22. {
  23. LoadPlugins();
  24. }
  25. return _Plugins;
  26. }
  27. }
  28. private static void LoadPlugins()
  29. {
  30. string pluginDirectory = Path.Combine(Environment.CurrentDirectory, "Plugins");
  31. // Process.GetCurrentProcess().MainModule crashes the game and Assembly.GetEntryAssembly() is NULL,
  32. // so we need to resort to P/Invoke
  33. string exeName = Path.GetFileNameWithoutExtension(AppInfo.StartupPath);
  34. Console.WriteLine(exeName);
  35. _Plugins = new List<IPlugin>();
  36. if (!Directory.Exists(pluginDirectory))
  37. return;
  38. String[] files = Directory.GetFiles(pluginDirectory, "*.dll");
  39. foreach (var s in files)
  40. {
  41. _Plugins.AddRange(LoadPluginsFromFile(Path.Combine(pluginDirectory, s), exeName));
  42. }
  43. // DEBUG
  44. Console.WriteLine("Running on Unity {0} using {1}", UnityEngine.Application.unityVersion, GetFrameworkVersion());
  45. Console.WriteLine("-----------------------------");
  46. Console.WriteLine("Loading plugins from {0} and found {1}", pluginDirectory, _Plugins.Count);
  47. Console.WriteLine("-----------------------------");
  48. foreach (var plugin in _Plugins)
  49. {
  50. Console.WriteLine(" {0}: {1}", plugin.Name, plugin.Version);
  51. }
  52. Console.WriteLine("-----------------------------");
  53. }
  54. private static IEnumerable<IPlugin> LoadPluginsFromFile(string file, string exeName)
  55. {
  56. List<IPlugin> plugins = new List<IPlugin>();
  57. if (!File.Exists(file) || !file.EndsWith(".dll", true, null))
  58. return plugins;
  59. try
  60. {
  61. Assembly assembly = Assembly.LoadFrom(file);
  62. foreach (Type t in assembly.GetTypes())
  63. {
  64. if (IsValidPlugin(t))
  65. {
  66. try
  67. {
  68. IPlugin pluginInstance = Activator.CreateInstance(t) as IPlugin;
  69. string[] filter = null;
  70. if (pluginInstance is IEnhancedPlugin)
  71. {
  72. filter = ((IEnhancedPlugin)pluginInstance).Filter;
  73. }
  74. if (filter == null || Enumerable.Contains(filter, exeName, StringComparer.OrdinalIgnoreCase))
  75. plugins.Add(pluginInstance);
  76. }
  77. catch (Exception e)
  78. {
  79. Console.WriteLine("[WARN] Could not load plugin {0} in {1}! {2}", t.FullName, Path.GetFileName(file), e);
  80. }
  81. }
  82. }
  83. }
  84. catch (Exception e)
  85. {
  86. Console.WriteLine("[ERROR] Could not load {0}! {1}", Path.GetFileName(file), e);
  87. }
  88. return plugins;
  89. }
  90. private static bool IsValidPlugin(Type type)
  91. {
  92. return typeof(IPlugin).IsAssignableFrom(type)
  93. && !type.IsAbstract
  94. && !type.IsInterface
  95. && type.GetConstructor(Type.EmptyTypes) != null;
  96. }
  97. private static string GetFrameworkVersion()
  98. {
  99. var version = Environment.Version.ToString();
  100. try
  101. {
  102. switch (version)
  103. {
  104. case "2.0.50727.1433":
  105. return ".NET 3.5 Equivalent";
  106. case "4.0.30319.17020":
  107. // For reasons unknown, switching to netstandard seems to set this back to .NET 4.0
  108. var netstandard = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name == "netstandard");
  109. if (netstandard != null)
  110. return $".NET Standard {netstandard.GetName().Version.ToString(2)}";
  111. goto default;
  112. case "4.0.30319.42000":
  113. return ".NET 4.x";
  114. default:
  115. return $".NET Framework {version}";
  116. }
  117. }
  118. catch
  119. {
  120. // In case something goes wrong, return the best we can guess
  121. return version;
  122. }
  123. }
  124. public class AppInfo
  125. {
  126. [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false)]
  127. private static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);
  128. private static HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero);
  129. public static string StartupPath
  130. {
  131. get
  132. {
  133. StringBuilder stringBuilder = new StringBuilder(260);
  134. GetModuleFileName(NullHandleRef, stringBuilder, stringBuilder.Capacity);
  135. return stringBuilder.ToString();
  136. }
  137. }
  138. }
  139. }
  140. }