Commit Graph

407 Commits

Author SHA1 Message Date
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
992215cc48 Implement native 0x202 color interpolation 2026-07-10 20:49:28 -04:00
gamer147
7f900c8fc6 Implement ADV foreground transition lifecycle 2026-07-10 18:49:53 -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
29b2dfca27 docs: mark matrix composition provisional 2026-07-10 10:57:02 -04:00
gamer147
c14c7fdced feat: split native scale and translation channels 2026-07-10 10:28:11 -04:00
gamer147
e899d06fd8 docs: archive EngineCtx design and implementation plan 2026-07-10 09:45:52 -04:00
gamer147
d9611a03b1 feat: model ADV coroutines and retained effect teardown 2026-07-10 09:45:43 -04:00
gamer147
54bd9a7006 docs: scene-entry state snapshot (capture_global_writes + --state)
engine-re.md: the write-log method, plaintext-value insight (store is obfuscated),
vm_operand_write ABI, the packer poll-until-unpacked fix, and the validation
(34k-global capture seeds the VM to match the engine's whole opening). Plus the
resync-tolerant align() / operand-hook blind-spot notes. tools-reference: the new
tool + trace --state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 13:32:52 -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
9aca1b733d feat(engine): 0xADDR=VAL seeds for trace --trace-json
Lets the differential oracle inject pre-scene state the cold --boot misses
(e.g. 0x6c1=1, the ADV-chrome enable). Seed test: seeding G[0x6c1]=1 pushes
SC0000 VM-vs-engine agreement 27 -> 65 ops; residual mismatches are operand-hook
blind spots (comment/set-string read inline args, not via vm_operand_fetch),
provably not control-flow forks. Observe-only; parity unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 12:45:08 -04:00
gamer147
d2e9cc5a99 re: record differential oracle outcome + first divergence
engine-re.md: the offset-path diff method, the working capture (operand hook
0x41b940; tick 0x410fb0 sees ecx!=ctx), the two capture caveats (hook-before-load
gating + operand-mode argc>=1 filter), SC0000 codebase id, and the first
divergence found (op 0xa0 jcc @ 0x8d on uninitialized G[0x6c1], the ADV-chrome
enable — a two-boot-gap state hole, not the predicted coroutine yield).
tools-reference.md: trace_engine_ops.py, diff_optrace.py, --trace-json.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 12:00:12 -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
06231b9459 feat(engine): --trace-json emitter for the differential oracle
JsonOffsetTraceSink records every executed instruction offset (bytecode word
index) of one target script, in order, filtered to the scene's own frame
(call-script subroutines excluded) to match the Frida engine tracer's
per-codebase filter. Wired as 'trace <SCENE.BIN> [--boot] --trace-json <out>'.
Observe-only; sweep path and trace parity untouched. +2 xUnit tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 11:20:23 -04:00
gamer147
43249f430b plan: differential VM-vs-engine oracle (lever #3, spec + plan)
Control-flow offset-path diff: Frida engine op-tracer (recon-gated
tick/0x41b940 hook) + VM ITraceSink offsets + diff_optrace.py first-
divergence report. Deterministic opening (SC0000 --boot). Ready to
execute in a fresh context; prereq = game running at the opening.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 11:06:31 -04:00
gamer147
5cd5abb00a re: hot-helper naming (lever #2, pivoted from STL/CRT auto-naming)
Function ID recon = WEAK (0 matches; bundled FidDbs don't cover the VC9
static runtime) and our library workers are already named. Pivoted to
naming the hottest documented-but-unnamed helpers by call-count: named 5
(~2400 call sites) in Ghidra — vm_operand_fetch@0x41b940 (1021 refs),
vm_operand_write@0x425fb0, vm_operand_lvalue@0x415f30,
__security_check_cookie@0x54f981 (692), operator_new@0x5502be (533).
Validated: gfx_op_0x215 reads near source-level. Spec/plan + engine-re.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 10:38:29 -04:00
gamer147
1b151f6e17 re: apply EngineCtx struct to /v2 handlers; doc + canonical-map wiring
Created the EngineCtx Ghidra struct (35 fields, 0xa1000) and retyped all
419 dispatch handlers' this -> EngineCtx* (CUSTOM_STORAGE, ctx in ECX).
Handlers now decompile ctx->cur_ctx_index / ctx->run_state_flags etc.
Validated: sleep_op_0xc8, gfx_op_0x215. tools-reference + engine-re.md
wired; CLAUDE.md canonical-map updated (root, outside repo).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 10:08:06 -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
e166cab2d5 re(frida): import-map applied to /v2 — 248 Win32 APIs named; validated
Labeled the module-resident IAT at RVA 0x16f000 (imp_<dll>_<func> x248,
0 clobbers). Validated in decomp: FUN_0044f390 -> imp_kernel32_CreateFileA
/ SetFilePointer; sleep_timer_arm -> imp_winmm_timeGetTime (pins
DAT_0056f3d4). d3d9/heap-resolved DLLs unlabeled by design.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 09:26:19 -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
7f8da4be71 plan: frida import-map slice (spec + implementation plan)
Replaces the abandoned pe-sieve Task B: attach + scan the live process to
map resolved import pointers (RVA->dll!Func) and label /v2. Recon-first
hard gate; clean labels; read-only Frida.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 09:19:36 -04:00
gamer147
23f518f39b re: document pe-sieve IAT failure on packed AGE.EXE; queue Frida import-map
pe-sieve /imp on the running game gave ~17 genuine imports (packer
bootstrap + one-per-DLL seed) and 300+ spurious stray-DWORD guesses:
the exe ships a zeroed IAT resolved via GetProcAddress, so there is no
conventional IAT to rebuild. Do not graft the output. Task B re-scoped
to a Frida live import-map (runtime_addr->dll!Func, RVA->name, label the
/v2 image); design captured in engine-re.md runbook.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 08:54:08 -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
51f6a421dc docs(re): scene-coroutine framework RE head-start (0x7b/0x7c/0x140 + gate) + magic-circle-stuck note
Head-start for the next slice: the fix for the slot-0 collapse is running label_125bd
via the scene-coroutine framework. 0x7b=yield-save, 0x7c=resume, 0x140=LABEL (target
TBD), G[0xaba5c] gate. Plus the revealed magic-circle-persists-across-transition issue.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 00:04:40 -04:00
gamer147
ac481b4002 diag+docs: confirm grey-BG root cause = unfilled slot-table (label_125bd via stubbed coroutine op 0x140)
Traced end-to-end (AGE_DIAG_SETTEX): set-texture slot=G[0x62452] <- query-gfx-object?
(-1 for unregistered CG handles) -> fallback lookup-array-2d(rec[s3]=G[0x3239])=0
because the slot table is never filled: label_125bd (SC0000 0x50f, slots 4..13) is
gated behind the scene-coroutine framework (0x140 coroutine-yield, stubbed). Adds
env-gated VM set-texture/query slot diagnostics + GfxState.IsRegistered.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 23:55:50 -04:00
gamer147
9dd96bbc84 docs: grey-BG root cause (color-op alpha=tint-strength; slot-0 collision) + --gfx-log tool
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 23:42:20 -04:00
gamer147
89d3341288 feat(godot): tint-strength lerp blend + --gfx-log compositor/op diagnostic
Compositor applies TintStrength as a texel->tint LERP (0=keep texel) with object
opacity independent. New --gfx-log <file>: per-frame per-object draw/skip CHANGE
log + set-texture/create-texture slot trace — the tool that root-caused the grey
background (everything collapsing into slot 0).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 23:41:03 -04:00
gamer147
c0b6199dbc fix: color-op alpha (0x202/0x203/0x232) is TINT STRENGTH, not object opacity
Root cause (evidence: gfx-log) of the opening-CG grey background: a CG drawn with
(alpha=0, color=white) means 'no tint' = fully opaque, but slice-A conflated the
color alpha with object opacity -> the CG rendered transparent. RenderObject now
carries TintStrength separately from Alpha (opacity); resolution keeps textured
objects opaque. Tests updated to the evidence-based semantics.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 23:41:03 -04:00
gamer147
620ffb4fb7 docs: record SC0000 anim cluster coverage (opcodes + slice plan)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 22:13:56 -04:00
gamer147
165a9f616c feat(godot): drive the anim interpolator off FrameClock (paced spritesheet+glow)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 22:09:02 -04:00
gamer147
a014b90189 feat: wire SC0000 anim cluster ops (0x22f/0x229 pos, 0x239/0x231 sheet, 0x232 glow, 0x228/0x23f query)
Coverage 67->74/129; parity held (79/79, sweep 284/13).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 22:07:51 -04:00
gamer147
b9ca284f90 feat: port anim interpolator (ping-pong spritesheet cell + color glow) on nowMs
BlendMath.PingPong + SnapshotVisibleObjects(nowMs); no-arg overload keeps
headless callers deterministic (parity held, 76/76 + sweep 284/13).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 22:05:00 -04:00
gamer147
7ca51bfdf3 feat: add src-rect (spritesheet) + animated-color channel fields/mutators
Adapted to Task-1 RE: position is a direct V24 set (not ping-pong); the
oscillating channels are src-rect scroll (0x231/0x239) and color glow (0x232).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 22:02:46 -04:00
gamer147
130eadee3d docs(re): SC0000 anim cluster op->field map (in-scope setters/queries + deferred)
Reversed via dispatch table: 0x22f/0x229 position, 0x239/0x231 spritesheet,
0x232 animated-color glow, 0x228/0x23f queries. Deferred 0x21f/0x223 matrix/scale
+ 0x236 movie. Ghidra renamed+annotated+saved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 21:58:55 -04:00
gamer147
a6377c6a60 docs(plan): SC0000 anim/transform/spritesheet cluster implementation plan
TDD plan: RE workers (known dispatch addresses) -> channel model -> ported
ping-pong interpolator on FrameClock -> wire setter ops -> host apply. Fixes
motion + spritesheet-cell + 'mach 5' pacing. Rotation/scale gated on Task 1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 21:25:07 -04:00
gamer147
4589b98be5 docs(spec): SC0000 anim/transform/spritesheet cluster design
One-unit scope for the gfx animation cluster (0x1fd, 0x21c-0x243): channel
model + faithful gfx_object_anim_interpolate port on FrameClock (fixes 'mach 5')
+ spritesheet cell selection. Grounded in the recovered dispatch table
(handler(op)=ctx[0x26c93+op]; Kelebek labels are drift) + the reversed
interpolator. Bounded RE Task-0 with known handler addresses.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 21:06:05 -04:00
gamer147
f33c824981 Merge feat/blend-transparency: colorkey + per-object alpha/tint blend (graphics slice A)
Fixes the SC0000 opening's opaque grey-wall: layers now alpha-blend and honor
per-surface colorkey. Hybrid arch (engine resolves RenderObject blend plan,
Godot host blits). Deferred: smooth color-anim interpolation + additive/glow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 19:13:18 -04:00
gamer147
689d3ef433 docs: record blend/transparency slice A (colorkey + alpha/tint + fade fill)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 19:10:31 -04:00
gamer147
ce6be0ee9a feat(godot): surfaceless color-fill quads for AE* fades (opening no longer opaque-grey)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 19:09:18 -04:00
gamer147
6992f303f6 feat(godot): colorkey bake + per-object alpha/tint blit
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 19:07:48 -04:00
gamer147
143fe8258c feat: resolve per-object alpha/tint/blend into RenderObject (colorkey retained)
0x202/0x203 now route through GfxState.SetObjectColor (sets HasColor);
SnapshotVisibleObjects resolves Alpha/Tint/BlendKind. Drops the stale
'alpha deferred' trace stub — alpha/tint is now consumed by the compositor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 19:06:34 -04:00
gamer147
4ee7a26e3f feat: add BlendMath (colorkey match + ARGB unpack)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 19:04:12 -04:00
gamer147
34cdfeda0e docs(re): interpolation RE pass stalled — anim-interp is ping-pong on frame clock; 0x202 consumer unlocated
Confirms both slice-A deferrals (smooth color-anim interp + additive). Ghidra
gfx_object_anim_interpolate annotated+saved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 18:48:50 -04:00