Implementing Mobile Game State Sync – Full Stack
State sync is the foundation of any multiplayer experience. The core problem: two devices must see the same game world at the same moment despite network latency, packet loss, and different compute power. There are several approaches, and the choice depends on genre. We implement full-stack sync: from protocol selection to testing under millisecond latency. For example, for a shooter, low latency and smoothness are critical, so we use client prediction and delta compression. For a turn-based strategy, event sourcing with fixed-point math suffices. Without proper architecture, players will face lag, desync, and progress loss.
What is State Sync in Mobile Games?
Sync is a mechanism that ensures data consistency between the server and all clients. Without it, multiplayer is impossible: players see different enemies, bullets fly through walls, progress is lost. The main dilemma: full accuracy requires bandwidth that mobile internet rarely provides. So we balance detail and traffic.
Snapshot vs State Delta vs Event Sourcing
Three main approaches to state distribution:
Full snapshot: the server sends the complete world state every N ms. Simple but wasteful. With 20 entities at 50 bytes each, 20 Hz – 20 KB/s per client. For 10 clients, the server sends 200 KB/s. Suitable for small games.
Delta compression: send only changes from the last acknowledged snapshot. The client confirms ack: last_received_tick, the server computes delta. Reduces traffic by 3-10x on dynamic scenes. Implementation is more complex: need to store state history for delta calculation, handle packet loss of a delta (without the base snapshot, delta cannot be applied).
Event sourcing: the server broadcasts events (PlayerMoved, BulletFired, EntityDied), the client replays them on top of the base state. Good for deterministic games: chess, card games, strategy. Bad for physics simulations: any float precision error diverges states within 30 seconds.
How Determinism Affects Sync?
For event sourcing, both platforms (iOS ARM64, Android ARM64/x86) must produce the same result from the same computations. Standard float in C# is deterministic on one platform but can give different results on different CPUs. Solution – fixed-point math: instead of float 1.5f, use FixedPoint 15000 (scale 1/10000). Addition and multiplication of integers are deterministic everywhere. Libraries: FixedMath.Net for Unity, libfixmath for native C++. Godot uses deterministic physics via _physics_process – all steps fixed. Unity Physics (DOTS) supports determinism with consistent object processing order. Classic Unity PhysX – not deterministic across platforms.
Why Fixed-Point Math Over Float for Sync?
Float can produce different results on different architectures due to rounding differences. Fixed-point guarantees determinism, critical for event sourcing. Additionally, fixed-point operations can be faster on some processors as they don't require hardware FPU. However, precision is lower: at 1/10000 scale, max error is 0.0001, acceptable for positions but may be insufficient for high-speed physics. We help choose the optimal format for your game.
Client-Side Prediction and Reconciliation
Detailed breakdown of the pattern for real-time games:
Client tick 100: apply input locally, send InputPayload{tick:100, input}
Client tick 101-110: continue predicting locally
Server: receive InputPayload{tick:100}, simulate, respond StatePayload{tick:100, pos, vel}
Client tick 112: receive server response for tick 100
→ Compare predicted state at tick 100 with server state
→ If discrepancy > threshold: rollback to server state at tick 100
→ Re-apply input buffer 101-112
The input buffer is a circular array of fixed size (typically 64-128 ticks). Each element: { tick, inputData, predictedState }. On reconciliation, iterate over buffer reapplying inputs. Threshold for reconciliation: non-zero. If 0.001 units discrepancy -> rollback -> client constantly jitters. Typical threshold: 0.1-0.5 units depending on character speed.
When is Interpolation Needed for Other Players?
Own character: client prediction. Other players: interpolation.
Client stores a buffer of snapshots with server timestamps:
[{time: 1000ms, pos: (10,0,5)}, {time: 1050ms, pos: (10.5,0,5)}, ...]
Rendering happens with an interpolation delay (usually 2-3 snapshots = 100-150 ms at 20 Hz). At render time, find two closest snapshots and linearly interpolate position:
float t = (renderTime - fromState.time) / (toState.time - fromState.time);
renderPosition = Vector3.Lerp(fromState.position, toState.position, t);
For rotation – Quaternion.Slerp. For speed – Hermite interpolation or Catmull-Rom over multiple points – smoother when changing direction.
How Client Prediction Reduces Latency?
Without prediction, the player sees latency equal to RTT/2 (time to server and back). With prediction, input is applied instantly, and the server only corrects. This cuts perceived latency by 2-5 times. For shooters, this is critical: even 50 ms latency is noticeable.
The Desync Problem
In deterministic games, desync doesn't appear immediately. Standard diagnosis: state hash comparison – every N ticks all clients send a hash of the current state to the server. If hashes don't match – desync, the server broadcasts a full snapshot for synchronization. The hash is computed from critical state fields (positions, HP, statuses) – not everything, to exclude irrelevant differences (animation weights, UI state).
How Mobile Internet Affects Sync?
Mobile internet is unstable. Design for worst case: 150 ms RTT, 5% packet loss, traffic budget 50 KB/s per player. Practical measures:
- Positions: int16 instead of float32 with scaling (50% savings)
- Rotation: quaternion → two int8 angles (75% savings)
- Entities out of sight: don't send or reduce update frequency
- Priority-based updates: fast-moving objects update more often
BitPacking libraries: NetStack (C#), LiteNetLib BitWriter – pack multiple small values into one byte.
How desync detection works in practice?
We implement state hash comparison once per second. On desync, the server sends a full snapshot to all clients for resync. Additionally, we use checksums for each packet to detect bit errors.What the Work Includes
| Stage | Deliverable | Duration (estimate) |
|---|---|---|
| Analysis | Sync protocol, traffic estimate | 3-7 days |
| Design | Architecture specification, stack selection | 5-10 days |
| Development | Sync implementation, client prediction, reconciliation | 30-60 days |
| Testing | Load testing, desync simulation | 7-14 days |
| Deployment | Integration with CDN/backend, monitoring | 5-10 days |
The cost is calculated individually based on complexity. Request a consultation – we'll evaluate your project in 1-2 days. Contact us – we'll tell you how to reduce latency and traffic.
Timelines
Snapshot sync with interpolation for 4-10 players: 2-3 weeks. Client prediction, reconciliation, delta compression, desync detection: 1.5-3 months. Deterministic simulation with fixed-point math: adds 3-6 weeks. Get in touch – we'll find the optimal solution for your budget.
Comparison of approaches:
| Approach | Traffic | Latency | Complexity |
|---|---|---|---|
| Snapshot | High | Medium | Low |
| Delta compression | Low | Low | Medium |
| Event sourcing | Medium | High | High |
Delta compression is 3-10x more efficient than snapshot in traffic, and event sourcing avoids server authority at the cost of complexity.







