Files
Drew T 1431b523a4 feat(phase-17): T4+T5 — actor struct recovered (comprehension) but byte-neutral for matching
- recovered the engine actor/player struct cold via PCSX-Redux (R10/R11): base 0x80078E00,
  ~154 fields over 0x24C bytes, 32 pointer fields; HP/BP/gold/day/hour/position/BP-drain all
  live-verified and anchored to the Phase-3 player state + the walk diff. -> docs/actor-struct.md
- tools/ram_probe.py: PCSX-Redux RAM capture/diff/read/ptr-scan workhorse for field-typing
- FINDING (the matching verdict): feeding the struct to m2c as --context is BYTE-NEUTRAL.
  m2c adopts it (arg0->f_X) but structural-miss sample scores 0 better / 10 same / 2 worse vs
  m2c-alone (full code+RAM pointer set). The misses are 50-98% mismatched = m2c decompiler
  limits, not missing types. T4 fn-ptr context unblocks compilation but functions stay structural.
- conclusion: rich context (struct/type recovery) is a comprehension / decomp.me win, NOT a
  byte-match lever -> Phase-16 wall re-confirmed from the type angle. struct-core-pivot.md updated.
- emulator field-naming pass deferred (comprehension, off the matching path); NEXT: T6 permuter
  validation on the 146 genuine near-misses, then T7 go/no-go.
2026-06-19 13:03:14 -06:00

3.1 KiB
Raw Permalink Blame History

Actor / Player struct — recovered layout + the byte-neutral finding (Phase 17 / T4-T5)

Base: 0x80078E00 (the player instance). ~154 fields over 0x24C bytes. This is the engine's central entity record — arg0 to 550/941 of the struct-heavy residual functions. Recovered by (a) static inference from the union of m2c M2C_FIELD(arg0, T, off) accesses across all drafts, (b) a live PCSX-Redux RAM pass (R10/R11), anchored to the Phase-3 player-state fields.

⚠ Key finding (the matching verdict)

Feeding this struct to m2c as --context is BYTE-NEUTRAL for the structural-miss bucket. Measured: on a 12-function structural-miss sample, m2c-with-struct vs m2c-alone → 0 better / 10 same / 2 worse (even with the full code-inferred + RAM pointer set, 32 pointers). arg0->f_X and M2C_FIELD(arg0, T*, X) emit identical bytes; the structural misses (50–98% instruction mismatch) are m2c decompiler limits, not missing types — so the struct does not crack them, and neither will the permuter at that mismatch magnitude. This confirms the Phase-17 deep-research caveat: type recovery is comprehension, not a blanket match-% lever. The struct is kept as a Gen2 quality artifact + decomp.me enabler, not a build input.

Confirmed fields (live-verified, R10)

offset type meaning evidence
+0x08C s32 gold =126 (Phase-3 anchor)
+0x0AC u8 day =2
+0x0B1 u8 hour =22
+0x0B2 u16 hp_max =150
+0x0B4 u16 hp_cur =150 (the plan's "+0xB4"; Phase-3 0x80078EB4)
+0x0B6 u16 bp_max =150
+0x0B8 u16 bp_cur (stamina) 74→50 as the player walked (BP-drain)
+0x108 s16 position X +6 on a walk north
+0x10C s16 position Z +10 on a walk north
+0xF0 s16 step/heading counter +1 per walk tick

Pointer fields (the m2c-can't-infer set; idle RAM scan + code-inferred)

RAM-observed: +0x54 → 0x8017E75C, +0x58 → 0x8017E720, +0x68 → 0x8017E91C (overlay code — likely behavior/handler function pointers), +0x6C/+0x70 → 0x800D1E20 (resident), +0x5C → 0x8010F5C8. Plus ~26 more offsets m2c dereferences as pointers in code (e.g. +0x08, +0x4C, +0x50). Full set in .run/actor_fields.json.

Reproduce

  • Static layout: aggregate M2C_FIELD(arg0, T*, off) over .run/wt_drafts/*.c (regen via the harvest).
  • Live typing: tools/ram_probe.py against PCSX-Redux (host in .run/ram/HOST.txt); snapshot/diff across controlled actions (walk/jump/swing/charge/damage) to type + name fields (R10 multi-datapoint).
  • The validation (struct byte-neutral): m2c-with-.run/actor_ctx2.c → match_one vs m2c-alone.

Deferred (comprehension, not the matching critical path)

Full field-naming via the emulator scenario list (jump=air-state/y-vel; swing=action-state+weapon-id; charge=charge-level; damage=hp/hurt-state; the +0x14/+0x15 dispatch-state per memory-map; the flashing-HUD "interactable nearby" Bincho flag). Resume when comprehension/decomp.me work is prioritized — it does not move the byte-match needle (proven above).