소스 검색

Unify Paths initializers; refactor preloader to unify build into one

ghorsington 5 년 전
부모
커밋
ba51ca8d8c

+ 3 - 2
BepInEx.Preloader/Entrypoint.cs

@@ -9,8 +9,9 @@ namespace BepInEx.Preloader
 	{
 		public static void PreloaderMain(string[] args)
 		{
-			Paths.SetExecutablePath(args[0]);
-			Paths.SetManagedPath(Environment.GetEnvironmentVariable("DOORSTOP_MANAGED_FOLDER_DIR"));
+			Paths.SetExecutablePath(args[0], 
+				Path.GetDirectoryName(Path.GetDirectoryName(Path.GetFullPath(Environment.GetEnvironmentVariable("DOORSTOP_INVOKE_DLL_PATH")))), 
+				Environment.GetEnvironmentVariable("DOORSTOP_MANAGED_FOLDER_DIR"));
 
 			AppDomain.CurrentDomain.AssemblyResolve += LocalResolve;
 			Preloader.Run();

+ 39 - 9
BepInEx.Preloader/Patching/AssemblyPatcher.cs

@@ -41,20 +41,50 @@ namespace BepInEx.Preloader.Patching
 
 		private static T CreateDelegate<T>(MethodInfo method) where T : class => method != null ? Delegate.CreateDelegate(typeof(T), method) as T : null;
 
+		private static PatcherPlugin ToPatcherPlugin(TypeDefinition type)
+		{
+			if (type.IsInterface || type.IsAbstract && !type.IsSealed)
+				return null;
+
+            var targetDlls = type.Methods.FirstOrDefault(m => m.Name.Equals("get_TargetDLLs", StringComparison.InvariantCultureIgnoreCase) &&
+															  m.IsPublic &&
+															  m.IsStatic);
+
+            if (targetDlls == null ||
+				targetDlls.ReturnType.FullName != "System.Collections.Generic.IEnumerable`1<System.String>")
+				return null;
+
+			var patch = type.Methods.FirstOrDefault(m => m.Name.Equals("Patch") &&
+														 m.IsPublic &&
+														 m.IsStatic &&
+														 m.ReturnType.FullName == "System.Void" &&
+														 m.Parameters.Count == 1 &&
+														 (m.Parameters[0].ParameterType.FullName == "Mono.Cecil.AssemblyDefinition&" ||
+														  m.Parameters[0].ParameterType.FullName == "Mono.Cecil.AssemblyDefinition"));
+
+			if (patch == null)
+				return null;
+
+			return new PatcherPlugin
+			{
+				Type = type,
+				Name = type.FullName
+			};
+		}
+
 		/// <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,
-			Func<TypeDefinition, PatcherPlugin> patcherLocator)
+        ///     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, patcherLocator);
+			var patchers = TypeLoader.FindPluginTypes(directory, ToPatcherPlugin);
 
 			foreach (var keyValuePair in patchers)
 			{
@@ -83,7 +113,7 @@ namespace BepInEx.Preloader.Patching
 
 						var patcher = methods.FirstOrDefault(m => m.Name.Equals("Patch", StringComparison.CurrentCultureIgnoreCase) &&
 																  m.ReturnType == typeof(void) &&
-																  m.GetParameters().Length == 0 &&
+																  m.GetParameters().Length == 1 &&
 																  (m.GetParameters()[0].ParameterType == typeof(AssemblyDefinition) ||
 																   m.GetParameters()[0].ParameterType == typeof(AssemblyDefinition).MakeByRefType()));
 
@@ -209,7 +239,7 @@ namespace BepInEx.Preloader.Patching
 
 			if (ConfigBreakBeforeLoadAssemblies.Value)
 			{
-				Logger.LogInfo($"BepInEx is about load the following assemblies:\n{string.Join("\n", patchedAssemblies.ToArray())}");
+				Logger.LogInfo($"BepInEx is about load the following assemblies:\n{String.Join("\n", patchedAssemblies.ToArray())}");
 				Logger.LogInfo($"The assemblies were dumped into {DumpedAssembliesPath}");
 				Logger.LogInfo("Load any assemblies into the debugger, set breakpoints and continue execution.");
 				Debugger.Break();

+ 19 - 49
BepInEx.Preloader/Preloader.cs

@@ -26,6 +26,20 @@ namespace BepInEx.Preloader
 		/// </summary>
 		private static PreloaderConsoleListener PreloaderLog { get; set; }
 
+		public static bool IsPostUnity2017 { get; } = File.Exists(Path.Combine(Paths.ManagedPath, "UnityEngine.CoreModule.dll"));
+
+		public static bool IsDotNet46 { get; } = string.Compare("4.0.30319.42000", Environment.Version.ToString(), StringComparison.Ordinal) <= 0;
+
+        static Preloader()
+		{
+			ConfigEntrypointAssembly = ConfigFile.CoreConfig.Wrap(
+				"Preloader.Entrypoint",
+				"Assembly",
+				"The local filename of the assembly to target.",
+				IsPostUnity2017 ? "UnityEngine.CoreModule.dll" : "UnityEngine.dll"
+            );
+        }
+
 		public static void Run()
 		{
 			try
@@ -57,13 +71,8 @@ namespace BepInEx.Preloader
 					Logger.LogMessage(attribute.Info);
 				}
 
-#if UNITY_2018
-				Logger.LogMessage("Compiled in Unity v2018 mode");
-#else
-				Logger.LogMessage("Compiled in Legacy Unity mode");
-#endif
-
-				Logger.LogInfo($"Running under Unity v{Process.GetCurrentProcess().MainModule.FileVersionInfo.FileVersion}");
+				Logger.LogInfo($"Running under Unity v{FileVersionInfo.GetVersionInfo(Paths.ExecutablePath).FileVersion}");
+				Logger.LogInfo($"CLR runtime version: {Environment.Version}");
 
 				Logger.LogMessage("Preloader started");
 
@@ -75,7 +84,7 @@ namespace BepInEx.Preloader
 					Name = "BepInEx.Chainloader"
 				});
 
-				AssemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath, ToPatcherPlugin);
+				AssemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);
 
 				Logger.LogInfo($"{AssemblyPatcher.PatcherPlugins.Count} patcher plugin(s) loaded");
 
@@ -123,36 +132,6 @@ namespace BepInEx.Preloader
 			}
 		}
 
-		public static PatcherPlugin ToPatcherPlugin(TypeDefinition type)
-		{
-			if (type.IsInterface || type.IsAbstract)
-				return null;
-
-			var targetDlls = type.Methods.FirstOrDefault(m => m.Name.Equals("get_TargetDLLs", StringComparison.InvariantCultureIgnoreCase) &&
-															  m.IsPublic &&
-															  m.IsStatic);
-
-			if (targetDlls == null ||
-				targetDlls.ReturnType.FullName != "System.Collections.Generic.IEnumerable`1<System.String>")
-				return null;
-
-			var patch = type.Methods.FirstOrDefault(m => m.Name.Equals("Patch") &&
-														 m.IsPublic &&
-														 m.IsStatic &&
-														 m.ReturnType.FullName == "System.Void" &&
-														 m.Parameters.Count == 1 &&
-														 (m.Parameters[0].ParameterType.FullName == "Mono.Cecil.AssemblyDefinition&" ||
-														  m.Parameters[0].ParameterType.FullName == "Mono.Cecil.AssemblyDefinition"));
-
-			if (patch == null)
-				return null;
-
-			return new PatcherPlugin
-			{
-				Type = type
-			};
-		}
-
 		/// <summary>
 		///     Inserts BepInEx's own chainloader entrypoint into UnityEngine.
 		/// </summary>
@@ -223,7 +202,7 @@ namespace BepInEx.Preloader
 					il.InsertBefore(ins,
 						il.Create(OpCodes.Ldc_I4_0)); //startConsole (always false, we already load the console in Preloader)
 					il.InsertBefore(ins,
-						il.Create(OpCodes.Call, initMethod)); //Chainloader.Initialize(string containerExePath, bool startConsole = true)
+						il.Create(OpCodes.Call, initMethod)); // Chainloader.Initialize(string containerExePath, string managedPath = null, bool startConsole = true)
 					il.InsertBefore(ins,
 						il.Create(OpCodes.Call, startMethod));
 				}
@@ -259,16 +238,7 @@ namespace BepInEx.Preloader
 
 		#region Config
 
-		private static readonly ConfigWrapper<string> ConfigEntrypointAssembly = ConfigFile.CoreConfig.Wrap(
-			"Preloader.Entrypoint",
-			"Assembly",
-			"The local filename of the assembly to target.",
-#if UNITY_2018
-			"UnityEngine.CoreModule.dll"
-#else
-			"UnityEngine.dll"
-#endif
-			);
+		private static readonly ConfigWrapper<string> ConfigEntrypointAssembly;
 
 		private static readonly ConfigWrapper<string> ConfigEntrypointType = ConfigFile.CoreConfig.Wrap(
 			"Preloader.Entrypoint",

+ 2 - 6
BepInEx.Preloader/RuntimeFixes/UnityPatches.cs

@@ -40,17 +40,13 @@ namespace BepInEx.Preloader.RuntimeFixes
 				__result = $"file://{location.Replace('\\', '/')}";
 		}
 
-#if UNITY_2018
-/*
- * DESC: Workaround for Trace class not working because of missing .config file
- * AFFECTS: Unity 2018+ (not .NET Standard / MonoBleedingEdge runtimes)
- */
 		[HarmonyPostfix, HarmonyPatch(typeof(AppDomain), nameof(AppDomain.SetupInformation), MethodType.Getter)]
 		public static void GetExeConfigName(AppDomainSetup __result)
 		{
+			if (!Preloader.IsDotNet46)
+				return;
 			__result.ApplicationBase = $"file://{Paths.GameRootPath}";
 			__result.ConfigurationFile = "app.config";
 		}
-#endif
 	}
 }

+ 2 - 4
BepInEx/Bootstrap/Chainloader.cs

@@ -39,15 +39,13 @@ namespace BepInEx.Bootstrap
 		/// <summary>
         /// Initializes BepInEx to be able to start the chainloader.
         /// </summary>
-        public static void Initialize(string containerExePath, string managedPath = null, bool startConsole = true)
+        public static void Initialize(string containerExePath, bool startConsole = true)
 		{
 			if (_initialized)
 				return;
 
 			//Set vitals
-			Paths.SetExecutablePath(containerExePath);
-			Paths.SetManagedPath(managedPath);
-			Paths.SetPluginPath(ConfigPluginsDirectory.Value);
+			Paths.SetExecutablePath(containerExePath, pluginPath: ConfigPluginsDirectory.Value);
 
             //Start logging
             if (ConsoleWindow.ConfigConsoleEnabled.Value && startConsole)

+ 12 - 16
BepInEx/Paths.cs

@@ -8,33 +8,29 @@ namespace BepInEx
 	/// </summary>
 	public static class Paths
 	{
-		internal static void SetExecutablePath(string executablePath)
+		internal static void SetExecutablePath(string executablePath, string bepinRootPath = null, string managedPath = null, string pluginPath = null)
 		{
 			ExecutablePath = executablePath;
 			ProcessName = Path.GetFileNameWithoutExtension(executablePath);
 			GameRootPath = Path.GetDirectoryName(executablePath);
-			ManagedPath = Utility.CombinePaths(GameRootPath, $"{ProcessName}_Data", "Managed");
-			BepInExRootPath = Path.Combine(GameRootPath, "BepInEx");
+
+			if (ManagedPath == null || managedPath != null)
+				ManagedPath = managedPath ?? Utility.CombinePaths(GameRootPath, $"{ProcessName}_Data", "Managed");
+
+			if (BepInExRootPath == null || bepinRootPath != null)
+				BepInExRootPath = bepinRootPath ?? Path.Combine(GameRootPath, "BepInEx");
+
 			ConfigPath = Path.Combine(BepInExRootPath, "config");
 			BepInExConfigPath = Path.Combine(ConfigPath, "BepInEx.cfg");
-			PluginPath = Path.Combine(BepInExRootPath, "plugins");
+
+			if (PluginPath == null || pluginPath != null)
+				PluginPath = pluginPath ?? Path.Combine(BepInExRootPath, "plugins");
+
 			PatcherPluginPath = Path.Combine(BepInExRootPath, "patchers");
 			BepInExAssemblyDirectory = Path.Combine(BepInExRootPath, "core");
 			BepInExAssemblyPath = Path.Combine(BepInExAssemblyDirectory, $"{Assembly.GetExecutingAssembly().GetName().Name}.dll");
 		}
 
-		internal static void SetManagedPath(string managedPath)
-		{
-			if (managedPath == null)
-				return;
-			ManagedPath = managedPath;
-		}
-
-		internal static void SetPluginPath(string pluginPath)
-		{
-			PluginPath = Utility.CombinePaths(BepInExRootPath, pluginPath);
-		}
-
 		/// <summary>
 		///     The directory that the core BepInEx DLLs reside in.
 		/// </summary>