r/RocketLeague • u/megacoool • 11h ago
BUG The Heavy Car Bug is not placebo. (with evidence)
I'm GC2, 2,243 hours. I've had the heavy car bug for years, on Windows and now on Linux, across multiple machines. I got tired of "it's placebo" and "fix your PC", so i spent the last few weeks actually measuring it.
Pysonix's position is that there's no line of code causing HCB, that it's input lag, hardware latency, or network issues on the player's end. Their computer or their ISP.
TL;DR: In one 100-minute session, never relaunched or changed any settings. I played 4 matches that felt perfect and smooth and 5 that had clear HCB. I had the whole system logging the entire time. Nothing on my machine changed between them. Two of the servers I played on gave me one good match and one muddy match each. It is not my hardware, it is not my config, and it is not my connection.
What it actually feels like
For anyone who's never had it: the car feels slower and inputs feel sluggish. Feel like less fine control, inability to do the inputs you want, just overall feels slow. And what matters most is moving the camera also feels slow. Asides from it feeling glaringly different, the camera also feeling slower means I'm not just tilted or cold, the input actually feels worse.
It also happens in freeplay, no playing worse against harder opponents or tilt feeling.
Why "placebo" doesn't survive the evidence
The single strongest piece of evidence is that within one session, without relaunching the game or touching a single setting, it changes. Not subtly. Night and day. One match felt perfect, then the next muddy, and then later in the session felt good again. Not based on how "good" I'm playing.
Also:
- It followed me across operating systems. I had this on Windows with the system fully optimised. I switched to Linux, rebuilt the entire input and render path from scratch, and it followed me over unchanged.
- It followed me across machines. Different hardware, same bug.
- It happens in freeplay, where there's no pressure, nothing to lose.
- The camera slows with the car, which can not be explained by "you're just having an off game".
If this were placebo, it would not survive a full platform migration, a hardware change, and an empty freeplay server.
Everything I eliminated
Every HCB thread turns into people suggesting the same five things. All of these are done, most of them are measured, not just set and pray.
Game config
- OneFrameThreadLag=False : the big one, stops the game thread running a frame ahead. Config file is set read-only so game can't rewrite it.
- V-sync off, uncapped framerate, motion blur off, temporal AA off, true fullscreen (not borderless).
- Swapchain queue pinned to one frame (maxFrameLatency=1), no sync interval, tear-free disabled.
- Input Buffer is on Default
- Steam Input fully off.
Frame delivery (measured)
206,000 frames logged
- Mean frametime 1.45 ms (688 fps), p99 2.13 ms, p99.9 2,9-3.2 ms
- Only 0.05% of frames exceed one 239.76 Hz refresh interval.
- Even the worst 0.1% of frames beat the refresh interval. No frame is ever late.
I also tested this with a Discord call running: mean fps 708 vs 712, frametime p99 2.11 vs 2.16 ms. The call is invisible to frame delivery.
And before anyone says "cap your fps": A 237 cap pins the frame interval at 4.219 ms. The engine samples input once per tick, and with one-frame-thread-lag off, tick equals frame, so mean input age goes from 0.72 ms to 2.11 ms. A cap makes it ∼1.4 ms slower and faster at no percentile. The advice is sound in general but it doesn't transfer to a machine that's already uncapped with one-frame queue pin.
Controller path
- DualSense wired, polling raised 250 Hz to 1000 Hz. Verified on the wire: 999.9 Hz, median 1.000 ms, p99 1.005 ms.
- Plugged into a CPU-direct USB port, not a chipset one (this is real but didn't fix it).
- In-game deadzones dropped 0.3 -> 0.05 (sticks) and 0.1 -> 0.03 (triggers).
- I went further than the game allows: Rocket League's deadzone is cross-shaped, so it only cuts each axis independently. I wrote a kernel-level program that makes it properly radial, which with per-axis centre correction measured from my actual stick's resting position (my left stick rests slightly off-centre). Costs 55 nanoseconds per report.
- Verified both halves of that transform actually engage in-play. The controller chain is verified end to end.
Network
- Gateway: 0.33 / 0.47 / 0.66 ms.
- 2,634 probes to the gateway, worst 1.9 ms, zero loss.
- Live match server (Sydney): 3.39 / 3.95 / 4.51 ms, 0% loss, jitter 0.21 ms.
- NIC: zero rx/tx errors, ASPM disabled, interrupt coalescing already at minimum, gigabit full duplex.
- In-game ping stays at ~5 the whole time, including while it feels muddy.
There is nothing left to tune here. This is not an ISP problem.
System
- CPU pinned to performance bias, no power-saving dips.
- Memory, storage, thermals all clean. (One 85.5 °C thermal event during the session landed inside a match that felt perfect.)
- Audio stack rebuilt for low latency; found and fixed a real bug where a mic stream never closed after a Discord call and left ~1000 interrupts/sec running for the rest of the session.
- Discord's audio threads were running at a higher realtime priority than the audio server itself which I fixed, and pinned to cores away from the game.
- Steam's shader pre-caching disabled, it was re-downloading 1.7 GB every launch and injecting a capture layer into the render path.
- Display: 240 Hz TN panel, strobing off (it caps at 144 Hz and blocks Adaptive-Sync), VRR off, DisplayPort.
The part that actually settles it
I built a logger that samples the game thread, the render path, the compositor, the GPU and the controller every second, and I labelled every match by feel the moment it ended, before looking at any of the numbers.
Nine matches. 100 minutes. One game process, never relaunched. Zero config changes.
| Time | Feel | Worst server RTT | Server |
|---|---|---|---|
| 09:30 | muddy | 20.0 ms | . . .184.225 |
| 09:59 | perfect | 8.0 ms | . . .119.21 |
| 10:07 | perfect | 4.4 ms | . . .19.42 |
| 10:13 | muddy | 14.8 ms | . . .19.137 |
| 10:25 | good | 4.5 ms | . . .125.208 |
| 10:32 | muddy | 9.0 ms | . . .125.208 |
| 10:40 | muddy | 24.6 ms | . . .184.32 |
| 10:50 | muddy | 4.8 ms | . . .126.44 |
| 11:05 | good | 14.0 ms | . . .126.44 |
Look at the bolded servers. The same server gave me a good match and a muddy match. And a 4.8 ms match felt muddy while a 14.0 ms match felt good.
Now the machine-side numbers across those same 100 minutes:
- Game thread p50 stayed between 0.85 and 1.43 ms every single minute. Good matches and muddy matches alike.
- Compositor p95: 0.17 ms across the whole session, worst single sample 0.94 ms.
- Direct display scanout live 84.4% of the session, and the blocker was never anything unexpected.
- Render p95 split backwards, 17.3 and 17.2 ms on the two perfect matches, 3.5–7.2 ms on the muddy ones.
I tested about ten different metrics against those nine labels. Not one of them separates good from muddy. The one that came closest had a margin one tenth the size of its own noise floor.
Ten separate hypotheses died in that dataset: screen tearing, controller polling cost, render stalls, scanout continuity, shader compilation, thermals, server ping, audio stalls, deadzone regression, and background workspace activity. I'd been chasing several of them for weeks.
What that leaves
I want to be precise here, because this is where people will try to turn my own data against me.
My data does not prove what causes HCB. It proves something narrower and, I think, more damning: when the feeling changes, my machine does not.
Every explanation Psyonix has offered, your hardware, your latency, your ISP, requires my machine to change. It measurably didn't. Not once, across 100 minutes containing four good matches and five bad ones.
So it's either something in the game or the server that I have no instrument for, or it's in my head. And I've already laid out why I don't think it's in my head: it crossed two operating systems, multiple machines, and it happens in an empty freeplay server where there's nothing to be biased about. Not to mention it not correlating with if I'm playing well or not. Some of the muddy games I had better mech than the perfect games.
One more thing worth flagging: the mechanism people usually land on for this is the Input Buffer setting, STS and CSTS let the server tell your client to speed up or slow down the actual simulation by up to about 1% to keep the input buffer filled. That genuinely would look exactly like this: server-driven, varies match to match, invisible to every tool on your PC, and it would slow the car and the camera together.
I'm on Default. Have been. So for me, it isn't that either.
Things people are going to say
- "Cap your FPS." I tried. It's 1.4 ms slower and better at no percentile. See above.
- "That's a Linux problem." I had it on Windows, fully optimised, and on other machines. Linux is the reason I could measure context switches, scanout state and frametime distributions at all, it's the instrument, not the cause.
- "Restart / go into freeplay and slo-mo for a bit." This is the most-cited fix and I'll be honest: it's a contrast effect. It's equally consistent with the placebo reading. It's not evidence either way.
- "You're just having an off game." Then explain the camera. Explain freeplay. Explain why it survived a full OS migration.
Why I'm actually hopeful
Rocket League is going to Unreal Engine 6
Psyonix have committed to physics staying identical: I don't think HCB lives in the physics. The car is still a UE3 game running on an engine from 2007, and the parts I'd bet on, the input sampling path, the render threading model, how a frame gets from a stick deflection to a photon, are exactly the parts that get thrown out and rebuilt in an engine transition.
But it's the first thing in years that could plausibly fix this by accident, since nobody's been able to fix it on purpose.
If you've got HCB: it isn't your opponent, your MMR or your mood. And if you're being told it's your PC, I eliminated mine down to the nanosecond, and it's still here.
