docs: map IDXD reflective framework; defaulted-field routes
Route-A investigation of the defaulted-field hunt: mapped the generic IDXD reflective serializer (IdxdLoad_Dispatch/Idxd_Parse/ Reflect_FindFieldIndex/Reflect_SetField + g_FieldNameRegistry) and the global name-vector. Established that Idxd_Parse only writes fields present in the pool; defaults come from each type's constructor via the reflection registry. Quantified the gap (534 craft: 30-70% of core stats defaulted) and documented the two finish routes (static constructor reversal vs. runtime registry dump). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,29 @@ strongly inferred from disassembly, **L** = tentative.
|
|||||||
| `0x82458508` | `Archive_StreamReadCrc32` | M | Streaming block reader that validates content with a reflected CRC-32 (init `0xFFFFFFFF`, final `~`, table at `g_Crc32Table`). Compares the computed CRC to a stored expected value (`state+144`). This is a **content-integrity** CRC, *not* the name-hash. |
|
| `0x82458508` | `Archive_StreamReadCrc32` | M | Streaming block reader that validates content with a reflected CRC-32 (init `0xFFFFFFFF`, final `~`, table at `g_Crc32Table`). Compares the computed CRC to a stored expected value (`state+144`). This is a **content-integrity** CRC, *not* the name-hash. |
|
||||||
| `0x828992F0` | `g_Crc32Table` (data) | H | 256-entry reflected CRC-32 lookup table. Referenced only by `Archive_StreamReadCrc32` and its sibling loop at `0x82457AF8`. |
|
| `0x828992F0` | `g_Crc32Table` (data) | H | 256-entry reflected CRC-32 lookup table. Referenced only by `Archive_StreamReadCrc32` and its sibling loop at `0x82457AF8`. |
|
||||||
|
|
||||||
|
## IDXD reflective serialization framework
|
||||||
|
|
||||||
|
Generic tagged-object (de)serializer shared by ~15 object families (craft,
|
||||||
|
weapon, message/character, effects, …). The `.pak` IDXD payloads are read
|
||||||
|
through this.
|
||||||
|
|
||||||
|
| Address | Name | Conf | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `0x824486C0` | `IdxdLoad_Dispatch` | M | Entry: reads the magic and dispatches across variants `IDXD` (`0x49445844`), `IDX2`, `IDX3`, `IDXC`, `IXUD` → the matching parser. **15 callers** (one per object family). The target object is passed in `r3` — already constructed (defaults set) by the caller. |
|
||||||
|
| `0x82448D00` | `IdxdLoad_Variant2` | M | Sibling variant loader (also materializes the `IDXD` magic). |
|
||||||
|
| `0x82449640` | `Idxd_Parse` | M | The IDXD body parser: skips a BOM, then loops the string pool — per field, reads the name token, `Reflect_FindFieldIndex`, then dispatches on the **value's first char** (jump table at `0x824497F8`, index `firstchar - 0x22`) to type-specific writers. Only fields **present** in the pool are written. |
|
||||||
|
| `0x8244A2F0` | `Reflect_FindFieldIndex` | M | Look up a field-name string in a global name-vector at `0x820B4F18` (std::vector-like: count `+20`, data `+24`/SSO), via a `strncmp`-style compare (`0x825EDCE0`). Returns index or `-1`. |
|
||||||
|
| `0x8244A4B0` | `Reflect_SetField` | L | Apply a value to `object` using its per-instance property registry at `object+64` and a config string at `0x820B4F28`. |
|
||||||
|
| `0x820B4F18` | `g_FieldNameRegistry` (data) | L | Global reflection name-vector (runtime-built) used by `Reflect_FindFieldIndex`. |
|
||||||
|
|
||||||
|
**Defaulted fields:** a field is written to the IDXD pool only when it differs
|
||||||
|
from its default, so `Idxd_Parse` never sets defaulted fields — their values are
|
||||||
|
established by each **type's constructor** (in the 15 `IdxdLoad_Dispatch`
|
||||||
|
callers) before load, via this same registry. Recovering them statically means
|
||||||
|
reversing those constructors and joining `field-name → struct-offset →
|
||||||
|
default-store`; a runtime dump of a loaded object's registry gives
|
||||||
|
`name → value` directly. (Open — see below.)
|
||||||
|
|
||||||
## 3D resource subsystem
|
## 3D resource subsystem
|
||||||
|
|
||||||
| Address | Name | Conf | Description |
|
| Address | Name | Conf | Description |
|
||||||
@@ -76,8 +99,23 @@ extraction limit.
|
|||||||
|
|
||||||
## Open threads
|
## Open threads
|
||||||
|
|
||||||
- **Defaulted IDXD fields** (`*Ratio`, the `*Count` family) carry no value on
|
- **Defaulted IDXD fields.** A field is omitted from the pool exactly when it
|
||||||
disc. The large 16-byte-record binary node table inside a craft IDXD is
|
equals the schema default, so present values are all *overrides* and the
|
||||||
**spatial/mesh data**, not defaults (ruled out: it is not keyed by
|
defaults cannot be inferred from them. Gap is large: across the 534 craft
|
||||||
`name_hash(field_key)`). Defaults must live in per-`schema_hash`
|
(`schema 0x43FAA517`) entries, explicit-presence is `Acceleration` 42%,
|
||||||
schema-definition tables (e.g. craft schema `0x43FAA517`) — location TBD.
|
`MaximumVelocity` 51%, `Turn_AngularVelocity` 31%, `FCSRange` 34%,
|
||||||
|
`ShieldRatio` 49% (`Size_X` 100%, `HP` 85%). So 40–70% of craft rely on
|
||||||
|
unknown defaults for core flight/defense stats.
|
||||||
|
- Ruled out: the big 16-byte-record binary node table inside a craft IDXD is
|
||||||
|
**spatial/mesh data**, not defaults (not keyed by `name_hash(field_key)`).
|
||||||
|
- `schema_hash` is **not** a code immediate and **not** `name_hash(typename)`.
|
||||||
|
- Defaults are set by each type's **constructor** (one per `IdxdLoad_Dispatch`
|
||||||
|
caller) via the reflection registry, not by `Idxd_Parse`.
|
||||||
|
- **Two finish routes.** (A, static) reverse the craft constructor: read its
|
||||||
|
field registrations (`name → offset`) and default-init stores
|
||||||
|
(`offset → value`), join them — heavy, and offset↔name correlation is
|
||||||
|
error-prone. (B, runtime) dump a loaded craft object's registry
|
||||||
|
(`obj+64`) / struct from xenia-rs or Canary — a fully-loaded craft already
|
||||||
|
holds every default; one dump yields `name → value`. **B is the efficient
|
||||||
|
finish** given the framework is generic; A's framework map above is the
|
||||||
|
prerequisite either way.
|
||||||
|
|||||||
@@ -11,3 +11,10 @@ UPDATE functions SET name = 'Str_ToLowerAscii' WHERE address = 2187284368
|
|||||||
UPDATE functions SET name = 'Pak_IsIPFBHeader' WHERE address = 2185627568; -- 0x824607B0
|
UPDATE functions SET name = 'Pak_IsIPFBHeader' WHERE address = 2185627568; -- 0x824607B0
|
||||||
UPDATE functions SET name = 'Archive_StreamReadCrc32' WHERE address = 2185594120; -- 0x82458508
|
UPDATE functions SET name = 'Archive_StreamReadCrc32' WHERE address = 2185594120; -- 0x82458508
|
||||||
UPDATE functions SET name = 'Res3D_LoadMeshChunk' WHERE address = 2187592336; -- 0x82640290
|
UPDATE functions SET name = 'Res3D_LoadMeshChunk' WHERE address = 2187592336; -- 0x82640290
|
||||||
|
|
||||||
|
-- IDXD reflective serialization framework (defaulted-field hunt, 2026-07-09)
|
||||||
|
UPDATE functions SET name = 'IdxdLoad_Dispatch' WHERE address = 2185529024; -- 0x824486C0 (magic dispatch IDXD/IDX2/IDX3/IDXC/IXUD; 15 callers)
|
||||||
|
UPDATE functions SET name = 'IdxdLoad_Variant2' WHERE address = 2185530624; -- 0x82448D00 (sibling variant loader)
|
||||||
|
UPDATE functions SET name = 'Idxd_Parse' WHERE address = 2185532992; -- 0x82449640 (tokenize pool; per-field lookup+set)
|
||||||
|
UPDATE functions SET name = 'Reflect_FindFieldIndex' WHERE address = 2185536240; -- 0x8244A2F0 (field-name -> index in name-vector @0x820B4F18)
|
||||||
|
UPDATE functions SET name = 'Reflect_SetField' WHERE address = 2185536688; -- 0x8244A4B0 (apply value via object registry @obj+64)
|
||||||
|
|||||||
Reference in New Issue
Block a user