Commit Graph

2 Commits

Author SHA1 Message Date
Sylpheed RE agent
6ce1a87d49 re: rebuild game_data on the IDXD record table — 966 misses and 596 flattened reads
Measured first, over GP_MAIN_GAME_E.pak, comparing every named-field read the
six struct loaders performed against the record table: 4435 reads, 2872 agreed,
**966 returned None for a field that has a value**, **596 flattened a field that
several records carry**, 1 was wrong (a weapon whose TargetType is the empty
string read back as the neighbouring token "Skip"). The prior report of
4453/2887/974/591/1 is the same picture; the small differences are definitional
(I count a read as flattened only when the records disagree).

Every read now goes through IdxdObject::record, and the types say where a value
comes from:

* Weapon = the `Weapon` record (launcher) + the `Shell` record (projectile).
  Both carry an ID and a Name and — with `ShellWake` — an `Interval`, which the
  flat reader merged; they are separate fields now. Power/Velocity/ranges/
  LifeTime are Shell fields, which is why 427 weapon reads used to miss.
* CraftUnit/Vessel = `Generic` (hull) + `Maneuver` (flight model) +
  `StructureCount` (counts) + `Shield`, plus a new `hardpoints: Vec<Hardpoint>`
  — one entry per Turret_/Bridge_/Thruster_/Hatch_/ShieldGenerator_ record, each
  with its own HP. A flat HP could only ever be one of them.
* PlayerConfig = `Player`, plus `phases: Vec<PlayerPhase>` (SpaceSize/SupplyRange
  are per Phase_N) and `score: ByDifficulty<ScoreRules>` (MainMissionBonus is per
  Score_<difficulty>; the flat answer was the Easy one).
* Character faces come from the `Faces` record's field names (identical output to
  the old token scrape, 0 of 68 objects differ — now by construction).
* Stage = `StageResource` + `phases: Vec<StagePhase>`, and the packages it names.
* The `fields: BTreeMap` on every struct became `records: RecordSet`, which keeps
  the record boundary; `RecordSet::everywhere(field)` answers "which record".

The token-scraping loaders move too, and this is where the old reader was worst:

* Arsenal: options are the positional fields of the STANDARD_<slot> records. The
  scrape returned 16 nose options of which 8 were field keys and pilot names, and
  47 for arm3 of which 38 were junk, while missing Mine_B2A and No_Equipment.
  Now 8/12/9/9, all real weapons.
* Squadron: one record per squadron, members are Count*4 positional slots
  (unit, message set, n, pilot) — 1160 squadrons with ids and 2295 member tuples,
  against 28 idless squadrons and 47 members before. Agrees exactly with the
  independent Python decode in docs/re/structures/unit-group-table.md.
* DemoMessage: 11775 lines against 10263, every one with a speaker, a portrait,
  a delivery mode and a voice token, from fixed positional slots.
* PilotRoster: assignments are the records the `UNITS` record names, so each one
  now carries its unit id, its loadout and the player marker.
* UnitRoster: the roster is the field *names* of the single `EnumUnit` record.
* load_weapons selects on the records (Weapon + Shell) rather than on token[0],
  whose first byte is often a stray pool byte ("#Weapon", "%Weapon"). Same 131
  objects, no heuristic. GP_HANGAR_ARSENAL.pak holds none of them — the module
  doc's claim that player weapons live there was wrong.

schema:: constants keep their names and values but are documented for what they
are: record 0's name hash (PLAYER = Difficulty_Easy, UNIT = Maneuver, VESSEL =
Bridge_000, MESSAGE = Message_000), not a schema id.

Two things the migration exposes and does not fix, flagged in the docs instead:
load_units' bucket is 43 Type=Craft + 46 Type=Vessel objects (new `unit_type`
field lets a caller separate them), and StructureCount.TurretCount is not the
number of Turret_* records (the player's craft says 4 and has 63).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-26 01:42:53 +00:00
MechaCat02
2930770060 game_data: Squadron loader — mission flight groups
Decode the per-stage Enumerate_Squadrons tables (UnitGroup_S<NN>.tbl)
into flight groups: formation shape, AI behaviour, side, and the member
craft. Definitions are delimited by the FormationID key; members are the
first `count` UN_ craft after the header (anything past them belongs to
the next squadron or the stage roster — the naive "all UN_ in span"
over-collected). e.g. the player's Rhino flight = a 2-craft TCAF
squadron of Delta Sabers flying Formation_2_Rhino. Schema hash varies
per stage so we match on the table name. Squadron id is positional and
left None when the id list and definitions don't line up (honest, not
guessed). +1 test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 19:54:48 +02:00