using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text; using BepInEx.Logging; namespace BepInEx.Bootstrap { /// /// Provides methods for loading specified types from an assembly. /// public static class TypeLoader { /// /// Loads a list of types from a directory containing assemblies, that derive from a base type. /// /// The specific base type to search for. /// The directory to search for assemblies. /// Returns a list of found derivative types. public static IEnumerable LoadTypes(string directory) { List types = new List(); Type pluginType = typeof(T); foreach (string dll in Directory.GetFiles(Path.GetFullPath(directory), "*.dll", SearchOption.AllDirectories)) { try { AssemblyName an = AssemblyName.GetAssemblyName(dll); Assembly assembly = Assembly.Load(an); foreach (Type type in assembly.GetTypes()) { if (!type.IsInterface && !type.IsAbstract && pluginType.IsAssignableFrom(type)) types.Add(type); } } catch (BadImageFormatException) { } //unmanaged DLL catch (ReflectionTypeLoadException ex) { Logger.LogError($"Could not load \"{Path.GetFileName(dll)}\" as a plugin!"); Logger.LogDebug(TypeLoadExceptionToString(ex)); } } return types; } private static string TypeLoadExceptionToString(ReflectionTypeLoadException ex) { StringBuilder sb = new StringBuilder(); foreach (Exception exSub in ex.LoaderExceptions) { sb.AppendLine(exSub.Message); if (exSub is FileNotFoundException exFileNotFound) { if (!string.IsNullOrEmpty(exFileNotFound.FusionLog)) { sb.AppendLine("Fusion Log:"); sb.AppendLine(exFileNotFound.FusionLog); } } else if (exSub is FileLoadException exLoad) { if (!string.IsNullOrEmpty(exLoad.FusionLog)) { sb.AppendLine("Fusion Log:"); sb.AppendLine(exLoad.FusionLog); } } sb.AppendLine(); } return sb.ToString(); } } }