using IllusionPlugin; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; namespace IllusionInjector { public static class PluginManager { private static List _Plugins = null; internal static readonly Logger debugLogger = new Logger("IllusionInjector"); /// /// Gets the list of loaded plugins and loads them if necessary. /// public static IEnumerable Plugins { get { if(_Plugins == null) { LoadPlugins(); } return _Plugins; } } private static void LoadPlugins() { string pluginDirectory = Path.Combine(Environment.CurrentDirectory, "Plugins"); // Process.GetCurrentProcess().MainModule crashes the game and Assembly.GetEntryAssembly() is NULL, // so we need to resort to P/Invoke string exeName = Path.GetFileNameWithoutExtension(AppInfo.StartupPath); debugLogger.Log(exeName); _Plugins = new List(); if (!Directory.Exists(pluginDirectory)) return; if (!Directory.Exists(Path.Combine(pluginDirectory, ".cache"))) { Directory.CreateDirectory(Path.Combine(pluginDirectory, ".cache")); } else { foreach (string plugin in Directory.GetFiles(Path.Combine(pluginDirectory, ".cache"), "*")) { File.Delete(plugin); } } String[] files = Directory.GetFiles(pluginDirectory, "*.dll"); foreach (string s in files) { string pluginCopy = pluginDirectory + "\\.cache" + s.Substring(s.LastIndexOf('\\')); File.Copy(Path.Combine(pluginDirectory, s), pluginCopy); _Plugins.AddRange(LoadPluginsFromFile(pluginCopy, exeName)); } // DEBUG debugLogger.Log($"Running on Unity {UnityEngine.Application.unityVersion}"); debugLogger.Log("-----------------------------"); debugLogger.Log($"Loading plugins from {pluginDirectory} and found {_Plugins.Count}"); debugLogger.Log("-----------------------------"); foreach (var plugin in _Plugins) { debugLogger.Log($"{plugin.Name}: {plugin.Version}"); if (!(plugin is IPluginNew)) { debugLogger.Warning($"{plugin.Name} uses a Deprecated Interface! This may cause errors!"); } } debugLogger.Log("-----------------------------"); } private static IEnumerable LoadPluginsFromFile(string file, string exeName) { List plugins = new List(); if (!File.Exists(file) || !file.EndsWith(".dll", true, null)) return plugins; try { Assembly assembly = Assembly.LoadFrom(file); foreach (Type t in assembly.GetTypes()) { if (t.GetInterface("IPlugin") != null) { try { IPlugin pluginInstance = Activator.CreateInstance(t) as IPlugin; string[] filter = null; if (pluginInstance is IEnhancedPlugin) { filter = ((IEnhancedPlugin)pluginInstance).Filter; } if(filter == null || filter.Contains(exeName, StringComparer.OrdinalIgnoreCase)) plugins.Add(pluginInstance); } catch (Exception e) { debugLogger.Exception($"Could not load plugin {t.FullName} in {Path.GetFileName(file)}! {e}"); } } } } catch (Exception e) { debugLogger.Error($"Could not load {Path.GetFileName(file)}! {e}"); } return plugins; } public class AppInfo { [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false)] private static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length); private static HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero); public static string StartupPath { get { StringBuilder stringBuilder = new StringBuilder(260); GetModuleFileName(NullHandleRef, stringBuilder, stringBuilder.Capacity); return stringBuilder.ToString(); } } } } }