private static void PostFindPluginTypes(Dictionary <string, List <PluginInfo> > __result, string directory, Func <TypeDefinition, PluginInfo> typeSelector, Func <AssemblyDefinition, bool> assemblyFilter, string cacheName) { // Prevent recursion if (directory != Paths.PluginPath) { return; } MultiFolderLoader.Logger.LogInfo("Finding plugins from mods..."); foreach (var pluginDir in ModManager.GetPluginDirs()) { var result = TypeLoader.FindPluginTypes(pluginDir, typeSelector, assemblyFilter, cacheName); foreach (var kv in result) { __result[kv.Key] = kv.Value; } } shouldSaveCache = true; if (cacheName != null) { TypeLoader.SaveAssemblyCache(cacheName, __result); } }
/// <summary> /// Adds all patchers from all managed assemblies specified in a directory. /// </summary> /// <param name="directory">Directory to search patcher DLLs from.</param> /// <param name="patcherLocator">A function that locates assembly patchers in a given managed assembly.</param> public static void AddPatchersFromDirectory(string directory) { if (!Directory.Exists(directory)) { return; } var sortedPatchers = new SortedDictionary <string, PatcherPlugin>(); var patchers = TypeLoader.FindPluginTypes(directory, ToPatcherPlugin); foreach (var keyValuePair in patchers) { var assemblyPath = keyValuePair.Key; var patcherCollection = keyValuePair.Value; if (patcherCollection.Count == 0) { continue; } var ass = Assembly.LoadFile(assemblyPath); foreach (var patcherPlugin in patcherCollection) { try { var type = ass.GetType(patcherPlugin.TypeName); var methods = type.GetMethods(ALL); patcherPlugin.Initializer = CreateDelegate <Action>(methods.FirstOrDefault(m => m.Name.Equals("Initialize", StringComparison.InvariantCultureIgnoreCase) && m.GetParameters().Length == 0 && m.ReturnType == typeof(void))); patcherPlugin.Finalizer = CreateDelegate <Action>(methods.FirstOrDefault(m => m.Name.Equals("Finish", StringComparison.InvariantCultureIgnoreCase) && m.GetParameters().Length == 0 && m.ReturnType == typeof(void))); patcherPlugin.TargetDLLs = CreateDelegate <Func <IEnumerable <string> > >(type.GetProperty("TargetDLLs", ALL).GetGetMethod()); var patcher = methods.FirstOrDefault(m => m.Name.Equals("Patch", StringComparison.CurrentCultureIgnoreCase) && m.ReturnType == typeof(void) && m.GetParameters().Length == 1 && (m.GetParameters()[0].ParameterType == typeof(AssemblyDefinition) || m.GetParameters()[0].ParameterType == typeof(AssemblyDefinition).MakeByRefType())); patcherPlugin.Patcher = (ref AssemblyDefinition pAss) => { //we do the array fuckery here to get the ref result out object[] args = { pAss }; patcher.Invoke(null, args); pAss = (AssemblyDefinition)args[0]; }; sortedPatchers.Add($"{ass.GetName().Name}/{type.FullName}", patcherPlugin); } catch (Exception e) { Logger.LogError($"Failed to load patcher [{patcherPlugin.TypeName}]: {e.Message}"); if (e is ReflectionTypeLoadException re) { Logger.LogDebug(TypeLoader.TypeLoadExceptionToString(re)); } else { Logger.LogDebug(e.ToString()); } } } Logger.Log(patcherCollection.Any() ? LogLevel.Info : LogLevel.Debug, $"Loaded {patcherCollection.Count} patcher methods from {ass.GetName().FullName}"); } foreach (KeyValuePair <string, PatcherPlugin> patcher in sortedPatchers) { AddPatcher(patcher.Value); } }