From d5b9604ce0d0fe3f5207becaec4758d7b90d57cb Mon Sep 17 00:00:00 2001 From: gamer147 Date: Mon, 3 Aug 2026 10:19:51 -0400 Subject: [PATCH] Split movie host contract --- docs/PROJECT-STRUCTURE.md | 4 ++- docs/remake-architecture-and-roadmap.md | 14 +++++++--- engine/Age.Engine/Hosting/IHost.cs | 26 +----------------- engine/Age.Engine/Hosting/IMovieHost.cs | 35 +++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 30 deletions(-) create mode 100644 engine/Age.Engine/Hosting/IMovieHost.cs diff --git a/docs/PROJECT-STRUCTURE.md b/docs/PROJECT-STRUCTURE.md index 2062c5b..aae44c9 100644 --- a/docs/PROJECT-STRUCTURE.md +++ b/docs/PROJECT-STRUCTURE.md @@ -165,7 +165,9 @@ implementations. `engine/Age.Engine/Hosting/IDiagnosticHost.cs` owns recoverable reporting contracts, while `engine/Age.Engine/Hosting/ILifecycleHost.cs` owns script-context entry/exit, sleep and timed-deadline waiting, frame yield, and scene reset. `engine/Age.Engine/Hosting/IAudioHost.cs` owns BGM, voice, SFX, fade, volume, and route-control contracts, including the compatibility overload/default chains used by -simple hosts. `IHost` inherits all three focused contracts; their required and default behavior is unchanged. +simple hosts. `engine/Age.Engine/Hosting/IMovieHost.cs` owns ordinary, positioned, mask-transition, activity-query, +and modal movie playback contracts. `IHost` inherits all four focused contracts; their required and default +behavior is unchanged, and movie/graphics transport records remain in their existing locations for now. `engine/Age.Engine/Model/GfxState.cs` retains cross-domain retained-graphics coordination. `engine/Age.Engine/Model/GfxState.Contracts.cs` owns its public render, transition, diagnostic, persistence, diff --git a/docs/remake-architecture-and-roadmap.md b/docs/remake-architecture-and-roadmap.md index 8f394d1..4921644 100644 --- a/docs/remake-architecture-and-roadmap.md +++ b/docs/remake-architecture-and-roadmap.md @@ -770,6 +770,12 @@ do not mix mechanical moves with semantic changes. compatibility overloads/default chains, and existing host classes remain behaviorally unchanged. Runtime validation remains green. + The third bounded contract slice introduced `IMovieHost` for ordinary, positioned, mask-transition, activity + queries for movie surfaces, and modal playback. `IHost` inherits the focused contract; all five default + members and existing host classes remain behaviorally unchanged. `GfxState` and + `MovieMaskTransitionRequest` remain in their prior locations pending a separate dependency-cleanup slice. + Runtime validation remains green. + 4. **Make the build graph express source ownership.** Stop linking production `.cs` files from `godot/` and `tools/movie-corpus-gate/` into `Age.Engine.Tests`. Extract the platform-neutral frontend/movie/diagnostic code into a small production project referenced by Godot, tests, and the corpus gate. Retain both existing @@ -1129,9 +1135,9 @@ layer's rendering diverges from ADV; save layout. ## 8. Immediate next step Continue step 3 of the **codebase consolidation** maintenance slice: clarify runtime contracts without changing -behavior or the aggregate host accepted by the VM. With diagnostic, lifecycle, and audio contracts established -beneath `IHost`, introduce the movie host contract next while leaving movie request/graphics transport records in -their current locations for a separate dependency-cleanup slice; preserve every required/default member and all -existing host implementations. +behavior or the aggregate host accepted by the VM. With diagnostic, lifecycle, audio, and movie contracts +established beneath `IHost`, move the neutral `MovieMaskTransitionRequest` contract from `Hosting` to `Model` next +to remove `GfxState`'s reverse dependency on the host namespace, preserving the record's public shape and every +consumer before separating larger host domains. 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. diff --git a/engine/Age.Engine/Hosting/IHost.cs b/engine/Age.Engine/Hosting/IHost.cs index 27d6c16..d5a8def 100644 --- a/engine/Age.Engine/Hosting/IHost.cs +++ b/engine/Age.Engine/Hosting/IHost.cs @@ -48,7 +48,7 @@ public enum SurfaceBlackFadeDirection ToBlack, } -public interface IHost : IDiagnosticHost, ILifecycleHost, IAudioHost +public interface IHost : IDiagnosticHost, ILifecycleHost, IAudioHost, IMovieHost { /// Present AGERc's modal full-width editor. Cancel preserves CurrentText. FullwidthTextEditResult EditFullwidthString(FullwidthTextEditRequest request) @@ -171,28 +171,4 @@ public interface IHost : IDiagnosticHost, ILifecycleHost, IAudioHost } void DrawTexture(int slot, int srcX, int srcY, int width, int height, int dstX, int dstY); (int Width, int Height) GetTextureSize(int slot); - // Native op 0x236 binds a movie decoder to an existing retained texture surface. - // Playback is non-modal: the VM advances to the following instruction while the host publishes frames. - /// The initialized movie graph's stop position in truncated integer milliseconds, or null - /// when the host could not obtain usable timing metadata. Native op 0x23f queries this state - /// immediately after 0x236 returns. - long? PlayMovieToSurface(long resourceId, int surfaceSlot, long movieFlags, long syncMask) => null; - // Native op 0x241 uses the same graph/surface lifecycle as 0x236, but seeks the graph before - // playback configuration. Hosts without positioned decoding may fall back to ordinary playback. - long? PlayMovieToSurfaceAtPosition( - long resourceId, int surfaceSlot, long movieFlags, long syncMask, long positionMs) - => PlayMovieToSurface(resourceId, surfaceSlot, movieFlags, syncMask); - // Native op 0x24d captures a retained range into the scratch surface, then publishes each - // decoded movie frame's green channel as an exact packed-alpha mask. A nonvisual host completes - // the lifecycle immediately so a following 0x21c can never strand script execution. - void PlayMovieMaskTransition(GfxState gfx, MovieMaskTransitionRequest request) - { - gfx.QueueMovieMaskTransition(request); - gfx.CompleteMovieMaskTransition(request.SurfaceSlot); - } - bool IsMovieSurfaceActive(int surfaceSlot) => false; - // Native op 0x20f uses a universal packed id and parks script execution until the movie - // reaches EOF or the player cancels it. The decoder remains asynchronous; the interactive host - // owns the modal wait so its render loop can continue publishing frames. - void PlayModalMovieToSurface(long resourceId, int surfaceSlot, long movieFlags) { } } diff --git a/engine/Age.Engine/Hosting/IMovieHost.cs b/engine/Age.Engine/Hosting/IMovieHost.cs new file mode 100644 index 0000000..965d152 --- /dev/null +++ b/engine/Age.Engine/Hosting/IMovieHost.cs @@ -0,0 +1,35 @@ +using Age.Engine.Model; + +namespace Age.Engine.Hosting; + +public interface IMovieHost +{ + // Native op 0x236 binds a movie decoder to an existing retained texture surface. + // Playback is non-modal: the VM advances to the following instruction while the host publishes frames. + /// The initialized movie graph's stop position in truncated integer milliseconds, or null + /// when the host could not obtain usable timing metadata. Native op 0x23f queries this state + /// immediately after 0x236 returns. + long? PlayMovieToSurface(long resourceId, int surfaceSlot, long movieFlags, long syncMask) => null; + + // Native op 0x241 uses the same graph/surface lifecycle as 0x236, but seeks the graph before + // playback configuration. Hosts without positioned decoding may fall back to ordinary playback. + long? PlayMovieToSurfaceAtPosition( + long resourceId, int surfaceSlot, long movieFlags, long syncMask, long positionMs) + => PlayMovieToSurface(resourceId, surfaceSlot, movieFlags, syncMask); + + // Native op 0x24d captures a retained range into the scratch surface, then publishes each + // decoded movie frame's green channel as an exact packed-alpha mask. A nonvisual host completes + // the lifecycle immediately so a following 0x21c can never strand script execution. + void PlayMovieMaskTransition(GfxState gfx, MovieMaskTransitionRequest request) + { + gfx.QueueMovieMaskTransition(request); + gfx.CompleteMovieMaskTransition(request.SurfaceSlot); + } + + bool IsMovieSurfaceActive(int surfaceSlot) => false; + + // Native op 0x20f uses a universal packed id and parks script execution until the movie + // reaches EOF or the player cancels it. The decoder remains asynchronous; the interactive host + // owns the modal wait so its render loop can continue publishing frames. + void PlayModalMovieToSurface(long resourceId, int surfaceSlot, long movieFlags) { } +}