JoinGG

Ping, Interpolation and Rubber-Banding: Netcode for Players

Why you get shot behind a wall, why you rubber-band, and why a steady 60ms connection beats a jumpy 30ms one. The client side of netcode, explained.

SweetMask · 8 min read

You stepped behind the container. You saw the wall arrive between you and the other player. A fraction of a second later the kill feed says you are dead, and the killcam shows you standing in the open, side on, not even moving. Someone in chat types lag, someone else types the name of a cheat, and neither of them has it right.

Nearly everything that feels unfair in an online shooter comes out of three mechanisms that were all working exactly as designed. Learning their names is worth it because you stop blaming the wrong part, and stop changing settings that could never have helped.

The server half of this story is tick rate — how often the server advances the simulation and publishes a new picture of the world. That has its own article, Server Tick Rate Explained, and this piece is deliberately its other half. Tick rate is what the server does; what follows is what your own machine does in the gaps between those updates, and why it has to fib to you slightly to be playable at all.

1. Your own movement is a guess, and that is why it feels instant

Your client does not ask permission to move you. If it did, every step would arrive one full round trip after you pressed the key, and the game would be unplayable at anything other than a LAN ping.

Instead the client runs the same movement code the server runs, on the same input, and shows you the result immediately. This is client-side prediction, and Valve's networking documentation is blunt about the requirement: the client executes exactly the same rules the server will use when it eventually processes that command. Your W key moves you now; the server's agreement arrives later and is expected to match.

That is why your own character feels crisp on a 90ms connection while everyone else looks slightly syrupy. You are not seeing them predicted. You are seeing them replayed.

2. Everyone else on your screen is deliberately in the past

If your client drew each server snapshot the instant it landed, other players would visibly teleport, and one dropped packet would produce a stutter. So the client holds snapshots in a small buffer and renders other entities between two it already has. That is entity interpolation, and the price is a fixed delay.

On the Source engine the documented default was cl_interp 0.1 — one hundred milliseconds of view lag, applied even on a listen server where client and server are the same machine. In Counter-Strike 2 that family of commands is no longer yours to set; cl_net_buffer_ticks is the exposed control and it takes 0, 1 or 2 ticks of buffering. Zero is the right answer on a wired connection that is behaving.

The number matters less than the shape of it. Other players are always drawn somewhere they used to be. Not somewhere they might be — somewhere they demonstrably were.

3. The server rewinds time to judge your shot

If the server simply tested your bullet against where players are now, you would have to lead every target by your ping, and nobody would tolerate that. So the server keeps a short history — one second of positions and animation poses, on Source — and when it processes your fire command it winds the other players back to the moment you actually saw them.

Valve state the arithmetic directly:

Command Execution Time = Current Server Time − Packet Latency − Client View Interpolation

Note that the client's interpolation delay is in that subtraction: the server knows your client was showing you a slightly old world and corrects for it. It moves the other players back, runs the shot against those historical hitboxes, puts everyone back, and applies the result. That is lag compensation, and without it a high-ping player could not hit anything.

4. "Shot behind a wall" is two true stories, not one lie

Now put those three together from both sides of the same fight.

The shooter's client showed your model in the open — an accurate picture of where you were roughly a hundred milliseconds ago, plus their ping. They aimed at what was on their screen and clicked. Nothing they did was wrong.

Your client predicted your movement instantly, so on your machine you were behind the wall before you finished the key press. Nothing you did was wrong either.

The server, asked to arbitrate, rewinds to the shooter's view of the world, finds a clean hit, and awards it. You die behind cover.

Two players can give completely honest and completely contradictory accounts of the same fight, and the server can side with one of them without anybody having cheated. That is not a flaw in the netcode. That is the netcode.

This is usually called favouring the shooter, and it is a design choice rather than a law of physics. Riot published their own analysis of what it costs in VALORANT: they put the head start a peeking player gets over a defender at roughly 141ms in their baseline case, and reported cutting about 40ms off that through routing work, 128-tick servers and trimming client buffering. Valve went a different way in Counter-Strike 2, timestamping inputs so the server knows the exact instant you fired rather than rounding it to the next tick. Different games weigh the same trade-off differently. None of them make it disappear.

5. Rubber-banding is your prediction being overruled

Prediction only works while the client and server agree. When the server's authoritative position for you differs from your predicted one, the client has to reconcile. Small disagreements are smoothed out over a few frames and you never notice. Large ones snap, and that snap is the rubber band.

Three things commonly cause it. Packets from the server go missing, so your client keeps predicting forward with no correction, drifts, then receives a batch of updates that yank you back. The server itself falls behind — an overloaded host or a badly written script blocking the main thread means its simulation is running late, which on FiveM in particular is the usual culprit and is picked apart in Fixing FiveM server lag. Or the client and server genuinely disagree about the rules, which is what happens after a mod or engine change breaks a movement assumption, as in how a Valve update breaks CS2 community servers.

There is a fast test for which one you have. If everybody in the server rubber-bands at the same moment, it is the server. If it is only you, it is the path between you and it.

6. A stable 60ms beats an erratic 30ms, every time

This is the part most players have backwards. Ping is an average, and averages hide the thing that actually hurts you.

Buffers get sized for the worst recent case, not the typical one. A connection that sits at 30ms but spikes to 120ms four times a minute forces your client to either buffer more — adding view delay, which makes you more exposed to the mechanism in section 4 — or run the buffer dry, which means a frozen enemy followed by a correction. A connection parked at 60ms with a couple of milliseconds of variance never does either. It is predictably 60ms late, and both prediction and lag compensation handle predictable late perfectly well.

Packet loss is worse still, because a lost snapshot is not a delayed one. The client has nothing to interpolate towards, so it holds the last known position or extrapolates a guess, then reconciles hard when the truth arrives.

7. What you can actually change

In rough order of how often it turns out to be the answer:

Use a cable. The problem with Wi-Fi is not its average latency, which is often fine. It is the variance — airtime shared with neighbours, retransmits after interference, power-saving states. Variance is exactly what section 6 says you cannot afford.

Test for bufferbloat and fix it. When a download saturates your line, your router queues game packets behind megabytes of someone else's video. Run a latency-under-load test rather than a plain speed test, and if latency climbs sharply while loaded, turn on your router's SQM or QoS — fq_codel or cake if the firmware offers them — with the bandwidth limits set slightly below your real line speed. That is the single change most likely to stop mid-match rubber-banding on an otherwise fast connection.

Pick servers by measured ping, not by the flag. Latency follows routing, not geography; a server two countries away on a good transit path often beats a nearer one on a bad one, which is the owner-side version of the argument in choosing a region to host in. A directory narrows the field — JoinGG queries every listing every fifteen minutes over the game's own protocol and reports uptime and busiest hour, described at /methodology — but it measures from its own vantage point, not from your living room. It can tell you a server is genuinely up and genuinely busy. It cannot tell you your ping. Shortlist with it, then connect and read the number yourself; how to find the right server covers the rest.

Beyond that: close whatever is syncing in the background, and stop pasting network settings from videos. On modern builds most of the classic rate commands do nothing or are locked, and the survivors mostly let you add delay you did not want.

8. What is not yours to fix

Tick rate, host oversubscription, a plugin stalling the server thread, an update that changed the movement rules — none of those respond to anything you do at your end. If one community feels bad while your connection to everything else is clean, the answer is a different community. Browse /servers and try a few: Counter-Strike 2 listings are at /servers/game/cs2, and the 1.6 scene, still very much alive, at /servers/game/cs.

The point of knowing any of this is not winning arguments in chat. It is that once you can tell a prediction correction from a routing problem, you stop reinstalling drivers over something that was never on your machine.

Common questions

What value should be set for cl_net_buffer_ticks in CS2?
Zero is the right answer on a wired connection that is behaving properly. In Counter-Strike 2, this command controls entity interpolation buffering and accepts values of 0, 1, or 2 ticks.
How can you tell if rubber-banding is caused by the server or your own connection?
Look at whether other players are affected at the same time. If everybody in the server rubber-bands simultaneously, the issue is on the server; if it is only happening to you, the problem is your connection path.
Why does a stable 60ms ping perform better in matches than an erratic 30ms ping?
Predictable latency allows client-side prediction and lag compensation to function smoothly without forcing extra buffering. An erratic connection forces the client to increase its buffer delay or run dry, leading to frozen enemies and harsh position snaps.
Tags
netcodelatencypingmultiplayertroubleshooting
Share

SweetMask

Published · 8 min read

All articles

Keep reading