LockToSeat.cs
using Sandbox;
using System.Collections.Generic;
/// <summary>
/// Locks this GameObject to wherever it started - position and rotation
/// snap back every frame, and any velocity a Rigidbody/PlayerController
/// picked up gets zeroed out immediately. Use this for a seated/stationary
/// player that should never be pushed, shoved, or drift away from a fixed
/// spot, regardless of what physics forces act on it.
///
/// Also separately locks any bones you drag into "Locked Bones" (e.g.
/// the pelvis) to THEIR starting LOCAL position/rotation each frame -
/// this handles bone-level jitter from the animation rig's own partial
/// ragdoll/IK physics blending, which is a different problem than the
/// whole-body physics push the main lock above handles, and needs
/// resetting separately since it happens in local (bone-relative) space
/// rather than world space.
///
/// SETUP: Attach directly to the same GameObject as your PlayerController
/// (or Body, whichever one is actually moving/drifting). Drag "pelvis"
/// (and any other bones you see drifting) into the "Locked Bones" list.
/// </summary>
public sealed class LockToSeat : Component
{
[Property] public List<GameObject> LockedBones { get; set; } = new();
private Vector3 _anchorPosition;
private Rotation _anchorRotation;
private Rigidbody _rigidbody;
private PlayerController _playerController;
private readonly List<Vector3> _bonePositions = new();
private readonly List<Rotation> _boneRotations = new();
protected override void OnStart()
{
_anchorPosition = Transform.Position;
_anchorRotation = Transform.Rotation;
_rigidbody = Components.Get<Rigidbody>();
_playerController = Components.Get<PlayerController>();
_bonePositions.Clear();
_boneRotations.Clear();
foreach ( var bone in LockedBones )
{
if ( bone is null )
continue;
_bonePositions.Add( bone.Transform.LocalPosition );
_boneRotations.Add( bone.Transform.LocalRotation );
}
}
protected override void OnFixedUpdate()
{
Transform.Position = _anchorPosition;
Transform.Rotation = _anchorRotation;
if ( _rigidbody is not null )
{
_rigidbody.Velocity = Vector3.Zero;
_rigidbody.AngularVelocity = Vector3.Zero;
}
for ( int i = 0; i < LockedBones.Count; i++ )
{
var bone = LockedBones[i];
if ( bone is null )
continue;
bone.Transform.LocalPosition = _bonePositions[i];
bone.Transform.LocalRotation = _boneRotations[i];
}
}
}