phys_ragdollconstraint rotational friction is broken after the double-precision vphysics update
Summary
Since the 2026 update that switched vphysics.dll to the double-precision
(TF2-style) build, the rotational friction of phys_ragdollconstraint (created
in Lua via constraint.AdvBallsocket with onlyRotation = 1) no longer works
correctly. Friction is applied inconsistently: it engages on some rotation
angles/axes and not others, depending on the relative orientation of the two
physics objects at the moment the constraint is created. On the old
single-precision build the same constraint applied smooth, symmetric friction on
all three axes in both directions.
This breaks every tool/addon that relies on AdvBallsocket rotational friction,
including the Adv. Ball Socket STool and the Wire Clutch entity.
Affected
constraint.AdvBallsocket(... onlyRotation = 1 ...) → phys_ragdollconstraint
- Adv. Ball Socket tool (
ballsocket_adv)
- Wire Clutch (
gmod_wire_clutch)
- Any contraption using ragdoll-constraint rotational friction as a brake/clutch
Environment
- Garry's Mod build: 2026.06.02 (10069) (also reproduced on earlier 2026 builds)
vphysics.dll: double-precision build introduced in the 2026 update
- OS: Windows, single-player listen server
- Was working correctly before the double-precision change
Steps to reproduce (minimal, tool-only — no addons required)
- Spawn two identical props.
- Use the Adv. Ball Socket tool with:
- X / Y / Z Minimum = -180, X / Y / Z Maximum = 180
- X / Y / Z Friction = 100
- Free Movement = ON (onlyRotation)
- No-Collide = ON
- Connect the two props (try both a center-to-center connection and a
face-to-face / off-center connection).
- By hand, rotate one prop relative to the other around each axis and observe
the friction.
Observed behaviour
With all three friction values set equally (100), friction does not apply
uniformly:
- One axis (e.g. yaw, depending on connection) resists rotation in both
directions correctly.
- The other axes resist rotation only within a narrow band of rotation angle
and then stop resisting once rotated past it — friction "appears and
disappears" as the prop is turned.
- Changing the connection point changes which axis fails. A center
connection and a face-to-face connection kill different axes (e.g. face-to-face
makes the pitch axis stop following entirely, even through a full 360°).
- The friction magnitude is irrelevant: 0.1, 100, 6000, 600000 all show the
same pass/fail pattern. The dead band does not respond to friction value at
all — it behaves like a rotation limit, not friction.
Orientation dependence (key detail)
The failure is determined by the relative orientation of the two physics
objects at the moment the constraint is created, not by world angle:
- If the two props are at their exact intended relative orientation when the
constraint is created, friction bakes correctly and then stays correct for the
life of the constraint, regardless of how the assembly is later rotated or how
hard it is spun.
- If the relative orientation is off by even a fraction of a degree at creation
time (e.g. a vehicle that has fallen and settled on its suspension), the
friction bakes degenerate and only resists in a narrow angular band.
- The Precision Alignment tool, which forces an exact relative orientation
before constraining, produces correct all-angle friction — further confirming
the dependence is on creation-time relative orientation.
This strongly suggests the constraint's friction-axis frame is computed from the
relative orientation of the two bodies (dot-product based), and that the
double-precision math degenerates that computation for non-exact relative
orientations (similar in class to other double-precision regressions seen after
the update, where a value that should be 0 becomes a tiny negative number and
breaks a subsequent sqrt/normalize).
Real-world impact (Wire Clutch)
A Wire Clutch is used as a vehicle brake: one AdvBallsocket per wheel between
the wheel and a shared axle, onlyRotation = 1, friction driven by a Wire
input.
- Immediately after a dupe is pasted (props at exact relative orientation), the
clutch brakes correctly at any vehicle angle and stays working until friction
is set back to 0.
- After releasing the clutch (friction 0) and re-engaging once the vehicle has
fallen / the suspension has flexed, the brake only works in a narrow range of
wheel rotation and engages/releases as the wheel turns. The vehicle is then
effectively unbrakeable in most orientations.
Expected behaviour
phys_ragdollconstraint rotational friction (via AdvBallsocket with
onlyRotation = 1) should apply smooth, symmetric friction on all three axes in
both rotation directions, independent of the bodies' relative orientation at
creation time and independent of the connection point — as it did on the
single-precision build.
Notes / things ruled out (Lua-side workaround attempts that do NOT fix it)
For anyone hitting this and looking for a Lua workaround — these were tried and
do not restore correct friction, which is why this needs an engine fix:
- Re-creating the constraint with normalized prop angles.
- Editing friction in place via
SetKeyValue / Fire (engine ignores runtime
friction changes on an existing constraint).
constraint.Axis (phys_hinge): friction is symmetric, but it locks the other
two axes, so it welds the wheel to the axle instead of only adding resistance.
PhysObj:SetDamping angular damping: only slows the wheel's absolute spin, not
its spin relative to the axle — feels like spin reduction, not friction.
- Lua torque /
AddAngleVelocity / motion-controller PhysicsSimulate force
injection: this is force, not a constraint friction; it diverges or just
weakens the spin and is not true friction.
- Splitting friction across per-axis
AdvBallsockets with wide limits: the
angle-dependent dead band still occurs.
- Clamping the friction axis's limit (Precision-tool style): makes it work at
all angles, but it then behaves as a hard rotation limit (grips regardless of
friction value), not as adjustable friction.
The only thing that produces correct friction is creating the constraint while
the two bodies are at an exact relative orientation, which is not controllable in
the general (vehicle / dynamic) case — hence this is an engine-level regression
in the double-precision vphysics.dll.
phys_ragdollconstraint rotational friction is broken after the double-precision vphysics update
Summary
Since the 2026 update that switched
vphysics.dllto the double-precision(TF2-style) build, the rotational friction of
phys_ragdollconstraint(createdin Lua via
constraint.AdvBallsocketwithonlyRotation = 1) no longer workscorrectly. Friction is applied inconsistently: it engages on some rotation
angles/axes and not others, depending on the relative orientation of the two
physics objects at the moment the constraint is created. On the old
single-precision build the same constraint applied smooth, symmetric friction on
all three axes in both directions.
This breaks every tool/addon that relies on
AdvBallsocketrotational friction,including the Adv. Ball Socket STool and the Wire Clutch entity.
Affected
constraint.AdvBallsocket(... onlyRotation = 1 ...)→phys_ragdollconstraintballsocket_adv)gmod_wire_clutch)Environment
vphysics.dll: double-precision build introduced in the 2026 updateSteps to reproduce (minimal, tool-only — no addons required)
face-to-face / off-center connection).
the friction.
Observed behaviour
With all three friction values set equally (100), friction does not apply
uniformly:
directions correctly.
and then stop resisting once rotated past it — friction "appears and
disappears" as the prop is turned.
connection and a face-to-face connection kill different axes (e.g. face-to-face
makes the pitch axis stop following entirely, even through a full 360°).
same pass/fail pattern. The dead band does not respond to friction value at
all — it behaves like a rotation limit, not friction.
Orientation dependence (key detail)
The failure is determined by the relative orientation of the two physics
objects at the moment the constraint is created, not by world angle:
constraint is created, friction bakes correctly and then stays correct for the
life of the constraint, regardless of how the assembly is later rotated or how
hard it is spun.
time (e.g. a vehicle that has fallen and settled on its suspension), the
friction bakes degenerate and only resists in a narrow angular band.
before constraining, produces correct all-angle friction — further confirming
the dependence is on creation-time relative orientation.
This strongly suggests the constraint's friction-axis frame is computed from the
relative orientation of the two bodies (dot-product based), and that the
double-precision math degenerates that computation for non-exact relative
orientations (similar in class to other double-precision regressions seen after
the update, where a value that should be 0 becomes a tiny negative number and
breaks a subsequent
sqrt/normalize).Real-world impact (Wire Clutch)
A Wire Clutch is used as a vehicle brake: one
AdvBallsocketper wheel betweenthe wheel and a shared axle,
onlyRotation = 1, friction driven by a Wireinput.
clutch brakes correctly at any vehicle angle and stays working until friction
is set back to 0.
fallen / the suspension has flexed, the brake only works in a narrow range of
wheel rotation and engages/releases as the wheel turns. The vehicle is then
effectively unbrakeable in most orientations.
Expected behaviour
phys_ragdollconstraintrotational friction (viaAdvBallsocketwithonlyRotation = 1) should apply smooth, symmetric friction on all three axes inboth rotation directions, independent of the bodies' relative orientation at
creation time and independent of the connection point — as it did on the
single-precision build.
Notes / things ruled out (Lua-side workaround attempts that do NOT fix it)
For anyone hitting this and looking for a Lua workaround — these were tried and
do not restore correct friction, which is why this needs an engine fix:
SetKeyValue/Fire(engine ignores runtimefriction changes on an existing constraint).
constraint.Axis(phys_hinge): friction is symmetric, but it locks the othertwo axes, so it welds the wheel to the axle instead of only adding resistance.
PhysObj:SetDampingangular damping: only slows the wheel's absolute spin, notits spin relative to the axle — feels like spin reduction, not friction.
AddAngleVelocity/ motion-controllerPhysicsSimulateforceinjection: this is force, not a constraint friction; it diverges or just
weakens the spin and is not true friction.
AdvBallsockets with wide limits: theangle-dependent dead band still occurs.
all angles, but it then behaves as a hard rotation limit (grips regardless of
friction value), not as adjustable friction.
The only thing that produces correct friction is creating the constraint while
the two bodies are at an exact relative orientation, which is not controllable in
the general (vehicle / dynamic) case — hence this is an engine-level regression
in the double-precision
vphysics.dll.