re: the capture names file offsets -- the twin collapse is an anchoring error
Locating each drawn buffer's positions inside Stage_S01.xpr shows vbase - offset is one constant (0x1A94FFF4, same in two runs), so a capture gives ground truth at file-offset granularity. Read against our anchor scan it is a defect list: full/_m resources starting at their own _l buffer, eight drawn buffers claimed by nobody, and the bdy_01_l/bdy_02_l twins sharing one buffer while the container carries both halves (0x3b3ee8 and its exact X-mirror at 0x3c55d8). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -582,4 +582,66 @@ resource by `vcount` plus decoded positions. The same match yields, for each
|
||||
part, the `vbase` the engine used — so two resources that our decoder gives the
|
||||
same geometry can be checked directly: different `vbase` in the capture ⇒ our
|
||||
shared decode is wrong. That is the per-part oracle any future anchor work should
|
||||
be validated against, and it needs no new capture run.
|
||||
be validated against, and it needs no new capture run.
|
||||
### ✅ It was run — and the capture gives file-offset ground truth
|
||||
|
||||
`examples/shared_vbase_check.rs` does the per-part check above, and then goes one
|
||||
step further than planned. Three results, in order of strength.
|
||||
|
||||
**1. A draw's `vbase` *is* the container file offset plus a constant.** Vertex
|
||||
POSITION is `f32×3` big-endian at vertex offset 0, so a draw's dumped positions
|
||||
are a value pattern that can be searched for in the `.xpr` itself. Doing that for
|
||||
every draw in `xenia_ship_capture_01/02.log` and histogramming `vbase − offset`:
|
||||
|
||||
```
|
||||
xenia_ship_capture_01.log: 11 distinct vbases located, 208 not in this container
|
||||
vbase - offset = 0x1A94FFF4 ×8 ← same constant in log 02
|
||||
```
|
||||
|
||||
The 208 "not in this container" are draws whose geometry lives in `Common.xpr`,
|
||||
a weapon pack or a backdrop — expected. The eight that do belong to `Stage_S01`
|
||||
share **one** constant, and the *same* constant in a second run, so the container
|
||||
is uploaded contiguously and **a capture names the exact file offset of every
|
||||
buffer the engine drew**. Log 03 loaded the container at a different address, so
|
||||
the constant is per-run, not baked.
|
||||
|
||||
**2. Read against our anchor scan, that is a defect list**
|
||||
([`captures/stage-s01-capture-truth-offsets.txt`](../captures/stage-s01-capture-truth-offsets.txt)):
|
||||
|
||||
| file offset | drawn vcount | claimed by our decode |
|
||||
|---|---|---|
|
||||
| `0x3b3ee8` | 119 | `e106_bdy_01_l`(119), `e106_bdy_02_l`(119) |
|
||||
| `0x3c55d8` | 119 | — **nobody** |
|
||||
| `0x3dd2c4` | 146 | `e106_bdy_03`(815), `e106_bdy_03_l`(146) |
|
||||
| `0x40763c` | 179 | `e106_bdy_04_l`(179) ✅ |
|
||||
| `0x40e418` | 51 | `e106_brg_01`(202), `e106_brg_01_m`(92) |
|
||||
| `0x444ccc` | 58 | `e106_eng_01_l`(58) ✅ |
|
||||
| `0x45705c` | 82 | `e106_wep_02_01_l`(82), `e106_wep_02_01_m`(294) |
|
||||
| `0x38788` `0x4b8b8` `0xb6574` `0xdbbac` `0x133da0` `0x162840` `0x44a32c` | 181, 93, 41, 77, 76, 60, 44 | — **nobody** |
|
||||
|
||||
Two resources land exactly (`bdy_04_l`, `eng_01_l`). Everywhere else a **full or
|
||||
`_m` resource starts at the offset of its own `_l` buffer** — `bdy_03` decodes
|
||||
815 vertices beginning where the engine's 146-vertex LOD begins — and eight
|
||||
drawn buffers are claimed by no resource at all. This is the anchor scan taking
|
||||
the first candidate that validates, seen directly rather than inferred.
|
||||
|
||||
**3. The twin pair is an anchoring error, and the mirror is in the data.** For
|
||||
`e106_bdy_01_l` ≡ `e106_bdy_02_l` the capture shows **two** 119-vertex buffers
|
||||
per run, `0x3b3ee8` and `0x3c55d8`; the first is byte-for-byte what we decode,
|
||||
and the second is its **exact X-reflection** (every dumped position matches ours
|
||||
with `x` negated). So the container carries both halves as separate baked
|
||||
geometry, the engine draws each from its own buffer, and our decoder returning
|
||||
one buffer for both names is the defect — which `correlate`'s mirror flag and
|
||||
`ship::apply_twin_mirrors` have been compensating for downstream all along.
|
||||
|
||||
That settles the question this section opened with, for this pair: **not
|
||||
legitimate reuse.** It also pins what the withdrawn neighbourhood-anchor fix
|
||||
could not: `0x3b3ee8` stays with whichever twin we already decode there, and the
|
||||
other twin must move to `0x3c55d8`. The invariant is checkable without a capture
|
||||
— *mirrored twins must decode to X-reflected buffers, never identical ones*.
|
||||
|
||||
Not settled: `e106_brg_01_b_02` ≡ `e106_brg_01_l` (51 verts). A second 51-vertex
|
||||
`vbase` exists in the logs but is **not** from this container, and the container
|
||||
holds three near-identical 51-vertex runs, so the pair has no oracle yet.
|
||||
`n006_01A` ≡ `n006_01B` shows a single `vbase` in all three logs — consistent
|
||||
with real reuse, but equally with only one of the two being on screen.
|
||||
|
||||
Reference in New Issue
Block a user