using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace SpaceEngineersBlueprintEditor.GameAssemblyLoader;
/// <summary>
/// Resolves Space Engineers managed and native dependencies directly from Bin64.
/// </summary>
public static class GameAssemblyLoader
{
private static readonly object SyncRoot = new object();
private static bool resolverRegistered;
/// <summary>
/// Gets the currently selected game root directory.
/// </summary>
public static string? GameRootPath { get; private set; }
/// <summary>
/// Gets the currently selected game Bin64 directory.
/// </summary>
public static string? GameBinPath { get; private set; }
/// <summary>
/// Detects the game, registers assembly resolution, and returns the validated game root.
/// This method is safe to call more than once before game types are used.
/// </summary>
public static string? Initialize(string? preferredPath = null)
{
lock (SyncRoot)
{
if (!resolverRegistered)
{
AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;
resolverRegistered = true;
}
var gameRoot = GameInstallationLocator.FindGameRootPath(preferredPath);
if (gameRoot is null)
{
return GameRootPath;
}
GameRootPath = gameRoot;
GameBinPath = Path.Combine(gameRoot, "Bin64");
SetDllDirectory(GameBinPath);
return GameRootPath;
}
}
/// <summary>
/// Initializes the loader or throws a descriptive error when the game is unavailable.
/// </summary>
public static string EnsureInitialized(string? preferredPath = null)
{
return Initialize(preferredPath) ?? throw new DirectoryNotFoundException(
"Space Engineers was not found. Install the Steam game or select its installation directory in Settings.");
}
private static Assembly? ResolveAssembly(object? sender, ResolveEventArgs args)
{
var binPath = GameBinPath;
if (string.IsNullOrWhiteSpace(binPath))
{
return null;
}
AssemblyName requestedName;
try
{
requestedName = new AssemblyName(args.Name);
}
catch (ArgumentException)
{
return null;
}
if (string.IsNullOrWhiteSpace(requestedName.Name))
{
return null;
}
var candidate = Path.Combine(binPath!, requestedName.Name + ".dll");
if (!File.Exists(candidate))
{
return null;
}
try
{
var candidateName = AssemblyName.GetAssemblyName(candidate);
if (!string.Equals(candidateName.Name, requestedName.Name, StringComparison.OrdinalIgnoreCase))
{
return null;
}
return Assembly.LoadFrom(candidate);
}
catch (BadImageFormatException)
{
return null;
}
catch (FileLoadException)
{
return null;
}
catch (FileNotFoundException)
{
return null;
}
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetDllDirectory(string lpPathName);
}
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
namespace SpaceEngineersBlueprintEditor.GameAssemblyLoader;
/// <summary>
/// Resolves Space Engineers managed and native dependencies directly from Bin64.
/// </summary>
public static class GameAssemblyLoader
{
private static readonly object SyncRoot = new object();
private static bool resolverRegistered;
/// <summary>
/// Gets the currently selected game root directory.
/// </summary>
public static string? GameRootPath { get; private set; }
/// <summary>
/// Gets the currently selected game Bin64 directory.
/// </summary>
public static string? GameBinPath { get; private set; }
/// <summary>
/// Detects the game, registers assembly resolution, and returns the validated game root.
/// This method is safe to call more than once before game types are used.
/// </summary>
public static string? Initialize(string? preferredPath = null)
{
lock (SyncRoot)
{
if (!resolverRegistered)
{
AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;
resolverRegistered = true;
}
var gameRoot = GameInstallationLocator.FindGameRootPath(preferredPath);
if (gameRoot is null)
{
return GameRootPath;
}
GameRootPath = gameRoot;
GameBinPath = Path.Combine(gameRoot, "Bin64");
SetDllDirectory(GameBinPath);
return GameRootPath;
}
}
/// <summary>
/// Initializes the loader or throws a descriptive error when the game is unavailable.
/// </summary>
public static string EnsureInitialized(string? preferredPath = null)
{
return Initialize(preferredPath) ?? throw new DirectoryNotFoundException(
"Space Engineers was not found. Install the Steam game or select its installation directory in Settings.");
}
private static Assembly? ResolveAssembly(object? sender, ResolveEventArgs args)
{
var binPath = GameBinPath;
if (string.IsNullOrWhiteSpace(binPath))
{
return null;
}
AssemblyName requestedName;
try
{
requestedName = new AssemblyName(args.Name);
}
catch (ArgumentException)
{
return null;
}
if (string.IsNullOrWhiteSpace(requestedName.Name))
{
return null;
}
var candidate = Path.Combine(binPath!, requestedName.Name + ".dll");
if (!File.Exists(candidate))
{
return null;
}
try
{
var candidateName = AssemblyName.GetAssemblyName(candidate);
if (!string.Equals(candidateName.Name, requestedName.Name, StringComparison.OrdinalIgnoreCase))
{
return null;
}
return Assembly.LoadFrom(candidate);
}
catch (BadImageFormatException)
{
return null;
}
catch (FileLoadException)
{
return null;
}
catch (FileNotFoundException)
{
return null;
}
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetDllDirectory(string lpPathName);
}