Skip to content

Spectator mode — development status & next steps #5

Description

@Vmarcelo49

Status: Code complete, pending runtime validation

All 5 phases of the spectator mode plan () are implemented and wired end-to-end, but never validated at runtime (requires Wine + MBAACC.exe).

What's done (code-level)

Phase Description Status
1 Protocol — message added to protocol ✅ Complete
2 Host-side — ported from CCCaster, integrated into NetworkThread ✅ Complete
2.5 NetworkThread integration — CONNECT/DISCONNECT handlers, re-enabled ✅ Re-enabled ()
3 Client-side — receives + + and replays ✅ Complete
4 Launcher/GUI — and GUI Spectate button working ✅ Complete
5 Relay spectate — via relay server ✅ Complete

Where we stopped

The spectator code was fully implemented in commits and (2026-07-14/15), including re-enabling the two DISABLERS that were blocking it in the network thread. Build is clean (MinGW cross-compile, zero warnings/errors).

What's missing is runtime validation — the feature has never been tested with actual Wine + MBAACC.exe.

Runtime validation matrix (pending)

  1. Regression test: host + join via localhost — must still work end-to-end (critical: previously caused a Wine regression)
  2. Direct spectate: host + join + 3rd instance as spectator via — spectator should receive SpectateConfig + InitialGameState + BothInputs stream and replay the match
  3. Relay spectate: — spectator connects via relay, host identifies as spectator, replay works
  4. Spectator disconnect mid-match — host's SpectatorManager removes spectator via , no crash, no impact on ongoing match
  5. Opponent disconnect mid-match with spectator connected — spectator should also be disconnected or notified

Known minor pendings (non-blocking for basic spectate)

  • SpectatorManager::step() detects pending spectator timeout but only does _pending.erase(peer) — no enet_peer_disconnect_later call. Relies on spectator's own client-side timeout.
  • frameStepRerun not adapted for spectator — may work as-is (spectator has no local inputs to predict), but needs runtime confirmation.
  • getInput() dispatcher has no explicit SpectateNetplay path — returns 0 by default (correct for spectator), but unverified at runtime.
  • SyncHash received by spectator is intentionally discarded — no desync detection for spectators by design.

Next steps

References

  • Full plan: docs/spectator-plan.md
  • Threading prerequisite: docs/threading-migration.md (Layer 4 — complete)
  • Key commits: 027d9ee (initial implementation), 3fd525e (re-enablement)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions