XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
UTF-8
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);
}