Multiplayer Synchronization
Synchronization Techniques
code
┌─────────────────────────────────────────────────────────────┐ │ SYNC TECHNIQUES OVERVIEW │ ├─────────────────────────────────────────────────────────────┤ │ CLIENT PREDICTION: │ │ → Execute input locally before server confirms │ │ → Feels responsive, requires reconciliation │ │ Best for: FPS, action games │ ├─────────────────────────────────────────────────────────────┤ │ INTERPOLATION: │ │ → Display positions between known states │ │ → Smooth visuals, adds latency │ │ Best for: Other players, NPCs │ ├─────────────────────────────────────────────────────────────┤ │ ROLLBACK NETCODE: │ │ → Rewind game state on correction │ │ → Re-simulate with corrected data │ │ Best for: Fighting games, precise timing │ ├─────────────────────────────────────────────────────────────┤ │ LOCKSTEP: │ │ → All clients advance together │ │ → Deterministic, waits for slowest │ │ Best for: RTS, turn-based │ └─────────────────────────────────────────────────────────────┘
Client Prediction & Reconciliation
code
PREDICTION FLOW: ┌─────────────────────────────────────────────────────────────┐ │ Frame N: │ │ 1. Capture input │ │ 2. Predict result locally (immediate response) │ │ 3. Store input + predicted state │ │ 4. Send input to server │ │ │ │ Frame N+RTT: │ │ 5. Receive server state for Frame N │ │ 6. Compare with stored prediction │ │ 7. If mismatch: RECONCILE │ │ a. Snap to server state │ │ b. Re-apply all inputs since Frame N │ │ c. Smooth correction to avoid visual pop │ └─────────────────────────────────────────────────────────────┘
csharp
// ✅ Production-Ready: Prediction Buffer
public class PredictionBuffer
{
private const int BUFFER_SIZE = 128;
private readonly PredictionEntry[] _buffer = new PredictionEntry[BUFFER_SIZE];
public void Store(uint tick, InputPayload input, PlayerState predictedState)
{
int index = (int)(tick % BUFFER_SIZE);
_buffer[index] = new PredictionEntry
{
Tick = tick,
Input = input,
PredictedState = predictedState
};
}
public void Reconcile(uint serverTick, PlayerState serverState)
{
int index = (int)(serverTick % BUFFER_SIZE);
var entry = _buffer[index];
if (entry.Tick != serverTick) return; // Stale data
float error = Vector3.Distance(entry.PredictedState.Position, serverState.Position);
if (error < 0.01f) return; // Within tolerance
// Misprediction detected - reconcile
PlayerState currentState = serverState;
// Re-simulate all inputs since server tick
for (uint t = serverTick + 1; t <= CurrentTick; t++)
{
int idx = (int)(t % BUFFER_SIZE);
if (_buffer[idx].Tick == t)
{
currentState = SimulateInput(currentState, _buffer[idx].Input);
}
}
// Apply corrected state (with smoothing)
ApplyCorrectedState(currentState);
}
}
Interpolation
code
INTERPOLATION BUFFER: ┌─────────────────────────────────────────────────────────────┐ │ RECEIVE: [State T-100ms] [State T-50ms] [State T-now] │ │ │ │ RENDER: Display interpolated position between T-100ms │ │ and T-50ms based on current render time │ │ │ │ WHY: Always have two states to interpolate between │ │ (render behind real-time by buffer amount) │ │ │ │ BUFFER SIZE: │ │ • Too small: Choppy when packets delayed │ │ • Too large: Everything feels delayed │ │ • Typical: 100-200ms for other players │ └─────────────────────────────────────────────────────────────┘
Rollback Netcode
code
ROLLBACK FLOW (Fighting Games): ┌─────────────────────────────────────────────────────────────┐ │ 1. Execute frame with predicted opponent input │ │ 2. Store complete game state snapshot │ │ 3. When actual input arrives: │ │ a. If matches prediction: continue │ │ b. If mismatch: │ │ - Load snapshot from that frame │ │ - Re-simulate all frames with correct input │ │ - "Rollback" visual to corrected state │ │ 4. Hide rollbacks with animation tricks │ └─────────────────────────────────────────────────────────────┘ ROLLBACK LIMITS: • Max rollback: 7-8 frames (~116ms at 60fps) • Beyond: Game stutters or desyncs • Input delay trade-off: 0-3 frames pre-delay
Lockstep Synchronization
code
LOCKSTEP (RTS Games): ┌─────────────────────────────────────────────────────────────┐ │ Frame 0: All clients send inputs │ │ Wait for all inputs │ │ Execute deterministically │ │ │ │ Frame 1: Repeat │ │ │ │ REQUIREMENTS: │ │ • Deterministic simulation (fixed-point math) │ │ • Synchronized RNG seeds │ │ • Identical execution order │ │ │ │ PROS: Minimal bandwidth (only inputs) │ │ CONS: Latency = slowest player, input delay │ └─────────────────────────────────────────────────────────────┘
🔧 Troubleshooting
code
┌─────────────────────────────────────────────────────────────┐ │ PROBLEM: Visible rubber-banding │ ├─────────────────────────────────────────────────────────────┤ │ SOLUTIONS: │ │ → Increase interpolation buffer │ │ → Smooth reconciliation (lerp, not snap) │ │ → Add visual damping │ │ → Check for consistent tick rate │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ PROBLEM: Clients desyncing │ ├─────────────────────────────────────────────────────────────┤ │ SOLUTIONS: │ │ → Use fixed-point math │ │ → Sync random number seeds │ │ → Periodic full-state resync │ │ → Add state hash verification │ │ → Check floating-point determinism │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ PROBLEM: Too many rollbacks (fighting games) │ ├─────────────────────────────────────────────────────────────┤ │ SOLUTIONS: │ │ → Add input delay frames (1-3) │ │ → Better input prediction │ │ → Limit max rollback frames │ │ → Disconnect players with bad connections │ └─────────────────────────────────────────────────────────────┘
Technique Selection
| Game Type | Primary | Secondary | Latency Budget |
|---|---|---|---|
| FPS | Prediction | Interpolation | 50-100ms |
| Fighting | Rollback | Input delay | 50-80ms |
| RTS | Lockstep | - | 200-500ms |
| MMO | Interpolation | Prediction | 100-200ms |
| Racing | Prediction | Extrapolation | 50-100ms |
Use this skill: When building multiplayer systems, optimizing netcode, or fixing desync issues.