Unify Paths initializers; refactor preloader to unify build into one

This commit is contained in:
ghorsington committed 2019-06-16 17:20:12 +03:00
1 parent c8118efcc0
commit ba51ca8d8c
6 files changed
+77 -86

No files matched your search

+3 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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",
@@ -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
View File
@@ -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
View File
@@ -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>