新增奥日2排障记录:Wwise 线程亲和性故障定位与兼容补丁(文章4篇+补丁包+诊断脚本4个,已脱敏)
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
#requires -Version 7.0
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[ValidateSet('Check', 'Install', 'Restore')]
|
||||
[string]$Action = 'Check',
|
||||
[Parameter(Mandatory=$true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string[]]$GameDirectory
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$originalHash = '8F90A4A3856540CB97D03CA07B4BB10B7A08F7B4AB3C524BE2BEC1AFDD29FECA'
|
||||
$patchedHash = '62B2079A988D23EB251D4E83366AC04068A6F47E0D38EFE92A76DF022826F9F0'
|
||||
$offset = 0x115F0
|
||||
$originalCode = [Convert]::FromHexString('4885C97403895104C3CCCCCCCCCCCCCC')
|
||||
$patchedCode = [Convert]::FromHexString('4885C97407C7410400000000C3CCCCCC')
|
||||
|
||||
function Get-BytesHash([byte[]]$Bytes) {
|
||||
[Convert]::ToHexString([Security.Cryptography.SHA256]::HashData($Bytes))
|
||||
}
|
||||
|
||||
if ($Action -ne 'Check' -and (Get-Process -Name 'oriwotw' -ErrorAction SilentlyContinue)) {
|
||||
throw '请先退出所有奥日 2 游戏窗口,再安装或还原补丁。'
|
||||
}
|
||||
|
||||
# Preflight every selected directory before any mutation. Unknown builds,
|
||||
# unrelated modifications and conflicting backups are never overwritten.
|
||||
$plans = foreach ($directory in $GameDirectory) {
|
||||
$root = (Resolve-Path -LiteralPath $directory).Path
|
||||
$target = Join-Path $root 'oriwotw_Data\Plugins\AkSoundEngine.dll'
|
||||
$backup = $target + '.before-ori-affinity-fix'
|
||||
$bytes = [IO.File]::ReadAllBytes($target)
|
||||
$hash = Get-BytesHash $bytes
|
||||
if ($hash -notin @($originalHash, $patchedHash)) {
|
||||
throw "文件版本或内容不匹配,未修改:$target;SHA256=$hash"
|
||||
}
|
||||
if (Test-Path -LiteralPath $backup) {
|
||||
if ((Get-FileHash -LiteralPath $backup -Algorithm SHA256).Hash -ne $originalHash) {
|
||||
throw "现有备份不匹配,未覆盖:$backup"
|
||||
}
|
||||
}
|
||||
if ($Action -eq 'Restore' -and $hash -eq $patchedHash -and -not (Test-Path -LiteralPath $backup)) {
|
||||
throw "找不到经过校验的原文件备份,无法还原:$backup"
|
||||
}
|
||||
if ($hash -eq $originalHash) {
|
||||
for ($i = 0; $i -lt $originalCode.Length; $i++) {
|
||||
if ($bytes[$offset + $i] -ne $originalCode[$i]) { throw '原始指令校验失败。' }
|
||||
}
|
||||
$candidate = [byte[]]$bytes.Clone()
|
||||
[Array]::Copy($patchedCode, 0, $candidate, $offset, $patchedCode.Length)
|
||||
if ((Get-BytesHash $candidate) -ne $patchedHash) { throw '补丁结果校验失败。' }
|
||||
} else {
|
||||
$candidate = $bytes
|
||||
}
|
||||
[pscustomobject]@{ Root=$root; Target=$target; Backup=$backup; Hash=$hash; Candidate=$candidate }
|
||||
}
|
||||
|
||||
foreach ($plan in $plans) {
|
||||
if ($Action -eq 'Check') {
|
||||
[pscustomobject]@{
|
||||
Directory=$plan.Root
|
||||
State=if ($plan.Hash -eq $patchedHash) { '已安装补丁' } else { '原版,符合补丁要求' }
|
||||
SHA256=$plan.Hash
|
||||
BackupExists=(Test-Path -LiteralPath $plan.Backup)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if ($Action -eq 'Install' -and $plan.Hash -eq $patchedHash) {
|
||||
Write-Host "已安装,无需重复修改:$($plan.Root)"
|
||||
continue
|
||||
}
|
||||
if ($Action -eq 'Restore' -and $plan.Hash -eq $originalHash) {
|
||||
Write-Host "已经是原文件:$($plan.Root)"
|
||||
continue
|
||||
}
|
||||
if ($Action -eq 'Install') {
|
||||
if (-not (Test-Path -LiteralPath $plan.Backup)) {
|
||||
[IO.File]::Copy($plan.Target, $plan.Backup, $false)
|
||||
}
|
||||
if ((Get-FileHash -LiteralPath $plan.Backup -Algorithm SHA256).Hash -ne $originalHash) {
|
||||
throw '备份验证失败;未覆盖游戏 DLL。'
|
||||
}
|
||||
$newBytes = $plan.Candidate
|
||||
$expected = $patchedHash
|
||||
} else {
|
||||
$newBytes = [IO.File]::ReadAllBytes($plan.Backup)
|
||||
$expected = $originalHash
|
||||
}
|
||||
# Detect changes made by another program since preflight.
|
||||
if ((Get-FileHash -LiteralPath $plan.Target -Algorithm SHA256).Hash -ne $plan.Hash) {
|
||||
throw "检查后文件发生变化,停止修改:$($plan.Target)"
|
||||
}
|
||||
if (Get-Process -Name 'oriwotw' -ErrorAction SilentlyContinue) {
|
||||
throw '游戏刚刚启动,已停止修改;请先退出游戏。'
|
||||
}
|
||||
$staging = $plan.Target + '.ori-fix-' + [Guid]::NewGuid().ToString('N') + '.tmp'
|
||||
try {
|
||||
$stream = [IO.File]::Open($staging, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None)
|
||||
try { $stream.Write($newBytes); $stream.Flush($true) } finally { $stream.Dispose() }
|
||||
if ((Get-FileHash -LiteralPath $staging -Algorithm SHA256).Hash -ne $expected) {
|
||||
throw '临时文件验证失败,未覆盖游戏 DLL。'
|
||||
}
|
||||
[IO.File]::Move($staging, $plan.Target, $true)
|
||||
if ((Get-FileHash -LiteralPath $plan.Target -Algorithm SHA256).Hash -ne $expected) {
|
||||
throw '写入后的校验失败,请保留备份并停止启动游戏。'
|
||||
}
|
||||
} finally {
|
||||
if (Test-Path -LiteralPath $staging) { Remove-Item -LiteralPath $staging }
|
||||
}
|
||||
Write-Host "${Action} 成功:$($plan.Target)"
|
||||
Write-Host "原文件备份:$($plan.Backup)"
|
||||
}
|
||||
Reference in New Issue
Block a user