diff --git a/tools/cdb/issue98-cellar-up-find-walkable.cdb b/tools/cdb/issue98-cellar-up-find-walkable.cdb new file mode 100644 index 0000000..861cec9 --- /dev/null +++ b/tools/cdb/issue98-cellar-up-find-walkable.cdb @@ -0,0 +1,88 @@ +$$ +$$ A6.P3 issue #98 cdb capture — 2026-05-23 +$$ +$$ Captures retail's walkable-query behavior during the Holtburg cottage +$$ cellar ascent. Pairs with tests/AcDream.Core.Tests/Physics/ +$$ Issue98CellarUpReplayTests for an evidence-based comparison: the +$$ acdream replay says "no walkable accepted" at the failing-frame +$$ sphere; retail succeeds. The cdb log tells us which polygon retail +$$ accepts, in which cell, at what sphere position. The divergence is +$$ then the input to the fix plan. +$$ +$$ Breakpoints (snake_case names from refs/acclient.pdb): +$$ BPA: BSPLEAF::find_walkable — per-leaf walkable query. Logs sphere +$$ center + outPoly pointer at entry. (outPoly is OUTPUT, only +$$ populated post-call; we capture inputs only here.) +$$ BPB: CPolygon::walkable_hits_sphere — per-polygon overlap test. +$$ Logs polygon vtable + sphere center. +$$ BPC: CPolygon::find_crossed_edge — per-polygon edge containment. +$$ Logs polygon vtable + sphere center. +$$ BPD: CTransition::check_other_cells — outer dispatcher. Logs +$$ otherCell pointer. +$$ BPE: COLLISIONINFO::set_contact_plane — gold-standard accept +$$ signal. Logs plane normal + d. (Mirrors BP7 in a6-probe.cdb.) +$$ BPF: CPolygon::adjust_sphere_to_plane — per-polygon sphere +$$ projection. Mirrors BP5 in a6-probe.cdb. +$$ +$$ All floats output as 32-bit hex via dwo() + %08X. Decode with +$$ struct.unpack('= 50000) { qd } .else { gc }" + +$$ BPB: CPolygon::walkable_hits_sphere(this, SPHEREPATH* sp, CSphere* sphere, Vector3* up) +$$ this = polygon (ecx) → plane @ +0x20 +$$ sphere = [esp+8] +bp acclient!CPolygon::walkable_hits_sphere "r $t2 = @$t2 + 1; r $t0 = @$t0 + 1; .printf /D \"[BPB] walkable_hits hit#%d poly=0x%08X Nx_h=0x%08X Ny_h=0x%08X Nz_h=0x%08X d_h=0x%08X cx_h=0x%08X cy_h=0x%08X cz_h=0x%08X r_h=0x%08X\\n\", @$t2, @ecx, dwo(@ecx+0x20), dwo(@ecx+0x24), dwo(@ecx+0x28), dwo(@ecx+0x2c), dwo(poi(@esp+8)+0), dwo(poi(@esp+8)+4), dwo(poi(@esp+8)+8), dwo(poi(@esp+8)+0xc); .if (@$t0 >= 50000) { qd } .else { gc }" + +$$ BPC: CPolygon::find_crossed_edge(this, CSphere* sphere, Vector3* up, Vector3* out) +bp acclient!CPolygon::find_crossed_edge "r $t3 = @$t3 + 1; r $t0 = @$t0 + 1; .printf /D \"[BPC] find_crossed_edge hit#%d poly=0x%08X Nx_h=0x%08X Ny_h=0x%08X Nz_h=0x%08X d_h=0x%08X cx_h=0x%08X cy_h=0x%08X cz_h=0x%08X r_h=0x%08X\\n\", @$t3, @ecx, dwo(@ecx+0x20), dwo(@ecx+0x24), dwo(@ecx+0x28), dwo(@ecx+0x2c), dwo(poi(@esp+4)+0), dwo(poi(@esp+4)+4), dwo(poi(@esp+4)+8), dwo(poi(@esp+4)+0xc); .if (@$t0 >= 50000) { qd } .else { gc }" + +$$ BPD: CTransition::check_other_cells(this, CObjCell* otherCell) +bp acclient!CTransition::check_other_cells "r $t4 = @$t4 + 1; r $t0 = @$t0 + 1; .printf /D \"[BPD] check_other_cells hit#%d trans=0x%08X otherCell=0x%08X\\n\", @$t4, @ecx, dwo(@esp+4); .if (@$t0 >= 50000) { qd } .else { gc }" + +$$ BPE: COLLISIONINFO::set_contact_plane(this, plane, is_water) — GOLD signal +$$ This fires when retail commits to a contact plane. The plane args +$$ are the polygon retail accepted. NO threshold gate — every contact +$$ plane write logs. +bp acclient!COLLISIONINFO::set_contact_plane "r $t5 = @$t5 + 1; .printf /D \"[BPE] set_contact_plane hit#%d Nx_h=0x%08X Ny_h=0x%08X Nz_h=0x%08X d_h=0x%08X isWater=%d\\n\", @$t5, dwo(poi(@esp+4)+0), dwo(poi(@esp+4)+4), dwo(poi(@esp+4)+8), dwo(poi(@esp+4)+0xc), dwo(@esp+8); gc" + +$$ BPF: CPolygon::adjust_sphere_to_plane(this, sphere_path, sphere, movement) +bp acclient!CPolygon::adjust_sphere_to_plane "r $t6 = @$t6 + 1; r $t0 = @$t0 + 1; .printf /D \"[BPF] adjust_sphere hit#%d poly=0x%08X Nx_h=0x%08X Ny_h=0x%08X Nz_h=0x%08X d_h=0x%08X cx_h=0x%08X cy_h=0x%08X cz_h=0x%08X r_h=0x%08X winterp_h=0x%08X\\n\", @$t6, @ecx, dwo(@ecx+0x20), dwo(@ecx+0x24), dwo(@ecx+0x28), dwo(@ecx+0x2c), dwo(poi(@esp+8)+0), dwo(poi(@esp+8)+4), dwo(poi(@esp+8)+8), dwo(poi(@esp+8)+0xc), dwo(poi(@esp+4)+0x1bc); .if (@$t0 >= 50000) { qd } .else { gc }" + +.printf "issue98-find-walkable cdb armed: BPA-BPF, 50000-hit threshold (BPE unbounded)\\n" + +g diff --git a/tools/cdb/issue98-runner.ps1 b/tools/cdb/issue98-runner.ps1 new file mode 100644 index 0000000..d6af74f --- /dev/null +++ b/tools/cdb/issue98-runner.ps1 @@ -0,0 +1,80 @@ +# A6.P3 issue #98 cdb capture runner — 2026-05-23 +# +# Attaches cdb to a live retail acclient.exe with +# issue98-cellar-up-find-walkable.cdb. Pairs with +# tests/AcDream.Core.Tests/Physics/Issue98CellarUpReplayTests.cs to +# answer: which polygon does retail accept during cellar ascent, in +# which cell, at what sphere position? +# +# Per-capture usage: +# .\tools\cdb\issue98-runner.ps1 -ScenarioTag "cellar_up_attempt_1" +# +# Prerequisites: +# 1. Retail acclient.exe v11.4186 running and in-world (matches +# refs/acclient.pdb). Verify with: +# py tools\pdb-extract\check_exe_pdb.py "C:\Turbine\Asheron's Call\acclient.exe" +# 2. ACE running locally on 127.0.0.1:9000. +# 3. Retail character at the BOTTOM of a Holtburg cottage cellar +# stair. Take a long breath; the next walk-forward is the capture +# window. cdb auto-detaches at 50,000 BP hits (~5-20s of motion). +# +# Output: +# docs\research\2026-05-23-a6-captures\\retail.log +# +# Reading the log: +# The relevant signal is [BPE] set_contact_plane lines — these tell +# you which plane retail accepted. Then trace back through [BPA] +# find_walkable + [BPF] adjust_sphere entries to see the sphere +# position + polygon when that acceptance happened. Cross-reference +# the polygon plane normal/d against the cell fixtures in +# tests/AcDream.Core.Tests/Fixtures/issue98/0x*.json to identify which +# cell + polyId retail picked. + +param( + [Parameter(Mandatory=$true)] + [string]$ScenarioTag +) + +$cdbExe = "C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\cdb.exe" +if (-not (Test-Path $cdbExe)) { + Write-Error "cdb.exe not found at $cdbExe. Install Microsoft Store WinDbg (~50 MB)." + exit 1 +} + +$scriptPath = Join-Path $PSScriptRoot "issue98-cellar-up-find-walkable.cdb" +if (-not (Test-Path $scriptPath)) { + Write-Error "issue98-cellar-up-find-walkable.cdb not found at $scriptPath." + exit 1 +} + +$captureDir = Join-Path $PSScriptRoot "..\..\docs\research\2026-05-23-a6-captures\$ScenarioTag" +if (-not (Test-Path $captureDir)) { + New-Item -ItemType Directory -Path $captureDir -Force | Out-Null +} + +$logPath = Join-Path $captureDir "retail.log" + +# Substitute ${ARG_LOG_TAG} in the .cdb script. +$scriptContent = Get-Content $scriptPath -Raw +$patchedScript = $scriptContent -replace '\$\{ARG_LOG_TAG\}', $ScenarioTag + +$tempScript = Join-Path $env:TEMP "issue98-$ScenarioTag.cdb" +Set-Content -Path $tempScript -Value $patchedScript -Encoding ASCII + +Write-Host "Attaching cdb to acclient.exe with scenario tag '$ScenarioTag'..." +Write-Host "Log: $logPath" +Write-Host "Script: $tempScript" +Write-Host "(cdb auto-detaches at 50K total hits across BPA/B/C/D/F; BPE unbounded.)" +Write-Host "" +Write-Host "TRIGGER: walk forward from the bottom of the cellar stair NOW." +Write-Host "" + +# ASCII output so subsequent grep does not have to deal with UTF-16 BOM. +& $cdbExe -pn acclient.exe -cf $tempScript 2>&1 | Out-File -FilePath $logPath -Encoding ASCII + +Remove-Item $tempScript -ErrorAction SilentlyContinue + +Write-Host "" +Write-Host "Capture complete. Log saved to $logPath" +Write-Host "Decode floats: dwo() hex bits → struct.unpack('