Co-op Overview
In short
Co-op is turn-based: 2 to 4 friends play one run on one map. One player bats until they make an out, then the next player bats. The host referees (whose turn, team score, shared outs pool, round end); every machine keeps its own batter, upgrades, coins and shop. Traffic goes over Steam’s relay or local UDP. Rejoin is not built.
How it works
- On the title screen, switch the mode card to CO-OP and press PLAY CO-OP. This opens the lobby
(
GameState.Lobby). See Lobby and Session. - One player presses HOST A GAME, the others JOIN with the code. The host picks the map and difficulty and presses START RUN.
- Every machine builds the same 9-inning run from the host’s seed (see Seeds and Determinism and
Run Structure), but with its own batter, coins and upgrades (its own
RunState). - The host presses PLAY BALL! (ALL READY). Before the first inning everyone watches the match intro at their own pace; the first turn waits until all are through it (Cutscenes). Turns go round the batting order. The batter plays a normal at-bat (At-Bat Loop) on their own machine; everyone else watches it live (Live Spectating).
- When the team reaches the inning goal, the inning is cleared: everyone gets their own coins and opens their own shop, then presses READY. When the shared outs pool runs out, the run is over for everyone. The end-of-game cutscenes (BOSS DOWN!, MAP BEATEN!, GAME OVER) play on every screen from local state. See Co-op Rules and Co-op Run Flow.
What is shared and what is not:
| Shared (host decides) | Per player (own machine) |
|---|---|
| Map, difficulty, seed, batting order | Batter, cosmetics, batter level bonus |
| Team score per inning, outs pool | Coins, upgrades, shop offers, rerolls |
| Whose turn it is, inning cleared or failed | Stats used while batting (the batter’s own) |
| Ready state of the shop | Meta points, XP, unlocks at run end |
Architecture
flowchart LR subgraph Host["Host (player 0)"] HR["CoopRun (host side)<br/>owns CoopRules: order, outs pool,<br/>team score, round end, READY"] HS["NetSession (Host role)<br/>roster, version check, StartRun, relay"] HR --> HS end subgraph Client["Each client (players 1-3)"] CR["CoopRun (client side)<br/>own RunState, own shop"] AB["AtBatController<br/>bats on its turn,<br/>spectates otherwise"] CS["NetSession (Client role)"] CR --> AB CR --> CS end NR["NetRuntime<br/>polls once a frame"] T["INetTransport<br/>LocalTransport (UDP) or SteamTransport (relay)"] HS <--> T CS <--> T NR -.-> T
The network is a star: clients only talk to the host; the host relays a batter’s messages to the others. See Transports and Net Messages.
Built and not built
| Feature | Status |
|---|---|
| Lobby: LOCAL / STEAM, host, join by code, COPY / PASTE, 4 seats, batter pick, host map and difficulty pick | built |
Version check (protocol + Application.version) | built, see Protocol Versions |
| Turns, shared score, shared outs pool, opener rotation, second life | built |
| Own shops with READY chips; host starts the next inning when all are ready | built |
| Live spectating (pose stream, pitches, swings, results) | built |
Match intro with a team gate (IntroDone / IntroProgress, WAITING FOR NAME), opener’s walk-up | built |
| End-of-game cutscenes on every screen, each at its own pace (no messages) | built |
| Boss balls, arcing pitches and The Phantom’s decoys reach spectators | built (in AtBatPitch) |
| Steam overlay invites (INVITE FRIENDS) and “Join game” | built (works even if the lobby is on LOCAL) |
| A player leaving mid-run (turn passes without an out) | built |
| Host leaving ends the run for everyone | built |
Rejoin into a run in progress (Snapshot) | not built |
| Shop timer (plan: 90 s) | not built |
| Save and resume a co-op run | not built (CanSaveAndQuit is false) |
| Co-op leaderboard | not built (no leaderboard entry in co-op) |
| Map vote, rich presence, lobby avatars, real Steam app id | not built |
| Head-to-Head mode | registered, IsAvailable = false |
Numbers
| What | Value | Where to tune |
|---|---|---|
| Players | 2 to 4 (1 allowed in the Editor) | NetSession.MaxPlayers = 4; LobbyView START RUN check |
| Clients per host | 3 | LocalTransport.MaxClients, SteamTransport.MaxClients |
| Protocol | HRD-COOP-7 | NetSession.Protocol |
| Steam app id | 480 (Valve’s Spacewar test app) | SteamBootstrap.AppId, steam_appid.txt |
In the code
| File | What it does |
|---|---|
Assets/_Project/Scripts/Net/NetRuntime.cs | MonoBehaviour on GameRoot; owns the transport and NetSession, polls them in Update |
Assets/_Project/Scripts/Net/NetSession.cs | Lobby roster, version check, StartRun, routes ids 30+ to the run |
Assets/_Project/Scripts/Run/CoopRun.cs | CoopRun : IRunDriver: this machine’s side of the run, host refereeing, turns, spectating hooks |
Assets/_Project/Scripts/Run/CoopRules.cs | Pure referee logic (no Unity objects), tested headless |
Assets/_Project/Scripts/Run/IRunDriver.cs | What the map, shop, pause and run-over screens talk to; GameRoot.Run returns ActiveCoop or the solo RunManager |
Assets/_Project/Scripts/Modes/GameModes.cs | CoopMode (IsAvailable = true, description “Two to four batters take turns, one out each, and share one score.“) |
Assets/_Project/Scripts/Core/GameRoot.cs | EnterLobby, HookSession (starts CoopRun on RunStarting), JoinFromPlatform (Steam invites) |
Gotchas
GameModes.cs’s comment onIGameModestill says Co-op is “registered but not yet playable”. The code below it setsCoopMode.IsAvailable = true; the comment is stale.- The README’s folder table calls
Net/“Phases 0-3”; live spectating (phase 4) is also on main. - The dev menu’s RUN tools are solo only: in co-op it shows “Co-op runs are refereed by the host, so the run tools are solo only.”
- Anti-cheat is out of scope: the batter’s machine reports its own result and the host trusts it.
Related
- Lobby and Session: hosting, joining and the roster
- Co-op Rules: what the host referees, with numbers
- Co-op Run Flow: the whole run, step by step
- Live Spectating: how others watch the batter
- Net Messages: every message on the wire
- Transports: Local UDP and Steam relay
- Protocol Versions: the version check
- Steam Test Guide: how two people test over Steam
- Cutscenes: the intro gate and outros in co-op
- Game States and Screens:
LobbyandCoopWatchstates