Compare commits
2 Commits
auto/re-sh
...
auto/re-un
| Author | SHA1 | Date | |
|---|---|---|---|
| 530555de9f | |||
| 69b4a2e569 |
@@ -22,7 +22,7 @@ Promote to a prose `structures/…md` file when a format needs behavioural notes
|
|||||||
| XBG7 mesh | 🟡/❔ | `sylpheed-formats/src/mesh.rs` + `tests/mesh_disc.rs` ([xbg7](structures/xbg7-mesh.md)) | weapons/props: declaration-driven variable stride (36 models), GPU-confirmed. **Stage containers: 5662 sub-models across 22 stages** via content-anchored grouped pools (`stage_models`). Quantized hero bodies (DeltaSaber `f004`) still declined |
|
| XBG7 mesh | 🟡/❔ | `sylpheed-formats/src/mesh.rs` + `tests/mesh_disc.rs` ([xbg7](structures/xbg7-mesh.md)) | weapons/props: declaration-driven variable stride (36 models), GPU-confirmed. **Stage containers: 5662 sub-models across 22 stages** via content-anchored grouped pools (`stage_models`). Quantized hero bodies (DeltaSaber `f004`) still declined |
|
||||||
| Capital-ship part placement | 🟡 | `sylpheed-formats/src/ship.rs` (static) + [runtime capture](ship-placement-runtime-capture.md) | hull placement static-exact; external parts approximate statically. **Runtime capture** (Canary F10 → VS-constant WorldView) gives ground truth — validated on `e106` destroyer; not yet baked into the viewer |
|
| Capital-ship part placement | 🟡 | `sylpheed-formats/src/ship.rs` (static) + [runtime capture](ship-placement-runtime-capture.md) | hull placement static-exact; external parts approximate statically. **Runtime capture** (Canary F10 → VS-constant WorldView) gives ground truth — validated on `e106` destroyer; not yet baked into the viewer |
|
||||||
| Weapon fields defaulted on disc | ✅ | [runtime struct](structures/weapon-struct-runtime.md) · [DATA SHEET route](weapon-datasheet-runtime.md) | **Solved.** Canary maps guest RAM into `/dev/shm`, so the parsed `Weapon`/`Shell` objects are readable live; their layout is solved against disc ground truth (zero contradictions over 100+ records). All 126 weapons, exact numbers, no story progress needed — [4 393 values](captures/weapon-runtime-fields.csv) the disc does not carry. Supersedes the letter-bucket limit of the DATA SHEET route, which now serves as the independent cross-check |
|
| Weapon fields defaulted on disc | ✅ | [runtime struct](structures/weapon-struct-runtime.md) · [DATA SHEET route](weapon-datasheet-runtime.md) | **Solved.** Canary maps guest RAM into `/dev/shm`, so the parsed `Weapon`/`Shell` objects are readable live; their layout is solved against disc ground truth (zero contradictions over 100+ records). All 126 weapons, exact numbers, no story progress needed — [4 393 values](captures/weapon-runtime-fields.csv) the disc does not carry. Supersedes the letter-bucket limit of the DATA SHEET route, which now serves as the independent cross-check |
|
||||||
| Unit (craft/vessel) fields defaulted on disc | ✅/🟡 | [runtime struct](structures/unit-struct-runtime.md) | The parsed `unit\UN_*.tbl` definition object, vtable `0x820af844`, ≥`0x380` bytes, one per unit — **discovered, not assumed** (`unit_discover.py`), and distinguished from the spawned-entity class `0x820af030` by being one-per-ID and byte-constant within a run. Across runs only pointer words move — `--crosscheck` proves **no reported field offset is run-dependent** (two words, `+0x2c8`/`+0x2d0`, are stage-dependent and remain unidentified). 27 fields ✅ (21 units, 7 runs); the `Maneuver` block is **schema declaration order, 4 bytes/field, base `0x9c` with a two-slot gap after `AA_Roll_Min`** (29 anchors, 0 conflicts), which also pins 5 fields *no* disc record ever values. Angles are **radians at runtime, degrees on disc**. Unlike weapons, unit definitions are instantiated **per stage**, so coverage (21/110) grows by visiting missions — [values](captures/unit-runtime-fields.csv) |
|
| Unit (craft/vessel) fields defaulted on disc | ✅/🟡 | [runtime struct](structures/unit-struct-runtime.md) | The parsed `unit\UN_*.tbl` definition object, vtable `0x820af844`, ≥`0x380` bytes, one per unit — **discovered, not assumed** (`unit_discover.py`), and distinguished from the spawned-entity class `0x820af030` by being one-per-ID and byte-constant within a run. Across runs only pointer words move — `--crosscheck` proves **no reported field offset is run-dependent** (two words, `+0x2c8`/`+0x2d0`, are stage-dependent and remain unidentified). 27 fields ✅ (21 units, 7 runs); the `Maneuver` block is **schema declaration order, 4 bytes/field, base `0x9c` with a two-slot gap after `AA_Roll_Min`** (29 anchors, 0 conflicts), which also pins 5 fields *no* disc record ever values. Angles are **radians at runtime, degrees on disc**. Unlike weapons, unit definitions are instantiated **per stage**, so coverage (21/110) grows by visiting missions — but a defaulted field is **not** a global constant: `Size_Y` provably inherits `Size_X` (7 independent units, 6 distinct values), and three more sibling rules are recorded ❔, recovering 65 values in units never visited — [values](captures/unit-runtime-fields.csv) |
|
||||||
| UI screen layout (`.rat`) | ✅/🟡 | [ui-rat-layout](structures/ui-rat-layout.md) | One pak per UI screen; each RATC = one (context × language) build; every `<name>.t32` sprite has a `<name>.rat` **layout record** (BE u32; 1280×720 design space; scale/tint/X/Y, keyframes for animated elements, `opt ` link to the focused state). **The tutorial PAUSE menu and the title main menu both rebuild pixel-accurately from the disc.** `loop1.rat` (screen-level draw order) not yet decoded |
|
| UI screen layout (`.rat`) | ✅/🟡 | [ui-rat-layout](structures/ui-rat-layout.md) | One pak per UI screen; each RATC = one (context × language) build; every `<name>.t32` sprite has a `<name>.rat` **layout record** (BE u32; 1280×720 design space; scale/tint/X/Y, keyframes for animated elements, `opt ` link to the focused state). **The tutorial PAUSE menu and the title main menu both rebuild pixel-accurately from the disc.** `loop1.rat` (screen-level draw order) not yet decoded |
|
||||||
|
|
||||||
## Runtime / dynamic-capture technique
|
## Runtime / dynamic-capture technique
|
||||||
|
|||||||
@@ -272,3 +272,84 @@ take-off, ~12 minutes in mid-combat, and after GAME OVER. 14 objects, the same
|
|||||||
is no need to play it, and no need to survive it.
|
is no need to play it, and no need to survive it.
|
||||||
|
|
||||||
Stages captured so far: `Ttrl` (BASIC CONTROLS), Stage 02.
|
Stages captured so far: `Ttrl` (BASIC CONTROLS), Stage 02.
|
||||||
|
|
||||||
|
## A defaulted unit field is not a global constant — some inherit from a sibling
|
||||||
|
|
||||||
|
**Confidence: 🟡 for `Size_Y`, ❔ for the rest. Analysis 2026-08-10, offline, from
|
||||||
|
[`captures/unit-runtime-fields.csv`](../captures/unit-runtime-fields.csv).**
|
||||||
|
|
||||||
|
The coverage limit above (21 of 110 units, growing only with story progress) is
|
||||||
|
worth attacking from the other side first: *if* a field the disc leaves unset
|
||||||
|
always took the same runtime value, the 21 captured units would pin that default
|
||||||
|
for all 110 and no further missions would be needed.
|
||||||
|
|
||||||
|
**It does not.** Restricting to the 150 values that are both ✅ CONFIRMED and
|
||||||
|
come from a field the disc leaves defaulted, only 6 of 24 fields have a single
|
||||||
|
value across every unit that defaults them (`HP`→10, `MassScore`→0,
|
||||||
|
`MaximumVelocity`→0, `RadarRange`→0, `DestroyMotionTime`→0, `Size_Z`→0.1). The
|
||||||
|
other 18 take several distinct values — so the default is computed per unit.
|
||||||
|
|
||||||
|
Where from? For each defaulted value, ask which *other* field of the same unit
|
||||||
|
holds exactly that value. Counting only cases where the value is **non-zero**
|
||||||
|
(otherwise `0 == 0` inflates every pair) and checking that the two fields are at
|
||||||
|
**different offsets** (so the match is not the layout solver aliasing them):
|
||||||
|
|
||||||
|
| defaulted field | takes the value of | support | independent units |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `Size_Y` (`0x034`) | `Size_X` (`0x030`) | 9/9 | **7**, 6 distinct values |
|
||||||
|
| `Size_Radius` (`0x050`) | `min(Size_X, Size_Z)` | 4/4 | 4, 3 distinct values |
|
||||||
|
| `FCSRange` (`0x2a4`) | `RadarRange` (`0x2a0`) | 4/4 | 2 |
|
||||||
|
| `DefencePoint` (`0x2bc`) | `AttackVesselPoint` (`0x2b4`) | 6/6 | 2 |
|
||||||
|
|
||||||
|
`Size_Y ← Size_X` is the one to trust: seven unrelated ships (`e105` 600,
|
||||||
|
`e106` 300, `e108` 80, `e201` 300, `f101` 400, `f105` 700, `f106` 200) each omit
|
||||||
|
`Size_Y` on disc and each shows its own `Size_X` at runtime. When both fields
|
||||||
|
*are* on disc they differ freely (14 distinct `Size_Y` values against 13 of
|
||||||
|
`Size_X`), so this is a default rule, not one value stored twice.
|
||||||
|
|
||||||
|
`Size_Radius`'s formula is **not yet separable**: `min(Size_X, Size_Z)` and "the
|
||||||
|
median of the three axes" fit all four units identically. `UN_e010_ADAN_Attacker_S`
|
||||||
|
is what rules out the simpler `Size_Radius ← Size_X` (X=100, Y=40, Z=50, radius
|
||||||
|
**50**). The last two rules rest on two independent units each and are ❔ —
|
||||||
|
recorded so they can be falsified, not relied on.
|
||||||
|
|
||||||
|
**Why it matters for the reimplementation:** filling a missing `Size_Y` with `0`
|
||||||
|
or with a global constant gives the game's largest hulls a wrong lateral extent
|
||||||
|
(`f105` 700, `e105` 600, `f101` 400 — all defaulted on disc). Applied across the
|
||||||
|
disc, the rules recover **65 (unit, field) values in units that have never been
|
||||||
|
visited**: `Size_Y` in 21 of the 21 units that omit it, `Size_Radius` in 22 of 26,
|
||||||
|
`FCSRange` in 14 of 56, `DefencePoint` in 8 of 60.
|
||||||
|
|
||||||
|
### Cross-check against the weapons: this is NOT an engine-wide mechanism
|
||||||
|
|
||||||
|
The obvious worry is that four rules from 21 units are coincidence. The
|
||||||
|
`Weapon`/`Shell` capture is the control: **complete coverage, 126 records**, with
|
||||||
|
the same "defaulted on disc" classification. Running the identical sweep there
|
||||||
|
(confirmed rows, non-zero values, offsets required to differ) finds **no sibling
|
||||||
|
rule at all** — the single 100 %-agreement candidate (`Shell.Length ←
|
||||||
|
`Shell.Volume`, 5 records) has one distinct value, i.e. it is really the constant
|
||||||
|
`Length → 10` coinciding with `Volume = 10`. Weapon defaults vary per record just
|
||||||
|
as unit defaults do (10 of 14 `Weapon` fields, 16 of 17 `Shell` fields), so the
|
||||||
|
phenomenon is general; the *sibling* explanation is not.
|
||||||
|
|
||||||
|
So `Size_Y ← Size_X` is **specific to the unit schema** (plausibly the size block
|
||||||
|
defaulting its axes), not a property of IDXD default resolution. Two consequences:
|
||||||
|
the rule cannot be justified by appeal to a general mechanism, and the two
|
||||||
|
two-unit hypotheses (`FCSRange`, `DefencePoint`) lose the support they would have
|
||||||
|
borrowed from one — treat them as **coincidence-not-excluded** until a new stage
|
||||||
|
tests them.
|
||||||
|
|
||||||
|
`Size_Y ← Size_X` itself survives this scrutiny, and was re-checked at the raw
|
||||||
|
token level rather than through the sub-record merge: `UN_e105_ADAN_Cruiser`,
|
||||||
|
`UN_f105_TCAF_Cruiser` and `UN_f101_TCAF_Acropolis` each declare `Size_X`,
|
||||||
|
`Size_Z` and `Size_Radius` and **no `Size_Y` at all**, and each reads back its own
|
||||||
|
`Size_X` (600 / 700 / 400) at runtime.
|
||||||
|
|
||||||
|
**How to falsify:** the rules predict a specific number for units in stages not
|
||||||
|
yet captured. Load any new stage, snapshot, and compare — one disagreement kills
|
||||||
|
the rule. Note what is *not* a useful test: Stage 01, the only other reachable
|
||||||
|
stage, adds just four uncaptured units (`e010`/`e106` variants) whose predictions
|
||||||
|
are the same numbers their already-captured base variants gave, so it would
|
||||||
|
re-measure rather than test. A real test needs a stage with unfamiliar classes,
|
||||||
|
i.e. story progress — which is now the *only* thing story progress is needed for
|
||||||
|
here.
|
||||||
|
|||||||
Reference in New Issue
Block a user