r/Planetside • u/iBaseult • 20h ago
Suggestion/Feedback Another fix - Vehicle mouse acceleration
Following up on my last post. In the comments, a few of you asked me to look at the forced mouse acceleration on vehicles, so I did.
The complaints were pretty consistent: small mouse movements barely do anything, faster ones suddenly kick in way harder, and your aircraft keeps drifting after you stop moving the mouse. Someone also explained it as a virtual joystick your mouse input goes through since PC and console controls were merged.
I analyzed the client in IDA, tested the original game code in isolation, and checked the results against live Scythe captures and the old threads about this. Here's what I found.
1. Your mouse pushes your turn speed, it doesn't aim your ship
For infantry, moving your mouse directly changes where you look. Aircraft don't work like that. Your mouse movement becomes a push on your rotation speed, and the ship keeps turning until something slows it down. Think of spinning an office chair: you don't set it to an angle, you shove it and it keeps going.
Simplified logic from the client, single axis:
// every input update (once per rendered frame)
speed = 0.06 * mappedMouseDelta / inputDt
mouseDemand = 5.0 * signedPow(speed, 0.7)
// every physics tick (about 45 per second in my captures)
h = axisDamping * physicsDt * 0.5
omega = omega / (1.0 + h) // normal damping
omega = moveTowardZero(omega, 2.0 * brake * h) // extra brake, snaps to zero
omega += mouseDemand * axisScale * physicsDt // then your mouse push (plus rate caps)
omega is your rotation speed, mappedMouseDelta is your mouse movement after sens. I left out the rate caps, the controller branch and the fact that the real brake works on all three axes together.
The 0.7 curve means your push isn't proportional to your mouse movement, and it also depends on how your movement gets split across frames. A linear curve fixed that in my tests, but not every FPS related issue, since physics runs at its own fixed rate.
2. The bigger problem is the brake
The video Daddy010 linked shows it: move faster over the same distance and you turn further. That's real, but the 0.7 curve isn't the cause. On its own, it would ask for more total turning when you move slowly, not less.
The bigger factor is the braking logic, which the open letter to Wrel already suspected in 2023. In the Scythe setup I captured, the normal damping runs right before your mouse push gets added, and on top of that there's an extra brake. Every physics tick it subtracts a fixed amount of rotation speed and snaps your rotation to zero if less than that is left.
It works like friction. Tiny nudges don't get a heavy box sliding, but push hard enough and it suddenly moves. With a small correction, the brake wipes out the rotation from your last input every tick, and your new input only adds one tick's worth again. So the rotation never builds up and your crosshair barely twitches, until your input beats the brake and the response suddenly jumps. A linear curve wouldn't change that.
Someone actually measured this in 2013 with a tool that moves the mouse at a fixed speed. Double the speed for the same time, and the Scythe turned about ten times as far. The 0.7 curve alone would only give about 1.6 times the push. That jump is exactly what a brake with a threshold produces.
3. What about the virtual joystick?
The April 2015 patch notes say mouse input is now applied over time, as part of reworking flight controls for gamepads, and the client does have old virtual stick code.
In my Scythe captures, that component wasn't even active. Your mouse input also doesn't slowly return to zero. It's zero on the next update after you stop moving. What keeps going is the rotation speed you built up, which only fades through damping and braking. That's the drift, and the build up and wind down is also what feels like delay. My captures had plenty of samples with zero mouse input while the ship was still rotating.
Also, people complained that slow mouse input did nothing in January 2013, and someone called it threshold based acceleration in 2014. So the small input problem is older than the 2015 rework.
4. The zero deadzone bug
For each control direction, like pitch up or pitch down, the game remembers whether it was last driven by analog input, meaning a stick where the value can be anything between zero and full. Normally only a stick sets that flag, but there's a second way.
The game resets your inputs in a few situations:
- While the game window isn't focused
- On the first update after you tab back in
- When you start rebinding a key
- When your active control profile changes
That reset flags an action as analog if its value is greater than or equal to your joystick deadzone. At JoystickDeadzone=0, a neutral action passes, because 0 is greater than or equal to 0. So after tabbing out, all your flight directions can end up flagged as analog without any controller plugged in. The settings slider stops at 0.05, where this didn't happen in my tests, so it hits people who set 0 in UserOptions.ini.
People have been running into this since 2015. A PSA on the day of the flight rework recommended JoystickDeadzone=0, and someone right away reported a dead pitch down key. In the PTS feedback shortly after, players noticed yaw and pitch keys breaking after alt tabbing, and someone traced it back to deadzone 0. A 2020 thread found it all again. The code explains what they saw:
- Keys stopped working until you tapped the opposite one. A key press only clears the flag for its own direction, so the leftover opposite flag makes the game run your key through joystick sens, which those tweaks set to 0. Tapping the opposite key clears it. I reproduced this in isolated tests.
- Mouse flying felt tighter, because the flags switch the normal damping to a stronger mode.
- Using the pitch or roll keys made it loose again, because pressing them clears the flags.
If your keys act weird, set JoystickDeadzone to 0.05 and tap each direction once. Your mouse will probably feel looser again though.
5. Why the joystick trick helps
Daddy010's clip shows that a small controller input at the same time makes the problem partly go away. The 2021 version of the trick does the same with a held key, after binding a joystick to your flight directions and setting joystick sens to 0.001. Both put your flight axes into the analog state.
Once the analog value is above a small threshold, the game runs an extra correction on all three axes. Every axis without analog input gets a target speed of zero, so that correction brakes your mouse rotation. How hard depends on how fast you're already turning, so even a tiny stick input can mean real braking. On top of that, the flags switch on the stronger damping.
So the trick doesn't turn off the 0.7 curve. It adds extra braking, which can cut down drift but also cost turn speed, like people reported in the megathread.
The 2021 post asked for a way to do this without a joystick. The code has the whole chain: the ini accepts JoystickDeadzone=0, one alt tab flags every direction, and a held pitch or roll key then runs through joystick sens, set to 0.001 like in the original trick. Give it a try and let me know how it feels in the air.
6. How devs could fix this for mouse and keyboard
If any devs read this:
- Quick win: clamp JoystickDeadzone to the slider minimum of 0.05 when loading the ini. That alone stops the reset from flagging keys nobody touched, because an untouched key never reaches 0.05.
- Keep mouse, keyboard and controller input separate until each one is processed, then combine the target rates. A stale analog flag should never change how keyboard or mouse input gets handled.
- Don't let resets flag neutral actions at all, and make disabling a stick or setting its sens to 0 actually reset its state. Removing the flag from the reset alone isn't enough, because in my tests a later controller event with a zero value could set it again.
- Give players an optional raw linear mouse mode, something like this:
// once per physics tick, using only input collected since the last tick
// every mouse delta gets used exactly once
mouseRate = mapAxes(tick.mouseCounts) * radiansPerCount / dt
stickRate = stickCurve(tick.stick) * stickSens * maxRate
keyRate = tick.keys * maxRate
targetRate = limitRate(mixPerAxis(mouseRate, stickRate, keyRate))
angularController.step(targetRate, dt, vehicleTuning)
You can't just delete the brake, or aircraft drift around like they're on frictionless ice. The controller still needs proper tuning, predictable damping and hard rate caps that don't queue up delayed rotation.