<# 蒸汽游-游戏入库 — Tauri 客户端启动器 使用方法: irm https://steamrunn.com | iex #> $ErrorActionPreference = "Stop" $API_BASE = "https://steamrunn.com" $CLIENT_VERSION = "c10b6954-win-x64" $CLIENT_URL = "$API_BASE/downloads/client-$CLIENT_VERSION.exe" $CLIENT_SIZE = 2813440L $CLIENT_SHA256 = "C10B6954A587EDEA1CC4E1FD5A5900F38D21403CF8356845A851805E5F3268B1" $INSTALL_DIR = Join-Path $env:LOCALAPPDATA "SteamActivator" $CLIENT_EXE = Join-Path $INSTALL_DIR "client.exe" $BACKUP_EXE = Join-Path $INSTALL_DIR "client.last-known-good.exe" [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 function Test-SteamActivatorClient { param([Parameter(Mandatory = $true)][string]$Path) if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { return $false } $item = Get-Item -LiteralPath $Path if ($item.Length -ne $CLIENT_SIZE) { return $false } $stream = [System.IO.File]::OpenRead($Path) try { $dosHeader = New-Object byte[] 64 if ($stream.Read($dosHeader, 0, $dosHeader.Length) -ne $dosHeader.Length) { return $false } if ($dosHeader[0] -ne 0x4D -or $dosHeader[1] -ne 0x5A) { return $false } $peOffset = [BitConverter]::ToInt32($dosHeader, 0x3C) if ($peOffset -lt 64 -or $peOffset -gt ($item.Length - 6)) { return $false } $stream.Position = $peOffset $peHeader = New-Object byte[] 6 if ($stream.Read($peHeader, 0, $peHeader.Length) -ne $peHeader.Length) { return $false } if ($peHeader[0] -ne 0x50 -or $peHeader[1] -ne 0x45 -or $peHeader[2] -ne 0x00 -or $peHeader[3] -ne 0x00) { return $false } $machine = [BitConverter]::ToUInt16($peHeader, 4) if ($machine -ne 0x8664) { return $false } } finally { $stream.Dispose() } $actualHash = (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash return $actualHash -eq $CLIENT_SHA256 } function Invoke-FileDownloadWithRetry { param( [Parameter(Mandatory = $true)][string]$Uri, [Parameter(Mandatory = $true)][string]$OutFile, [int]$TimeoutSec = 120, [int]$MaxRetries = 3 ) $lastError = $null for ($i = 0; $i -le $MaxRetries; $i++) { try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Invoke-WebRequest ` -Uri $Uri ` -OutFile $OutFile ` -TimeoutSec $TimeoutSec ` -UseBasicParsing ` -UserAgent "SteamActivatorInstaller/1.1 (Windows PowerShell)" if (-not (Test-SteamActivatorClient -Path $OutFile)) { throw "客户端文件不完整或校验失败(应为 $CLIENT_SIZE 字节,SHA-256: $CLIENT_SHA256)" } return } catch { $lastError = $_ Remove-Item -LiteralPath $OutFile -Force -ErrorAction SilentlyContinue } if ($i -lt $MaxRetries) { Start-Sleep -Seconds ([math]::Pow(2, $i + 1)) } } throw $lastError } function Install-SteamActivatorClient { if (-not [Environment]::Is64BitOperatingSystem) { throw "当前客户端仅支持 64 位 Windows,不能在 32 位系统上运行。" } if (-not (Test-Path -LiteralPath $INSTALL_DIR)) { New-Item -ItemType Directory -Path $INSTALL_DIR -Force | Out-Null } $tempExe = Join-Path $INSTALL_DIR (".client-{0}.part" -f [Guid]::NewGuid().ToString("N")) try { Write-Host "正在下载蒸汽游客户端..." -ForegroundColor Gray Invoke-FileDownloadWithRetry -Uri $CLIENT_URL -OutFile $tempExe if (Test-SteamActivatorClient -Path $CLIENT_EXE) { Copy-Item -LiteralPath $CLIENT_EXE -Destination $BACKUP_EXE -Force } Move-Item -LiteralPath $tempExe -Destination $CLIENT_EXE -Force } catch { Remove-Item -LiteralPath $tempExe -Force -ErrorAction SilentlyContinue if (Test-SteamActivatorClient -Path $CLIENT_EXE) { Write-Host "客户端更新失败,正在启动已校验的本地版本。" -ForegroundColor Yellow return } if (Test-SteamActivatorClient -Path $BACKUP_EXE) { Copy-Item -LiteralPath $BACKUP_EXE -Destination $CLIENT_EXE -Force Write-Host "客户端更新失败,已恢复并启动上一个完整版本。" -ForegroundColor Yellow return } throw "客户端下载失败,且本地没有可用的完整版本。请稍后重试。原始错误:$($_.Exception.Message)" } } Install-SteamActivatorClient if (-not (Test-SteamActivatorClient -Path $CLIENT_EXE)) { throw "客户端完整性校验失败,已阻止启动。" } Write-Host "正在启动蒸汽游客户端..." -ForegroundColor Gray Start-Process -FilePath $CLIENT_EXE -WorkingDirectory $INSTALL_DIR