re: RATC +0x0c is two u16s forming an ordered interval, not one number

Read as a u32 it looks meaningless -- 179 distinct values up to 248581842. The
raw values give it away (0x0007000F, 0x000F001A, 0x003C0064): two big-endian
u16s. Over all 2985 bundles, high < low in 2985/2985 with no equal and no
inverted cases, and both are bounded by the animation length at +0x08. Span
runs 1-1200, clustering on 1/10/30/8/20; low equals the animation length in 4%.

A strict ordering holding 2985 times rules out flags or a packed count. Which
interval it is stays yellow -- playback range, loop region and active window all
fit equally.

Recorded the alternative I did NOT test: that (high, low) is simply the min and
max keyframe time, making it a derived summary rather than an authored range.
First step written down. The 34.9% of bundles with high == 0 leans against it
but is not evidence on its own.
This commit is contained in:
Sylpheed RE agent
2026-08-26 06:46:50 +00:00
parent 13a97daf75
commit 49cd4996f2
2 changed files with 48 additions and 2 deletions

View File

@@ -509,7 +509,7 @@ composable bundles with a real declaration table
|---|---|---|
| `+0x04` | **3** — `0x3C0000` ×2 843, `0x1E0000` ×12, `0x3C0001` ×4 | 🟡 **frame rate in 16.16**: `0x3C0000` is exactly `60.0`, `0x1E0000` exactly `30.0` |
| `+0x08` | 22 — 30, 1200, 120, 60, … | ✅ the **animation length**, in the same unit as a keyframe's `time` — see below |
| `+0x0c` | 170 | ❔ |
| `+0x0c` | 179 as a u32 — but it is **two u16 fields**, see below | ✅ structure, 🟡 meaning |
| `+0x10` | 83 — `0x9400`, `0x9200`, `0x8212`, … | ❔ flags; bit 15 set on **91 %** of all bundles |
| `+0x18` | **2** — `1280` ×2 829 | ✅ **design width** |
| `+0x1c` | **3** — `720` ×2 823 | ✅ **design height** |
@@ -597,3 +597,46 @@ bundles and 1 on four. What that low field means is ❔.
Nothing here measures a wall-clock duration, and **nothing in this container
can**: the emulator runs on software Vulkan far from real time, so timing an
animation would measure lavapipe, not the game.
## ✅ `+0x0c` is two `u16`s forming an ordered interval
**2026-08-26.** Read as one `u32`, `+0x0c` looks meaningless — 179 distinct
values ranging to 248 581 842. Read as **two big-endian `u16`s** it is highly
structured. The tell is in the raw values: `0x0007000F`, `0x000F001A`,
`0x003C0064` — small numbers in both halves.
Over all **2 985** RATC bundles on the disc:
| | |
|---|---|
| `high < low` | **2 985 / 2 985 (100 %)** |
| `high == low` | 0 |
| `high > low` | 0 |
| `high ≤` animation length `+0x08` | **2 985 / 2 985** |
| `low ≤` animation length `+0x08` | **2 985 / 2 985** |
`high` is 0 in 34.9 % and ranges 03 793; `low` ranges 13 794; the span
`low high` runs 11 200 and clusters on 1, 10, 30, 8, 20. `low` equals the
animation length exactly in 4.0 %.
So the field is **an ordered pair bounded by the animation length, in the same
unit as `+0x08` and the keyframe times** — a time interval. A strict ordering
holding 2 985 times with no exceptions is not a coincidence, and it rules out
the field being flags or a packed count.
🟡 **Which interval is not settled.** A playback range, a loop region and an
active window all fit an ordered pair inside the animation, and nothing measured
here separates them.
❔ **The alternative I have not ruled out** is the obvious one: that
`(high, low)` is simply the **minimum and maximum keyframe time** in the bundle,
which would make it a derived summary rather than an authored range. That is
testable and I did not test it — it needs the keyframe times parsed per bundle,
which the `ui_layout` reader can do. **First step**: for each bundle, compare
`(high, low)` against `(min, max)` of its keyframe times. If they match, the
field is a cached extent; if `high` is often 0 where the first keyframe is not,
it is authored. The 34.9 % of bundles with `high == 0` is suggestive of the
latter but is not evidence on its own.
`+0x10` is untouched by this and remains ❔.