* OH1 walk-oracle capture: ALPHA + DEPTH LIFECYCLE (2026-09-02). Captures * the two retail FIFO alpha lists (oh1-alpha-list-contract.md) and the * persistent portalsDrawnCount depth state machine (oh1-depth-lifecycle.md) * at call-entry granularity. Frame count default 5 (substitute ). * * SCOPE NOTE: oh1-depth-lifecycle.md's exact state machine touches specific * PCs INSIDE PView::DrawCells (0x5A4885 mid-frame stamp increment, 0x5A488C * counter read, 0x5A489E counter reset, 0x5A48A9 conditional clear -- see * that doc's "Ghidra branch arbitration table"). This script does NOT set * breakpoints at those interior addresses: OH1's own report supplies the PC * ranges but this task did not re-disassemble them, so the exact register * holding the counter value at each of those specific mid-function PCs is * unconfirmed here -- guessing a register at an arbitrary mid-function * instruction (as opposed to a function ENTRY, where the calling convention * fixes argument locations) is a materially different and riskier kind of * guess than anything else in this directory. Instead this script samples * the GLOBAL portalsDrawnCount memory cell (0x008719B4, confirmed by OH1's * Ghidra xref set as the ONLY three accesses to that address in the whole * binary) at two safe, function-ENTRY breakpoints: PView::DrawCells itself * (the "PC" line, giving counterBefore for that eligible call -- which, * per oh1-depth-lifecycle.md's own "Consecutive-call example" table, IS the * same value as counterAfter for the previous eligible call, so sampling * only at entry is sufficient to reconstruct the sequence offline) and * every DrawPortalPolyInternal attempt (the "PM" line, giving the * pre-this-call's-own-increment counter value for each individual mask * attempt). This is a deliberate, documented scope reduction, not an * oversight -- see the README's open questions. * * AUTO-DETACH: same fall-through + top-level qd recipe as the other two * scripts in this directory. Never qd inside a bp action. * * LINE FORMATS: * F -- unchanged from FW0 * P -- unchanged from FW0 * AM mesh= surf= new=<0|1> clip=<0|1> listSel= -- NEW. * D3DPolyRender::AddMeshToAlphaList @0x0059C230 entry. mesh/surf are * arg1 (MeshBuffer*) / arg2 (surfaceNum); new = arg4 (bNewObject); * clip = arg5 (overrideClipmapSetting); listSel = arg6 (0 selects the * ALPHA list, nonzero selects the CLIP list -- confirmed directly from * the decompiled body at acclient_2013_pseudo_c.txt:424925-424982, which * branches on "arg6 == 0" to the alphaedMeshCountAlpha/List* globals vs. * the alphaedMeshCountClip/List* globals). See the calling-convention * note below before trusting these stack offsets. * FL thresh= ret= -- NEW. * D3DPolyRender::FlushAlphaList @0x0059D2E0 entry. thresh = arg1's raw * float bits (decode offline; oh1-alpha-list-contract.md ss7 lists the * five call sites and their literal threshold constants -- 0f/0f/0f/0f * from DrawBuilding/PView::DrawCells/SmartBox::RenderNormalMode/ * CreatureMode::Render, 0.75f from DrawBlock's emergency-capacity * drain); ret = the return address on the stack at function entry * (poi(@esp), i.e. [esp] itself before the callee's own push ebp), * which a human can map back to one of those five sites offline via * `ln` or the oh1-alpha-list-contract.md ss7 table. * PM poly= mode=<0|1> counterBefore= -- NEW. * D3DPolyRender::DrawPortalPolyInternal @0x0059BC90 entry. poly = arg1 * (CPolygon*); mode = arg2 (0 = true-depth / exit-seal or mode-3 * fallback, nonzero = far-Z / building punch -- oh1-depth-lifecycle.md * "Far-Z punches and true-depth exit seals" table); counterBefore is * the GLOBAL portalsDrawnCount sampled BEFORE this specific call's own * local-boundary-reject-then-maybe-increment logic runs. Far-mode * (mode!=0) attempts NEVER change the counter; true-mode (mode==0) * attempts increment it by 1 UNLESS the whole-polygon local x/y==+/-12 * boundary reject fires first (which this script cannot observe -- * only the audited CPU clip in a real port could). * PC ov= counter= fc=<0|1> -- NEW. * PView::DrawCells @0x005A4840 entry (SAME breakpoint address as FW0's * DC line, but this script does NOT also emit a DC line -- the task * spec for this script only asked for the alpha/depth family, not the * cell-shell roster; see oh-capture-walk.cdb.template for DC). ov = * outside_view.view_count (PView+0x38); counter = portalsDrawnCount * sampled at this call's entry (the "previous eligible call's" final * value, per oh1-depth-lifecycle.md); fc = the forceClear global * (0x008ED824, expected 0 -- OH1 found no write site for it in this * binary, so a nonzero read here would itself be a notable finding). * * CALLING-CONVENTION NOTE (OPEN QUESTION -- the second big one, see README): * AddMeshToAlphaList, FlushAlphaList, and DrawPortalPolyInternal all show * NO "this" receiver in the named pseudo-C signatures (unlike * DrawBuilding/DrawEnvCell/DrawPartCell/DrawMeshInternal, which explicitly * annotate "this @ ecx"). This script ASSUMES that absence means a plain * stack-argument layout starting immediately at esp+4 for arg1 (i.e. * either true __cdecl, or __thiscall with an entirely UNUSED ecx receiver * that does not consume a stack slot either way) -- NOT that some visible * argument is silently arg2 of an unshown receiver. oh-recon.cdb includes * `uf` disassembly dumps of all three functions specifically so a human * can read the prologue and confirm (or refute) this before trusting the * stack offsets below. If `uf` shows the first instructions touching * [esp+4] before referencing ecx for anything other than a dead/unused * load, the assumption holds. * * BEFORE USE: replace (plain decimal digits) and (output * path). is pre-resolved to Render::viewer_pos @0x0081ef00, same as * the other two scripts in this directory. .logopen .sympath C:\Users\erikn\source\repos\acdream\refs .symopt+ 0x40 .reload /f acclient.exe r $t0 = 0 bp 00453aa0 "r $t0 = @$t0 + 1; .printf \"F %d\\n\", @$t0; .printf \"P %08x %08x %08x %08x %08x %08x %08x %08x\\n\", poi(0081ef00+4), poi(0081ef00+0x3c), poi(0081ef00+0x40), poi(0081ef00+0x44), poi(0081ef00+8), poi(0081ef00+0xc), poi(0081ef00+0x10), poi(0081ef00+0x14); .if (@$t0 < 0n) { gc }" bp 005a4840 ".printf \"PC ov=%d counter=%04x fc=%d\\n\", poi(@ecx+0x38), wo(008719b4), poi(008ed824); gc" bp 0059c230 ".printf \"AM mesh=%08x surf=%d csurf=%08x new=%d clip=%d listSel=%d\\n\", poi(@esp+4), poi(@esp+8), poi(@esp+0xc), by(@esp+0x10), by(@esp+0x14), by(@esp+0x18); gc" bp 0059d2e0 ".printf \"FL thresh=%08x ret=%08x\\n\", poi(@esp+4), poi(@esp); gc" bp 0059bc90 ".printf \"PM poly=%08x mode=%d counterBefore=%04x\\n\", poi(@esp+4), by(@esp+8), wo(008719b4); gc" g .echo ===DETACHING=== qd .logclose