Recon script, three capture templates (walk / parts / alpha-depth), runner, and operator README under tools/walk-oracle/oh/. FW0 line formats are kept byte-identical; new EC/OC/PD/DM/AM/FL/PM/PC line kinds are documented. Auto-detach uses the fall-through + top-level qd recipe; qd never appears inside a breakpoint action. Lead-resolved: DBObj::m_DID is +0x28 (header layout, first base of CGfxObj and CObjCell, matches the proven FW0 cell reads); the three D3DPolyRender alpha functions are static cdecl with stack arguments, uint8 arguments read with by(). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
131 lines
5.6 KiB
PowerShell
131 lines
5.6 KiB
PowerShell
# OH1 walk-oracle capture runner (2026-09-02).
|
|
#
|
|
# Substitutes <LOG> and the <FRAMES> frame-count token into one of this
|
|
# directory's oh-capture-*.cdb.template files (or runs oh-recon.cdb
|
|
# unmodified, since it has no <FRAMES> token to fill), verifies the LIVE
|
|
# retail acclient.exe process actually pairs with our named-retail PDB
|
|
# (aborting on mismatch -- see claude-memory/project_retail_debugger.md and
|
|
# CLAUDE.md's "Retail debugger toolchain" section for why this matters: a
|
|
# 2015 C:\Turbine\Asheron's Call\acclient.exe build does NOT pair with
|
|
# refs/acclient.pdb, only the 2013 v11.4186 build does), then launches cdb
|
|
# in the BACKGROUND (non-blocking -- the operator needs the foreground to
|
|
# drive the retail client during the capture) with output redirected to a
|
|
# companion ".console" file next to -Log.
|
|
#
|
|
# NOTE: this script does NOT resolve every token some templates need.
|
|
# oh-capture-parts.cdb.template has two <GFXOBJ_DID_OFF> occurrences that
|
|
# are NOT substituted here (see that file's own OPEN QUESTION comment and
|
|
# the README) -- hand-edit those before pointing -Script at that template
|
|
# for a real session.
|
|
#
|
|
# Usage:
|
|
# .\oh-run-capture.ps1 -Script oh-recon.cdb -Log C:\path\to\oh-recon.log
|
|
# .\oh-run-capture.ps1 -Script oh-capture-walk.cdb.template `
|
|
# -Log C:\path\to\holtburg-doorway-still.walk.log -Frames 5
|
|
#
|
|
# Then, in another shell (this script returns immediately):
|
|
# Get-Content C:\path\to\holtburg-doorway-still.walk.log -Tail 50 -Wait
|
|
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Script,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Log,
|
|
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateRange(1, 200)]
|
|
[int]$Frames = 5
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
$cdbExe = "C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\cdb.exe"
|
|
if (-not (Test-Path -LiteralPath $cdbExe)) {
|
|
throw "cdb.exe was not found at '$cdbExe'. Install Microsoft Store WinDbg (~50 MB)."
|
|
}
|
|
|
|
$symbolPath = "C:\Users\erikn\source\repos\acdream\refs"
|
|
if (-not (Test-Path -LiteralPath $symbolPath)) {
|
|
throw "Symbol directory '$symbolPath' does not exist. Every template in this " +
|
|
"directory hardcodes '.sympath $symbolPath' -- fix that path or create the directory."
|
|
}
|
|
|
|
$scriptDir = $PSScriptRoot
|
|
$scriptPath = if ([System.IO.Path]::IsPathRooted($Script)) { $Script } else { Join-Path $scriptDir $Script }
|
|
if (-not (Test-Path -LiteralPath $scriptPath)) {
|
|
throw "Capture script '$scriptPath' does not exist."
|
|
}
|
|
|
|
# --- verify the LIVE acclient.exe pairs with refs/acclient.pdb ---
|
|
$retail = Get-CimInstance Win32_Process -Filter "Name = 'acclient.exe'" |
|
|
Select-Object -First 1
|
|
if ($null -eq $retail) {
|
|
throw "No live retail acclient.exe process was found. Launch retail and get " +
|
|
"in-world before running a capture (see CLAUDE.md's Retail debugger " +
|
|
"toolchain section step 2)."
|
|
}
|
|
|
|
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..\..")).Path
|
|
$checkScript = Join-Path $repoRoot "tools\pdb-extract\check_exe_pdb.py"
|
|
if (-not (Test-Path -LiteralPath $checkScript)) {
|
|
throw "PDB pairing checker not found at '$checkScript'."
|
|
}
|
|
|
|
$pairing = & py $checkScript $retail.ExecutablePath 2>&1 | Out-String
|
|
if ($pairing -notmatch "=== MATCH:") {
|
|
throw @"
|
|
The live retail executable at '$($retail.ExecutablePath)' does NOT pair with
|
|
refs/acclient.pdb. Do not attach -- symbol offsets will be silently wrong.
|
|
The matching binary is documented in claude-memory/project_retail_debugger.md
|
|
as v11.4186 (Sept 2013 EoR build, PDB GUID
|
|
9e847e2f-777c-4bd9-886c-22256bb87f32); a 2015 C:\Turbine\Asheron's
|
|
Call\acclient.exe build will MISMATCH.
|
|
|
|
$pairing
|
|
"@
|
|
}
|
|
Write-Host "PDB pairing OK: $($retail.ExecutablePath) (PID $($retail.ProcessId))"
|
|
|
|
# --- substitute <LOG> and <FRAMES>, write a temp copy ---
|
|
$logPath = if ([System.IO.Path]::IsPathRooted($Log)) { $Log } else { Join-Path (Get-Location) $Log }
|
|
$logDir = Split-Path -Parent $logPath
|
|
if ($logDir -and -not (Test-Path -LiteralPath $logDir)) {
|
|
New-Item -ItemType Directory -Path $logDir -Force | Out-Null
|
|
}
|
|
|
|
$content = Get-Content -LiteralPath $scriptPath -Raw
|
|
$content = $content.Replace('<LOG>', $logPath)
|
|
$content = $content.Replace('<FRAMES>', $Frames.ToString([System.Globalization.CultureInfo]::InvariantCulture))
|
|
|
|
if ($content -match '<GFXOBJ_DID_OFF>') {
|
|
Write-Warning ("'$scriptPath' still contains an unresolved <GFXOBJ_DID_OFF> " +
|
|
"token -- this runner does not fill it in. Hand-edit the template with " +
|
|
"the offset oh-recon.cdb's 'dt acclient!CGfxObj' reports for the " +
|
|
"inherited DBObj::m_DID field before proceeding, or the capture will " +
|
|
"produce a garbage 'did=' field on every PD/DM line.")
|
|
}
|
|
|
|
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
|
$tempScript = Join-Path $env:TEMP "oh-capture-$timestamp.cdb"
|
|
Set-Content -LiteralPath $tempScript -Value $content -Encoding ASCII
|
|
|
|
# --- launch cdb in the background ---
|
|
$consoleLog = "$logPath.console"
|
|
Write-Host "Attaching cdb to acclient.exe PID $($retail.ProcessId)."
|
|
Write-Host "Trace log: $logPath"
|
|
Write-Host "Console log: $consoleLog"
|
|
Write-Host "Temp script: $tempScript (not auto-deleted -- cdb needs it while running)"
|
|
Write-Host "Frame threshold: $Frames"
|
|
Write-Host "Tail the trace live with: Get-Content '$logPath' -Tail 50 -Wait"
|
|
|
|
$proc = Start-Process -FilePath $cdbExe `
|
|
-ArgumentList @("-pn", "acclient.exe", "-cf", $tempScript) `
|
|
-RedirectStandardOutput $consoleLog `
|
|
-RedirectStandardError "$consoleLog.err" `
|
|
-WindowStyle Hidden `
|
|
-PassThru
|
|
|
|
Write-Host "cdb launched in the background, PID $($proc.Id). This script returns now --"
|
|
Write-Host "drive the retail client into the target pose and hold still until the"
|
|
Write-Host "capture auto-detaches (frame marker hits the $Frames-frame threshold)."
|