Networking · July 6, 2026
Online Co-Op Netcode for Shmups: Latency, Desync, and Drop-In Play
Local co-op on a shared screen is forgiving: both players see the same frame at the same instant. Move that same two-player run across the internet and every assumption about synchronized state has to be rebuilt from scratch.
Published July 6, 2026
A bullet-hell shmup is a bad candidate for the rollback-and-predict techniques that fighting games rely on, because the screen can hold hundreds of independently moving objects rather than two characters with a handful of inputs each. Rolling back and resimulating hundreds of bullets every time a late packet arrives is expensive, and the visual snap when a predicted bullet pattern corrects itself is far more jarring than a fighting game's frame of input correction. Most small teams shipping online co-op shmups land on one of two simpler models instead: authoritative host simulation, or full lockstep with a fixed simulation tick.
Host-authoritative simulation is the easier path to ship first
In this model, one player's machine (usually whoever created the lobby) runs the real simulation — enemy spawns, bullet patterns, collision, scoring — and streams a compressed snapshot of relevant state to the other player every tick or two. The remote client renders what it's told and sends its own input back to the host. This sidesteps determinism entirely: the two machines never need to agree on floating-point math or RNG sequencing, because only one of them is actually deciding what happens. The tradeoff is that the non-host player experiences everything through an extra round trip of latency, which is noticeable but survivable in a genre where reaction windows are already tuned around player skill rather than twitch-perfect precision. Bandwidth is the real constraint here — a bullet-hell stage can have far more moving entities than a handful of players, so snapshot compression (delta-encoding positions against the previous tick, culling off-screen bullets from the payload) matters more than it would in a lower-density genre.
Lockstep keeps both machines honest but punishes any hitch equally
The alternative is to run the identical deterministic simulation on both machines, exchanging only inputs rather than state, the same approach covered from the competitive side in versus mode netcode for indie shmups. For co-op this is attractive because both players get equal latency treatment — nobody is "the host" experiencing an advantage — but it requires the exact bit-for-bit determinism discussed there, and a single player's connection hiccup stalls the whole run for both of them rather than degrading gracefully. That stall-on-hitch behavior is usually the deciding factor against lockstep for a cooperative mode: two friends playing together tend to tolerate an occasional half-second freeze far less patiently than two strangers in a ranked match, because there's no competitive stake to justify the wait.
Desync detection has to exist even if you never expect to need it
Whichever model is chosen, ship a checksum comparison — hash the relevant simulation state (score, entity count, RNG cursor position) every few seconds and compare it between clients. When it's a host-authoritative design this is a sanity check that catches serialization bugs early; in lockstep it's the only reliable signal that something has silently drifted, because the visible symptom of desync (players seeing different bullet layouts) often doesn't show up until well after the actual divergence happened. Log the mismatch with enough context — tick number, both hash values — to actually debug it later, because "desync happened somewhere in a three-minute stage" without that data is nearly unreproducible.
Design drop-in and drop-out before launch, not after complaints
Co-op runs get interrupted — a router hiccups, a player alt-tabs too long and the connection times out, someone just needs to step away. Decide up front what happens to the run: does it pause for the whole party, continue solo with the departed player's ship parked safely off-screen, or end the session entirely? Each choice has real design consequences. Pausing a bullet-hell stage indefinitely while waiting for a reconnect is generous to players but awkward if the reconnect never comes; auto-continuing solo is smoother but needs the game to handle a suddenly-empty second player slot without leaving orphaned pickups or a broken split-screen layout. Whatever the choice, surface it clearly in the UI the moment a disconnect happens — a silent stall with no explanation is the fastest way to make players assume the game itself has crashed. The general architecture question of how ownership and state authority move between clients is one that Valve's Steamworks networking documentation covers well even outside the Steam-specific plumbing, and it's worth reading before committing to a model.
None of this needs to be more elaborate than the game requires. A two-player co-op shmup with a modest bullet count can get away with a simpler host-authoritative setup than a four-player horde mode would need, and it's worth prototyping the actual worst-case entity count on a real internet connection — not a LAN — before deciding the architecture is solid enough to build the rest of the game on top of.