Commit Graph

99 Commits

Author SHA1 Message Date
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
7591336ad5 Rename Godot app to Open Maid Engine 2026-07-11 22:21:50 -04:00
gamer147
5275ec5f4f Restore ADV wait indicator 2026-07-11 21:12:24 -04:00
gamer147
0cb72e0d5e Cache compositor source pixels 2026-07-11 14:37:35 -04:00
gamer147
3bee46611a Batch compositor backbuffer updates 2026-07-11 14:28:53 -04:00
gamer147
3b5dbc6c2c Optimize static wait presentation 2026-07-11 13:56:30 -04:00
gamer147
54d11f513d Fix ADV chrome one-shot blending 2026-07-11 13:28:31 -04:00
gamer147
78174df03a Fix movie compositor publication 2026-07-11 12:41:37 -04:00
gamer147
024accd8d1 Implement SC0000 movie playback lifecycle 2026-07-11 12:27:51 -04:00
gamer147
233f791c10 Migrate audio payloads onto asset VFS 2026-07-11 11:01:11 -04:00
gamer147
a1f6d0ab51 Decode AGF textures through the asset store 2026-07-11 09:55:58 -04:00
gamer147
b6c3b1660d Implement base SYS4 asset store 2026-07-11 09:14:14 -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
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
c14c7fdced feat: split native scale and translation channels 2026-07-10 10:28:11 -04:00
gamer147
d9611a03b1 feat: model ADV coroutines and retained effect teardown 2026-07-10 09:45:43 -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
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
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
dfaad2e95a feat: throttle Godot VM to a per-frame op budget on FrameClock (fixes opening speed-through)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 17:32:29 -04:00
gamer147
1f9bde3739 docs+godot: finish frame-cadence RE notes + headless shot null-guard
Prior-session WIP: RE findings on the engine frame cadence (engine-re.md,
phase-a-slice-plan.md, tools-reference.md) and a null-guard so headless
--shot-sequence advances without a rendered viewport texture.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 17:26:27 -04:00
gamer147
9ccfc43959 feat(diag): aggregating + filtered trace sinks (histogram, op-filter, per-script)
The existing trace framework only had a flat text formatter, so every question
became 'dump millions of lines, then grep'. This session that cost a long wrong
detour. Add, all observe-only (parity preserved):

- HistogramTraceSink: execution counts per opcode AND per call-site (script:pc)
  with a sample operand. Dumped sorted after the run. This is what instantly
  showed the 493k headless 'sleep's are INPUTNAME.BIN:0x1c3 (a name-entry poll
  loop), not the opening.
- TraceSinkBase: tracks the frame stack -> attributes each step to its REAL
  script (nested call-script frames included) = the 'which script is this pc in?'
  answer a bare step trace can't give.
- TextTraceSink: op-filter (--trace-ops sleep,draw-texture,...) + script:pc tags.
- CompositeTraceSink: fan-out (text + histogram + Godot's call-script queue).
- OpcodeTable.ByLabel: mnemonic -> opcode for --trace-ops.
- CLI: --trace-histogram, --trace-ops, robust --trace-file (mkdir -p).
- Godot: --trace-histogram <file> profiles the REAL run (headless flow diverges:
  real run to page 1 is 562 steps / 0 sleeps vs headless 2M steps / 493k sleeps).
- Also: --sleep-scale <f> debug knob to slow the paced opening for inspection.

Engine 56/56 (4 new); sweep parity 284/13; Godot builds + dogfooded end-to-end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 09:50:07 -04:00
gamer147
2ed5eed261 feat(godot): --shot-sequence per-frame capture for verifying paced animation
Dumps one PNG per _Process frame (auto-advancing past input waits), so a
time-based sleep-paced effect can be verified as distinct frames. Confirmed
the SC0000 opening now steps through paced AE*/character/CG frames instead of
jumping straight to the final state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 09:07:22 -04:00
gamer147
0d666523c7 feat(godot): Sleep blocks the VM thread so the compositor presents paced frames
op 0xc8 -> Thread.Sleep(duration ms) on the VM background thread (capped 10s);
main thread keeps compositing -> the sleep-paced opening burst gets frames to show.
Unit = ms (RE-confirmed). Selftest OK (plumbing parity; synthetic scene has no sleep).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 09:02:01 -04:00
gamer147
08b5dbdbb6 feat(gfx): Godot per-object alpha tween + alpha-aware blit + --shot-settle
Retained-object animation channel wired into the compositor: wall-clock tween of
the anim channel over the GLOBAL clock (0x238), opacity from the 3rd vec component,
applied via an alpha-aware BlitLayer. Non-regressing (SC0000 opening page 2 pixel-
identical at settle 3 and 300; selftest OK). Added --shot-settle <frames> to capture
mid-tween.

NOTE: this drives RETAINED-object animations; the opening AE* explosion (AE001D/
AE002B/AE003B) is an immediate-mode slot-0 frame sequence paced by sleep/the render
loop, which our instant execution burst collapses -> needs frame-pacing (scene-
coroutine backlog), not this per-object channel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:48:23 -04:00
gamer147
0458d8e5f2 feat(gfx): Godot per-frame compositor on the surface/object model + restore --boot
Main._Process composites visible objects in ascending-handle order from their live
surface (resId->BMP); GodotAdvHost.DrawTexture no-op'd (retained), ResolveResIdTexture
added. Restored the --boot system-boot handling that the revert had dropped (Main.cs
was running cold, which is why nothing matched the oracle). Verified: booted opening
event CG renders correctly. Selftest green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 20:38:07 -04:00
gamer147
ad5fa85d82 chore(godot): track GodotTraceSink.cs.uid (Godot import artifact)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 15:27:51 -04:00
gamer147
d202990b7b refactor(godot): report subroutines via GodotTraceSink, not the IHost queue
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 15:23:25 -04:00
gamer147
7f92a35966 Add subroutine-execution diagnostics + Godot --scene
- CLI run: report call-script dispatch count + distinct source scripts per run.
- Godot --scene <NAME>: play any scene (not just SC0000).
- Godot reports the call-scripts executed as nested frames at scene end (collected
  thread-safely; Godot drops GD.Print from the VM background thread).

Demonstrated live: SC0240 in Godot executes 29 call-scripts (RESETLAND, SETEN,
ADDEN, RENDERMAP, SETOBJ, DRAWOBJ, CALCREVISE, LOOK) as nested subroutine frames.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 14:10:55 -04:00
gamer147
8031f8e33a Wire provider into Godot (play + selftest); honest full-handling selftest
- Play path: VM now gets Sys4ScriptProvider, so call-script executes live on screen
  (subroutines run; input-wait loops break on real player input).
- Selftest: was 'run SC0000 stubbed, match vm0-trace (186)'. Now runs a SYNTHESIZED
  scene (show-text + wait-for-input + real nested call-script) through the Godot
  thread/semaphore/CallDeferred plumbing and asserts it matches a headless run of the
  same scene — full handling, expected computed live, no frozen golden, no vm0 dep.
- Verified: godot --headless -- --selftest => 'threaded host matches headless (3 lines)'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 13:48:47 -04:00
gamer147
34dfa2f747 feat(godot): --seed 0xADDR=VAL for the playable frontend + doc CLI/frontend commands
godot -- --seed 0xa57=1 seeds initial global state in the ADV frontend (e.g.
Lily's form-gated voiced dialogue plays live; forms A/B/C = 0xa57/0xa58/0xa59).
Additive: no seed = unchanged, selftest OK. Also documents the engine CLI
(run/trace/audio/gfx/play/sweep) + Godot frontend flags in tools-reference.md
(they lived only in memory/commits).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 07:54:22 -04:00
gamer147
78199e9b8c feat(a2b): screen-backbuffer blit compositor + real GetTextureSize
Godot host: source images kept per slot with dims read from the BMP header on
the VM thread (synchronous, so the bytecode's geometry math sees real sizes);
draw-texture blits src rect -> dst into one 800x600 canvas in execution order,
shown by a single TextureRect. Selftest byte-parity preserved.

Slot 0 = primary/screen surface: seed its dims to 800x600 (the boot-time
create-texture the single-scene harness skips) and record create-texture(w,h),
so the first CG's anchor-preserve math stays an identity instead of corrupting
the persistent base globals. Fixes the grey-first-CG opening. Verified: SC0000
pages 1/3 composite the opening event CG at (0,0) with dialogue over it.

Also adds a --shot <png> [--shot-page N] dev capture to Main (page-gated on a
VM-thread counter) for headless visual verification.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 23:02:58 -04:00
gamer147
ea0f1ddc7a feat(a2b): implement 0x208 get-texture-size (geometry keystone)
Promote 0x208 from stub to a real VM op that writes the loaded texture's
width/height into its two output globals, via new IHost.GetTextureSize. This is
the single native primitive the CG-load subroutine (SC0000 label_12649) needs;
all downstream centering/anchor geometry is already computed in bytecode.

Non-Godot hosts return (0,0) so trace/selftest parity holds (engine 9/9 incl.
TraceDiffTests). Godot host gets a temporary (0,0) stub; real impl in the
compositor task.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 22:48:10 -04:00
gamer147
ee70beb93d feat(a2b): audio — wire play-bgm/play-voice, fix BGM addressing
Wire audio end-to-end (OGG plays natively in Godot; no Frida, no decode):
- IHost.PlayBgm/PlayVoice + VM dispatch for play-bgm(0xbf)/play-voice(0xc4).
  Non-Godot hosts no-op them so --selftest + engine 8/8 stay byte-identical.
- GodotAdvHost resolves id->OGG; Main plays via two AudioStreamPlayer nodes
  (BGM looping; voice interrupt-on-new).

Key finding (by-ear, systematic-debugging): the two audio ops use DIFFERENT
addressing — the earlier "unified manifest" assumption was wrong for BGM.
- play-voice -> per-scene manifest files[base+id] (offset 0, same as textures).
  Confirmed by ear; upgraded med->HIGH.
- play-bgm  -> DIRECT LITERAL NAME BGM{id:03d}.OGG, NOT the manifest.
  Real game: play-bgm 5->BGM005, 8->BGM008 (manifest gave +1). Proven by
  play-bgm 0x23->BGM035 (real standalone track; BGM set skips 030-034) that the
  manifest mis-resolved to a graphics entry. Fix is BGM-only:
  ResourceMap.BgmPathById; voices/textures unchanged.

Also: Lily's silence root-caused as correct form-gating (G[0xa57/0xa58/0xa59]),
left unseeded by choice (no dummy state). Added diagnostic
`Age.Cli audio <SCENE.BIN> [0xADDR=VAL ...]`. Corrected opcodes.toml (play-bgm
direct-name, play-voice HIGH) + docs/memory (dropped the bogus unified-manifest
/ Frida-BGM006 claims).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 22:26:54 -04:00
gamer147
10f6656c2d feat(a2b): first-pass texture render — full-screen event-CG layer
Wire asset resolution into a live Godot render. VM executes set-texture ->
ResourceMap resolves (scene,resId) -> files[section_base+resId] across all
archives -> pre-converted BMP -> composite behind the dialogue. The full-screen
event-CG layer (EV052*) renders end-to-end from the executed bytecode.

- Age.Engine/Sys4/ResourceMap.cs: Resolve + BMP TexturePath; Paths: asset JSONs
- GodotAdvHost: create/set/draw-texture -> TextureRect in a _stage layer
- IHost.DrawTexture + VM dispatch extended with dst x/y (draw-texture args 7/8)
- project.godot 800x600; convert_agf.py all-archive + --scene batch
- engine 8/8, C# --selftest still byte-matches vm0 trace (VM behaviour unchanged)

Known limitations (next chunk = graphics geometry/blend subsystem):
- sprites + BG* via the CG-load subroutine get garbage dst/size — native ops
  stubbed (0x208 get-texture-size + sprite position/anim chain)
- AE* fades draw opaque/instant (no alpha); no chromakey
- slot model approximates the game's immediate-mode blit-onto-slot-0 canvas
- AGF pre-converted to BMP offline (runtime decoder deferred)
See docs/phase-a-slice-plan.md (A2b section).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 21:22:42 -04:00
gamer147
783b771020 fix(a2a): advance on mouse click (use _Input; root Control ate clicks in _UnhandledInput)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 15:09:23 -04:00
gamer147
78b7d92e93 feat(a2a): CJK font for the message window; mark A2a done in the slice plan
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 14:52:40 -04:00
gamer147
fcaa4caf47 feat(a2a): worker-thread ADV host + blocking wait-for-input + headless self-test
SELFTEST OK: 186 lines match vm0 trace; real SemaphoreSlim gate + CallDeferred exercised headless.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 14:51:07 -04:00
gamer147
d3286cf96b feat(a2a): Godot 4.7 .NET project scaffold referencing Age.Engine (headless smoke)
SMOKE: Paths resolves to age-reimpl inside Godot; Age.Engine parses SC0000 in-process.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 14:49:57 -04:00