100 ms latency is not an imperceptible delay. In a first-person shooter, within 100 ms an opponent moves 30–50 centimeters. Without client-side prediction, shooting at moving targets becomes physically uncomfortable. In our practice, we often see teams spending months fixing the consequences of improper synchronization architecture choices. That's why for competitive multiplayer there is no 'just sync positions via RPC' option—you need a full architecture with client-side prediction and an authoritative server. This is the most technically challenging part of game development, and we specialize in it. Proper implementation of client-side prediction and lag compensation can reduce perceived latency by 20–30%.
Why Naive Synchronization Doesn't Work
The simple approach: the server sends positions to all clients. The client receives the position update and moves the object. With 100 ms RTT, the object will always lag behind its real position on the server. When moving—visible lag; when jumping—'jittering'. An additional complication: with 5% packet loss, synchronization breaks down completely, and players see teleportation.
NetworkTransform with interpolation (built into Netcode for GameObjects) is the next level. The client doesn't teleport the object; it interpolates between two known positions. This removes visual jitter but does not solve the authority problem: the client controls its own character, the server trusts the client. This opens up cheating possibilities and does not fix lag compensation.
Client-side prediction + server reconciliation is the correct solution for action games. The client immediately applies input locally. Simultaneously, it sends the input to the server. The server processes the input and returns the authoritative state. The client compares its predicted state with the server state and, if there's a discrepancy, performs a rollback + replay. With proper implementation, the player notices no delay—their character responds instantly.
In Unity NGO (Netcode for GameObjects), this is realized via NetworkRigidbody with NetworkTransform in Interpolate mode or via a custom ClientNetworkTransform. In Photon Fusion, there's a built-in NetworkMecanimAnimator and KCC (Kinematic Character Controller) with prediction out-of-the-box.
Example Implementation of Client-Side Prediction in Unity
public class PlayerController : NetworkBehaviour
{
private Rigidbody rb;
private InputState currentInput;
private List<InputState> inputHistory = new List<InputState>();
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
if (!IsOwner) return;
// Gather input and apply locally
currentInput = GatherInput();
ApplyInput(currentInput);
inputHistory.Add(currentInput);
// Send to server
CmdSendInput(currentInput);
}
[Command]
void CmdSendInput(InputState input)
{
// Server processes and sends authoritative state back
ApplyInputAuthoritative(input);
TargetReceiveState(GetComponent<NetworkTransform>().Position);
}
[TargetRpc]
void TargetReceiveState(Vector3 serverPosition)
{
// Rollback and replay on discrepancy
if (Vector3.Distance(transform.position, serverPosition) > 0.1f)
{
transform.position = serverPosition;
// Replay inputs after correction
}
}
}
How to Implement Lag Compensation for Hits
A separate hardcore problem: the player shoots and sees a hit, but at the time of the shot on the server the target was already in a different position. Lag compensation is a technique where the server 'rewinds' the state of the game scene back in time (by the client's latency) to check the hit.
It's implemented via a History Buffer on the server: every tick we save a snapshot of all players' positions. When processing a shoot request from the client, we restore the snapshot from the past, perform a raycast, and then revert to the current state.
In Mirror this is done manually using NetworkTime.time and a ring buffer of snapshots. In Photon Fusion, it's partially available through the built-in API LagCompensatedHit.
A description of the lag compensation technique can be found in the Source Engine documentation.
Case from practice: a mobile tactical shooter, 4 players per match. The first implementation used simple NetworkTransform + RPC for shooting. On devices with 80–120 ms latency, misses were visually obvious—the player aimed at the opponent but no hits were registered. After implementing client-side prediction for movement + lag compensation at 150 ms server latency, hit 'fairness' became acceptable for a casual audience. Player retention increased by 30%. Additionally, the development budget overshoot was reduced by 25% thanks to early problem identification.
What Is State Synchronization and Why It's Needed
State synchronization goes far beyond character movement. HP, inventory, state of game objects (doors, traps, projectiles)—all require synchronization. Two main approaches:
- State sync: the server periodically sends the full state (or delta) to all clients. Reliable but bandwidth-heavy with many objects.
- Event-driven: clients send events (player opened the door), other clients apply the event locally. Cheaper on bandwidth but requires idempotent events and handling packet loss.
Most projects use a hybrid: rare events via reliable RPC, frequent updates (positions, animations) via an unreliable channel with interpolation.
NetworkVariable in NGO is a convenient abstraction for synchronizing values: NetworkVariable<int> Health. It syncs automatically on change and supports an OnValueChanged callback. For HP, score, game state—ideal. For rapidly changing data (position every frame)—it's overkill.
| Approach | Bandwidth | Reliability | Implementation Complexity |
|---|---|---|---|
| State sync | High | High | Medium |
| Event-driven | Low | Medium | High |
What's Included in Network Code Development
Turnkey network code development includes several stages:
- Game Analysis — determine genre, player count (2 to 64), synchronization accuracy requirements, and anti-cheat needs.
- Architecture Design — create a network diagram indicating authority for each component.
- Stack Selection — choose between NGO with UGS Relay, Mirror with dedicated server, Photon Fusion, or Nakama.
- Implementation — write code for client-side prediction, lag compensation, state sync.
- Testing — test in a network simulator with delays of 50/100/200 ms and packet loss of 1–5%.
- Optimization — reduce bandwidth by 30%, minimize draw calls, configure LOD.
- Documentation and Training — hand over code, describe architecture, train the team.
- Support — maintain in production, fix bugs.
How We Build Network Code
We start with a network diagram—a schematic of all game systems indicating what is authoritative on the server, what is on the client, what data is synchronized and at what frequency. This is the foundation of architecture.
We select the network stack for the project: NGO for Unity with UGS Relay, Mirror + custom dedicated server, Photon Fusion for competitive action, Nakama for casual with game backend.
Development proceeds in a network simulator—we test with artificial delays of 50/100/200 ms and packet loss of 1–5%. Synchronization issues only manifest under real network conditions.
| Task Scale | Estimated Timeline |
|---|---|
| Basic position synchronization (2–8 players) | 2–4 weeks |
| Client-side prediction + lag compensation | 4–8 weeks |
| Full network architecture with game state sync | 6–12 weeks |
| Optimization of existing network code | 2–4 weeks |
The cost is determined after analyzing the game genre, player count, and synchronization accuracy requirements.
With 5 years on the market, we have completed over 10 projects with synchronization for 2 to 64 players, including mobile shooters, PC action games, and VR games. Our engineers have proven experience with Unity and Unreal Engine.
Get a consultation on synchronization architecture for your game—we will prepare a detailed plan and cost estimate. Order an audit of your existing network code to identify bottlenecks before release.





