From 281f37747ab50fa4d9e598e2cade46ec55905d3c Mon Sep 17 00:00:00 2001 From: gamer147 Date: Mon, 3 Aug 2026 11:04:35 -0400 Subject: [PATCH] Extract ADV host contract --- docs/PROJECT-STRUCTURE.md | 13 ++-- docs/remake-architecture-and-roadmap.md | 12 +++- engine/Age.Engine/Hosting/IAdvHost.cs | 79 +++++++++++++++++++++++++ engine/Age.Engine/Hosting/IHost.cs | 77 +----------------------- 4 files changed, 97 insertions(+), 84 deletions(-) create mode 100644 engine/Age.Engine/Hosting/IAdvHost.cs diff --git a/docs/PROJECT-STRUCTURE.md b/docs/PROJECT-STRUCTURE.md index 3e85f4c..a7149b3 100644 --- a/docs/PROJECT-STRUCTURE.md +++ b/docs/PROJECT-STRUCTURE.md @@ -166,12 +166,13 @@ reporting contracts, while `engine/Age.Engine/Hosting/ILifecycleHost.cs` owns sc 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. `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. `engine/Age.Engine/Hosting/IGraphicsHost.cs` owns mutable surfaces, retained-range/frame -presentation, transitions, texture lifecycle, pixel capture/replace, draw, and size contracts; `IHost` also -inherits this focused surface without changing existing hosts. `engine/Age.Engine/Hosting/IInputHost.cs` owns -modal fullwidth entry, ADV waits/callback servicing, input clock, cursor resources, and skip-state interaction; -its required wait and overload/default chains remain unchanged. The neutral +and modal movie playback contracts. `engine/Age.Engine/Hosting/IGraphicsHost.cs` owns mutable surfaces, +retained-range/frame presentation, transitions, texture lifecycle, pixel capture/replace, draw, and size +contracts. `engine/Age.Engine/Hosting/IInputHost.cs` owns modal fullwidth entry, ADV waits/callback servicing, +input clock, cursor resources, and skip-state interaction. `engine/Age.Engine/Hosting/IAdvHost.cs` owns live and +surface text, history presentation, ADV layout publication, message presentation settings, wait indicators, and +page-presentation suspension. `IHost` inherits all seven focused contracts; every required member and +overload/default chain remains unchanged. The neutral `engine/Age.Engine/Model/MovieMaskTransitionRequest.cs` record carries movie mask work between the VM, host, and retained graphics without making `Model` depend on `Hosting`. `engine/Age.Engine/Model/RgbaImage.cs` owns the format-independent packed RGBA image transported between SYS4 diff --git a/docs/remake-architecture-and-roadmap.md b/docs/remake-architecture-and-roadmap.md index 3e2808a..04c65ff 100644 --- a/docs/remake-architecture-and-roadmap.md +++ b/docs/remake-architecture-and-roadmap.md @@ -809,6 +809,12 @@ do not mix mechanical moves with semantic changes. its focused tests required new imports; record shape, editor defaults, wait overloads, and all runtime behavior remain unchanged. Runtime validation remains green. + The tenth bounded contract slice introduced `IAdvHost` for live and surface text, text-history presentation, + ADV layout publication, message presentation settings, wait-indicator control, and page-presentation + suspension. `IHost` now contains no members of its own and inherits all seven focused host contracts; all + twenty-three ADV members, required implementations, overload/default chains, existing hosts, and transport + record locations remain behaviorally unchanged. 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 @@ -1169,8 +1175,8 @@ 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, audio, and movie contracts -established beneath `IHost`, shared graphics transport neutral, and graphics/input contracts now separated, move -the remaining ADV text/history/layout/presentation members into `IAdvHost` next. Preserve all required/default -members and existing hosts, leaving `IHost` as the unchanged aggregate runtime entry point. +established beneath `IHost`, shared graphics/input transport neutral, and graphics/input/ADV contracts now +separated, move the unchanged `AdvWaitIndicatorConfig` and `DiagnosticMessage` declarations from `Hosting` to +`Model` next. Preserve all consumers while removing the remaining transport declarations from interface files. 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/IAdvHost.cs b/engine/Age.Engine/Hosting/IAdvHost.cs new file mode 100644 index 0000000..1835a3d --- /dev/null +++ b/engine/Age.Engine/Hosting/IAdvHost.cs @@ -0,0 +1,79 @@ +using Age.Engine.Model; + +namespace Age.Engine.Hosting; + +public readonly record struct AdvWaitIndicatorConfig( + int LayoutSlot, int X, int Y, int SurfaceSlot, + int SourceX, int SourceY, int CellWidth, int CellHeight, + int TerminalFrame, long FramePeriodMs) +{ + /// Select the current atlas frame. TerminalFrame is the exclusive native upper bound, + /// so SYSTEM4's value 12 addresses the twelve cells 0 through 11. + public int FrameAt(long elapsedMs) + { + int frameCount = System.Math.Max(1, TerminalFrame); + long period = System.Math.Max(1, FramePeriodMs); + return (int)(System.Math.Max(0, elapsedMs) / period % frameCount); + } +} + +public interface IAdvHost +{ + void ShowText(int offset, string text); + void ShowText(AdvLiveTextRun run, int glyphDelayMilliseconds) + => ShowText(run.SourceOffset, run.Text); + AdvRetainedTextRunResult? ShowText( + GfxState gfx, + AdvTextLayoutPresentationBinding binding, + AdvLiveTextRun run, + int glyphDelayMilliseconds) + { + ShowText(run, glyphDelayMilliseconds); + return null; + } + int MessageGlyphDelayMilliseconds => 50; + void SetMessageGlyphDelayMilliseconds(int milliseconds) { } + // Native ADV text subsystem: op 0x7a updates the selected layout's last 20-byte cursor record; + // op 0x204 rasterizes a string into a numbered surface before 0x1fb binds that surface. + void SetAdvTextCursor(int layoutSlot, int x, int y) { } + void DrawStringToSurface(int surfaceSlot, int x, int y, string text) { } + void DrawStringToSurface(int surfaceSlot, int x, int y, string text, AdvTextStyle style) + => DrawStringToSurface(surfaceSlot, x, y, text); + void ClearRenderedAdvTextLayout(int layoutSlot) { } + void ResetRenderedAdvTextLayout( + GfxState gfx, AdvTextLayoutPresentationBinding binding) + => ClearRenderedAdvTextLayout(binding.LayoutSlot); + void RenderTextHistory(AdvTextHistoryRenderBatch batch) { } + bool RenderTextHistory( + GfxState gfx, + AdvTextLayoutPresentationBinding binding, + AdvTextHistoryRenderBatch batch) + { + RenderTextHistory(batch); + return false; + } + // History render batches are transient bindings, unlike the retained backlog itself. HISTORY.BIN's + // recording re-enable at exit ends that presentation and drops every bound target layout. + void EndTextHistoryPresentation() { } + void EndTextHistoryPresentation(GfxState gfx) => EndTextHistoryPresentation(); + int MessageWindowAlphaSetting => 0; + void SetMessageWindowAlphaSetting(int value) { } + void ConfigureAdvWaitIndicator(AdvWaitIndicatorConfig config) { } + // Op 0x212 supplies the ordinary retained handle used to publish the configured atlas cell. + void BindAdvWaitIndicator( + AdvTextLayoutPresentationBinding binding, + AdvTextLayoutSnapshot layout) { } + // Op 0x1ce explicitly starts/stops the same animated marker that op 0x72 starts for an ADV wait. + void SetAdvWaitIndicatorEnabled(bool enabled) { } + // Op 0x20a republishes one retained ADV text layout and includes the current marker frame when active. + void PublishAdvTextLayout(int layoutSlot) { } + void PublishAdvTextLayout( + GfxState gfx, AdvTextLayoutPresentationBinding binding) + => PublishAdvTextLayout(binding.LayoutSlot); + // Op 0x199 temporarily yields the active ADV page into its registered hide-window coroutine. + // The retained scene continues to render, but the text layout and its wait marker are suspended + // until op 0x7c restores the saved page PC. + void SetAdvPagePresentationSuspended(bool suspended) { } + void SetAdvPagePresentationSuspended(GfxState gfx, bool suspended) + => SetAdvPagePresentationSuspended(suspended); +} diff --git a/engine/Age.Engine/Hosting/IHost.cs b/engine/Age.Engine/Hosting/IHost.cs index 974a448..5dc52f7 100644 --- a/engine/Age.Engine/Hosting/IHost.cs +++ b/engine/Age.Engine/Hosting/IHost.cs @@ -1,82 +1,9 @@ -using Age.Engine.Model; - namespace Age.Engine.Hosting; -public readonly record struct AdvWaitIndicatorConfig( - int LayoutSlot, int X, int Y, int SurfaceSlot, - int SourceX, int SourceY, int CellWidth, int CellHeight, - int TerminalFrame, long FramePeriodMs) -{ - /// Select the current atlas frame. TerminalFrame is the exclusive native upper bound, - /// so SYSTEM4's value 12 addresses the twelve cells 0 through 11. - public int FrameAt(long elapsedMs) - { - int frameCount = System.Math.Max(1, TerminalFrame); - long period = System.Math.Max(1, FramePeriodMs); - return (int)(System.Math.Max(0, elapsedMs) / period % frameCount); - } -} - /// A synchronous AGE-owned diagnostic prompt after native body/context formatting. public readonly record struct DiagnosticMessage(string Caption, string Text); -public interface IHost : IDiagnosticHost, ILifecycleHost, IAudioHost, IMovieHost, IGraphicsHost, IInputHost +public interface IHost : IDiagnosticHost, ILifecycleHost, IAudioHost, IMovieHost, IGraphicsHost, IInputHost, + IAdvHost { - void ShowText(int offset, string text); - void ShowText(AdvLiveTextRun run, int glyphDelayMilliseconds) - => ShowText(run.SourceOffset, run.Text); - AdvRetainedTextRunResult? ShowText( - GfxState gfx, - AdvTextLayoutPresentationBinding binding, - AdvLiveTextRun run, - int glyphDelayMilliseconds) - { - ShowText(run, glyphDelayMilliseconds); - return null; - } - int MessageGlyphDelayMilliseconds => 50; - void SetMessageGlyphDelayMilliseconds(int milliseconds) { } - // Native ADV text subsystem: op 0x7a updates the selected layout's last 20-byte cursor record; - // op 0x204 rasterizes a string into a numbered surface before 0x1fb binds that surface. - void SetAdvTextCursor(int layoutSlot, int x, int y) { } - void DrawStringToSurface(int surfaceSlot, int x, int y, string text) { } - void DrawStringToSurface(int surfaceSlot, int x, int y, string text, AdvTextStyle style) - => DrawStringToSurface(surfaceSlot, x, y, text); - void ClearRenderedAdvTextLayout(int layoutSlot) { } - void ResetRenderedAdvTextLayout( - GfxState gfx, AdvTextLayoutPresentationBinding binding) - => ClearRenderedAdvTextLayout(binding.LayoutSlot); - void RenderTextHistory(AdvTextHistoryRenderBatch batch) { } - bool RenderTextHistory( - GfxState gfx, - AdvTextLayoutPresentationBinding binding, - AdvTextHistoryRenderBatch batch) - { - RenderTextHistory(batch); - return false; - } - // History render batches are transient bindings, unlike the retained backlog itself. HISTORY.BIN's - // recording re-enable at exit ends that presentation and drops every bound target layout. - void EndTextHistoryPresentation() { } - void EndTextHistoryPresentation(GfxState gfx) => EndTextHistoryPresentation(); - int MessageWindowAlphaSetting => 0; - void SetMessageWindowAlphaSetting(int value) { } - void ConfigureAdvWaitIndicator(AdvWaitIndicatorConfig config) { } - // Op 0x212 supplies the ordinary retained handle used to publish the configured atlas cell. - void BindAdvWaitIndicator( - AdvTextLayoutPresentationBinding binding, - AdvTextLayoutSnapshot layout) { } - // Op 0x1ce explicitly starts/stops the same animated marker that op 0x72 starts for an ADV wait. - void SetAdvWaitIndicatorEnabled(bool enabled) { } - // Op 0x20a republishes one retained ADV text layout and includes the current marker frame when active. - void PublishAdvTextLayout(int layoutSlot) { } - void PublishAdvTextLayout( - GfxState gfx, AdvTextLayoutPresentationBinding binding) - => PublishAdvTextLayout(binding.LayoutSlot); - // Op 0x199 temporarily yields the active ADV page into its registered hide-window coroutine. - // The retained scene continues to render, but the text layout and its wait marker are suspended - // until op 0x7c restores the saved page PC. - void SetAdvPagePresentationSuspended(bool suspended) { } - void SetAdvPagePresentationSuspended(GfxState gfx, bool suspended) - => SetAdvPagePresentationSuspended(suspended); }