Skip to content

Engine Decoupling — Phase 2: Headless adapter development #5

@JohnLudlow

Description

@JohnLudlow

Summary

Provide a minimal, dependency-free adapter for CI, deterministic tests, and server/headless runs.

Objective

Implement HeadlessAdapter that records render commands (no GPU), simulates input via scripted events, and provides deterministic execution for reproducible integration tests.

Implementation Status

Component Status Notes
HeadlessAdapter ✅ Complete Implements all Phase 1 contracts
HeadlessRenderProvider ✅ Complete Records sprites, texts, and meshes in separate typed lists
HeadlessInputProvider ✅ Complete Stateful, scriptable input (HashSet-based)
HeadlessUserInterfaceProvider ✅ Complete (stub) Empty pending UI contract finalisation
HeadlessAssetProvider + HeadlessAssetLoader ✅ Complete In-memory cache; stub loader
HeadlessAudioPlayer ⚠️ Bug Records calls but with stale method name strings ("Play"/"Stop" instead of "StartPlayback"/"StopPlayback")
RecordedCall DTO ✅ Complete
TestAdapter ⚠️ Partial Records lifecycle calls only; provider call recording not yet implemented
DeterministicEngineRunner ⚠️ Partial Frame loop runs; SimulationTime not exposed, RNG not accessible to callers, camera hardcoded
Integration test suite ❌ Not started No AI/combat/map-generation scenario tests exist

Technical Details

  • HeadlessAdapter implements IEngineAdapter and composes all headless providers. No native platform dependencies.
  • HeadlessRenderProvider records SubmitSprite, SubmitText, and SubmitMesh calls to separate typed lists (RecordedSprites, RecordedTexts, RecordedMeshes).
  • HeadlessInputProvider maintains scriptable key and mouse button state via sets of strings and integers.
  • HeadlessAudioPlayer records calls as (Method, AudioAssetId, Arg) tuples, but currently uses stale method name strings — fix tracked in docs/plans/phase-2-consistency-fixes.md.
  • TestAdapter wraps HeadlessAdapter and records adapter lifecycle calls (InitializeAsync, ShutdownAsync) to a call list. Provider call recording is not yet implemented — tracked in docs/plans/phase-2-completion.md.
  • DeterministicEngineRunner stores a fixed timestep and seeded RNG and runs a frame loop. It does not yet expose SimulationTime or a tick callback — tracked in docs/plans/phase-2-completion.md.

Requirements

  • (Not complete) Headless adapter passes integration scenarios for AI, combat and map generation.
    • GIVEN deterministic seeds and scenario scripts
    • WHEN CI runs integration suite
    • THEN results are stable and asserted by tests.

Outstanding Tasks

Acceptance Criteria

  • HeadlessAdapter implements all Phase 1 contracts.
  • Deterministic tick mode and seeded RNG supported. (Partial — runner exists but SimulationTime not exposed and RNG not accessible to callers)
  • Integration tests for AI, combat, and map generation scenarios pass.
  • TestAdapter available for recording and asserting adapter calls. (Partial — lifecycle calls only)
  • No native platform dependencies.

Dependencies

Parent: #2
Phase 1 interfaces: complete (#1)

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-libItems related to reusable librariesarea-technicalsystemsInternal systems to do with game developmentenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions