# OH1 walk-oracle capture runner (2026-09-02). # # Substitutes and the frame-count token into one of this # directory's oh-capture-*.cdb.template files (or runs oh-recon.cdb # unmodified, since it has no 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 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 and , 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('', $logPath) $content = $content.Replace('', $Frames.ToString([System.Globalization.CultureInfo]::InvariantCulture)) if ($content -match '') { Write-Warning ("'$scriptPath' still contains an unresolved " + "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)."