Skip to content
Home
Multiplayer Networking: Protocols, Prediction, and State Sync

Multiplayer Networking: Protocols, Prediction, and State Sync

Game Development Game Development 9 min read 1721 words Intermediate ExcellentWiki Editorial Team

Multiplayer networking is widely regarded as the most technically demanding area of game development. It requires balancing responsiveness, consistency, bandwidth, and cheating prevention across unpredictable network conditions. A player with 200 ms latency should have a playable experience alongside a player with 10 ms latency. This guide covers transport protocol trade-offs, client-server synchronization algorithms, bandwidth optimization, and netcode patterns used in production games, drawing on GDC networking talks and protocol documentation.

Transport Protocol Selection

The choice between TCP, UDP, and emerging protocols like WebTransport has profound implications for game feel and reliability.

TCP: Reliability at a Cost

TCP (Transmission Control Protocol) guarantees ordered, error-checked delivery. If a packet is lost, TCP buffers subsequent packets and retransmits the lost one before releasing the buffer. This creates head-of-line blocking: a single lost packet delays all following packets, even if they contain time-independent data. For this reason, TCP is unsuitable for real-time gameplay data like positions and inputs. Use TCP for non-time-critical data: chat messages, matchmaking requests, inventory transactions, and leaderboard updates. HTTP and WebSocket both run over TCP, making TCP the default for browser games that do not require frame-perfect precision.

UDP: Speed Without Guarantees

UDP (User Datagram Protocol) sends packets with no delivery guarantees: packets may be lost, duplicated, or arrive out of order. This lack of overhead makes UDP ideal for time-critical data where a late packet is worse than a lost packet. Game networking libraries build reliability on top of UDP by implementing their own acknowledgment and retransmission systems for specific packet types. The key insight: position updates every 33 ms do not need reliable delivery because a newer update replaces each one. The Unreal Engine networking documentation describes how the engine’s UDP implementation classifies channels into reliable and unreliable categories per connection.

WebTransport

WebTransport, standardized as a W3C Candidate Recommendation in 2024, provides UDP-like unreliable streams and TCP-like reliable streams over QUIC (Quick UDP Internet Connections). It is designed for browser-based real-time applications and is supported in Chromium-based browsers. WebTransport eliminates head-of-line blocking while providing connection migration (the IP address can change without dropping the connection). As of 2025, adoption is growing among browser-based multiplayer games, though native game engines still primarily use raw UDP.

Packet Structure and MTU

The Maximum Transmission Unit (MTU) on Ethernet is 1500 bytes. With IP and UDP headers (28 bytes), the payload that a game can send in a single UDP packet is 1472 bytes. Packets exceeding the MTU are fragmented at the IP layer, increasing the chance of loss: a single lost fragment drops the entire packet. Game networking best practice is to keep packets under 1200 bytes to comfortably fit within the MTU. The Source Engine’s packet format documented in Valve’s developer wiki shows how they compress player state into 20-60 byte packets using bit-packing and quantization.

Client-Server Synchronization

Input Pipeline Architecture

The client-server input pipeline has four stages: input sampling, prediction, transmission, and reconciliation. Input sampling captures player inputs each frame at the engine’s update rate. The prediction stage immediately applies the input to the local entity state. The transmission stage serializes the input into a packet and sends it to the server. The reconciliation stage, upon receiving a server snapshot, compares it with the predicted state and corrects discrepancies. Each stage has a timing budget: input sampling under 0.1 ms, prediction under 0.5 ms, serialization under 0.2 ms, reconciliation under 1 ms.

Snapshot Compression

Server snapshots contain the state of every relevant entity at a given time. Without compression, a snapshot for a 64-player shooter contains thousands of bytes. Compression strategies include quantization (encoding floats as uint16 or uint8 with known ranges), delta compression (sending only changed values since the last snapshot), and implicit state derivation (sending only inputs, letting clients derive state). Unreal’s networking manual explains that replicated properties use delta compression by default, sending only changed properties since the last update.

Delta Compression Algorithms

Delta compression stores a baseline full snapshot every 5-10 frames and sends only deltas between frames. The delta is computed by XORing the current bits with the baseline bits. If the player’s position changed by (1.5, 0.3, 0.0), the delta encodes only those two differences rather than resending the full 12-byte vector. For a typical entity with 8 replicated properties, delta compression reduces per-entity bandwidth from 100+ bytes to 10-30 bytes per update. The Netcode for GameObjects documentation describes how NetworkVariable implements automatic delta compression for supported types.

Interest Management

In a game with 100 players, each player does not need updates about all 99 others. Interest management limits entity updates to only those relevant to each client.

Distance-Based Interest Management

Each client receives updates for entities within a configured radius, typically 100-500 meters depending on game scale. Entities outside this radius are not replicated. This reduces bandwidth from O(NM) to O(NK) where K is the average entities in range (typically 10-30). Distance-based interest management is the simplest and most widely used approach, effective for battle royale and open-world games.

Priority and Bandwidth Allocation

Not all entities within range need equal update frequency. A distant enemy far outside engagement range can update at 5 Hz while a nearby enemy in combat updates at 30 Hz. Priority systems assign each entity an importance score based on distance, angle to camera, and recency of interaction. The server allocates bandwidth budget per client per frame, updating higher-priority entities first. The Battlefield series network system, described in DICE’s GDC 2011 talk, uses priority-based update scheduling with per-client bandwidth caps.

Relevance and Occlusion Culling

Entities behind walls, around corners, or on different floors need not be replicated at all. Server-side occlusion tests using the navmesh, spatial queries, or simple line-of-sight checks eliminate irrelevant updates. Zone-based partitioning divides the world into regions (rooms, floors, sectors) and only replicates entities within the same or adjacent region. Riot Games revealed that Valorant’s map is manually partitioned into zones, with each player receiving updates only for entities in their current zone and visible adjacent zones.

Netcode Implementation Patterns

Input Buffering and Batching

Sending individual packets per input frame every 16.6 ms at 60 FPS creates 60 packets per second per player, which is too many for efficient networking. Input buffering collects inputs over 33-50 ms and sends them in a single batch. The server buffers received inputs and processes them in order. This reduces packet count from 60/s to 20-30/s per player while adding minimal latency (the batch delay is offset by reduced packet processing overhead). The Valve networking documentation recommends 50 ms buffers for client inputs.

State Compression and Quantization

Quantization reduces floating-point precision to save bits. A position in a 1 km by 1 km world can be represented as a uint16 with 1.5 cm precision (65536 units covering 1000 meters). A quaternion for rotation compresses to 48 bits using smallest-three encoding: encode the index of the largest component (2 bits) and the three remaining components as 15-bit signed integers (45 bits). The Physics for Game Programmers talk at GDC 2018 demonstrated that players cannot perceive quantization errors below 5 cm or 1 degree of rotation for networked objects.

Latency Hiding with Buffering

The client maintains a jitter buffer of 50-150 ms of incoming snapshots. By rendering from the buffer rather than the latest snapshot, the client smooths out network jitter. A 100 ms buffer absorbs typical internet jitter (20-50 ms) with headroom. The trade-off is increased constant latency: the player sees the world as it was 100 ms ago. Adaptive buffer sizing adjusts the buffer depth based on measured jitter: increase during high jitter periods, decrease during stable connections.

Testing Multiplayer Netcode

Network Condition Simulation

Tools like Clumsy (Windows), Network Link Conditioner (macOS), and netem (Linux) simulate latency, packet loss, jitter, and bandwidth limits. Test with: 50 ms and 0% loss for excellent conditions, 100 ms and 1% loss for typical, 200 ms and 3% loss for poor, and 400 ms and 5% loss for edge cases. The Unreal Engine network simulation settings replicate these conditions without external tools via console variables.

Regression Testing with Record and Replay

Record a full multiplayer session including all inputs, random seeds, and server timestamps. Replay the recording after code changes to verify that the deterministic simulation produces identical results. Desync detection compares client and server state CRC checksums. The For Honor networking team at Ubisoft described their record and replay regression system at GDC 2019, catching 90% of desync bugs before public builds.

Geographic Playtesting

Test with players in different geographic regions. Use cloud-hosted server instances in US East, US West, Europe, and Asia. Measure per-region metrics: median ping, 95th percentile ping, packet loss rate, and jitter. Regional testing frequently reveals issues invisible in local testing, such as route-specific packet loss or server tick spikes under load.

For a broader view of multiplayer game architecture, see Multiplayer Game Development. For engine-specific networking, consult Unity Guide.

Frequently Asked Questions

Q: How do I choose between TCP and UDP for my multiplayer game? A: Use UDP for all real-time gameplay data (positions, inputs, actions). Use TCP for chat, inventory, matchmaking, and leaderboard updates. Never use TCP for player movement because head-of-line blocking makes movement appear stuttery under packet loss.

Q: What is the ideal server tick rate for a competitive shooter? A: 128 ticks per second for competitive play (CS:GO, Valorant). 64 ticks per second for casual play. Higher tick rates increase server CPU cost linearly (2x cost for 2x rate) and require client interpolation to fill gaps.

Q: How do I handle NAT traversal for peer-to-peer games? A: Use STUN to discover public IP and port, then TURN as a fallback when symmetric NAT blocks direct connection. Libraries like SteamNetworkingSockets and ENet handle NAT traversal automatically.

Q: What causes rubber-banding in multiplayer games? A: Rubber-banding occurs when the client’s predicted position is repeatedly corrected by the server. Common causes: high jitter, low server tick rate, or overly aggressive reconciliation that does not smoothly interpolate corrections.

Q: How much bandwidth does a multiplayer game need? A: A well-optimized 64-player shooter uses 5-20 KB/s per client upstream and 30-100 KB/s downstream. Voice chat adds 8-32 KB/s per speaking player. A 32-player strategy game uses 2-5 KB/s per client for state updates.

For a comprehensive overview, read our article on 2D Game Development Guide.

For a comprehensive overview, read our article on 3D Game Development Guide.

Section: Game Development 1721 words 9 min read Intermediate 756 articles in section Report inaccuracy Back to top