private static async Task <List <UserModule> > GetModulesFromDirectoriesAsync(string[] directories) { var modTasks = directories.Where(dir => !dir.EndsWith("...ignore")).Select(async dir => { var files = Directory.GetFiles(dir, "*.dll", SearchOption.AllDirectories); UserModule mod = null; try { foreach (var file in files) { var asm = Assembly.LoadFrom(file); if (mod != null) { goto foundMod; } var startClasses = asm.GetTypes().Where(t => t.IsClass && t.BaseType == typeof(ModuleAPI.Module) && t.GetCustomAttribute <ApplicationHookAttribute>() != null ).ToList(); if (startClasses.Count <= 0) { continue; } var startupClass = startClasses[0]; mod = await UserModule.FromTypeAsync(startupClass); } foundMod: return(mod); } catch (Exception exc) { Logger.Log("Module loading error", exc); return(null); } }).ToList(); var foundModules = new List <UserModule>(); foreach (var modTask in modTasks) { if (modTask == null) { continue; } var um = await modTask; if (um != null) { foundModules.Add(um); } } return(foundModules); }
public static async Task LoadAllAsync() { ModuleLoadOrder = ModuleLoadOrder ?? new Dictionary <int, UserModule>(); ModuleLoadOrder?.Clear(); var sysModule = await UserModule.FromTypeAsync(typeof(SystemCommands)); ModuleLoadOrder.Add(ModuleLoadOrder.Count, sysModule); var directories = Directory.GetDirectories(ModuleDirectory, "*", SearchOption.TopDirectoryOnly); LoadingStarted?.Invoke(directories.Length); var foundModules = await GetModulesFromDirectoriesAsync(directories); foundModules.ForEach(um => { var index = ModuleLoadOrder.Count + 1; var canUse = false; do { if (!ModuleLoadOrder.ContainsKey(index)) { canUse = true; ModuleLoadOrder.Add(index, um); ModuleLoaded?.Invoke(um); } else { index++; } } while(canUse == false); }); LoadingEnded?.Invoke(); }
/// <summary> /// Load a module anywhere inside a specific directory /// </summary> /// <param name="directory">Location of the module</param> /// <returns></returns> private static UserModule GetModuleFromDirectory(string directory) { var files = Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories); UserModule mod = null; // Load each *.dll file found in the directory files.ToList().ForEach(async file => { try { var asm = Assembly.LoadFrom(file); // Search for a type in the loaded assembly that:- // 1. Is a child of the Module class // 2. Has the ApplicationHook attribute (that can only be applied to one class) var startClasses = asm.GetTypes().Where(t => t.IsClass && t.BaseType == typeof(ModuleAPI.Module) && t.GetCustomAttribute <ApplicationHookAttribute>() != null ).ToList(); // If any class meeting these conditions is found, // Store that as the 'Startup Class' i.e. the class // which will recieve commands through Project Butler if (startClasses.Count > 0) { var startupClass = startClasses[0]; mod = await UserModule.FromTypeAsync(startupClass); } } catch (Exception exc) { Logger.Log("Module loading error", exc); } }); return(mod); }