Bladeren bron

Implement new API structure for chainloader

Bepis 5 jaren geleden
bovenliggende
commit
a6fd33cb05
3 gewijzigde bestanden met toevoegingen van 74 en 45 verwijderingen
  1. 2 8
      BepInEx.Bootstrap/Linker.cs
  2. 39 11
      BepInEx/Bootstrap/Chainloader.cs
  3. 33 26
      BepInEx/Bootstrap/Preloader.cs

+ 2 - 8
BepInEx.Bootstrap/Linker.cs

@@ -1,5 +1,4 @@
 using System.Diagnostics;
-using System.Reflection;
 
 namespace BepInEx.Bootstrap
 {
@@ -7,13 +6,8 @@ namespace BepInEx.Bootstrap
 	{
 		public static void StartBepInEx()
 		{
-			var property = typeof(Paths)
-				.GetProperty("ExecutablePath", BindingFlags.Static | BindingFlags.Public)
-				?.GetSetMethod(true);
-
-			property?.Invoke(null, new object[] {Process.GetCurrentProcess().MainModule.FileName});
-			
-			Chainloader.Initialize();
+			Chainloader.Initialize(Process.GetCurrentProcess().MainModule.FileName);
+			Chainloader.Start();
 		}
 	}
 }

+ 39 - 11
BepInEx/Bootstrap/Chainloader.cs

@@ -4,6 +4,7 @@ using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using System.Reflection;
+using System.Text;
 using BepInEx.Logging;
 using UnityEngine;
 using UnityInjector.ConsoleUtil;
@@ -28,29 +29,56 @@ namespace BepInEx.Bootstrap
 
 
 		private static bool _loaded = false;
+		private static bool _initialized = false;
 
 		/// <summary>
-		/// The entry point for the BepInEx plugin system, called on the very first LoadScene() from UnityEngine.
+		/// Initializes BepInEx to be able to start the chainloader.
 		/// </summary>
-		public static void Initialize()
+		public static void Initialize(string containerExePath, bool startConsole = true)
 		{
-			if (_loaded)
+			if (_initialized)
 				return;
 
-			if (!Directory.Exists(Paths.PluginPath))
-				Directory.CreateDirectory(Paths.PluginPath);
+			//Set vitals
+			Paths.ExecutablePath = containerExePath;
 
-			Preloader.AllocateConsole();
+			//Start logging
 
-			try
+			if (startConsole)
 			{
-				UnityLogWriter unityLogWriter = new UnityLogWriter();
+				ConsoleWindow.Attach();
+				
+				ConsoleEncoding.ConsoleCodePage = (uint)Encoding.UTF8.CodePage;
+				Console.OutputEncoding = Encoding.UTF8;
+			}
+			
+			UnityLogWriter unityLogWriter = new UnityLogWriter();
 
-				if (Preloader.PreloaderLog != null)
-					unityLogWriter.WriteToLog($"{Preloader.PreloaderLog}\r\n");
+			if (Preloader.PreloaderLog != null)
+				unityLogWriter.WriteToLog($"{Preloader.PreloaderLog}\r\n");
 
-				Logger.SetLogger(unityLogWriter);
+			Logger.SetLogger(unityLogWriter);
 
+
+			_initialized = true;
+		}
+
+		/// <summary>
+		/// The entrypoint for the BepInEx plugin system.
+		/// </summary>
+		public static void Start()
+		{
+			if (_loaded)
+				return;
+
+			if (!_initialized)
+				throw new InvalidOperationException("BepInEx has not been initialized. Please call Chainloader.Initialize prior to starting the chainloader instance.");
+
+			if (!Directory.Exists(Paths.PluginPath))
+				Directory.CreateDirectory(Paths.PluginPath);
+
+			try
+			{
 				if (bool.Parse(Config.GetEntry("chainloader-log-unity-messages", "false", "BepInEx")))
 					UnityLogWriter.ListenUnityLogs();
 

+ 33 - 26
BepInEx/Bootstrap/Preloader.cs

@@ -226,27 +226,31 @@ namespace BepInEx.Bootstrap
 			string entrypointMethod = Config.GetEntry("entrypoint-method", ".cctor", "Preloader");
 
 			bool isCctor = entrypointMethod.IsNullOrWhiteSpace() || entrypointMethod == ".cctor";
+
+
+			var entryType = assembly.MainModule.Types.FirstOrDefault(x => x.Name == entrypointType);
+
+			if (entryType == null)
+			{
+				throw new Exception("The entrypoint type is invalid! Please check your config.ini");
+			}
 			
 			using (var injected = AssemblyDefinition.ReadAssembly(Paths.BepInExAssemblyPath))
 			{
-				var originalInjectMethod = injected.MainModule.Types.First(x => x.Name == "Chainloader").Methods
+				var originalInitMethod = injected.MainModule.Types.First(x => x.Name == "Chainloader").Methods
 					.First(x => x.Name == "Initialize");
 
-				var injectMethod = assembly.MainModule.ImportReference(originalInjectMethod);
-
-
-				var entryType = assembly.MainModule.Types.FirstOrDefault(x => x.Name == entrypointType);
-
-				if (entryType == null)
-				{
-					throw new Exception("The entrypoint type is invalid! Please check your config.ini");
-				}
+				var originalStartMethod = injected.MainModule.Types.First(x => x.Name == "Chainloader").Methods
+					.First(x => x.Name == "Start");
 
+				var initMethod = assembly.MainModule.ImportReference(originalInitMethod);
+				var startMethod = assembly.MainModule.ImportReference(originalStartMethod);
+				
+				List<MethodDefinition> methods = new List<MethodDefinition>();
 
 				if (isCctor)
 				{
 					MethodDefinition cctor = entryType.Methods.FirstOrDefault(m => m.IsConstructor && m.IsStatic);
-					ILProcessor il;
 
 					if (cctor == null)
 					{
@@ -256,29 +260,32 @@ namespace BepInEx.Bootstrap
 							assembly.MainModule.ImportReference(typeof(void)));
 
 						entryType.Methods.Add(cctor);
-						il = cctor.Body.GetILProcessor();
+						ILProcessor il = cctor.Body.GetILProcessor();
 						il.Append(il.Create(OpCodes.Ret));
 					}
 
-					Instruction ins = cctor.Body.Instructions.First();
-					il = cctor.Body.GetILProcessor();
-					il.InsertBefore(ins, il.Create(OpCodes.Call, injectMethod));
+					methods.Add(cctor);
 				}
 				else
 				{
-					List<MethodDefinition> methods = entryType.Methods.Where(x => x.Name == entrypointMethod).ToList();
-
-					if (!methods.Any())
-					{
-						throw new Exception("The entrypoint method is invalid! Please check your config.ini");
-					}
+					methods.AddRange(entryType.Methods.Where(x => x.Name == entrypointMethod));
+				}
 
-					foreach (var method in methods)
-					{
-						var il = method.Body.GetILProcessor();
+				if (!methods.Any())
+				{
+					throw new Exception("The entrypoint method is invalid! Please check your config.ini");
+				}
 
-						il.InsertBefore(method.Body.Instructions[0], il.Create(OpCodes.Call, injectMethod));
-					}
+				foreach (var method in methods)
+				{
+					var il = method.Body.GetILProcessor();
+
+					Instruction ins = il.Body.Instructions.First();
+						
+					il.InsertBefore(ins, il.Create(OpCodes.Ldstr, Paths.ExecutablePath)); //containerExePath
+					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.InsertBefore(ins, il.Create(OpCodes.Call, startMethod));
 				}
 			}
 		}