Commit Graph

117 Commits

Author SHA1 Message Date
gamer147
458b65aee6 Reverse shared SAVE.DAT integer opcodes 2026-07-20 13:33:27 -04:00
gamer147
26b6c2137c Reverse opcode 0x1ad save resume boundary 2026-07-20 12:06:02 -04:00
gamer147
0fb608c35e Implement ADV text publication service 2026-07-20 10:18:10 -04:00
gamer147
e0aae05f32 Implement AGE text line spacing 2026-07-19 23:32:38 -04:00
gamer147
b8928ec7b8 Implement History mouse wheel navigation 2026-07-19 21:38:34 -04:00
gamer147
5ba16505d6 Implement History timed callback scrolling 2026-07-19 21:15:15 -04:00
gamer147
8f94ef86ac Implement ADV History voice replay 2026-07-19 14:11:49 -04:00
gamer147
280705d69c Correct ADV History layout addressing 2026-07-19 10:43:52 -04:00
gamer147
ac5437c5cf Implement ADV History data navigation 2026-07-18 23:41:23 -04:00
gamer147
9a6bc38f40 Document ADV History retained-record model 2026-07-18 23:16:50 -04:00
gamer147
56f8adfa2d Correct ADV Hide Window restore behavior 2026-07-18 22:23:06 -04:00
gamer147
d8ead3da6e Implement native ADV Hide Window path 2026-07-18 21:14:06 -04:00
gamer147
6255f42794 Document ADV history and remaining button paths 2026-07-18 20:28:36 -04:00
gamer147
d52e5b4725 Implement native ADV message skip 2026-07-18 17:32:12 -04:00
gamer147
05518a200f Implement ADV controls and native Auto timing 2026-07-18 17:16:06 -04:00
gamer147
96e5306148 Fix retained background lifecycle 2026-07-12 00:00:45 -04:00
gamer147
fb3a7206ce feat: add runtime ADV page locator 2026-07-11 22:52:26 -04:00
gamer147
593a24b510 fix(gfx): restore third CG glow 2026-07-11 20:05:51 -04:00
gamer147
99ce351041 Implement native-backed SC0000 SFX lifecycle 2026-07-11 02:15:17 -04:00
gamer147
34db35903b Implement native ADV retained text 2026-07-10 22:46:27 -04:00
gamer147
8bee45f483 Refresh retained presentation references 2026-07-10 21:56:57 -04:00
gamer147
82afcf5506 Fix native retained presentation batching 2026-07-10 21:37:42 -04:00
gamer147
bb16a5496a feat: add affine rotation rendering and timeline diagnostics 2026-07-10 17:54:33 -04:00
gamer147
014d128ccd fix: align animation pacing and transforms with native 2026-07-10 15:41:17 -04:00
gamer147
d9611a03b1 feat: model ADV coroutines and retained effect teardown 2026-07-10 09:45:43 -04:00
gamer147
5eff724b17 feat: scene-entry state capture -> auto-seed for single-scene runs
capture_global_writes.py hooks vm_operand_write@0x425fb0 (plaintext values,
before the obfuscated store — sidesteps the shelved flat-scan problem) and folds
the engine's global-int writes into a GameSession snapshot. --spawn captures from
boot (packer-aware: polls until the code unpacks, then attaches — AGE.EXE unpacks
in-place so a spawn-time hook hits packed bytes; also kills the spawned pid if
setup fails so no suspended orphan). Age.Cli 'trace ... --state <snap>' runs a
scene from the captured state.

Validated: a real boot->new-game->SC0000 capture (34008 globals incl. G[0x6c1]=1)
seeds the VM to match the engine's ENTIRE opening (542 ops, no non-realignable
fork) with zero manual seeding. Residual: a 2-op color detour (0x202/0x203)
unfixed by state = a real branch diff to chase. Engine 81/81, diff 5/5.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 13:30:14 -04:00
gamer147
453f9b1861 re: diff_optrace resync-tolerant alignment (blind spots vs real forks)
Strict lockstep over-reported: the operand hook misses any op whose operands
aren't fetched via vm_operand_fetch (comment 0x1a7, set-string 0x192, the
0x1c7/0x1cc/0x131/... string-op cluster) — the engine executes them (they sit
after non-branching ops) but they're absent from its trace. New align() resyncs
over such one-sided insertions and reports only NON-realignable forks; it
separates VM-only blind spots (artifacts) from engine-only detours (real,
reconverging branch/state gaps, surfaced honestly). +2 tests (7/7).

Result: with G[0x6c1] seeded the SC0000 opening has NO non-realignable fork
across all 539 VM ops (was: false 'diverge at 0x8d'); residual = a 2-op
engine-only color detour (0x202/0x203 @ 0x122d0). Cold's first real fork is a
later G[0x6c1] gate. Validates the pre-scene-state theory end-to-end.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 12:55:21 -04:00
gamer147
10a5f24c31 re: diff_optrace operand-mode VM filtering (argc>=1 subsequence)
Operand-hook captures skip zero-operand ops (stmt markers, script-entry 0x259),
so the VM offset trace is filtered to argc>=1 instructions before diffing — same
subsequence both sides. +1 unit test. Default on; --full for a tick-mode capture.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 11:57:55 -04:00
gamer147
d032431c73 re(frida): engine op-path tracer (tick/operand hook, per-script offsets)
Reads cur_ctx_index/frame_pc/frame_codebase from the engine ctx per executed op
and emits (codebase, offset=(pc-codebase)/4) to build/engine-optrace.jsonl.
Recon result: the tick hook (0x410fb0) does NOT expose ctx via ecx (0 entries);
the operand hook (0x41b940) is the working capture (100% of offsets land on valid
SC0000 instruction starts). Writes a tracer-live.flag so the capture can be gated
on hooks-installed before the scene loads (else the entry burst is missed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 11:57:55 -04:00
gamer147
0ba965d7e6 re: diff_optrace.py — engine-vs-VM offset-path divergence oracle
Pure first_divergence + pick_scene_codebase (longest-common-prefix codebase
identification), unit-tested (test_diff_optrace.py, 4/4). CLI loads the engine
jsonl + VM json, isolates the scene's codebase, and reports the first divergence
with the mis-modeled instruction and +/-3 ops of context on each side (opcode
+ rendered line via sys4load).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 11:25:20 -04:00
gamer147
4a5d64a679 re: EngineCtx field registry (engine-ctx.toml) + builder
Canonical source vm-map/engine-ctx.toml (35 documented ctx fields) +
engine_ctx_build.py (--build/--lint, unit-tested) -> build/engine-ctx.json
+ docs/engine-ctx-reference.md. Applied to Ghidra in the next task.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 10:01:54 -04:00
gamer147
fa7b48c4da re(frida): write import-map.json (in-table matches; singletons set aside)
248 module-resident core imports at the RVA 0x16f000 rebuilt IAT
(kernel32/user32/gdi32/winmm/advapi32/ole/oleaut/version/ntdll);
29 singletons set aside. Anchors confirmed: ReadFile/CreateFileA/
SetFilePointer + timeGetTime@0x16f3d4 (=DAT_0056f3d4). d3d9/shell32
etc. are heap-resolved (out of dump) — expected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 09:23:25 -04:00
gamer147
c02e348bf3 re(frida): import-map recon — export scan + clustering gate
GATE-PASS: 23342 exports mapped, 277 in-range pointer matches clustering
into a module-resident import table at RVA 0x16f000 (VA 0x56f000);
23 singletons. ~254 real imports vs pe-sieve's 17-in-noise.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 09:21:16 -04:00
gamer147
ace8ddf8eb re: auto-label all opcode dispatch handlers from FUN_00413860
Extract op->real-handler map (handler(op)=ctx[0x26c93+op]) from the
registration routine's override stores; ghidra_handler_map.py +
build/op-handler-map.json (420 overrides). Cross-check vs opcodes.toml
found 0 real drift. One-shot Ghidra pass then labeled the /v2 image:
281 raw FUN_/LAB_ handlers -> op_0xNN_handler, 107 bare VAs -> functions,
31 hand-named preserved, opcode plate comment on every handler.

Includes the Task A spec + plan and the two-program (/v2 vs SMM) gotcha.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 08:32:01 -04:00
gamer147
cdc50b571f docs: frame-stepped-vm spec+plan + frame-cadence Frida probes
Design artifacts for the merged frame-stepped VM work (throttle the Godot VM
to a per-frame op budget). Probes measured the native ~1788 ops/sec cadence
and uncapped D3D9 Present that motivated the wall-clock-op-rate approach.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 17:34:52 -04:00
gamer147
a8f742cf57 feat(tools): per-scene opcode completeness tracker + 0x259 marker fix
Add tools/scene_opcode_coverage.py: histograms a scene's static opcodes and
classifies each vs the C# VM as impl / safe-noop / GAP (effectful op the VM
silently stubs). Implemented set is parsed live from VirtualMachine.cs case arms
(no drift); metadata from build/opcodes.json. Makes a half-rendered scene legible
("N ops still stubbed") instead of implying everything runs.

SC0000 baseline: 129 distinct ops, ~94.8% instruction-weighted handled, 68 GAP.
The tracker cross-checks opcodes.toml vs VM behavior and surfaced 0x259
(script-entry marker) missing its noop_headless flag -> reconciled in opcodes.toml
and rebuilt (regen: age_opcodes_himegari.py, opcode-reference.md).

Docs: tools-reference.md (tool row), phase-a-slice-plan.md (completeness gauge).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 22:57:25 -04:00
gamer147
7c03371519 chore(gfx): set dispatch labels for the gfx command-buffer ops
VM dispatches on the opcodes.toml label field (OpcodeTableJson), so the 14 gfx
ops' labels are set to their dispatch strings. Ops still stubbed until the VM
cases land (Task 3.3+); full suite green (34), lint clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 17:44:32 -04:00
gamer147
e0ac60e668 docs(gfx): reverse the full gfx command-buffer op contract (Phase 1)
Ghidra-read all 13 still-stubbed gfx-family handlers via the dispatch table
(0x1a2/0x1f7/0x1fa/0x1ff/0x202/0x203/0x212/0x213/0x216/0x217/0x218/0x219/0x21a);
recovered 0x219 (was unanalyzed). Every op writes a cmd-type into the current
object record then SETs fields (native worker) or QUERYs fields (returns to
operands). Recorded the op-contract table in engine-re.md, set opcodes.toml
semantics (source=investigation, confidence=high), renamed handlers in Ghidra.

Key finding: the drift has TWO stubbed drivers, not one — 0x215 (slot-select)
AND 0x218/0x21a (per-object geometry vectors feeding the anchor-preserve math).
The subsystem is a per-object record model (slot + position/anchor 3-vectors +
color) queried by the ops; native DirectDraw workers need not be modelled. This
is the spec for Phase 2 (host-side model design).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 17:01:14 -04:00
gamer147
ea4bf99fab docs(gfx): settle render drift as native cmd-buffer op 0x215 (Ghidra), align docs
Read op 0x215's real handler FUN_0042a0b0 (resolved via the dispatch table
ctx[0x26c93+op]; Kelebek's 0x421160 is VA-drift). It writes cmd-type 5 into the
current gfx-object record and returns a std::map::find over an engine-internal
registry populated by sibling gfx ops (0x1a2 hash insert). The return is native
command-buffer state, not the VM global bank -> seeding story-state cannot fix
the drift. Verdict: (b) a genuine native op, NOT (a) state-divergence.

Reconcile the previously contradictory drift accounts onto one canonical home
(engine-re.md op 0x215), with opcodes.toml carrying the opcode-level semantics
and phase-a-slice-plan / tools-reference / frida README corrected to point at it
instead of repeating the disproven state-divergence conclusion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 16:40:59 -04:00
gamer147
14ad23b8c7 Resolve call-script dispatch: id = raw SYS4INI file index
Native-RE (Ghidra) cracked call-script <id> (opcode 0x03): its handler
FUN_0041bc90 -> loader FUN_0040e980 -> resolver FUN_0044f390 indexes an
80-byte record table at base + id*0x50 == the SYS4INI record layout. So
`call-script <id>` is a direct RAW index into the SYS4INI global file
table (the asset index we already parse) -- there is no separate on-disk
id->code registry. This resolves name-resolution.md #1, statically, no
Frida.

Confirmed: all 297 distinct corpus call-script ids resolve to a .BIN
script with a semantically-exact name (0x1ab->ADDITEM, 0x2ae7->MES,
0x143->BUNKI, 0x329d->CALCREVISE), 0 out-of-range, 0 alternate-pack.
Companion op 0x8f `call` is an intra-script JSR (FUN_0041fba0), not
cross-script.

- parse_sys4ini.py: preserve `raw_index` per entry (= the engine file id;
  index the RAW records incl. '@' placeholders) + emit
  build/callscript-names.json (id->name).
- sys4load.py: annotate `call-script 0x1ab =ADDITEM.BIN`.
- opcodes.toml 0x03/0x8f refined (source=investigation, confidence high,
  handler VAs) + rebuilt opcode-reference.md.
- docs: engine-re.md (op 0x03 section + backlog re-aimed),
  name-resolution.md #1 (SOLVED), script-inventory.md (call graph +
  living-reference decision), tools-reference.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 12:44:51 -04:00
gamer147
057a26a97a docs: propagate u00428010/op-0x1a2 correction into opcodes.toml + name-resolution
op 0x1a2 resolve-handle? -> gfx-cmd-register (verified handler FUN_0042d360, gfx
command-buffer op). name-resolution: decision->scene hop is native+unidentified, not
u00428010 (disproven). Regenerated opcode-reference + shim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 11:47:35 -04:00
gamer147
e76fb6b373 feat: --verify execution-driven VM cross-check for SCJUMP decode (Task 4)
Reworked from static-witness-only to execution-driven: ~99% of SCJUMP decisions
are gated by a native computed value (op 0x60), so witness-synthesis alone can't
cover them. Value-local tracking resolves load-then-compare guards to real globals;
native terms honestly marked opaque. Verify: static 3/3 exact + 279/279 execution-
driven consistent over 2000 seeds, 0 failures.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 09:30:10 -04:00
gamer147
a67ebfa263 feat: emit SCJUMP decision table (json+md, registry-named) (Task 3)
build/scjump-decisions.* are generated (build/ gitignored).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 09:20:33 -04:00
gamer147
ad27167c95 feat: SCJUMP guarded-DFS decode -> decision list (Task 2)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 09:18:29 -04:00
gamer147
0b348a87d5 feat: SCJUMP decoder scaffold — CFG acyclic check + chapter dispatch (Task 1)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 09:17:30 -04:00
gamer147
169075fe37 feat: curate story-flags into registry + docs (Task 6)
Bootstrap 56 high-signal skeletons; name game_mode/route_branch/scjump_decision_out2,
recategorize CONFIG-written globals as non-story. Docs: name-resolution.md registry
section, CLAUDE.md canonical+SoT tables + trigger (root, untracked), tools-reference rows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 08:33:51 -04:00
gamer147
f0d7775d15 feat: story_flags --bootstrap seeds skeletons into globals.toml (Task 5)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 08:27:31 -04:00
gamer147
681737604c feat: static story-flag miner -> candidates JSON (Task 4)
Mines 1261 branch-read globals (205 story-flag candidates); build/story-flags-
candidates.json is generated (build/ gitignored). Known anchors 0x3234/0xa57 verified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 08:26:03 -04:00
gamer147
69c788b65a feat: sys4load labels globals from merged build/globals.json (Task 3)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 08:24:36 -04:00
gamer147
84a8da765f feat: globals_build --build merge + generated JSON/MD (Task 2)
build/globals.json is generated (build/ is gitignored, regenerable via
globals_build.py --build); docs/global-reference.md is the tracked human view.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 08:23:17 -04:00