Commit Graph

3 Commits

Author SHA1 Message Date
Sylpheed RE agent
074c0296af re: every weapon placed (declared x mounted, 131); a fourth undeclared table
Partitioned all 131 Weapon.ID records against the two data routes by which a
weapon is ever named - a field name in an EnumWeapon record, and a Turret_NNN
record's WeaponID value:

                    mounted   not mounted
  declared            105         22
  not declared          0          4

105 + 22 + 0 + 4 = 131, with no unexplained cell. Both marginals re-derive
unit-substructure-records' own numbers independently: mounted 105, and
22 + 4 = its "26 weapons no turret mounts".

The empty cell is the result: nothing is mounted without being declared, 0 of
131, so declaration is the superset of mounting. The four undeclared and
unmounted records are therefore reachable by neither route. Each appears
exactly once per pak copy (x6) and only as a Weapon record's ID value; the live
control Weapon_TCAF_DeltaSaber_Beam appears x18 as an EnumWeapon field name and
x228 as a Turret_NNN.WeaponID. That places Weapon_TCAF_DeltaSaber_Laser_Ttrl,
the weapon this pass set out to find, and unifies all four as orphan datasheet
rows.

Recorded as powerless rather than as evidence: the image holds 0 exact strings
for the four, but also 0 for the live control and 0 for Weapon_NULL. Only three
Weapon_-prefixed strings exist at all and 0 contain Ttrl - the executable names
no weapon, so the negative does not discriminate.

New: sweeping EnumWeapon RECORDS rather than the three declared tables gives 130
distinct field names, not 127. The extra three come from a fourth record, pak
key 305595319, resolved as EnumWeapon_TestS01.tbl, carrying Weapon_TestS01_Gun/
_Laser/_Missile. It dangles at both ends - no stage declares it, and its three
weapons are the only declared names with no Weapon.ID record. 130 - 3 = 127
restores the previous pass's union.

All fifteen artefacts byte-identical.
2026-08-28 04:50:35 +00:00
Sylpheed RE agent
ad03991fa1 re: EnumWeapon_EX5.tbl adds exactly one weapon; a tutorial expectation refuted
Diffed S28's bespoke weapon table against the common one. The disc has exactly
three weapon tables, and each is a single EnumWeapon record whose FIELD NAMES
are the weapons - the Enumerate-style declaration shape again:

  EnumWeapon_Test.tbl       126 names
  EnumWeapon_EX5.tbl        127 names = the same 126, same order, plus one
  EnumWeapon_Tutorial.tbl     9 names = a strict subset of Test
  union                     127

The whole of S28's bespoke table is one extra weapon,
Weapon_TCAF_Ship_AAGun_EX5. Zero removals, identical order on the shared 126.

That explains one of weapon-struct-runtime's five "never instantiated" disc
records: the AA-gun variant is declared by EnumWeapon_EX5.tbl only, and that
table belongs to S28 alone, which the captured save was not playing.

It also refutes that document's expectation that "running the tutorial should
instantiate the _Ttrl pair". It will not: EnumWeapon_Tutorial.tbl's nine names
are Weapon_NULL, Weapon_ADAN_Puppy_NoseGun, Weapon_DSaber_P_wep_{01_Beam,
02_Missile,58_Laser} and Weapon_TCAF_DeltaSaber_{Beam,Cannon,Missile,
ASMissile} - neither _Ttrl weapon is among them. Four of the five
uninstantiated records are declared by no weapon table on the disc at all.

EX is still not identified but narrowed hard: the entire content of S28's own
weapon table is a single _EX5 AA-gun variant, and the only other _EX5 name on
the disc is UN_f001_TCAF_DeltaSaber_T_EX5.

All fifteen artefacts byte-identical.
2026-08-28 04:17:15 +00:00
9daac6f1f0 re: read the defaulted weapon stats out of live guest memory
Canary backs the whole guest address space with one shared-memory file, so the
game's RAM is readable from the host while it runs -- no debugger, no emulator
patch. That turns the parked Route-B question (fields the IDXD omits because
they sit at their default) from "unreachable" into a table lookup.

gmem.py maps guest VAs into /dev/shm/xenia_memory_* via Xenia's fixed table and
searches only the allocated extents, so a full-RAM scan is ~0.2 s.

weapon_runtime.py finds the parsed objects by scanning for their vtable, then
*solves* the struct layout instead of guessing it: every (field, offset,
encoding) triple is scored against the disc records, and a binding is accepted
only with zero contradictions -- and marked confirmed only when >=10 records
agree on >=3 distinct values, because a field whose samples are all one number
matches any offset holding that constant.

Result: Weapon (0xc0) and Shell (0x200) mapped, 4393 values the disc does not
carry, for all 126 weapons at 5 % save progress. Cross-checks hold -- the
Arsenal DATA SHEET read 4 for wep_05/wep_60 Max. Lock Ons and the memory read
agrees; the in-flight HUD's 06000/00300 match LoadingCount; all 252 objects are
byte-identical across a screen change, so this is definition data, not state.

Two findings fell out: `IsCharging = Yes` switches LoadingCount and
TriggerShotCount to float32 (it partitions the 8 float-encoded records exactly),
and two .tbl entries declare Shell_TCAF_Ship_AAGun with conflicting Power -- the
runtime keeps the one that omits it.

Where the defaulted values *come from* (the IDXD's undecoded binary node region
vs code defaults) is not settled here; they vary per weapon, so they are not one
constructor constant.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 05:29:34 +00:00