Camera state: 2,005 per-frame float triples, one singleton candidate

The guard-band clip test's blocker is named in core-data-regions.md: the algorithm
needs the camera and the frustum, both per-frame, so it needs a savestate. Two
savestates give that as a differential -- anything that moved is per-frame state --
without needing to know where the camera lives.

Frames .01 and .04, 33,554,432 bytes each. Of every 16-byte-aligned triple of
finite floats with magnitude 0.001..100,000, 2,005 differ.

Two shapes, clearly different things: the 0x1886xx block repeats one triple four
times at 16-byte stride, which is a per-object array, and 0x18aa70 holds a
near-unit vector that reads as a direction. 0x152c70 is a singleton,
[247.000, 194.000, 49.890] -> [300.170, 227.480, 128.000], in the range Aranos
occupies.

Not claimed as the camera. 2,005 candidates is not a shortlist and a plausible shape
is not evidence -- this stretch has produced enough of those.

Three confirmation steps recorded, cheapest first: smooth motion across .01-.04, a
singleton rather than an array element, and perturbing the camera in an emulator to
watch that one address change. The first two need only the savestates already on
disk; the third is what the lighting verification used.

286 passing with the disc present and GC_SSTATE set, clippy clean.
This commit is contained in:
2026-10-15 02:15:05 +02:00
parent e3e0a30030
commit a991088103
2 changed files with 144 additions and 0 deletions
+50
View File
@@ -2646,3 +2646,53 @@ That is the same mistake one level down from the section-indexing bug: I used a
decoding I had never checked to produce results, and then measured the results
with the same unverified decoding. The check existed as a tool from the first
commit.
## Camera position in EE RAM: the differential measurement
The guard-band clip test needs the camera, and the doc says so explicitly -- "both
are per-frame game state, so this needs the camera at a savestate". Two savestates
give a differential: **anything that moved between them is per-frame state**, and
anything static is not. That is the measurement, and it needs no knowledge of where
the camera lives.
Frames `.01` and `.04`, both 33,554,432 bytes. Of every 16-byte-aligned triple of
finite floats with magnitude 0.001..100,000, **2,005 differ** between the two.
Two shapes in the output, and they are clearly different things:
0x152c70 [247.000, 194.000, 49.890] -> [300.170, 227.480, 128.000]
0x188660 [251.864, 195.641, 51.895] -> [298.396, 224.011, 128.948]
0x188670 [251.864, 195.641, 51.895] -> [298.396, 224.011, 128.948]
0x188680 [251.864, 195.641, 51.895] -> [298.396, 224.011, 128.948]
0x188690 [251.864, 195.641, 51.895] -> [298.396, 224.011, 128.948]
The `0x1886xx` block repeats the same triple four times at 16-byte stride -- that
is a per-object array, not a camera. And `0x18aa70` holds
`[0.033, -0.212, 0.977] -> [0.506, 0.644, 0.574]`, a near-unit vector that reads as
a direction rather than a position.
**`0x152c70` is the interesting one** and it is only a candidate:
[247.000, 194.000, 49.890] -> [300.170, 227.480, 128.000]
Small positive coordinates in the range Aranos occupies, moving between frames, at
an address that is a singleton rather than an array element.
**Not claimed as the camera position.** 2,005 candidates is not a shortlist, and
this stretch has produced enough confident-looking numbers built on unverified
premises that the bar for saying "this is X" is an independent check, not a
plausible shape.
**What would confirm it**, in order of cheapness:
1. The same address should move *smoothly* between adjacent frames. Take `.01`,
`.02`, `.03`, `.04` and check the series is monotone-ish rather than jumping --
a camera between consecutive frames moves a little, not 50 units.
2. It should be a **singleton**: the camera is one thing, not an array. `0x152c70`
is already in a sparse region, but that needs confirming rather than assuming.
3. Perturb the camera in an emulator and watch that address alone change.
Point 3 is the decisive one and it is cheap -- it is the same technique the
lighting verification used. Points 1 and 2 need no emulator at all and run off the
savestates already on disk.