mirror of
https://github.com/BepInEx/BepInEx.git
synced 2026-10-19 15:51:45 +00:00
145 lines
5.6 KiB
C#
145 lines
5.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
|
|
// This code is shared between the .NET Framework launcher and the .NET Core entrypoint projects.
|
|
// However, it cannot be placed in the NetLauncher.Common project because this has to do with assembly resolution,
|
|
// and placing this logic inside of an external assembly will cause a crash.
|
|
// A shared project is the only way to deduplicate code here
|
|
|
|
namespace BepInEx.NET.Shared
|
|
{
|
|
internal static class SharedEntrypoint
|
|
{
|
|
public static ResolveEventHandler RemoteResolve(List<string> resolveDirectories)
|
|
{
|
|
return (sender, args) => RemoteResolveInternal(sender, args, resolveDirectories);
|
|
}
|
|
|
|
private static Assembly RemoteResolveInternal(object sender,
|
|
ResolveEventArgs reference,
|
|
List<string> resolveDirectories)
|
|
{
|
|
var assemblyName = new AssemblyName(reference.Name);
|
|
|
|
foreach (var directory in resolveDirectories)
|
|
{
|
|
if (!Directory.Exists(directory))
|
|
continue;
|
|
|
|
var potentialDirectories = new List<string> { directory };
|
|
|
|
potentialDirectories.AddRange(Directory.GetDirectories(directory, "*", SearchOption.AllDirectories));
|
|
|
|
var potentialFiles = potentialDirectories.Select(x => Path.Combine(x, $"{assemblyName.Name}.dll"))
|
|
.Concat(potentialDirectories.Select(x =>
|
|
Path
|
|
.Combine(x,
|
|
$"{assemblyName.Name}.exe")));
|
|
|
|
foreach (var path in potentialFiles)
|
|
{
|
|
if (!File.Exists(path))
|
|
continue;
|
|
|
|
Assembly assembly;
|
|
|
|
try
|
|
{
|
|
assembly = Assembly.LoadFrom(path);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (assembly.GetName().Name == assemblyName.Name)
|
|
return assembly;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static Assembly LocalResolve(object sender, ResolveEventArgs args)
|
|
{
|
|
var assemblyName = new AssemblyName(args.Name);
|
|
|
|
var foundAssembly = AppDomain.CurrentDomain.GetAssemblies()
|
|
.FirstOrDefault(x => x.GetName().Name == assemblyName.Name);
|
|
|
|
if (foundAssembly != null)
|
|
return foundAssembly;
|
|
|
|
if (LocalUtility.TryResolveDllAssembly(assemblyName, Paths.BepInExAssemblyDirectory, out foundAssembly)
|
|
|| LocalUtility.TryResolveDllAssembly(assemblyName, Paths.PatcherPluginPath, out foundAssembly)
|
|
|| LocalUtility.TryResolveDllAssembly(assemblyName, Paths.PluginPath, out foundAssembly))
|
|
return foundAssembly;
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Generic helper properties and methods.
|
|
/// </summary>
|
|
internal static class LocalUtility
|
|
{
|
|
/// <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>
|
|
private static bool TryResolveDllAssembly<T>(AssemblyName assemblyName,
|
|
string directory,
|
|
Func<string, T> loader,
|
|
out T assembly) where T : class
|
|
{
|
|
assembly = null;
|
|
|
|
if (!Directory.Exists(directory))
|
|
return false;
|
|
|
|
var potentialDirectories = new List<string> { directory };
|
|
|
|
potentialDirectories.AddRange(Directory.GetDirectories(directory, "*", SearchOption.AllDirectories));
|
|
|
|
foreach (var subDirectory in potentialDirectories)
|
|
{
|
|
var path = Path.Combine(subDirectory, $"{assemblyName.Name}.dll");
|
|
|
|
if (!File.Exists(path))
|
|
continue;
|
|
|
|
try
|
|
{
|
|
assembly = loader(path);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return 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) =>
|
|
TryResolveDllAssembly(assemblyName, directory, Assembly.LoadFile, out assembly);
|
|
}
|
|
}
|