← BACK_TO_LOGS
NETWORKING[2024.09.15] // 6 min read

Latency Compensation in Fast-Paced PvP

How we solved the peekers advantage using server-side rollbacks and client-side interpolation techniques without sacrificing visual fidelity.

NetworkingMultiplayerC#Unity

Latency Compensation in Fast-Paced PvP

In competitive multiplayer games, network latency is the enemy of fairness. The "peeker's advantage" — where the player who moves first sees the opponent before being seen — is a direct consequence of naive netcode.

The Problem

With a 100ms round-trip latency, a player's visual position is always behind their actual server position. When they peek a corner, the server knows they're visible but the opponent's client hasn't received that update yet.

Server-Side Rewind (Lag Compensation)

public class LagCompensator : MonoBehaviour {
    private const int HISTORY_SIZE = 32;
    private Queue<WorldSnapshot> history = new();

    public HitResult Raycast(Ray ray, float clientTime) {
        // Rewind world to client's perceived time
        var snapshot = GetSnapshot(clientTime);
        ApplySnapshot(snapshot);

        var hit = Physics.Raycast(ray, out RaycastHit info);

        // Restore present state
        RestoreSnapshot();

        return hit ? new HitResult(info) : HitResult.Miss;
    }
}

Client-Side Interpolation

Smooth visual movement despite discrete server updates (20 ticks/sec → smooth 120fps visuals):

void Update() {
    float renderTime = Time.time - INTERPOLATION_DELAY;
    var (from, to, t) = GetInterpolationFrames(renderTime);
    transform.position = Vector3.Lerp(from.position, to.position, t);
    transform.rotation = Quaternion.Slerp(from.rotation, to.rotation, t);
}

Results

Implementing these systems in our PvP prototype eliminated 90% of "I shot first" complaints while keeping server authority intact. The perceived fairness improvement had a direct impact on player retention.

Conclusion

Lag compensation and interpolation are not optional for competitive games — they're table stakes. The complexity is worth every line of code.