re(ui): a RATC child's name is stated, not inferred -- and it was hiding every menu background
`ratc::parse` named each child by scanning backwards for the last printable run of bytes before its magic. The format states the name explicitly instead, in an `opt ` block: `"opt " | BE32 len | name | NUL | 3 bytes | magic` -- the same block `ui_layout::opt_link` already read for a button's focus link. The scan agrees with it 17 918 times out of 17 942 and is wrong 24 times, every one the same failure: the 3 trailing payload bytes are themselves printable and beat the real name. For `pteff05.t32` those bytes are `38 41 58` = `8AX`, so the full-resolution background of all five menu screens registered under a name no element declares, resolved to no sprite, and `compose` dropped it through an early `continue` that -- unlike the two arms above it -- records nothing. The screen lost its background and `screen render` still reported "all resolved". `8AX` was never a name. Docs that treated it as one are corrected here. Disc-wide, and the control is the 17 918 the scan already got right: the `opt ` reading reproduces every one of them. Effect on the five screens is the signature of the same art at twice the resolution -- mean brightness unmoved, high-frequency detail x1.15..x1.30 -- which is what the separately-measured `ui-8ax-fullres-background` result said the game draws. Also closes a long-standing dangling reference: `pmbase.t32`, recorded as "on the disc nowhere", is the `GP_STAGE_CLEAR` child the scan called `8AX`. RATC sibling references now resolve 10 148 of 10 148. Verified: 114/114 sylpheed-formats unit tests (including two new ones pinning the `8AX` case byte for byte and the no-block fallback), and every disc-gated integration suite in sylpheed-formats/sylpheed-cli.
This commit is contained in:
@@ -21,7 +21,7 @@ Promote to a prose `structures/…md` file when a format needs behavioural notes
|
||||
| IDXD nameless field keys | ✅/❌ | [idxd-unnamed-keys](structures/idxd-unnamed-keys.md) + [`tools/re-capture/idxd_unnamed_keys.py`](../../tools/re-capture/idxd_unnamed_keys.py) | Census of every field entry whose `name_off` is `0xFFFFFFFF`, disc-wide: **7 750 objects, 2 757 039 field entries, 0 parse failures**, `tag_hash` reproducing **1 271 462/1 271 462** named keys. **7 094 distinct keys are never named — and 7 052 of them are not hashes at all**, but author-assigned element ids (equal to the field's own index in 1 404 924 of 1 485 577 cases; `tag_hash("BGM_001")` is `0xC662435B` while the key valued `BGM_001.slb` is `0x000003E9`). ⚠️ **The "504 hash-keyed nameless fields" figure is 504 ENTRIES, not 504 names** — 42 distinct keys × 6 language copies × 2 records. All 42 are **ISL script-symbol hashes** in `<lang>\script\ID.tbl` (GP_READY_ROOM.pak), the link map built by `PrepareScript`'s "isl script prescanning"; 41 of 42 appear as little-endian call targets inside the `.isb` bytecode, forming a coherent launcher/helper call graph. The hash's own algebra pins the **trailing digits of 30 of the 42 names** (deltas of exactly `+0x01000001` across `stage01..09`, `stage10..16`, `challenge01..06`; `+0x01010000` across `tutorial0101..0601`). ❌ **No name was cracked, and the negative is quantified**: seven attacks up to a 3.5×10⁸ composition space found nothing above the noise floor; exhaustive preimage search recovers `"Stage01"` from its own hash but returns nothing for the real targets at ≤6 characters, and at 7 characters one target already has **1 176** preimages — a 24-bit modulus cannot name an 8+ character identifier uniquely |
|
||||
| XPR2 texture + cubemap | 🟡/✅ | `sylpheed-formats/src/texture.rs` + [colour check](xpr2-colour-check.md) | de-tile + A8R8G8B8 and DXT1. **Channel order ✅ confirmed against the running game**: the Delta Saber's decoded atlas is orange-dominant (median saturated hue 23.3°, *zero* cool pixels) and the game renders the same hull at 9.3° — a red↔blue swap would sit at ≈200°. Exact fidelity (gamma/sRGB curve, premultiplied alpha, per-channel scale) is 🟡 untested, since a hue comparison cannot see it; cubemap face ordering ❔. **2026-08-29, for the UI path only:** our composite is brighter than the emulator's frame by a gamma of **≈1.34–1.49** across three screens ([tone curve](structures/ui-render-tone-curve.md)) — 🟡 measured, not decoded, constrained only over render values ~0–60, and possibly canary's own `kernel_display_gamma_type = 2` (BT.709) output stage rather than the game's |
|
||||
| T8aD 2D texture | ✅ | `sylpheed-formats/src/t8ad.rs` | **100 % of the disc decodes** (19 216/19 216, measured). The "~15 % deferred variants" were a wrong model, not a variant: a surface is a list of **arbitrary sub-rectangles**, each with a 16-byte header of `dst X, dst Y, width, height`, not a 256×256 grid — `0x1c` is the **rectangle count**. Uncovered area stays transparent. **Colours ✅ CONFIRMED** ([k8888](structures/texture-color-k8888.md)) |
|
||||
| RATC bundle | ✅ | `sylpheed-formats/src/ratc.rs` | child listing confirmed. **"One level deep" is not a limitation — there is nothing deeper**: 2 859 bundles hold 18 002 children at depth 1 and **0 at depth 2**, with no parse failures. Nested RATC blobs are **leaf records that reference siblings by name** (`opt `, the sprite name): 3 311 leaves, all embedding sibling names, **10 144 of 10 148 references resolve**. The 4 that do not are one dangling asset — `pmbase.rat` → `pmbase.t32` in `GP_STAGE_CLEAR.pak`'s four language builds, and `pmbase.t32` is **on the disc nowhere** |
|
||||
| RATC bundle | ✅ | `sylpheed-formats/src/ratc.rs` | **✅ 2026-08-29: a child's NAME is stated by an `opt ` block** (`"opt " | BE32 len | name | NUL | 3 bytes | magic`), not by the printable bytes before it. We had been guessing it from the last printable run, which is right 17 918 times and **wrong 24**, each time because the 3-byte tail is itself printable — `8AX` (×22) and `'OX` (×2). `8AX` is **not a name**; it hid `pteff05.t32`/`pteff04.t32`, the full-resolution background of all five menu screens, which `compose` then dropped with no diagnostic ([ratc-child-names](structures/ratc-child-names.md)). 🟡 60 of 18 002 children carry no `opt ` block and still use the scan. Child listing confirmed. **"One level deep" is not a limitation — there is nothing deeper**: 2 859 bundles hold 18 002 children at depth 1 and **0 at depth 2**, with no parse failures. Nested RATC blobs are **leaf records that reference siblings by name** (`opt `, the sprite name): 3 311 leaves, all embedding sibling names, **✅ 10 148 of 10 148 references resolve, as of 2026-08-29.** The 4 that did not were `pmbase.rat` → `pmbase.t32` in `GP_STAGE_CLEAR.pak`'s four language builds, recorded as "`pmbase.t32` is on the disc nowhere". It was on the disc all along, as the child the printable-run scan named `8AX` — the `opt ` name fix above resolves it in all four builds (3 686 767 B each). A dangling reference that closes itself when an unrelated decode lands is the corroboration that decode wanted |
|
||||
| LSTA sprite list | ✅ | `sylpheed-formats/src/lsta.rs` | A display list of inline elements: **T8aD sprites and `PRMD` primitives**. The `count` at `0x04` is **exact and counts both** — `count == T8aD + PRMD` for **64/64** lists on the disc, which retires the old "a few entries disagree" note (it compared sprites against a total including primitives). **All 1 281 sprite frames decode** after the T8aD rectangle-list fix |
|
||||
| IXUD subtitle + caption text | ✅ | `sylpheed-formats/src/ixud.rs` + `movie_subtitle.rs` ([container](structures/idxd-container.md) · [movie link](movie-subtitle-link.md)) | **The IXUD record/field table is decoded and wired in (2026-08-26)** — `IxudObject` mirrors `IdxdObject`; uniform 16-byte records, 12-byte fields, every offset in **chars**, and the word at `0x08` is record 0's hash, not a schema id. Verified disc-wide: **1104/1104** objects, **1476/1476** records, **628 165/628 165** named fields reproducing their `ixud_hash` (`tests/ixud_records_disc.rs`). **Caption text: 537 → 8800 lines, which is 8800 of 8800 distinct keys.** Two steps — generalising the key parser from `MSG_DEMO_*` to all **eight** families (`ACRO ADAN ADPL BIRD DEMO RHIN TCAF` use `MSG_<FAM>_<id>_<page>_<line>`, `VOICE` alone inserts a family letter) took 537 → 8074; switching from **token adjacency to record fields** took it to 8800. ⚠️ An earlier "1.3 % of the game's text" figure of mine counted *occurrences across blocks* — the honest denominator is **8800 distinct keys**, so the real starting point was 6.1 %. The `DEMO` control shows why the field route matters: token adjacency finds 537 lines there, fields find **541** — it was dropping lines in the one family it was written for. | timed cues. **The movie↔subtitle↔voice link is solved — statically**, and as of 2026-08-25 read from the IDXD **record table** rather than scraped from the string pool: **104 cutscene slots binding 101 distinct movies**, 99 slots / 96 movies with a subtitle, 99 / 96 with a voice track, 22 / 22 with a telop. ⚠️ The previous counts (94 / 83 / 21) were the numbers of **distinct pool strings** — a repeat reference contributes no token, so 13 later `VOICE_D_450..454` references read as "no binding". **All 18 hokyu movies are bound**, not five. 93 of the 94 distinct subtitle members resolve; `SUBTITLE_S12B.tbl` resolves in none of the six languages — a dangling reference on the disc. The ~104 **script ids are no longer ❔**: they are literal positional field keys in `BASE_INFO`, each naming its record, and all 104 resolve. `movie_manifest::parse` now reads the record table; CSV regenerated by `examples/movie_map_csv.rs` |
|
||||
| Fonts (ttf/otf/ttc) | ✅ | `sylpheed-formats/src/font.rs` | standard OpenType, parsed via ttf-parser |
|
||||
|
||||
@@ -838,3 +838,22 @@ agent's loop prompt, i.e. nowhere durable. See [`README.md`](README.md) for the
|
||||
"measured" covers several kinds of evidence, and the page that recorded it
|
||||
usually says which — `ui-screen-runtime.md` said "child slots" in as many
|
||||
words. Read that line before building an argument on top of it.
|
||||
|
||||
* **A heuristic that is right 99.9 % of the time still has a shape to its
|
||||
failures — find it before trusting the field.** RATC child names were read by
|
||||
scanning backwards for the last printable run of bytes. That agrees with the
|
||||
format's own `opt ` declaration on 17 918 of 17 942 children, which is the kind
|
||||
of agreement that stops people looking. The 24 exceptions were not random: all
|
||||
24 are the *same* case, a 3-byte binary tail that happens to be printable ASCII
|
||||
(`8AX`), and one of them was the full-resolution background of every menu
|
||||
screen we care about. Ask what the format *states* before settling for what a
|
||||
scan *infers*, especially when the stated version is already decoded elsewhere
|
||||
in the same file — `opt ` was being read for button focus links the whole time.
|
||||
|
||||
* **A `continue` that silently skips is a defect even when the skip is correct.**
|
||||
`compose` drops an element whose sprite does not resolve. Two arms above it
|
||||
record the name into `missing` first; the `el.sprite.is_none()` arm does not.
|
||||
So a screen lost its background and `screen render` still reported "sprites
|
||||
that did not resolve: none" — the diagnostic was structurally unable to see it.
|
||||
When adding an early-out to a loop that already reports what it discards, make
|
||||
it report through the same channel, or it becomes a place findings go to die.
|
||||
|
||||
@@ -605,3 +605,15 @@ neighbourhood, not just the line.
|
||||
them regardless. The no-overlap measurement was correct; the inference from it
|
||||
was not. What survives: a capture of this screen can only cross-check the order
|
||||
*within* each half. [`ui-prm-primitives.md`](structures/ui-prm-primitives.md)
|
||||
|
||||
* "`8AX` is the name a `T8aD` is registered under" → **it is not a name at all.**
|
||||
It is three bytes of the preceding record's payload (`38 41 58`) that happen to
|
||||
be printable ASCII, which our backwards printable-run scan preferred over the
|
||||
name the format actually states in its `opt ` block. The claim sat in
|
||||
`HANDOFF.md` and `ui-8ax-fullres-background.md` as though `8AX` were a real
|
||||
identifier, and cost every menu screen its full-resolution background.
|
||||
[`ratc-child-names.md`](structures/ratc-child-names.md)
|
||||
* "`pmbase.t32` is on the disc nowhere" (the one dangling asset behind
|
||||
`10 144 of 10 148 references resolve`) → **withdrawn; it is on the disc.** It is
|
||||
the `GP_STAGE_CLEAR` child the same scan named `8AX`. With the name decoded the
|
||||
count is **10 148 of 10 148**. [`ratc-child-names.md`](structures/ratc-child-names.md)
|
||||
|
||||
52
docs/re/data/ratc-child-name-audit.txt
Normal file
52
docs/re/data/ratc-child-name-audit.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
# RATC child names: the printable-run scan vs the `opt ` block, all 33 dat/*.pak
|
||||
# 2026-08-29, crates/sylpheed-formats/examples/ratc_child_names.rs
|
||||
#
|
||||
# RUN 1 was taken BEFORE the fix, when ratc::parse still named children by
|
||||
# scanning for the last printable run. It is the evidence for the defect.
|
||||
|
||||
RATC children scanned : 18002
|
||||
with an `opt ` block: 17942
|
||||
scanned name AGREES : 17918
|
||||
scanned name DIFFERS : 24
|
||||
|
||||
distinct disagreements (scanned -> opt), with counts:
|
||||
'OX -> po_keys_win1.t32 x2
|
||||
8AX -> pbbg.t32 x12
|
||||
8AX -> pmbase.t32 x4
|
||||
8AX -> pteff04.t32 x2
|
||||
8AX -> pteff05.t32 x4
|
||||
|
||||
first 20 occurrences:
|
||||
GP_OPTIONS.pak entry 20 'OX -> po_keys_win1.t32
|
||||
GP_OPTIONS.pak entry 22 'OX -> po_keys_win1.t32
|
||||
GP_READY_ROOM.pak entry 132 8AX -> pbbg.t32
|
||||
GP_READY_ROOM.pak entry 141 8AX -> pbbg.t32
|
||||
GP_READY_ROOM.pak entry 211 8AX -> pbbg.t32
|
||||
GP_READY_ROOM.pak entry 219 8AX -> pbbg.t32
|
||||
GP_READY_ROOM.pak entry 233 8AX -> pbbg.t32
|
||||
GP_READY_ROOM.pak entry 234 8AX -> pbbg.t32
|
||||
GP_READY_ROOM.pak entry 264 8AX -> pbbg.t32
|
||||
GP_READY_ROOM.pak entry 265 8AX -> pbbg.t32
|
||||
GP_READY_ROOM.pak entry 967 8AX -> pbbg.t32
|
||||
GP_READY_ROOM.pak entry 999 8AX -> pbbg.t32
|
||||
GP_READY_ROOM.pak entry 1097 8AX -> pbbg.t32
|
||||
GP_READY_ROOM.pak entry 1099 8AX -> pbbg.t32
|
||||
GP_STAGE_CLEAR.pak entry 2 8AX -> pmbase.t32
|
||||
GP_STAGE_CLEAR.pak entry 4 8AX -> pmbase.t32
|
||||
GP_STAGE_CLEAR.pak entry 7 8AX -> pmbase.t32
|
||||
GP_STAGE_CLEAR.pak entry 8 8AX -> pmbase.t32
|
||||
GP_TITLE.pak entry 4 8AX -> pteff04.t32
|
||||
GP_TITLE.pak entry 5 8AX -> pteff05.t32
|
||||
|
||||
# RUN 2, same command AFTER the fix. ratc::parse now prefers the `opt ` name, so
|
||||
# the two readings must agree everywhere -- which is the check that the fix is
|
||||
# complete rather than partial.
|
||||
|
||||
RATC children scanned : 18002
|
||||
with an `opt ` block: 17942
|
||||
scanned name AGREES : 17942
|
||||
scanned name DIFFERS : 0
|
||||
|
||||
distinct disagreements (scanned -> opt), with counts:
|
||||
|
||||
first 20 occurrences:
|
||||
26
docs/re/data/ratc-name-fix-render-effect.txt
Normal file
26
docs/re/data/ratc-name-fix-render-effect.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
# Effect on the five port screens of naming RATC children from the `opt `
|
||||
# block. 2026-08-29. `sylpheed-cli screen render --build N GP_TITLE.pak`,
|
||||
# before vs after the ratc.rs change. The newly-resolved element is the
|
||||
# full-resolution background (pteff04.t32 on the title, pteff05.t32 on the
|
||||
# menus), which the old name `8AX` hid.
|
||||
|
||||
build screen mean brightness high-frequency detail
|
||||
4 title 72.77 -> 72.81 8.722 -> 10.062 x1.15 pixels changed >2: 30.0%
|
||||
5 main menu (JP) 42.73 -> 42.74 3.978 -> 5.051 x1.27 pixels changed >2: 20.0%
|
||||
6 EXTRAS (JP) 44.08 -> 44.09 3.953 -> 5.025 x1.27 pixels changed >2: 19.4%
|
||||
8 main menu 41.57 -> 41.58 3.830 -> 4.970 x1.30 pixels changed >2: 21.0%
|
||||
9 EXTRAS 42.99 -> 43.00 3.867 -> 5.000 x1.29 pixels changed >2: 20.2%
|
||||
|
||||
# Brightness unmoved, detail up ~a quarter = the same artwork at twice the
|
||||
# resolution replacing a 2x upscale. New CONTENT would move the mean.
|
||||
|
||||
# Covering check: the background is opaque and full-screen and paints 4th
|
||||
# of 16 on the menu, so it could hide what follows. Standard deviation
|
||||
# inside each element's resting rect (build 8), before vs after:
|
||||
ptbtn01 sd 59.98 -> 60.03
|
||||
ptbtn03 sd 63.40 -> 63.45
|
||||
ptbtn05 sd 66.54 -> 66.58
|
||||
ptframe1 sd 51.16 -> 51.20
|
||||
ptmsg sd 56.11 -> 56.12
|
||||
loop-area sd 50.99 -> 51.04
|
||||
# Nothing is covered.
|
||||
137
docs/re/structures/ratc-child-names.md
Normal file
137
docs/re/structures/ratc-child-names.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# A RATC child's name is stated by an `opt ` block, not by the bytes before it
|
||||
|
||||
**Status:** ✅ `DECODED`, with a disc-wide check. This fixes a decoder defect that
|
||||
silently dropped the **full-resolution background from all five menu screens**.
|
||||
|
||||
## The field
|
||||
|
||||
Immediately before nearly every child of a `RATC` bundle — 17 942 of the disc's
|
||||
18 002 — sits an `opt ` block:
|
||||
|
||||
```text
|
||||
"opt " | BE32 length | name | NUL | 3 bytes | <child magic>
|
||||
```
|
||||
|
||||
Two children of the main menu bundle (`GP_TITLE.pak` entry 8), raw:
|
||||
|
||||
```text
|
||||
opt 00 00 00 0a p t b a s e . t 3 2 00 0e 10 a4 T8aD
|
||||
opt 00 00 00 0b p t e f f 0 5 . t 3 2 00 38 41 58 T8aD
|
||||
^^^^^^^^
|
||||
"8AX"
|
||||
```
|
||||
|
||||
This is the **same `opt ` block** `ui_layout::opt_link` already decodes for a
|
||||
button's focus link. Nothing new had to be discovered to read it — only noticed.
|
||||
|
||||
## The defect it fixes
|
||||
|
||||
`ratc::parse` named each child with `name_before`: the last printable run in the
|
||||
96 bytes before the child's magic. That is a heuristic, and it is *usually* right
|
||||
— `ptbase.t32`'s three trailing bytes are `0e 10 a4`, not printable, so the scan
|
||||
walks back to the real name.
|
||||
|
||||
But `pteff05.t32`'s trailing three bytes are `38 41 58`, which is `"8AX"` in
|
||||
ASCII. The scan takes those, the child is registered under the name `8AX`, the
|
||||
element that declares `pteff05.t32` matches nothing in the sprite table, and
|
||||
`compose` drops it through
|
||||
|
||||
```rust
|
||||
let Some(sprite) = el.sprite.as_ref() else { continue };
|
||||
```
|
||||
|
||||
— *before* the arm that records a `missing` sprite. So the screen's background
|
||||
vanished with **no diagnostic at all**: `screen render` reported "all resolved".
|
||||
|
||||
⚠️ `8AX` was carried in `docs/` as though it were a name the game uses — the old
|
||||
text read "the `T8aD` behind its `opt ` link is registered under the name `8AX`".
|
||||
It is not a name. It is three bytes of the preceding record's payload.
|
||||
|
||||
## The disc-wide check
|
||||
|
||||
[`examples/ratc_child_names.rs`](../../../crates/sylpheed-formats/examples/ratc_child_names.rs)
|
||||
compares the two readings for every RATC child in all 33 `dat/*.pak`
|
||||
([data](../data/ratc-child-name-audit.txt)):
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| RATC children scanned | **18 002** |
|
||||
| carrying an `opt ` block | 17 942 |
|
||||
| scanned name **agrees** with it | **17 918** |
|
||||
| scanned name **differs** | **24** |
|
||||
|
||||
Every one of the 24 is the same failure: a 3-byte printable tail beating a real
|
||||
name.
|
||||
|
||||
| scanned | actual | count | where |
|
||||
|---|---|---|---|
|
||||
| `8AX` | `pbbg.t32` | 12 | `GP_READY_ROOM` |
|
||||
| `8AX` | `pteff05.t32` | 4 | `GP_TITLE` 5, 6, 8, 9 — the menus |
|
||||
| `8AX` | `pmbase.t32` | 4 | `GP_STAGE_CLEAR` |
|
||||
| `8AX` | `pteff04.t32` | 2 | `GP_TITLE` 4, 7 — the title |
|
||||
| `'OX` | `po_keys_win1.t32` | 2 | `GP_OPTIONS` |
|
||||
|
||||
⚠️ **What I checked about the 24, precisely.** That the recovered name is the one
|
||||
the bundle actually wants is verified for the ten `GP_TITLE` and `GP_STAGE_CLEAR`
|
||||
cases: on the title screens `pteff04.t32`/`pteff05.t32` are *declared elements*
|
||||
that previously resolved to nothing and now resolve, and `pmbase.t32` is the
|
||||
target of `GP_STAGE_CLEAR`'s long-standing dangling reference (below). For the 12
|
||||
`GP_READY_ROOM` (`pbbg.t32`) and 2 `GP_OPTIONS` (`po_keys_win1.t32`) cases I
|
||||
checked only that no element in those bundles is left unresolved afterwards —
|
||||
which is consistent with, not proof of, the same story. None of the 14 is on the
|
||||
five menu screens.
|
||||
|
||||
**The control is the 17 918 the heuristic already got right**: the `opt ` reading
|
||||
reproduces every one of them. A reading that fixed the 24 but disturbed the rest
|
||||
would be a different rule, not this one.
|
||||
|
||||
🟡 **Reach.** 60 children (0.3 %) have **no** `opt ` block within 128 bytes and
|
||||
still fall back to the scan. None of them is on the five menu screens. Whether
|
||||
they genuinely lack the block or sit past the search window is not established.
|
||||
|
||||
## What it changes in the composite
|
||||
|
||||
Resolving the name makes the element resolve, so `compose` now draws it. On all
|
||||
five port screens ([before/after](../data/ratc-name-fix-render-effect.txt)):
|
||||
|
||||
| build | screen | mean brightness | high-frequency detail |
|
||||
|---|---|---|---|
|
||||
| 4 | title | 72.77 → 72.81 | **×1.15** |
|
||||
| 5 | main menu (JP) | 42.73 → 42.74 | **×1.27** |
|
||||
| 6 | `EXTRAS` (JP) | 44.08 → 44.09 | **×1.27** |
|
||||
| 8 | main menu | 41.57 → 41.58 | **×1.30** |
|
||||
| 9 | `EXTRAS` | 42.99 → 43.00 | **×1.29** |
|
||||
|
||||
The brightness is unmoved and the detail is up by a quarter — which is exactly
|
||||
the signature of *the same artwork at twice the resolution* replacing a 2×
|
||||
upscale, and not of new content appearing. That it *should* be the full-res art
|
||||
was settled separately and against the running game, in
|
||||
[`ui-8ax-fullres-background.md`](ui-8ax-fullres-background.md); this page only
|
||||
supplies the name that lets the renderer find it.
|
||||
|
||||
✅ **Nothing is covered.** The background is opaque and full-screen, and on the
|
||||
menu it paints 4th of 16, so the worry is real. Measured at each element's
|
||||
resting rect, before vs after: `ptbtn01` sd 59.98 → 60.03, `ptbtn03` 63.40 →
|
||||
63.45, `ptbtn05` 66.54 → 66.58, `ptframe1` 51.16 → 51.20, `ptmsg` 56.11 → 56.12.
|
||||
Everything survives; only the two `loop*` elements paint beneath it, and those
|
||||
are excluded from the default composite anyway.
|
||||
|
||||
⚠️ **Both backgrounds are now drawn** — `ptbase.t32` upscaled 2×, then the
|
||||
full-res one opaquely over it. Correct output, wasted fill. The port should draw
|
||||
only the full-res one, and take its *timing* from `ptbase`'s element, which is
|
||||
the one carrying the keyframes.
|
||||
|
||||
## What is NOT decoded
|
||||
|
||||
❔ **No declaration word points at the child.** Before reading the bytes I tested
|
||||
whether the 60-byte element declaration indexes the T8aD child table. Its unread
|
||||
words are `+28`, `+36`, `+44` and `+56`; the control is the resolved elements,
|
||||
whose child index is known. On the main menu, of 13 controls the words reproduce
|
||||
the child index **1, 0, 0 and 1** times — and both 1s are the trivial index-0
|
||||
case. There is no pointer; the association is by name, and the name is the `opt `
|
||||
string. [`decl_word_probe.rs`](../../../crates/sylpheed-formats/examples/decl_word_probe.rs)
|
||||
|
||||
✅ Incidental, from the same probe: **`+44` is a button ordinal.** It is `1…5` on
|
||||
exactly the five `ptbtn0N.rat` elements of the main menu, in order, and `−1` on
|
||||
every other element. Not needed for anything open, and recorded rather than
|
||||
chased.
|
||||
@@ -1,8 +1,26 @@
|
||||
# 🟡 `pteff04` / `pteff05` are dropped — the texture is registered as `8AX`
|
||||
# ✅ `pteff04` / `pteff05` — the full-resolution background, once dropped as `8AX`
|
||||
|
||||
**Status:** 🟡 a real name-resolution gap, **currently harmless to look at**, and
|
||||
the obvious fix would make the render *worse*. Found by auditing what
|
||||
`screen render` silently omits on the port's five screens.
|
||||
**Status:** ✅ **RESOLVED 2026-08-29.** This page's two questions are both closed
|
||||
and it is kept for the evidence, not as an open item.
|
||||
|
||||
* *Which of the two backgrounds does the game draw?* — the **full-resolution**
|
||||
one. Measured against a capture; the section below stands unchanged.
|
||||
* *Why did ours drop it?* — because `8AX` **is not a name.** It is three bytes of
|
||||
the preceding record's payload (`38 41 58`) that happen to be printable ASCII,
|
||||
and our backwards printable-run scan preferred them to the name the format
|
||||
states in its `opt ` block. Decoded, with a disc-wide check, in
|
||||
[`ratc-child-names.md`](ratc-child-names.md); `ratc::parse` now reads the
|
||||
stated name and `screen render` draws the background on all five screens.
|
||||
|
||||
⚠️ **Read the rest of this page with that correction in mind.** It was written
|
||||
while `8AX` was believed to be a name the game uses, and says so in several
|
||||
places — "the texture is registered as `8AX`", "the `T8aD` behind its `opt ` link
|
||||
is registered under the name `8AX`". The `opt ` link was never the problem; the
|
||||
`opt ` block was the answer, sitting unread three bytes away.
|
||||
|
||||
<sub>Original status line: 🟡 a real name-resolution gap, currently harmless to
|
||||
look at, and the obvious fix would make the render *worse*. Found by auditing
|
||||
what `screen render` silently omits on the port's five screens.</sub>
|
||||
|
||||
## What `screen render` drops, and why
|
||||
|
||||
|
||||
@@ -330,8 +330,14 @@ parser limitation. It is not — **there is nothing deeper on the disc**:
|
||||
- The children that are themselves RATC (the `.rat` layout records) are **leaf
|
||||
records**: they carry no child list and instead **reference their siblings by
|
||||
name** — the sprite they place and, via `opt `, their focused variant.
|
||||
**3 311** such leaves, every one embedding sibling names, and **10 144 of
|
||||
**3 311** such leaves, every one embedding sibling names, and **10 148 of
|
||||
10 148** references resolve to a sibling of the same bundle.
|
||||
⚠️ It read **10 144 of 10 148** until 2026-08-29. The 4 misses were
|
||||
`pmbase.rat` → `pmbase.t32` in `GP_STAGE_CLEAR.pak`, written up as an asset
|
||||
that is "on the disc nowhere". It was on the disc: it is the child our name
|
||||
scan called `8AX`. See [ratc-child-names](ratc-child-names.md) — the same
|
||||
defect that hid the menu backgrounds. Nothing about the reference was wrong;
|
||||
the thing it pointed at had the wrong name in our index.
|
||||
|
||||
That is the same by-name convention used one level up, where a screen's config
|
||||
names `.prt` components, and one level up again, where the movie table names
|
||||
|
||||
Reference in New Issue
Block a user