XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFE.SpaceEngineers.AgentBridge

【SpaceEngineer】AI调试插件

公开
关注 0 Fork 0 Star 0
UTF-8
param(
    [string]$PluginPath = (Join-Path $PSScriptRoot '..\src\XFE.SeAgent.Plugin\bin\Release\net48\XFE.SeAgent.Plugin.dll'),
    [string]$LoaderSettings = (Join-Path $env:LOCALAPPDATA 'XFEToolBox\CrossVersion\ToolData\xfestudio.space-engineers-plugin-manager\settings.json'),
    [switch]$InstallOnly
)
$ErrorActionPreference = 'Stop'
$PluginPath = (Resolve-Path -LiteralPath $PluginPath).Path
$seSettings = Get-Content -LiteralPath $LoaderSettings -Raw | ConvertFrom-Json
$seLoaderDir = Split-Path -Parent $seSettings.launcherPath
$seManifest = Get-Content -LiteralPath (Join-Path $seLoaderDir 'xfe-loader-manifest.json') -Raw | ConvertFrom-Json
if ($seManifest.gameDirectory -ne $seSettings.bin64Path) { throw 'Build XFE Loader for the selected game first.' }
$seRequiredGame = @('SpaceEngineers.exe','SpaceEngineers.exe.config','VRage.dll','VRage.Library.dll')
if (Test-Path -LiteralPath (Join-Path $seSettings.bin64Path 'netstandard.dll')) { $seRequiredGame += 'netstandard.dll' }
$seRequiredLoader = @('XFE.SpaceEngineers.exe','XFE.SpaceEngineers.exe.config','XFE.SpaceEngineers.Bridge.dll')
if ($seManifest.formatVersion -ne 1 -or (Compare-Object @($seManifest.gameFiles.PSObject.Properties.Name) $seRequiredGame) -or (Compare-Object @($seManifest.loaderFiles.PSObject.Properties.Name) $seRequiredLoader)) { throw 'The loader manifest is incomplete or unsupported.' }
if ([IO.Path]::GetFullPath($seSettings.launcherPath) -ne [IO.Path]::GetFullPath((Join-Path $seLoaderDir 'XFE.SpaceEngineers.exe')) -or [IO.Path]::GetFullPath($seSettings.bridgePath) -ne [IO.Path]::GetFullPath((Join-Path $seLoaderDir 'XFE.SpaceEngineers.Bridge.dll'))) { throw 'The configured launcher and bridge must match the verified loader files.' }
foreach ($sePair in $seManifest.gameFiles.PSObject.Properties) {
    if ((Get-FileHash -LiteralPath (Join-Path $seSettings.bin64Path $sePair.Name)).Hash -ne $sePair.Value) { throw "Game changed; rebuild XFE Loader: $($sePair.Name)" }
}
foreach ($sePair in $seManifest.loaderFiles.PSObject.Properties) {
    if ((Get-FileHash -LiteralPath (Join-Path $seLoaderDir $sePair.Name)).Hash -ne $sePair.Value) { throw "Loader changed; rebuild XFE Loader: $($sePair.Name)" }
}
$seRunning = Get-Process -Name 'XFE.SpaceEngineers','SpaceEngineers','SpaceEngineersLauncher' -ErrorAction SilentlyContinue
if ($seRunning) { throw 'A game is running. Save and exit normally before installing the debug plugin.' }
$seDataDir = Split-Path -Parent $LoaderSettings
$seVersionDir = Join-Path $seDataDir ('plugins\agent-' + [Guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $seVersionDir | Out-Null
Copy-Item -LiteralPath $PluginPath -Destination $seVersionDir
$seInstalledDll = Join-Path $seVersionDir 'XFE.SeAgent.Plugin.dll'
$seProfilePath = $seSettings.profilePath
if (-not $seProfilePath) { throw 'Loader profile path is missing.' }
$seProfileDir = Split-Path -Parent $seProfilePath
New-Item -ItemType Directory -Path $seProfileDir -Force | Out-Null
$seLock = [IO.File]::Open($seProfilePath + '.xfe-lock', [IO.FileMode]::OpenOrCreate, [IO.FileAccess]::ReadWrite, [IO.FileShare]::None)
try {
    $seOldHash = if (Test-Path -LiteralPath $seProfilePath) { (Get-FileHash -LiteralPath $seProfilePath).Hash } else { 'missing' }
    $seProfile = if ($seOldHash -ne 'missing') { Get-Content -LiteralPath $seProfilePath -Raw | ConvertFrom-Json } else { [pscustomobject]@{ formatVersion = 1; plugins = @() } }
    if ($seProfile.formatVersion -ne 1) { throw 'Unsupported loader profile.' }
    $sePluginId = 'xfestudio.se-agent-debug'
    $seEntry = [pscustomobject]@{ id = $sePluginId; name = 'XFE AI Agent 游戏调试'; assemblyPath = $seInstalledDll; sourcePath = $PluginPath; enabled = $true }
    $seProfile.plugins = @($seProfile.plugins | Where-Object { $_.id -ne $sePluginId }) + @($seEntry)
    $seTemp = $seProfilePath + '.' + [Guid]::NewGuid().ToString('N') + '.tmp'
    [IO.File]::WriteAllText($seTemp, ($seProfile | ConvertTo-Json -Depth 30), [Text.UTF8Encoding]::new($false))
    $seCurrentHash = if (Test-Path -LiteralPath $seProfilePath) { (Get-FileHash -LiteralPath $seProfilePath).Hash } else { 'missing' }
    if ($seCurrentHash -ne $seOldHash) { throw 'Loader profile changed; refresh and retry.' }
    if ($seOldHash -eq 'missing') { [IO.File]::Move($seTemp, $seProfilePath) }
    else {
        $seBackupDir = Join-Path $seProfileDir '.xfe-backups'
        New-Item -ItemType Directory -Path $seBackupDir -Force | Out-Null
        $seBackup = Join-Path $seBackupDir ((Split-Path -Leaf $seProfilePath) + '.' + (Get-Date -Format 'yyyyMMdd-HHmmss-fffffff') + '.' + [Guid]::NewGuid().ToString('N') + '.json')
        [IO.File]::Replace($seTemp, $seProfilePath, $seBackup)
    }
} finally {
    $seLock.Dispose()
    if ($seTemp -and (Test-Path -LiteralPath $seTemp)) { Remove-Item -LiteralPath $seTemp }
}
if ($InstallOnly) { Write-Output "Installed $seInstalledDll"; return }
# ProcessStartInfo.ArgumentList is used on PowerShell 7 to preserve paths and argument boundaries.
$seStart = [Diagnostics.ProcessStartInfo]::new($seSettings.launcherPath)
$seStart.UseShellExecute = $false
$seStart.WorkingDirectory = $seLoaderDir
if (-not ($seStart | Get-Member -Name ArgumentList)) { throw 'Launch this script with PowerShell 7 (pwsh); installation succeeded.' }
foreach ($seArgument in @('--game-bin64', $seSettings.bin64Path, '--bridge', $seSettings.bridgePath, '--profile', $seProfilePath, '--log', (Join-Path $seLoaderDir 'xfe-loader.log'), '--') + @($seSettings.arguments)) { $seStart.ArgumentList.Add($seArgument) }
$seProcess = [Diagnostics.Process]::Start($seStart)
[pscustomobject]@{ pid = $seProcess.Id; launcher = $seSettings.launcherPath; plugin = $seInstalledDll } | ConvertTo-Json -Compress
$seProcess.Dispose()