diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index 902e6434..45e01b54 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -4432,3 +4432,47 @@ was designed, not before. The rule says grep the doc that owns the DATA first; here the data was "wingman", the owning doc was `isl-condition-builtins.md`, and reading it first would have reframed the iteration rather than corrected it afterwards. + +--- + +## βœ…πŸ”΄ 2026-08-27 β€” `AA_`/`AV_` are one interleaved block; the selection is still unfound + +**Docs greped BEFORE designing the experiment** (the rule that cost me last +iteration): `unit-datasheet-static.md` **owns the field family** and already says +🟑 "anti-air vs anti-vessel is the obvious reading β€” **not adopted**, nothing here +shows the selection"; `live-unit-definitions.md` owns the runtime field map and +records that `AA_AxisMode_*`/`AV_AxisMode_*` default to 0; +`unit-struct-runtime.md` owns the `Maneuver` declaration-order result; +`flight-speed-law.md` and `isl-builtins.md` mention the prefixes in passing. +**What none of them says is which code reads them.** + +βœ… **Exactly one function references the names.** `sub_822F9498` β€” the +unit-definition loader, called only from `sub_821A6CF0` β€” reads 78 named float +fields; nothing else in the image touches an `AA_`/`AV_` string. + +βœ… **The layout is an exact interleave: `AV_` at `X`, `AA_` at `X+8`.** +PitchPlus `+196/+200` vs `+204/+208`; PitchMinus `+212/+216` vs `+220/+224`; +Yaw `+228/+232` vs `+236/+240`; Roll `+244/+248` vs `+252/+256`; AxisMode +`+320/+324` vs `+328/+332`. **The constant +8 is the finding** β€” a selector is an +offset of 0 or 8, not two lookups. + +βœ… **Data control:** the ten suffixes match **exactly** between families (list +equality, not a count); 690 records each for the eight rate fields, 36 each for +`AxisMode`. `AA_` is usually the larger value (`AA_AxisMode_Min` 100 vs 35; +`AA_Yaw_Max` 50 vs 25) β€” but `AA_PitchPlus_Min` 100 vs `AV_` 200 goes the other +way, so that is a description, not a rule. + +⚠️ **The 20 strings exist twice** (`0x82085B98…` and `0x8209F674…`); the loader +uses the second block and **the first 20 are referenced by nothing**. + +πŸ”΄ **The selection is NOT settled, and the offset route failed again.** Functions +loading two or more of `+196`/`+204`/`+320`/`+328` number **39** across the image +β€” those offsets are far too common to identify a consumer. Only two are +call-graph-reachable from the loader's owner (`sub_821A6CF0`, `sub_821AB650`); +that is the next handle. **"Anti-air vs anti-vessel" stays a reading**, exactly as +`unit-datasheet-static.md` had it. + +**Method slip to record:** I dumped ~1 100 disassembled instructions to find the +nameβ†’offset mapping when a scripted `addi`β†’`stfs` pairing (which I then wrote +anyway) gave the same 20 lines. Script the extraction first; never eyeball a +4.5 KB function. diff --git a/docs/re/INDEX.md b/docs/re/INDEX.md index 9b552839..57694b92 100644 --- a/docs/re/INDEX.md +++ b/docs/re/INDEX.md @@ -107,7 +107,7 @@ files, which is how the same ground got covered twice. | [`structures/hangar-loadout-system.md`](structures/hangar-loadout-system.md) | The Hangar loadout system β€” loadout β†’ per-slot allow-list β†’ arsenal item | βœ… CONFIRMED β€” 60/60 slot refs, 70/88 item refs (18 = the `No_Equipment` sentinel) | | [`structures/arsenal-item-weapon-chain.md`](structures/arsenal-item-weapon-chain.md) | The 59-of-131 arsenal question β€” an item names a hardpoint slot, not a weapon | βœ…βœ… CONFIRMED β€” 0/59 `PlayerWeapon` are a `Weapon.ID`, 59/59 are a `Turret_NNN` slot | | [`structures/unit-substructure-records.md`](structures/unit-substructure-records.md) | The destructible-subsystem model β€” a unit's `Turret`/`Bridge`/`Hatch`/`ShieldGenerator`/`Thruster` sub-records | βœ… CONFIRMED β€” 835 turrets, 835/835 `WeaponID` resolve, `StructureCount` control 667/684 | -| [`structures/unit-datasheet-static.md`](structures/unit-datasheet-static.md) | The static unit datasheet and AI flight model β€” `Generic`, `Maneuver`, `Effect` | βœ… CONFIRMED β€” 394 Generic + 114 Maneuver + 114 Effect records read | +| [`structures/unit-datasheet-static.md`](structures/unit-datasheet-static.md) | The static unit datasheet and AI flight model β€” `Generic`, `Maneuver`, `Effect` | βœ… CONFIRMED β€” 394 Generic + 114 Maneuver + 114 Effect records read; AA_/AV_ are one interleaved block (AV at X, AA at X+8), selection still unfound | | [`structures/weapon-datasheet-static.md`](structures/weapon-datasheet-static.md) | The static weapon datasheet β€” `Weapon`, `Shell`, `AssortMissileParam` | βœ… CONFIRMED β€” 131 Weapon + 131 Shell + 9 AssortMissileParam records read | | [`structures/isl-timers.md`](structures/isl-timers.md) | A ScriptPhase owns 32 stopwatches, and they count seconds | βœ… CONFIRMED β€” the advance is read from `sub_822710D0`, the unit from | | [`structures/isl-message-dialogue-link.md`](structures/isl-message-dialogue-link.md) | Mission scripts as dialogue β€” built-in 64 -> message id -> caption text | βœ… CONFIRMED total, 2 683/2 683 call sites across all 28 stages resolve, no residue | diff --git a/docs/re/structures/unit-datasheet-static.md b/docs/re/structures/unit-datasheet-static.md index 9ec901cf..386ab1ea 100644 --- a/docs/re/structures/unit-datasheet-static.md +++ b/docs/re/structures/unit-datasheet-static.md @@ -109,8 +109,49 @@ AA_* and AV_* Pitch/Yaw/Roll Min/Max pairs ``` 🟑 The `AA_` / `AV_` prefixes pair with `AttackCraftPoint` / `AttackVesselPoint`, -so *anti-air* vs *anti-vessel* rate limits is the obvious reading β€” **not -adopted**, nothing here shows the selection. +so *anti-air* vs *anti-vessel* rate limits is the obvious reading β€” **still not +adopted**. See below for what the executable does say. + +### βœ… The two families are one interleaved block (2026-08-27) + +Exactly **one** function in the image references the `AA_`/`AV_` name strings: +`sub_822F9498`, the unit-definition loader, itself called only from +`sub_821A6CF0`. Mapping each `addi rN, r29, -offset` (the name) to the `stfs` +that follows gives the definition-object layout, and it is a clean interleave β€” +**`AV_` at `X`, `AA_` at `X+8`**, for all five axes: + +| axis | `AV_Max` / `AV_Min` | `AA_Max` / `AA_Min` | +|---|---|---| +| `PitchPlus` | `+196` / `+200` | `+204` / `+208` | +| `PitchMinus` | `+212` / `+216` | `+220` / `+224` | +| `Yaw` | `+228` / `+232` | `+236` / `+240` | +| `Roll` | `+244` / `+248` | `+252` / `+256` | +| `AxisMode` | `+320` / `+324` | `+328` / `+332` | + +The **constant `+8` displacement** is the structural point: whatever selects +between the families does it as an offset of `0` or `8`, not as two separate +lookups. The loader reads 78 named float fields in total. + +Data side: the ten suffixes match **exactly** between the two families (checked +as a list equality, not a count), with 690 records each for the eight rate fields +and 36 each for `AxisMode`. Where the values differ, **`AA_` is consistently the +larger** β€” `AA_AxisMode_Min` 100 vs `AV_` 35, `AA_Yaw_Max` 50 vs `AV_` 25, +`AA_PitchPlus_Min` 100 vs `AV_` 200 being the exception that keeps this a +description, not a rule. + +⚠️ **The 20 strings exist twice** in the image, at `0x82085B98…` and +`0x8209F674…`. The loader uses the second block; **the first 20 are referenced by +nothing**. + +### πŸ”΄ The selection is still not found + +Looking for the consumer by offset does not work here: functions loading two or +more of `+196`/`+204`/`+320`/`+328` number **39** across the image, and those +offsets are far too common to identify anything β€” the same trap the corpus has +paid for before. Only two of the 39 are call-graph-reachable from the loader's +owner (`sub_821A6CF0` itself, and `sub_821AB650`); that is the next handle, and +it was not followed this iteration. **So "anti-air vs anti-vessel" remains a +reading.** ## `Effect`