Extract ADV host contract

This commit is contained in:
gamer147
2026-08-03 11:04:35 -04:00
parent bd53989498
commit 281f37747a
4 changed files with 97 additions and 84 deletions

View File

@@ -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, 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 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, 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 and modal movie playback contracts. `engine/Age.Engine/Hosting/IGraphicsHost.cs` owns mutable surfaces,
behavior is unchanged. `engine/Age.Engine/Hosting/IGraphicsHost.cs` owns mutable surfaces, retained-range/frame retained-range/frame presentation, transitions, texture lifecycle, pixel capture/replace, draw, and size
presentation, transitions, texture lifecycle, pixel capture/replace, draw, and size contracts; `IHost` also contracts. `engine/Age.Engine/Hosting/IInputHost.cs` owns modal fullwidth entry, ADV waits/callback servicing,
inherits this focused surface without changing existing hosts. `engine/Age.Engine/Hosting/IInputHost.cs` owns input clock, cursor resources, and skip-state interaction. `engine/Age.Engine/Hosting/IAdvHost.cs` owns live and
modal fullwidth entry, ADV waits/callback servicing, input clock, cursor resources, and skip-state interaction; surface text, history presentation, ADV layout publication, message presentation settings, wait indicators, and
its required wait and overload/default chains remain unchanged. The neutral 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 `engine/Age.Engine/Model/MovieMaskTransitionRequest.cs` record carries movie mask work between the VM, host, and
retained graphics without making `Model` depend on `Hosting`. retained graphics without making `Model` depend on `Hosting`.
`engine/Age.Engine/Model/RgbaImage.cs` owns the format-independent packed RGBA image transported between SYS4 `engine/Age.Engine/Model/RgbaImage.cs` owns the format-independent packed RGBA image transported between SYS4

View File

@@ -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 its focused tests required new imports; record shape, editor defaults, wait overloads, and all runtime behavior
remain unchanged. Runtime validation remains green. 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 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 `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 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 ## 8. Immediate next step
Continue step 3 of the **codebase consolidation** maintenance slice: clarify runtime contracts without changing 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 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 established beneath `IHost`, shared graphics/input transport neutral, and graphics/input/ADV contracts now
the remaining ADV text/history/layout/presentation members into `IAdvHost` next. Preserve all required/default separated, move the unchanged `AdvWaitIndicatorConfig` and `DiagnosticMessage` declarations from `Hosting` to
members and existing hosts, leaving `IHost` as the unchanged aggregate runtime entry point. `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 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,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)
{
/// <summary>Select the current atlas frame. TerminalFrame is the exclusive native upper bound,
/// so SYSTEM4's value 12 addresses the twelve cells 0 through 11.</summary>
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);
}

View File

@@ -1,82 +1,9 @@
using Age.Engine.Model;
namespace Age.Engine.Hosting; 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)
{
/// <summary>Select the current atlas frame. TerminalFrame is the exclusive native upper bound,
/// so SYSTEM4's value 12 addresses the twelve cells 0 through 11.</summary>
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);
}
}
/// <summary>A synchronous AGE-owned diagnostic prompt after native body/context formatting.</summary> /// <summary>A synchronous AGE-owned diagnostic prompt after native body/context formatting.</summary>
public readonly record struct DiagnosticMessage(string Caption, string Text); 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);
} }