Browse Source

Make TypeLoader generic loader

ghorsington 5 years ago
parent
commit
a89ae05e40
3 changed files with 67 additions and 61 deletions
  1. 41 3
      BepInEx/Bootstrap/Chainloader.cs
  2. 10 49
      BepInEx/Bootstrap/TypeLoader.cs
  3. 16 9
      BepInEx/Utility.cs

+ 41 - 3
BepInEx/Bootstrap/Chainloader.cs

@@ -79,6 +79,44 @@ namespace BepInEx.Bootstrap
 			_initialized = true;
 		}
 
+		private static PluginInfo ToPluginInfo(TypeDefinition type)
+		{
+			if (type.IsInterface || type.IsAbstract || !type.IsSubtypeOf(typeof(BaseUnityPlugin)))
+				return null;
+
+			var metadata = BepInPlugin.FromCecilType(type);
+
+			if (metadata == null)
+			{
+				Logger.LogWarning($"Skipping over type [{type.Name}] as no metadata attribute is specified");
+				return null;
+			}
+
+			//Perform a filter for currently running process
+			var filters = BepInProcess.FromCecilType(type);
+
+			bool invalidProcessName = filters.Any(x => x.ProcessName.ToLower().Replace(".exe", "") == Paths.ProcessName);
+
+			if (invalidProcessName)
+			{
+				Logger.LogWarning($"Skipping over plugin [{metadata.GUID}] due to process filter");
+				return null;
+			}
+
+			var dependencies = BepInDependency.FromCecilType(type);
+
+			Logger.LogInfo($"Type path: {type.Module.FileName}");
+
+			return new PluginInfo
+			{
+				Metadata = metadata,
+				Processes = filters,
+				Dependencies = dependencies,
+				CecilType = type,
+				Location = type.Module.FileName
+			};
+		}
+
 		/// <summary>
 		/// The entrypoint for the BepInEx plugin system.
 		/// </summary>
@@ -108,7 +146,7 @@ namespace BepInEx.Bootstrap
 
 				UnityEngine.Object.DontDestroyOnLoad(ManagerObject);
 
-				var pluginsToLoad = TypeLoader.FindPluginTypes(Paths.PluginPath);
+				var pluginsToLoad = TypeLoader.FindPluginTypes(Paths.PluginPath, ToPluginInfo);
 
 				var pluginInfos = pluginsToLoad.SelectMany(p => p.Value).ToList();
 
@@ -184,8 +222,8 @@ namespace BepInEx.Bootstrap
 					if (missingDependencies.Count != 0)
 					{
 						Logger.LogError($@"Missing the following dependencies for [{pluginInfo.Metadata.Name}]: {"\r\n"}{
-												string.Join("\r\n", missingDependencies.Select(s => $"- {s}").ToArray())
-											}{"\r\n"}Loading will be skipped; expect further errors and unstabilities.");
+								string.Join("\r\n", missingDependencies.Select(s => $"- {s}").ToArray())
+							}{"\r\n"}Loading will be skipped; expect further errors and unstabilities.");
 
 						invalidPlugins.Add(pluginGUID);
 						continue;

+ 10 - 49
BepInEx/Bootstrap/TypeLoader.cs

@@ -16,13 +16,6 @@ namespace BepInEx.Bootstrap
 	/// </summary>
 	public static class TypeLoader
 	{
-		private static bool Is(this TypeDefinition self, Type td)
-		{
-			if (self.FullName == td.FullName)
-				return true;
-			return self.FullName != "System.Object" && (self.BaseType?.Resolve().Is(td) ?? false);
-		}
-
 		private static DefaultAssemblyResolver resolver;
 		private static ReaderParameters readerParameters;
 
@@ -35,7 +28,9 @@ namespace BepInEx.Bootstrap
 			{
 				var name = new AssemblyName(reference.FullName);
 
-				if (Utility.TryResolveDllAssembly(name, Paths.BepInExAssemblyDirectory, readerParameters, out AssemblyDefinition assembly) || Utility.TryResolveDllAssembly(name, Paths.PluginPath, readerParameters, out assembly) || Utility.TryResolveDllAssembly(name, Paths.ManagedPath, readerParameters, out assembly))
+				if (Utility.TryResolveDllAssembly(name, Paths.BepInExAssemblyDirectory, readerParameters, out AssemblyDefinition assembly) ||
+					Utility.TryResolveDllAssembly(name, Paths.PluginPath, readerParameters, out assembly) ||
+					Utility.TryResolveDllAssembly(name, Paths.ManagedPath, readerParameters, out assembly))
 					return assembly;
 
 				return null;
@@ -48,11 +43,9 @@ namespace BepInEx.Bootstrap
 		/// <typeparam name="T">The specific base type to search for.</typeparam>
 		/// <param name="directory">The directory to search for assemblies.</param>
 		/// <returns>Returns a list of found derivative types.</returns>
-		public static Dictionary<AssemblyDefinition, IEnumerable<PluginInfo>> FindPluginTypes(string directory)
+		public static Dictionary<AssemblyDefinition, IEnumerable<T>> FindPluginTypes<T>(string directory, Func<TypeDefinition, T> typeSelector) where T : class
 		{
-			var result = new Dictionary<AssemblyDefinition, IEnumerable<PluginInfo>>();
-			var pluginType = typeof(BaseUnityPlugin);
-			string currentProcess = Process.GetCurrentProcess().ProcessName.ToLower();
+			var result = new Dictionary<AssemblyDefinition, IEnumerable<T>>();
 
 			foreach (string dll in Directory.GetFiles(Path.GetFullPath(directory), "*.dll", SearchOption.AllDirectories))
 			{
@@ -60,47 +53,15 @@ namespace BepInEx.Bootstrap
 				{
 					var ass = AssemblyDefinition.ReadAssembly(dll, readerParameters);
 
-					var matchingTypes = ass.MainModule.Types.Where(t => !t.IsInterface && !t.IsAbstract && t.Is(pluginType)).ToList();
+					var matches = ass.MainModule.Types.Select(typeSelector).Where(t => t != null).ToList();
 
-					if (matchingTypes.Count == 0)
-						continue;
-
-					var pluginInfos = new List<PluginInfo>();
-
-					foreach (var pluginTypeDefinition in matchingTypes)
+					if (matches.Count == 0)
 					{
-						var metadata = BepInPlugin.FromCecilType(pluginTypeDefinition);
-
-						if (metadata == null)
-						{
-							Logger.LogWarning($"Skipping over type [{pluginTypeDefinition.Name}] as no metadata attribute is specified");
-							continue;
-						}
-
-						//Perform a filter for currently running process
-						var filters = BepInProcess.FromCecilType(pluginTypeDefinition);
-
-						bool invalidProcessName = filters.Any(x => x.ProcessName.ToLower().Replace(".exe", "") == currentProcess);
-
-						if (invalidProcessName)
-						{
-							Logger.LogInfo($"Skipping over plugin [{metadata.GUID}] due to process filter");
-							continue;
-						}
-
-						var dependencies = BepInDependency.FromCecilType(pluginTypeDefinition);
-
-						pluginInfos.Add(new PluginInfo
-						{
-							Metadata = metadata,
-							Processes = filters,
-							Dependencies = dependencies,
-							CecilType = pluginTypeDefinition,
-							Location = dll
-						});
+						ass.Dispose();
+						continue;
 					}
 
-					result[ass] = pluginInfos;
+					result[ass] = matches;
 				}
 				catch (Exception e)
 				{

+ 16 - 9
BepInEx/Utility.cs

@@ -25,7 +25,7 @@ namespace BepInEx
 		/// <param name="input">The string to parse</param>
 		/// <param name="defaultValue">The value to return if parsing is unsuccessful.</param>
 		/// <returns>Boolean value of input if able to be parsed, otherwise default value.</returns>
-		public static bool SafeParseBool(string input, bool defaultValue = false) { return bool.TryParse(input, out bool result) ? result : defaultValue; }
+		public static bool SafeParseBool(string input, bool defaultValue = false) { return Boolean.TryParse(input, out bool result) ? result : defaultValue; }
 
 		/// <summary>
 		/// Converts a file path into a UnityEngine.WWW format.
@@ -39,7 +39,7 @@ namespace BepInEx
 		/// </summary>
 		/// <param name="self">The string to test.</param>
 		/// <returns>True if the value parameter is null or empty, or if value consists exclusively of white-space characters.</returns>
-		public static bool IsNullOrWhiteSpace(this string self) { return self == null || self.All(char.IsWhiteSpace); }
+		public static bool IsNullOrWhiteSpace(this string self) { return self == null || self.All(Char.IsWhiteSpace); }
 
 		public static IEnumerable<TNode> TopologicalSort<TNode>(IEnumerable<TNode> nodes, Func<TNode, IEnumerable<TNode>> dependencySelector)
 		{
@@ -128,14 +128,21 @@ namespace BepInEx
 			return false;
 		}
 
+		public static bool IsSubtypeOf(this TypeDefinition self, Type td)
+		{
+			if (self.FullName == td.FullName)
+				return true;
+			return self.FullName != "System.Object" && (self.BaseType?.Resolve().IsSubtypeOf(td) ?? false);
+		}
+
 		/// <summary>
-		/// Try to resolve and load the given assembly DLL.
-		/// </summary>
-		/// <param name="assemblyName">Name of the assembly, of the type <see cref="AssemblyName" />.</param>
-		/// <param name="directory">Directory to search the assembly from.</param>
-		/// <param name="assembly">The loaded assembly.</param>
-		/// <returns>True, if the assembly was found and loaded. Otherwise, false.</returns>
-		public static bool TryResolveDllAssembly(AssemblyName assemblyName, string directory, out Assembly assembly) { return TryResolveDllAssembly(assemblyName, directory, Assembly.LoadFile, out assembly); }
+        /// Try to resolve and load the given assembly DLL.
+        /// </summary>
+        /// <param name="assemblyName">Name of the assembly, of the type <see cref="AssemblyName" />.</param>
+        /// <param name="directory">Directory to search the assembly from.</param>
+        /// <param name="assembly">The loaded assembly.</param>
+        /// <returns>True, if the assembly was found and loaded. Otherwise, false.</returns>
+        public static bool TryResolveDllAssembly(AssemblyName assemblyName, string directory, out Assembly assembly) { return TryResolveDllAssembly(assemblyName, directory, Assembly.LoadFile, out assembly); }
 
 		/// <summary>
 		/// Try to resolve and load the given assembly DLL.