diff --git a/docs/PROJECT-STRUCTURE.md b/docs/PROJECT-STRUCTURE.md index 443bc4c..3c0ef0f 100644 --- a/docs/PROJECT-STRUCTURE.md +++ b/docs/PROJECT-STRUCTURE.md @@ -169,7 +169,9 @@ simple hosts. `engine/Age.Engine/Hosting/IMovieHost.cs` owns ordinary, positione 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. The neutral +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 `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 e55b3c5..8a39569 100644 --- a/docs/remake-architecture-and-roadmap.md +++ b/docs/remake-architecture-and-roadmap.md @@ -798,6 +798,12 @@ do not mix mechanical moves with semantic changes. imported `Model`, so no call sites changed; surface request shape, enum values, and graphics behavior remain unchanged. Runtime validation remains green. + The eighth bounded contract slice introduced `IInputHost` for modal fullwidth entry, ADV wait overloads and + callback servicing, input clock, cursor resources, and skip-state interaction. `IHost` inherits the focused + contract; all fourteen members, the required base wait, overload/default chains, and existing host classes + remain behaviorally unchanged. Input transport records remain in their prior locations pending a separate + cleanup. 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 @@ -1158,9 +1164,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 movie/image transport neutral, and the graphics contract now separated, move -the input host contract next: modal text entry, ADV waits and callback servicing, input clock, cursor resources, -and skip-state interaction. Preserve the existing overload/default chains and aggregate `IHost` entry point before -separating the remaining ADV text/presentation contract. +established beneath `IHost`, shared graphics transport neutral, and graphics/input contracts now separated, move +the unchanged `FullwidthTextEditRequest`, `FullwidthTextEditResult`, and `AdvAutoWaitState` declarations from +`Hosting` to `Model` next. Preserve all consumers before extracting the remaining ADV text/presentation contract. 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 b9b1822..dc7810b 100644 --- a/engine/Age.Engine/Hosting/IHost.cs +++ b/engine/Age.Engine/Hosting/IHost.cs @@ -27,11 +27,8 @@ public readonly record struct DiagnosticMessage(string Caption, string Text); public readonly record struct FullwidthTextEditRequest(string CurrentText, string InitialText); public readonly record struct FullwidthTextEditResult(bool Accepted, string Text); -public interface IHost : IDiagnosticHost, ILifecycleHost, IAudioHost, IMovieHost, IGraphicsHost +public interface IHost : IDiagnosticHost, ILifecycleHost, IAudioHost, IMovieHost, IGraphicsHost, IInputHost { - /// Present AGERc's modal full-width editor. Cancel preserves CurrentText. - FullwidthTextEditResult EditFullwidthString(FullwidthTextEditRequest request) - => new(false, request.CurrentText); void ShowText(int offset, string text); void ShowText(AdvLiveTextRun run, int glyphDelayMilliseconds) => ShowText(run.SourceOffset, run.Text); @@ -89,33 +86,4 @@ public interface IHost : IDiagnosticHost, ILifecycleHost, IAudioHost, IMovieHost void SetAdvPagePresentationSuspended(bool suspended) { } void SetAdvPagePresentationSuspended(GfxState gfx, bool suspended) => SetAdvPagePresentationSuspended(suspended); - void WaitForInput(); - void WaitForInput(int layoutSlot) => WaitForInput(); - // Interactive hosts service script callbacks on the VM thread while the enclosing ADV page remains - // parked. The callback returns true while another queued input callback is ready to run. - void WaitForInput(int layoutSlot, Func serviceInputCallback) - { - while (serviceInputCallback()) { } - WaitForInput(layoutSlot); - } - void WaitForInput(int layoutSlot, Func serviceInputCallback, - Func autoWaitState) - => WaitForInput(layoutSlot, serviceInputCallback); - void WakeInputCallbackService() { } - void InputCallbackCompleted(GfxState gfx) { } - // Generic AGE input-callback services (ops 0xcc/0xcd, 0xfb/0xff/0x100, 0x108). - // Interactive hosts expose the same monotonic clock used by their frame scheduler. - long InputClockMilliseconds => Environment.TickCount64; - void SetCursorResource(long resourceId) { } - void ClearCursorResource() { } - // Native 0x1c7/0x1cc query two distinct ADV skip channels. Headless and non-interactive - // hosts default to normal playback; the Godot host supplies the live interactive values. - void SetMessageSkipActive(bool active) { } - // Logical action 6 is the native hold-to-fast-forward channel. Keep it separate from the - // persistent op-0x88 channel so releasing the key cannot turn off the user's Skip toggle. - void SetPhysicalMessageSkipActive(bool active) { } - bool IsMessageSkipActive => false; - // Optional diagnostic override. Native ReadTextDB state is VM/profile-owned; interactive hosts - // normally leave this false. - bool IsAdvReadSkipActive => false; } diff --git a/engine/Age.Engine/Hosting/IInputHost.cs b/engine/Age.Engine/Hosting/IInputHost.cs new file mode 100644 index 0000000..db03e0f --- /dev/null +++ b/engine/Age.Engine/Hosting/IInputHost.cs @@ -0,0 +1,49 @@ +using Age.Engine.Model; + +namespace Age.Engine.Hosting; + +public interface IInputHost +{ + /// Present AGERc's modal full-width editor. Cancel preserves CurrentText. + FullwidthTextEditResult EditFullwidthString(FullwidthTextEditRequest request) + => new(false, request.CurrentText); + + void WaitForInput(); + void WaitForInput(int layoutSlot) => WaitForInput(); + + // Interactive hosts service script callbacks on the VM thread while the enclosing ADV page remains + // parked. The callback returns true while another queued input callback is ready to run. + void WaitForInput(int layoutSlot, Func serviceInputCallback) + { + while (serviceInputCallback()) { } + WaitForInput(layoutSlot); + } + + void WaitForInput(int layoutSlot, Func serviceInputCallback, + Func autoWaitState) + => WaitForInput(layoutSlot, serviceInputCallback); + + void WakeInputCallbackService() { } + void InputCallbackCompleted(GfxState gfx) { } + + // Generic AGE input-callback services (ops 0xcc/0xcd, 0xfb/0xff/0x100, 0x108). + // Interactive hosts expose the same monotonic clock used by their frame scheduler. + long InputClockMilliseconds => Environment.TickCount64; + + void SetCursorResource(long resourceId) { } + void ClearCursorResource() { } + + // Native 0x1c7/0x1cc query two distinct ADV skip channels. Headless and non-interactive + // hosts default to normal playback; the Godot host supplies the live interactive values. + void SetMessageSkipActive(bool active) { } + + // Logical action 6 is the native hold-to-fast-forward channel. Keep it separate from the + // persistent op-0x88 channel so releasing the key cannot turn off the user's Skip toggle. + void SetPhysicalMessageSkipActive(bool active) { } + + bool IsMessageSkipActive => false; + + // Optional diagnostic override. Native ReadTextDB state is VM/profile-owned; interactive hosts + // normally leave this false. + bool IsAdvReadSkipActive => false; +}