There is a lot of misconception going around the Left 4 Dead series about the “best” rate and interpolation settings. This article aims to explain the problem in detail and suggest tweaks to improve your game.
So what is this interpolation? Basically it’s a client-side method for drawing smooth movement between entity position updates from the server using the the gamestate you received XXms ago. Without interpolation, you would see everything teleport from location A to location B without any movement drawn in-between. This means that the interpolation value + your ping to the server is the exactly how much in the past thing are happening on your screen. While network latency is a common multiplayer synchronization issue, Source uses other methods to negate it’s downsides like lag compensation and motion prediction. Don’t worry about those as they’re doing their job pretty well, let’s just focus on the interpolation and rates.
The most important aspect of the L4D Source engine version is it’s internal 30 tick server limit. Valve most probably enforced this rule on purpose due to the increased amount of NPC entities on screen and the general habit of Source engine server owners to beef up their performance to the max, which would in many cases create a laggy experience for the average Player 1 (L4D is quite performance demanding even on default).
In effect, this means that the server simulates the game world only 30 times per second and therefore requires the client to interpolate heavily to achieve smooth entity movement because it receives only 30 updates per second. This limit is quite low for a game currently based on skeet whoring, heavy pounces and fast-moving Chargers. Any experienced player can tell you that the difference between 30 tick (L4D, L4D2) and 66 tick (CS:S, TF2) is night and day and 30 tick is nowhere near ego-driven serious gaming.
So what can really be done to push the performance a bit higher? First, let’s take a look at the vanilla netcode “out of the box” game settings:
cl_updaterate 20 cl_cmdrate 30 cl_interp_ratio 2 cl_interp 0.1 rate 10000
This means that the client receives data from the server 20 times per second, sends 30 commands per second and due to the fail-safe interpolation ratio 2 (which doubles interpolation to prevent netcode instability in cases where the world snapshot is lost), the client is pushed upwards to an ugly 100ms interpolation. However, since the vanilla servers should and in general do perform at ~28+ tick (and can even be pushed to static 30 with sm_cvar fps_max through SourceMod), there is no need to stay on 20 updates. The rate setting defines the bandwidth that the client can accept from a server, but it is enforced in vanilla Left 4 Dead to a maximum of 30000 bytes/second (roughly a 256kbps downstream, which is more than enough for all these tweaks). Therefore, the vanilla client interpolation can be greatly improved by just adjusting your rates to the said limit:
cl_updaterate 30 cl_cmdrate 30 cl_interp_ratio 2 cl_interp 0 rate 30000
This results in a 66.7ms interpolation and presents a 33% improvement over vanilla. cl_interp 0 doesn’t really turn off interpolation, it just limits it to the currently lowest available value. This is a setting that any average L4D player should use to improve his game experience. But what about them close-up skeets and stable dead stops? Let’s suck out the “max” out of the vanilla game then:
cl_updaterate 30 cl_cmdrate 30 cl_interp_ratio 1 cl_interp 0 rate 30000
By lowering the interpolation fail-safe ratio to 1 we get to a nice 33.3ms interpolation which is a major improvement over the vanilla 100ms and actually an entry-level setting for any serious competitive gamer. With a ratio of 1 however, every part of the Source netcode would have to perform perfectly to avoid choke and jittery entity movement, which is rarely the case.
Now let’s push this even further for the Rotoblin/Confogl crowd. Although the 30 tick limit is still present and the client won’t get any more updates than 30, setting the cl_updaterate to 100 (automatically limited to 60 on vanilla servers) will allow for half the client interpolation. Note that SourceMod is able to unlock the vanilla cl_updaterate beyond 60 for an even lower client interpolation and this setting will automatically adjust to the lowest possible cl_interp. This is where we get funky with a very noticable jittery movement on the NPC zombies, but NOT on the player controlled Special Infected as for some reason, their movement interpolation seems unaffected by the tick limit. This sets a nice 16.7ms interpolation on vanilla servers:
cl_updaterate 60 cl_cmdrate 30 cl_interp_ratio 1 cl_interp 0 rate 30000
Because your allowed min max rates and ratio are server limited and SourceMod is able to unlock this limit (Rotoblin, Confogl configs do that), you may as well set all the variables higher. You won’t really be sending/receiving more than 30 commands per second, but it will allow your interp to go as low as possible on both vanilla and modded servers:
cl_updaterate 100 // limited to 60 on vanilla servers cl_cmdrate 100 // still sending only 30 commands due to the tick lock cl_interp_ratio 0 // adjusted to the server allowed minimum cl_interp 0 // lowest possible calculation rate 30000
Keep in mind that the lower the interpolation, the closer the server hitboxes are synced to the on-screen models in you game, but that doesn’t mean that the lowest values are necessarily the best option for you personally. It is always a trade-off between smooth movement and better game response. Also when playing the Infected side, using higher interpolation can be more forgiving when connecting a pounce or landing a Tank punch (remember the lerp hacking Tanks?), so I wrote a little toggle that allows you to set 2 different rate setings that you prefer and can be used when switching sides (originally for Mr. Binswees):
cl_updaterate 100 cl_cmdrate 100 cl_interp 0 cl_interp_ratio 0 rate 30000 alias rates.sur "cl_interp 0" // >= 0ms alias rates.inf "cl_interp 0.0667" // 66.7ms alias rates1 "rates.sur; alias rates.toggle rates2" alias rates2 "rates.inf; alias rates.toggle rates1" alias rates.toggle rates1 bind XXX rates.toggle
Copypaste this in your autoexec.cfg, adjust the interpolation values to your preference, replace XXX with a bind of your choice and you’re good to go.
My personally preferred rates are as follows, since it feels like a good trade-off between hitbox sync and not so jittery common zombie movement:
cl_updaterate 100 cl_cmdrate 100 cl_interp_ratio 0 cl_interp 0.02 // 20ms rate 30000
More info on this specific topic can be found at:
Hope this helps, let me know!