Second capture round (owner-driven): every frame carries the camera pose from Render::viewer_pos, closing the FW0 pose gap. The holtburg-transitions fixture records a full out-and-back doorway crossing with all four root flips. README documents the P-line format and the marker-timing caveat that gates still fixtures first. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
84 lines
6.5 KiB
Markdown
84 lines
6.5 KiB
Markdown
# FW0 — retail walk-oracle traces (captured 2026-08-30)
|
|
|
|
Live cdb captures of retail's per-frame draw walk (2013 v11.4186 client,
|
|
PDB-paired, connected to local ACE; owner drove the character). These are
|
|
the conformance fixtures for Campaign FW slice FW1: `RetailFrameWalk` must
|
|
reproduce these sequences position-for-position. Capture harness:
|
|
`tools/walk-oracle/` (`fw0-recon.cdb` dumped the offsets; `fw0-capture.cdb`
|
|
is the template the per-pose scripts derive from).
|
|
|
|
## Trace format
|
|
|
|
One line per event, frames delimited by `F <n>`:
|
|
|
|
- `F n` — frame start (`SmartBox::RenderNormalMode` @0x00453AA0 entry).
|
|
- `LS` — `LScape::draw` @0x00506330 (the landscape walk ran).
|
|
- `BLD <cellid>` — `RenderDeviceD3D::DrawBuilding` @0x0059F2A0; the id is
|
|
the building's `Position.objcell_id` (CBuildingObj+0x4C).
|
|
- `DI <cellid>` — `PView::DrawInside` @0x005A5860; the EnvCell being
|
|
descended into (arg at esp+4; id = CEnvCell+0x28 `m_DID`).
|
|
- `DC pv=<PView*> ov=<outside_view.view_count> n=<cell_draw_num>: <ids…>`
|
|
— `PView::DrawCells` @0x005A4840 entry; dumps the PView's whole
|
|
`cell_draw_list` (PView+0x50 data / +0x60 count / +0x38 ov).
|
|
|
|
The last frame of each capture can be truncated (the auto-detach fires at
|
|
the frame marker, before that frame's draws) — ignore the final frame when
|
|
replaying.
|
|
|
|
## Traces
|
|
|
|
| File | Pose | Root shape | Why it matters |
|
|
|---|---|---|---|
|
|
| `terrace-center.log` | Sanctuary terrace center, still, 40f | OUTDOOR | Baseline outdoor frame: `LS`, 14 buildings far-to-near **including 0xF518002E every frame**, terrace cells drawn as 1-cell look-in punches at their building's turn. |
|
|
| `terrace-edge.log` | Waterfall ledge (the #456 pose), still, 40f | OUTDOOR | **The #456 acceptance oracle.** Retail STILL draws 0xF518002E all 39 complete frames — the vista is hidden by depth cover, not by culling. Edge adds a second look-in cell (n=2: f4180106 f418010f). |
|
|
| `cathedral-arrival.log` | Cathedral portal-in arrival, still, 40f | INTERIOR (DI f4180106) | Interior root: DI → DC(ov=1) → LS drawn THROUGH the exit view — and the building roster is culled to 10; **0xF518002E is absent**. Rooting selects the mechanism. |
|
|
| `holtburg-doorway-still.log` | Standing in a cottage doorway, still, 40f | INTERIOR (DI a9b4013f) | The flap scene: root is rock-stable all 39 frames at the threshold. Note the same cell (a9b40100) punched by three consecutive look-in views — retail tolerates duplicate punches. |
|
|
| `holtburg-walkout.log` | Walking inside → out of the cottage, 80f | DI a9b4013f (F1-76) → DI a9b40150 (F77-79) → OUTDOOR (F80) | The handover contract: interior cell-to-cell at F77, a clean ONE-FRAME interior→outdoor flip at F80. No intermediate state. |
|
|
| `holtburg-street-porchcam.log` | Player in the street facing away from the cottage, still, 40f | INTERIOR (DI a9b40150) | **Proof the frame roots at the CAMERA's cell, not the player's** — the chase camera tucked into the porch keeps the frame interior-rooted while the player stands outdoors. Wide doorway view culls nothing (full 14-building roster). |
|
|
| `holtburg-street-outdoor.log` | Mid-street, camera in the open, still, 40f | OUTDOOR | Clean outdoor town fixture: LS, 13 buildings, two look-in punches (n=3, n=2), zero DI. |
|
|
| `holtburg-walkabout.log` | Walking through Holtburg outdoors, 80f | OUTDOOR throughout | Moving outdoor fixture; dense look-in punch activity (~10 DC/frame) as doorways sweep the view. |
|
|
| `foundry-entry.log` | Walking from the street into the Holtburg foundry and down, 80f | OUTDOOR (F1-56) → DI a9b40178 (F57-78, **LS=false**) → DI a9b40177 (F79) | The outdoor→interior flip in one frame — and the pure-interior shape: the moment the camera faces down the stairs, no exit view survives, so NO landscape and NO buildings draw (ov=0). |
|
|
| `foundry-deep.log` | Bottom of the foundry, still, 40f | INTERIOR (DI a9b40176) | Deep interior with a surviving chain: ov=1 through the stairwell, so retail draws the landscape AND 12 town buildings from the basement — all buried by depth. Confirms draw-and-let-z-cover is the philosophy everywhere. |
|
|
|
|
## Findings that bind the FW1 port
|
|
|
|
1. **The frame roots at the camera-eye's cell** (porchcam trace). Player
|
|
position is irrelevant to rooting.
|
|
2. **Outdoor root draws every distance-eligible building — including the
|
|
#456 far building — and hides them by depth**, never by omission
|
|
(terrace-edge trace). acdream's #456 bleed is therefore a HOLE in our
|
|
drawn cover at that pose, not extra visibility. The cover mechanism
|
|
inside `RenderDeviceD3D::DrawBuilding` (pre-punch flush + portal far-Z
|
|
pass) is the next decomp read.
|
|
3. **Interior root gates the world through the exit-view chain**: the
|
|
building roster and landscape are whatever survives the chain's
|
|
cone/clip — from nothing (foundry entry, ov=0) to the whole town
|
|
(foundry deep, porchcam).
|
|
4. **Look-ins draw at the owning building's walk turn**, as 1-3 cell
|
|
`DrawCells` punches (ov=0) interleaved with the building sequence, and
|
|
duplicate punches of the same cell are tolerated.
|
|
5. **Transitions are one-frame flips** with no blended or intermediate
|
|
state (walkout F80, foundry F57), and the root is perfectly stable
|
|
when stationary — even standing in a doorway.
|
|
6. **Buildings draw far-to-near** (`LScape::calc_draw_order`), and the
|
|
whole-frame sequence repeats bit-for-bit while the camera is still.
|
|
|
|
## Pose-stamped round (2026-08-30 evening, `posed/`)
|
|
|
|
The second capture round adds a `P` line per frame (raw IEEE-754 dwords
|
|
from `Render::viewer_pos` @0x0081ef00: camera cell id, world origin xyz,
|
|
the four Frame quaternion components in storage order) — the exact-replay
|
|
inputs the first round lacked. Ten fixtures in `posed/`: cathedral-arrival,
|
|
terrace-center (interior-rooted this round — different camera state than
|
|
the morning; the pose stamp makes each fixture self-consistent),
|
|
terrace-edge (outdoor, the #456 pose), holtburg-doorway-still,
|
|
holtburg-walkout, holtburg-transitions (a full out-and-back crossing with
|
|
all four root flips — supersedes walkout as the transition contract),
|
|
holtburg-street-outdoor, holtburg-walkabout (80 moving frames),
|
|
foundry-entry (outdoor approach; the flip fell outside the window),
|
|
foundry-deep (the pure-interior shape: DI + DC ov=0, no landscape).
|
|
Caveat: the pose is dumped at the frame MARKER (RenderNormalMode entry),
|
|
i.e. before update_viewpoint copies the new camera state — for moving
|
|
captures the stamped pose belongs to the PREVIOUS frame's draw; still
|
|
captures are unaffected. FW1 conformance gates on the STILL fixtures
|
|
first for exactly this reason.
|