Extract VM animation opcode handler

This commit is contained in:
gamer147
2026-08-02 23:54:44 -04:00
parent ee86bf144a
commit 803df2826f
4 changed files with 71 additions and 28 deletions

View File

@@ -183,6 +183,8 @@ surface release; its labels remain at their existing dispatcher positions around
object cases. `engine/Age.Engine/Vm/VirtualMachine.RetainedObjects.cs` owns retained-object registry queries, object cases. `engine/Age.Engine/Vm/VirtualMachine.RetainedObjects.cs` owns retained-object registry queries,
default-slot and geometry mutation, direct and range transforms, clone, and erase dispatch; animation, surface, default-slot and geometry mutation, direct and range transforms, clone, and erase dispatch; animation, surface,
ADV-binding, and presentation labels remain in their respective dispatcher groups. ADV-binding, and presentation labels remain in their respective dispatcher groups.
`engine/Age.Engine/Vm/VirtualMachine.Animation.cs` owns retained spritesheet and color channels, timed and cyclic
transforms, per-object animation control, frame-time sampling, and the shared animation-clock opcode handler.
The disposable `build/page-map-<SCENE>.jsonl` files are produced by editor/development Godot runs and map The disposable `build/page-map-<SCENE>.jsonl` files are produced by editor/development Godot runs and map
runtime ADV page ordinals to their authoritative script offsets for `tools/locate_page.py`. Packaged exports runtime ADV page ordinals to their authoritative script offsets for `tools/locate_page.py`. Packaged exports

View File

@@ -649,6 +649,12 @@ do not mix mechanical moves with semantic changes.
color, surface release, ADV binding, and presentation behavior remain outside this handler. Runtime validation color, surface release, ADV binding, and presentation behavior remain outside this handler. Runtime validation
remains green. remains green.
The fifth bounded `VirtualMachine.Step` extraction moved retained spritesheet and color channels, timed and
cyclic transforms, per-object animation control, frame-time sampling, and shared animation-clock dispatch into
`engine/Age.Engine/Vm/VirtualMachine.Animation.cs`. The top-level dispatcher retains all labels at their
existing positions and routes the separated groups through `StepAnimation`; presentation transitions and movie
masking remain outside the guarded handler. Runtime validation remains green.
**Gate:** no externally visible behavior or command changes; generated artifacts are byte-identical where **Gate:** no externally visible behavior or command changes; generated artifacts are byte-identical where
deterministic, and the corresponding engine, Python, Godot, and corpus validations remain green after deterministic, and the corresponding engine, Python, Godot, and corpus validations remain green after
each domain move. each domain move.
@@ -1020,9 +1026,8 @@ layer's rendering diverges from ADV; save layout.
## 8. Immediate next step ## 8. Immediate next step
Continue step 2 of the **codebase consolidation** maintenance slice: behavior-neutral physical splits backed Continue step 2 of the **codebase consolidation** maintenance slice: behavior-neutral physical splits backed
by the tracked launcher and layered validation driver. With the planned `Main`, `GodotAdvHost`, and `GfxState` by the tracked launcher and layered validation driver. With the planned `Main`, `GodotAdvHost`, and `GfxState`
domains isolated and the audio, movie, and surface/texture `VirtualMachine.Step` families routed through domain domains isolated and the audio, movie, surface/texture, retained-object, and animation `VirtualMachine.Step`
handlers, with retained-object query/mutation and transform dispatch now isolated as well, extract the retained families routed through domain handlers, extract retained presentation/transition dispatch next without replacing
animation/color/spritesheet opcode family next without replacing the proven dispatcher or changing public types, the proven dispatcher or changing public types, commands, and generated output.
commands, and generated output.
Concrete playthrough blockers may still preempt this bounded maintenance work; the consolidation effort does Concrete playthrough blockers may still preempt this bounded maintenance work; the consolidation effort does
not replace Phase B gameplay validation or the open cross-platform gates. not replace Phase B gameplay validation or the open cross-platform gates.

View File

@@ -0,0 +1,54 @@
using Age.Engine.Model;
namespace Age.Engine.Vm;
public sealed partial class VirtualMachine
{
private int StepAnimation(string label, IReadOnlyList<Operand> a, int pc)
{
switch (label)
{
case "u004223C0": // 0x239 spritesheet cell: (handle)(delay)(duration)(frame count)(columns)(cell)
Gfx.SetSrcRect(Read(a[0]), Read(a[3]), Read(a[4]), Read(a[5]), 0); return pc + 1;
case "reset-gfx-cyclic-animations": // 0x230: stop all five retained looping channels
case "u00421E70":
Gfx.ResetCyclicAnimationChannels(Read(a[0])); return pc + 1;
case "u00421EA0": // 0x231 looping spritesheet: (handle)(ms per frame)(frame count)(columns)
Gfx.SetSrcRect(Read(a[0]), Read(a[2]), Read(a[3]), 0, Read(a[1])); return pc + 1;
case "u00421EF0": // 0x232 cyclic packed ARGB; negative alpha/RGB preserve static obj color
Gfx.SetColorAnimResolved(Read(a[0]), Read(a[1]), Read(a[2]), Read(a[3])); return pc + 1;
case "set-scale-cycle": // 0x233 (handle)(period ms)(target scale x/y/z percent)
Gfx.SetScaleCycle(Read(a[0]), Read(a[1]), (Read(a[2]), Read(a[3]), Read(a[4])));
return pc + 1;
case "sample-frame-time": // 0x23c: previous <- current; current <- monotonic time
Gfx.SampleFrameTime(_host.InputClockMilliseconds); return pc + 1;
case "gfx-blit-color": // 0x202 (handle)(delay)(duration)(alpha)(color) — one-shot color
Gfx.SetAnimatedObjectColorResolved(Read(a[0]), Read(a[1]), Read(a[2]), Read(a[3]), Read(a[4]));
return pc + 1;
case "gfx-draw-color": // 0x203 (handle)(v)(alpha)(color) — static alpha/tint
Gfx.SetStaticObjectColorResolved(Read(a[0]), Read(a[1]), Read(a[2]), Read(a[3])); return pc + 1;
// ---- sprite transform / animation cluster (docs/engine-re.md "0x21c-0x243 ... ANIMATION") ----
case "set-anim-transform-abs": // 0x220 (handle)(delay)(duration)(tx)(ty)(tz)
Gfx.SetTranslationChannel(Read(a[0]), Read(a[1]), Read(a[2]),
(Read(a[3]), Read(a[4]), Read(a[5]))); return pc + 1;
case "set-anim-transform-norm": // 0x21e (handle)(delay)(duration)(sx%)(sy%)(sz%)
Gfx.SetScaleChannel(Read(a[0]), Read(a[1]), Read(a[2]),
(Read(a[3]), Read(a[4]), Read(a[5]))); return pc + 1;
case "set-anim-rotation-axis-angle": // 0x21f (handle)(delay)(duration)(axis x/y/z)(angle deg)
Gfx.SetRotationChannel(Read(a[0]), Read(a[1]), Read(a[2]),
(Read(a[3]), Read(a[4]), Read(a[5])), Read(a[6])); return pc + 1;
case "anim-start": // 0x234 legacy name: (handle)(period)(axis x/y/z), cyclic rotation channel
Gfx.SetRotationCycle(Read(a[0]), Read(a[1]), (Read(a[2]), Read(a[3]), Read(a[4]))); return pc + 1;
case "set-anim-clock": // 0x238 (duration) — global, non-blocking (host advances it per-frame)
Gfx.SetAnimClock(Read(a[0])); return pc + 1;
case "set-object-animation-detached": // 0x242 (handle)(flags): bit 0 is nonblocking/force-proof
Gfx.SetOneShotAnimationControl(Read(a[0]), Read(a[1])); return pc + 1;
case "reset-anim-clock": // 0x243: force unprotected one-shots and reset the global service clock
Gfx.ResetAnimClock(); return pc + 1;
case "set-gfx-animation-service-flags": // 0x24e: bit 1 suppresses op 0x243
Gfx.SetAnimationServiceFlags(Read(a[0])); return pc + 1;
default:
throw new InvalidOperationException($"Non-animation opcode routed to animation handler: {label}");
}
}
}

View File

@@ -2550,25 +2550,20 @@ public sealed partial class VirtualMachine
case "set-gfx-range-scale-target": // 0x22d (delay)(duration)(sx%)(sy%)(sz%) case "set-gfx-range-scale-target": // 0x22d (delay)(duration)(sx%)(sy%)(sz%)
return StepRetainedObject(label, a, pc); return StepRetainedObject(label, a, pc);
case "u004223C0": // 0x239 spritesheet cell: (handle)(delay)(duration)(frame count)(columns)(cell) case "u004223C0": // 0x239 spritesheet cell: (handle)(delay)(duration)(frame count)(columns)(cell)
Gfx.SetSrcRect(Read(a[0]), Read(a[3]), Read(a[4]), Read(a[5]), 0); return pc + 1;
case "reset-gfx-cyclic-animations": // 0x230: stop all five retained looping channels case "reset-gfx-cyclic-animations": // 0x230: stop all five retained looping channels
case "u00421E70": case "u00421E70":
Gfx.ResetCyclicAnimationChannels(Read(a[0])); return pc + 1;
case "u00421EA0": // 0x231 looping spritesheet: (handle)(ms per frame)(frame count)(columns) case "u00421EA0": // 0x231 looping spritesheet: (handle)(ms per frame)(frame count)(columns)
Gfx.SetSrcRect(Read(a[0]), Read(a[2]), Read(a[3]), 0, Read(a[1])); return pc + 1;
case "u00421EF0": // 0x232 cyclic packed ARGB; negative alpha/RGB preserve static obj color case "u00421EF0": // 0x232 cyclic packed ARGB; negative alpha/RGB preserve static obj color
Gfx.SetColorAnimResolved(Read(a[0]), Read(a[1]), Read(a[2]), Read(a[3])); return pc + 1;
case "set-scale-cycle": // 0x233 (handle)(period ms)(target scale x/y/z percent) case "set-scale-cycle": // 0x233 (handle)(period ms)(target scale x/y/z percent)
Gfx.SetScaleCycle(Read(a[0]), Read(a[1]), (Read(a[2]), Read(a[3]), Read(a[4]))); return StepAnimation(label, a, pc);
return pc + 1;
case "u00421940": // 0x228: (succ)(handle)(outX)(outY)(outZ) <- target translation matrix case "u00421940": // 0x228: (succ)(handle)(outX)(outY)(outZ) <- target translation matrix
return StepRetainedObject(label, a, pc); return StepRetainedObject(label, a, pc);
case "u00422930": case "u00422930":
case "query-surface-stop-time-ms": case "query-surface-stop-time-ms":
case "query-movie-surface-active": case "query-movie-surface-active":
return StepMovie(label, ins, pc); return StepMovie(label, ins, pc);
case "sample-frame-time": // 0x23c: previous <- current; current <- monotonic time case "sample-frame-time":
Gfx.SampleFrameTime(_host.InputClockMilliseconds); return pc + 1; return StepAnimation(label, a, pc);
case "set-gfx-geom3-c": case "set-gfx-geom3-c":
case "u00420620": // upstream ABI label case "u00420620": // upstream ABI label
case "gfx-set-scale-current": // 0x1fd (handle)(sx%)(sy%)(sz%) -> current scale matrix case "gfx-set-scale-current": // 0x1fd (handle)(sx%)(sy%)(sz%) -> current scale matrix
@@ -2596,31 +2591,18 @@ public sealed partial class VirtualMachine
_host.ReleaseSurface((int)Read(a[0])); Gfx.ClearSurface((int)Read(a[0])); return pc + 1; _host.ReleaseSurface((int)Read(a[0])); Gfx.ClearSurface((int)Read(a[0])); return pc + 1;
case "clone-gfx-object": case "clone-gfx-object":
return StepRetainedObject(label, a, pc); return StepRetainedObject(label, a, pc);
case "gfx-blit-color": // 0x202 (handle)(delay)(duration)(alpha)(color) — one-shot color case "gfx-blit-color":
Gfx.SetAnimatedObjectColorResolved(Read(a[0]), Read(a[1]), Read(a[2]), Read(a[3]), Read(a[4])); case "gfx-draw-color":
return pc + 1;
case "gfx-draw-color": // 0x203 (handle)(v)(alpha)(color) — static alpha/tint
Gfx.SetStaticObjectColorResolved(Read(a[0]), Read(a[1]), Read(a[2]), Read(a[3])); return pc + 1;
// ---- sprite transform / animation cluster (docs/engine-re.md "0x21c-0x243 ... ANIMATION") ---- // ---- sprite transform / animation cluster (docs/engine-re.md "0x21c-0x243 ... ANIMATION") ----
case "set-anim-transform-abs": // 0x220 (handle)(delay)(duration)(tx)(ty)(tz) case "set-anim-transform-abs": // 0x220 (handle)(delay)(duration)(tx)(ty)(tz)
Gfx.SetTranslationChannel(Read(a[0]), Read(a[1]), Read(a[2]),
(Read(a[3]), Read(a[4]), Read(a[5]))); return pc + 1;
case "set-anim-transform-norm": // 0x21e (handle)(delay)(duration)(sx%)(sy%)(sz%) case "set-anim-transform-norm": // 0x21e (handle)(delay)(duration)(sx%)(sy%)(sz%)
Gfx.SetScaleChannel(Read(a[0]), Read(a[1]), Read(a[2]),
(Read(a[3]), Read(a[4]), Read(a[5]))); return pc + 1;
case "set-anim-rotation-axis-angle": // 0x21f (handle)(delay)(duration)(axis x/y/z)(angle deg) case "set-anim-rotation-axis-angle": // 0x21f (handle)(delay)(duration)(axis x/y/z)(angle deg)
Gfx.SetRotationChannel(Read(a[0]), Read(a[1]), Read(a[2]),
(Read(a[3]), Read(a[4]), Read(a[5])), Read(a[6])); return pc + 1;
case "anim-start": // 0x234 legacy name: (handle)(period)(axis x/y/z), cyclic rotation channel case "anim-start": // 0x234 legacy name: (handle)(period)(axis x/y/z), cyclic rotation channel
Gfx.SetRotationCycle(Read(a[0]), Read(a[1]), (Read(a[2]), Read(a[3]), Read(a[4]))); return pc + 1;
case "set-anim-clock": // 0x238 (duration) — global, non-blocking (host advances it per-frame) case "set-anim-clock": // 0x238 (duration) — global, non-blocking (host advances it per-frame)
Gfx.SetAnimClock(Read(a[0])); return pc + 1;
case "set-object-animation-detached": // 0x242 (handle)(flags): bit 0 is nonblocking/force-proof case "set-object-animation-detached": // 0x242 (handle)(flags): bit 0 is nonblocking/force-proof
Gfx.SetOneShotAnimationControl(Read(a[0]), Read(a[1])); return pc + 1;
case "reset-anim-clock": // 0x243: force unprotected one-shots and reset the global service clock case "reset-anim-clock": // 0x243: force unprotected one-shots and reset the global service clock
Gfx.ResetAnimClock(); return pc + 1;
case "set-gfx-animation-service-flags": // 0x24e: bit 1 suppresses op 0x243 case "set-gfx-animation-service-flags": // 0x24e: bit 1 suppresses op 0x243
Gfx.SetAnimationServiceFlags(Read(a[0])); return pc + 1; return StepAnimation(label, a, pc);
case "play-movie-mask-transition": case "play-movie-mask-transition":
return StepMovie(label, ins, pc); return StepMovie(label, ins, pc);
case "queue-surface-alpha-transition": // 0x223: target surface crossfade over two object ranges case "queue-surface-alpha-transition": // 0x223: target surface crossfade over two object ranges