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)
- Regression test: host + join via localhost — must still work end-to-end (critical: previously caused a Wine regression)
- Direct spectate: host + join + 3rd instance as spectator via — spectator should receive SpectateConfig + InitialGameState + BothInputs stream and replay the match
- Relay spectate: — spectator connects via relay, host identifies as spectator, replay works
- Spectator disconnect mid-match — host's SpectatorManager removes spectator via , no crash, no impact on ongoing match
- 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)
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)
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)
Known minor pendings (non-blocking for basic spectate)
SpectatorManager::step()detects pending spectator timeout but only does_pending.erase(peer)— noenet_peer_disconnect_latercall. Relies on spectator's own client-side timeout.frameStepRerunnot adapted for spectator — may work as-is (spectator has no local inputs to predict), but needs runtime confirmation.getInput()dispatcher has no explicitSpectateNetplaypath — returns 0 by default (correct for spectator), but unverified at runtime.Next steps
References
docs/spectator-plan.mddocs/threading-migration.md(Layer 4 — complete)027d9ee(initial implementation),3fd525e(re-enablement)