Player/PlayerPickup.cs
public sealed class PlayerPickup : Component, IScenePhysicsEvents
{
	private const float PlayerUseRadius = 80.0f;
	private const float PlayerPickupMassLimit = 35.0f;
	private const float PlayerPickupSizeLimit = 128.0f;
	private const float PlayerPickupMassEstimateUnitVolume = 4096.0f;
	private const float PlayerPickupMassTrustRatio = 4.0f;
	private const float PlayerPickupError = 12.0f;
	private const float PlayerPickupHoldBase = 24.0f;
	private const float PlayerPickupAngularDamping = 10.0f;
	private const float PlayerPickupReducedMass = 1.0f;
	private const float PlayerPickupMaxSpeed = 1000.0f;
	private const float PlayerPickupMaxAngularSpeed = 62.83185f;
	private const float PlayerPickupDetachSpeed = 480.0f;
	private const float PlayerPickupDetachAngularSpeed = 12.56637f;
	private const float PlayerPickupAngleAlignment = 30.0f;
	private const float PlayerPickupDefaultPlayerHalfWidth = 16.0f;

	[RequireComponent] public Player Player { get; set; }

	[Sync( SyncFlags.FromHost )]
	public GameObject HeldObject { get; private set; }

	[ConVar( "player_throwforce", ConVarFlags.Cheat | ConVarFlags.Replicated | ConVarFlags.Server )]
	public static float PlayerThrowForce { get; set; } = 1000.0f;

	public bool IsHoldingObject => _isHoldingObject || HeldObject.IsValid();
	public bool IsBlockingWeaponInput => IsOwnerControllingPickup || _ownerSuppressInputUntilRelease;

	private readonly PlayerPickupController _pickupController = new();
	private bool _isHoldingObject;
	private bool _pickupEffectsActive;
	private bool _ownerIsControllingPickup;
	private bool _ownerSuppressInputUntilRelease;

	private bool IsOwnerControllingPickup => IsHoldingObject || _ownerIsControllingPickup;

	public bool OnControl()
	{
		if ( !Player.IsLocalPlayer )
			return false;

		if ( _ownerSuppressInputUntilRelease )
		{
			if ( !IsOwnerControllingPickup && !IsHeldInputDown() )
			{
				_ownerSuppressInputUntilRelease = false;
				return false;
			}

			ClearHeldInputs();
			return true;
		}

		if ( IsOwnerControllingPickup )
		{
			if ( IsDropInputPressed() )
			{
				_ownerSuppressInputUntilRelease = true;
				HostUseHeldObject( PickupUseType.Off );
			}
			else if ( IsThrowInputPressed() )
			{
				_ownerSuppressInputUntilRelease = true;
				HostUseHeldObject( PickupUseType.Throw );
			}

			ClearHeldInputs();
			return true;
		}

		if ( Input.Pressed( "use" ) && FindUseObject( out _, true ) )
		{
			_ownerIsControllingPickup = true;
			HostTryPickupObject();
			ClearHeldInputs();
			return true;
		}

		return false;
	}

	protected override void OnFixedUpdate()
	{
		base.OnFixedUpdate();

		if ( !Networking.IsHost )
			return;

		if ( !_pickupController.IsHoldingObject )
		{
			if ( IsHoldingObject )
				Shutdown();

			return;
		}

		if ( !HeldObject.IsValid() || !_pickupController.GetAttached().IsValid() )
			Shutdown();
	}

	void IScenePhysicsEvents.PrePhysicsStep()
	{
		if ( !Networking.IsHost )
			return;

		if ( !_pickupController.IsHoldingObject )
			return;

		var result = _pickupController.Use( PickupUseType.Set, Time.Delta );
		if ( result != PickupUseResult.KeepHolding )
		{
			FinishUseResult( result );
			return;
		}

		_pickupController.Simulate( Time.Delta );
	}

	void IScenePhysicsEvents.PostPhysicsStep()
	{
		if ( !Networking.IsHost )
			return;

		if ( !_pickupController.IsHoldingObject )
			return;

		_pickupController.FinishSimulate();
	}

	protected override void OnDisabled()
	{
		base.OnDisabled();

		if ( Networking.IsHost )
			Shutdown();

		StopPickupEffects();
	}

	[Rpc.Host]
	private void HostTryPickupObject()
	{
		if ( !IsCallerOwner() ) return;
		if ( _pickupController.IsHoldingObject || _isHoldingObject ) return;

		if ( !FindUseObject( out var body, false ) )
		{
			OwnerCancelPickup();
			return;
		}

		if ( !PlayerPickupObject( body, Rpc.Caller ?? Player.Network.Owner ) )
		{
			OwnerCancelPickup();
			return;
		}
	}

	[Rpc.Host]
	private void HostUseHeldObject( PickupUseType useType )
	{
		if ( !IsCallerOwner() ) return;

		FinishUseResult( _pickupController.Use( useType, Time.Delta ) );
	}

	private void FinishUseResult( PickupUseResult result )
	{
		if ( result == PickupUseResult.Throw )
		{
			var body = _pickupController.GetAttached();
			Shutdown();
			Launch( body );
			return;
		}

		if ( result == PickupUseResult.Drop )
			Shutdown();
	}

	private bool IsCallerOwner()
	{
		var owner = Player.Network.Owner;
		if ( owner is null ) return false;
		if ( Rpc.Caller == owner ) return true;

		return Networking.IsHost && Rpc.Caller is null && Connection.Local == owner;
	}

	private bool FindUseObject( out Rigidbody body, bool allowProxy )
	{
		body = null;

		var eyeTransform = Player.EyeTransform;
		var traceDistance = MathF.Max( PlayerUseRadius, Player.Controller.ReachLength );
		var trace = Scene.Trace.Ray( eyeTransform.Position, eyeTransform.Position + eyeTransform.Forward * traceDistance )
			.IgnoreGameObjectHierarchy( Player.GameObject.Root )
			.WithoutTags( "player", "playercontroller", "trigger", "ragdoll" )
			.Run();

		if ( !trace.Hit || trace.Body is null ) return false;
		if ( HasUsableComponent( trace ) ) return false;
		if ( trace.Component is not Rigidbody hitBody ) return false;

		if ( !CanPickupObject( hitBody, Rpc.Caller ?? Player.Network.Owner, allowProxy ) )
			return false;

		body = hitBody;
		return true;
	}

	private bool HasUsableComponent( SceneTraceResult trace )
	{
		var hitObject = trace.Collider?.GameObject ?? trace.GameObject;
		if ( !hitObject.IsValid() ) return false;

		Component foundComponent = default;
		PlayerController.IEvents.PostToGameObject( Player.GameObject, x => foundComponent = x.GetUsableComponent( hitObject ) ?? foundComponent );
		if ( foundComponent.IsValid() ) return true;

		if ( hitObject.GetComponents<IPressable>().Any() )
			return true;

		if ( hitObject.GetComponentInParent<IPressable>( true ) is not null )
			return true;

		return false;
	}

	private bool CanPickupObject( Rigidbody body, Connection grabber, bool allowProxy = false )
	{
		if ( !body.IsValid() ) return false;
		if ( body.IsProxy && !allowProxy ) return false;
		if ( !allowProxy && !body.PhysicsBody.IsValid() ) return false;
		if ( !allowProxy && !body.MotionEnabled ) return false;
		if ( !allowProxy && PlayerPickupController.IsPlayerStandingOnBody( Player, body ) ) return false;
		if ( IsHeldByPhysgun( body ) ) return false;

		var bounds = body.GetWorldBounds();
		var size = bounds.Size;
		if ( size.x > PlayerPickupSizeLimit || size.y > PlayerPickupSizeLimit || size.z > PlayerPickupSizeLimit )
			return false;

		if ( !allowProxy && GetPickupMass( body, bounds ) > PlayerPickupMassLimit )
			return false;

		var grabEvent = new IPhysgunEvent.GrabEvent { Grabber = grabber };
		body.GameObject.Root.RunEvent<IPhysgunEvent>( x => x.OnPhysgunGrab( grabEvent ) );
		return !grabEvent.Cancelled;
	}

	private static float GetPickupMass( Rigidbody body, BBox bounds )
	{
		var explicitMass = GetExplicitPickupMass( body );
		if ( explicitMass > 0.0f ) return explicitMass;

		var estimatedMass = EstimatePickupMass( bounds.Size );
		var liveMass = GetLivePickupMass( body );
		if ( !IsUsableMass( liveMass ) ) return estimatedMass;
		if ( estimatedMass <= 0.0f ) return liveMass;
		if ( liveMass > estimatedMass * PlayerPickupMassTrustRatio ) return estimatedMass;

		return MathF.Max( liveMass, estimatedMass );
	}

	private static float GetExplicitPickupMass( Rigidbody body )
	{
		if ( !body.IsValid() ) return 0.0f;

		var mass = 0.0f;
		foreach ( var properties in body.GameObject.Root.GetComponentsInChildren<PhysicalProperties>( true ) )
		{
			if ( !properties.IsValid() || properties.Mass <= 0.0f )
				continue;

			mass += properties.Mass;
		}

		return mass;
	}

	private static float GetLivePickupMass( Rigidbody body )
	{
		if ( !body.IsValid() ) return 0.0f;
		if ( body.PhysicsBody.IsValid() ) return body.PhysicsBody.Mass;

		return body.Mass;
	}

	private static float EstimatePickupMass( Vector3 size )
	{
		var volume = MathF.Max( size.x, 0.0f ) * MathF.Max( size.y, 0.0f ) * MathF.Max( size.z, 0.0f );
		return volume / PlayerPickupMassEstimateUnitVolume;
	}

	private static bool IsUsableMass( float mass )
	{
		return mass > 0.0f && !float.IsNaN( mass ) && !float.IsInfinity( mass );
	}

	private bool IsHeldByPhysgun( Rigidbody body )
	{
		if ( !body.IsValid() ) return false;

		var root = body.GameObject.Root;
		foreach ( var physgun in Scene.GetAllComponents<Physgun>() )
		{
			if ( !physgun.IsValid() ) continue;

			var state = physgun._state;
			if ( !state.IsValid() ) continue;
			if ( state.GameObject.IsValid() && state.GameObject.Root == root ) return true;

			var heldBody = state.Body;
			if ( !heldBody.IsValid() ) continue;
			if ( heldBody.GameObject.Root == root ) return true;
		}

		return false;
	}

	private bool PlayerPickupObject( Rigidbody body, Connection grabber )
	{
		if ( !CanPickupObject( body, grabber ) )
			return false;

		if ( !_pickupController.Init( Player, body ) )
			return false;

		HeldObject = body.GameObject;
		_isHoldingObject = true;
		OwnerStartPickup();
		return true;
	}

	private void Shutdown()
	{
		var wasHolding = _pickupController.IsHoldingObject || IsHoldingObject;

		_pickupController.Shutdown( false );
		HeldObject = null;
		_isHoldingObject = false;

		if ( wasHolding )
			OwnerStopPickup();
	}

	[Rpc.Owner]
	private void OwnerStartPickup()
	{
		_ownerIsControllingPickup = true;
		_ownerSuppressInputUntilRelease = false;
		StartPickupEffects();
	}

	[Rpc.Owner]
	private void OwnerStopPickup()
	{
		StopPickupEffects();
		_ownerSuppressInputUntilRelease = IsHeldInputDown();
		ClearHeldInputs();
	}

	[Rpc.Owner]
	private void OwnerCancelPickup()
	{
		_ownerIsControllingPickup = false;
		_ownerSuppressInputUntilRelease = false;
		ClearHeldInputs();
	}

	private void StartPickupEffects()
	{
		_pickupEffectsActive = true;

		var inventory = Player.GetComponent<PlayerInventory>();
		if ( !inventory.IsValid() ) return;

		inventory.ActiveWeapon?.HolsterForPickup();
	}

	private void StopPickupEffects()
	{
		_ownerIsControllingPickup = false;
		if ( !_pickupEffectsActive ) return;

		_pickupEffectsActive = false;

		var inventory = Player.GetComponent<PlayerInventory>();
		if ( !inventory.IsValid() ) return;

		inventory.ActiveWeapon?.Deploy();
	}

	private void Launch( Rigidbody body )
	{
		if ( !body.IsValid() ) return;
		if ( body.IsProxy ) return;
		if ( !body.PhysicsBody.IsValid() ) return;

		var massFactor = body.PhysicsBody.Mass.Clamp( 0.5f, 15.0f ).Remap( 0.5f, 15.0f, 0.5f, 4.0f );
		var force = Player.EyeTransform.Forward * PlayerThrowForce * massFactor;

		body.ApplyImpulse( force );
		body.PhysicsBody.ApplyAngularImpulse( Vector3.Random * 10.0f * massFactor );
	}

	private static void ClearHeldInputs()
	{
		Input.Clear( "use" );
		Input.Clear( "attack1" );
		Input.Clear( "attack2" );
		Input.Clear( "drop" );
		Input.MouseWheel = default;
	}

	private static bool IsDropInputPressed()
	{
		return Input.Pressed( "use" ) || Input.Pressed( "attack2" ) || Input.Pressed( "drop" );
	}

	private static bool IsThrowInputPressed()
	{
		return Input.Pressed( "attack1" );
	}

	private static bool IsHeldInputDown()
	{
		return Input.Down( "use" ) || Input.Down( "attack1" ) || Input.Down( "attack2" ) || Input.Down( "drop" );
	}

	private enum PickupUseType
	{
		Set,
		Off,
		Throw
	}

	private enum PickupUseResult
	{
		KeepHolding,
		Drop,
		Throw
	}

	private sealed class PlayerPickupController
	{
		private readonly GrabController _grabController = new();
		private Player _player;

		public bool IsHoldingObject => _grabController.IsAttached;

		public bool Init( Player player, Rigidbody body )
		{
			Shutdown( false );

			if ( !player.IsValid() ) return false;
			if ( !body.IsValid() ) return false;
			if ( !body.PhysicsBody.IsValid() ) return false;

			_player = player;
			_grabController.SetIgnorePitch( true );
			_grabController.SetAngleAlignment( PlayerPickupAngleAlignment );
			_grabController.AttachObject( player, body );
			return true;
		}

		public void Shutdown( bool clearVelocity )
		{
			_grabController.DetachObject( clearVelocity );
			_player = null;
		}

		public PickupUseResult Use( PickupUseType useType, float delta )
		{
			var attached = _grabController.GetAttached();
			if ( !attached.IsValid() || useType == PickupUseType.Off || _grabController.ComputeError() > PlayerPickupError )
				return PickupUseResult.Drop;

			if ( !attached.PhysicsBody.IsValid() || !attached.MotionEnabled )
				return PickupUseResult.Drop;

			if ( useType == PickupUseType.Throw )
				return PickupUseResult.Throw;

			if ( useType == PickupUseType.Set && !_grabController.UpdateObject( _player, PlayerPickupError, delta ) )
				return PickupUseResult.Drop;

			return PickupUseResult.KeepHolding;
		}

		public void Simulate( float delta )
		{
			_grabController.Simulate( delta );
		}

		public void FinishSimulate()
		{
			_grabController.FinishSimulate();
		}

		public Rigidbody GetAttached()
		{
			return _grabController.GetAttached();
		}

		public static bool IsPlayerStandingOnBody( Player player, Rigidbody body )
		{
			if ( !player.IsValid() || !body.IsValid() ) return false;
			if ( !player.Controller.IsValid() ) return false;

			var groundObject = player.Controller.GroundObject;
			if ( !groundObject.IsValid() ) return false;

			var root = body.GameObject.Root;
			return groundObject == body.GameObject || groundObject == root || root.IsAncestor( groundObject );
		}
	}

	private sealed class GrabController
	{
		private Rigidbody _body;
		private Vector3 _targetPosition;
		private Rotation _targetRotation;
		private Vector3 _targetVelocity;
		private bool _hasTargetVelocity;
		private Rotation _attachedAnglesPlayerSpace;
		private Vector3 _attachedPositionObjectSpace;
		private float _distanceOffset;
		private float _angleAlignment;
		private float _savedAngularDamping;
		private float _savedMass;
		private bool _savedInterpolation;
		private bool _savedImpactDamageEnabled;
		private bool _savedUseController;
		private bool _massWasReduced;
		private bool _ignoreRelativePitch;
		private float _errorTime;
		private float _error;

		public bool IsAttached => _body.IsValid();

		public Rigidbody GetAttached()
		{
			return _body;
		}

		public void SetIgnorePitch( bool ignore )
		{
			_ignoreRelativePitch = ignore;
		}

		public void SetAngleAlignment( float angleAlignment )
		{
			_angleAlignment = angleAlignment;
		}

		public void AttachObject( Player player, Rigidbody body )
		{
			DetachObject( false );

			_body = body;
			_savedAngularDamping = body.AngularDamping;
			_savedInterpolation = body.GameObject.Network.Interpolation;
			_savedImpactDamageEnabled = body.EnableImpactDamage;

			body.AngularDamping = PlayerPickupAngularDamping;
			body.GameObject.Network.Interpolation = false;
			body.EnableImpactDamage = false;
			body.MotionEnabled = true;

			if ( body.PhysicsBody.IsValid() )
			{
				_savedUseController = body.PhysicsBody.UseController;
				_savedMass = body.PhysicsBody.Mass;

				if ( _savedMass > PlayerPickupReducedMass )
				{
					body.PhysicsBody.Mass = PlayerPickupReducedMass;
					_massWasReduced = true;
				}
			}

			var bodyTransform = body.WorldTransform.WithScale( 1.0f );
			var center = body.GetWorldBounds().Center;
			_attachedPositionObjectSpace = bodyTransform.PointToLocal( center );
			_attachedAnglesPlayerSpace = TransformAnglesToPlayerSpace( bodyTransform.Rotation, player );

			if ( _angleAlignment != 0.0f )
				_attachedAnglesPlayerSpace = _attachedAnglesPlayerSpace.Angles().SnapToGrid( _angleAlignment );

			_distanceOffset = 0.0f;
			_errorTime = -1.0f;
			_error = 0.0f;

			SetTargetPosition( center - bodyTransform.Rotation * _attachedPositionObjectSpace, bodyTransform.Rotation );
			UpdateObject( player, PlayerPickupError, Time.Delta );
		}

		public void DetachObject( bool clearVelocity = false )
		{
			if ( _body.IsValid() )
			{
				_body.AngularDamping = _savedAngularDamping;
				_body.GameObject.Network.Interpolation = _savedInterpolation;
				_body.EnableImpactDamage = _savedImpactDamageEnabled;

				if ( _body.PhysicsBody.IsValid() )
				{
					_body.PhysicsBody.UseController = _savedUseController;

					if ( _massWasReduced )
						_body.PhysicsBody.Mass = _savedMass;

					if ( clearVelocity )
					{
						_body.PhysicsBody.Velocity = Vector3.Zero;
						_body.PhysicsBody.AngularVelocity = Vector3.Zero;
					}
					else
					{
						_body.PhysicsBody.Velocity = _body.PhysicsBody.Velocity.ClampLength( PlayerPickupDetachSpeed );
						_body.PhysicsBody.AngularVelocity = _body.PhysicsBody.AngularVelocity.ClampLength( PlayerPickupDetachAngularSpeed );
					}
				}
			}

			_body = null;
			_targetPosition = default;
			_targetRotation = Rotation.Identity;
			_attachedAnglesPlayerSpace = Rotation.Identity;
			_attachedPositionObjectSpace = default;
			_targetVelocity = default;
			_hasTargetVelocity = false;
			_distanceOffset = 0.0f;
			_savedAngularDamping = 0.0f;
			_savedMass = 0.0f;
			_savedInterpolation = false;
			_savedImpactDamageEnabled = false;
			_savedUseController = false;
			_massWasReduced = false;
			_errorTime = 0.0f;
			_error = 0.0f;
		}

		public bool UpdateObject( Player player, float errorLimit, float delta )
		{
			if ( ComputeError() > errorLimit ) return false;
			if ( !_body.IsValid() ) return false;
			if ( _body.IsProxy ) return false;
			if ( !_body.MotionEnabled ) return false;
			if ( !_body.PhysicsBody.IsValid() ) return false;
			if ( PlayerPickupController.IsPlayerStandingOnBody( player, _body ) ) return false;

			var angles = player.Controller.EyeAngles;
			angles.pitch = angles.pitch.Clamp( -75.0f, 75.0f );

			var shootPosition = GetShootPosition( player, delta, out var playerPosition );
			var eyeRotation = angles.ToRotation();
			var forward = eyeRotation.Forward;
			var bounds = _body.GetWorldBounds();
			var center = GetWorldSpaceCenter();
			var radius = GetPlayerRadius( player ) + GetCollideExtent( _body.PhysicsBody, center, bounds, forward );
			var distance = PlayerPickupHoldBase + radius * 2.0f + _distanceOffset;
			var end = TraceCollideAgainstStatic( player, _body, shootPosition, forward, distance, radius );

			end = PushTargetOutsidePlayer( player, end, forward, radius, playerPosition );

			var targetRotation = TransformAnglesFromPlayerSpace( _attachedAnglesPlayerSpace, player );
			var targetPosition = end - targetRotation * _attachedPositionObjectSpace;
			_targetVelocity = _hasTargetVelocity && delta > 0.0f ? (targetPosition - _targetPosition) / delta : Vector3.Zero;
			_hasTargetVelocity = true;
			SetTargetPosition( targetPosition, targetRotation );

			return true;
		}

		public float ComputeError()
		{
			if ( _errorTime <= 0.0f ) return 0.0f;
			if ( !_body.IsValid() ) return 9999.0f;
			if ( !_body.PhysicsBody.IsValid() ) return 9999.0f;

			_errorTime = MathF.Min( _errorTime, 1.0f );

			var error = Vector3.DistanceBetween( _targetPosition, _body.PhysicsBody.Position );
			var speed = error / _errorTime;
			if ( speed > PlayerPickupMaxSpeed )
				error *= 0.5f;

			_error = (1.0f - _errorTime) * _error + error * _errorTime;
			_errorTime = 0.0f;

			return _error;
		}

		public void Simulate( float delta )
		{
			if ( !_body.IsValid() ) return;
			if ( _body.IsProxy ) return;

			var physicsBody = _body.PhysicsBody;
			if ( !physicsBody.IsValid() ) return;

			physicsBody.Sleeping = false;
			physicsBody.UseController = true;
			physicsBody.Move( new Transform( _targetPosition, _targetRotation ), MathF.Max( delta, 0.001f ) );
			physicsBody.Velocity = physicsBody.Velocity.ClampLength( PlayerPickupMaxSpeed );
			physicsBody.AngularVelocity = physicsBody.AngularVelocity.ClampLength( PlayerPickupMaxAngularSpeed );
			_errorTime += MathF.Max( delta, 0.0f );
		}

		public void FinishSimulate()
		{
			if ( !_body.IsValid() ) return;
			if ( _body.IsProxy ) return;

			var physicsBody = _body.PhysicsBody;
			if ( !physicsBody.IsValid() ) return;

			physicsBody.Velocity = _targetVelocity.ClampLength( PlayerPickupMaxSpeed );
			physicsBody.AngularVelocity = physicsBody.AngularVelocity.ClampLength( PlayerPickupMaxAngularSpeed );
		}

		private void SetTargetPosition( Vector3 targetPosition, Rotation targetRotation )
		{
			_targetPosition = targetPosition;
			_targetRotation = targetRotation;
		}

		private Vector3 GetWorldSpaceCenter()
		{
			if ( !_body.IsValid() ) return default;

			var transform = _body.PhysicsBody.IsValid()
				? _body.PhysicsBody.Transform.WithScale( 1.0f )
				: _body.WorldTransform.WithScale( 1.0f );

			return transform.PointToWorld( _attachedPositionObjectSpace );
		}

		private Rotation TransformAnglesToPlayerSpace( Rotation angles, Player player )
		{
			if ( _ignoreRelativePitch )
				return Rotation.FromYaw( player.Controller.EyeAngles.yaw ).Inverse * angles;

			return player.WorldRotation.Inverse * angles;
		}

		private Rotation TransformAnglesFromPlayerSpace( Rotation angles, Player player )
		{
			if ( _ignoreRelativePitch )
				return Rotation.FromYaw( player.Controller.EyeAngles.yaw ) * angles;

			return player.WorldRotation * angles;
		}

		private static Vector3 GetShootPosition( Player player, float delta, out Vector3 playerPosition )
		{
			if ( !player.Controller.IsValid() )
			{
				playerPosition = player.WorldPosition;
				return player.EyeTransform.Position;
			}

			var controller = player.Controller;
			playerPosition = controller.WorldPosition;
			var playerBody = controller.Body;

			if ( playerBody.IsValid() && playerBody.PhysicsBody.IsValid() )
			{
				var physicsBody = playerBody.PhysicsBody;
				playerPosition = physicsBody.Position + physicsBody.Velocity * MathF.Max( delta, 0.0f );
			}

			return playerPosition + Vector3.Up * (controller.CurrentHeight - controller.EyeDistanceFromTop);
		}

		private static float GetPlayerRadius( Player player )
		{
			var playerHalfWidth = player.Controller.IsValid()
				? player.Controller.BodyRadius * 0.5f
				: PlayerPickupDefaultPlayerHalfWidth;

			return MathF.Sqrt( playerHalfWidth * playerHalfWidth * 2.0f );
		}

		private static float GetCollideExtent( PhysicsBody physicsBody, Vector3 center, BBox bounds, Vector3 forward )
		{
			var aabbExtent = GetProjectedExtent( bounds.Extents, forward );
			if ( !physicsBody.IsValid() ) return aabbExtent;

			var probeDistance = MathF.Max( bounds.Size.Length + PlayerPickupHoldBase, PlayerPickupSizeLimit );
			var supportPoint = physicsBody.FindClosestPoint( center - forward * probeDistance );
			if ( supportPoint.IsNaN || supportPoint.IsInfinity ) return aabbExtent;

			var extent = MathF.Abs( Vector3.Dot( forward, supportPoint - center ) );
			return extent.Clamp( 0.0f, aabbExtent );
		}

		private static float GetProjectedExtent( Vector3 extents, Vector3 forward )
		{
			return MathF.Abs( extents.x * forward.x )
				+ MathF.Abs( extents.y * forward.y )
				+ MathF.Abs( extents.z * forward.z );
		}

		private static Vector3 TraceCollideAgainstStatic( Player player, Rigidbody body, Vector3 start, Vector3 forward, float distance, float radius )
		{
			var end = start + forward * distance;
			var trace = player.Scene.Trace.Ray( start, end )
				.IgnoreGameObjectHierarchy( player.GameObject.Root )
				.IgnoreGameObjectHierarchy( body.GameObject.Root )
				.WithoutTags( "player", "playercontroller", "trigger", "ragdoll" )
				.IgnoreDynamic()
				.Run();

			if ( !trace.Hit )
				return end;

			if ( trace.Fraction < 0.5f )
				return start + forward * (radius * 0.5f);

			return start + forward * (distance - radius);
		}

		private static Vector3 PushTargetOutsidePlayer( Player player, Vector3 end, Vector3 forward, float radius, Vector3 playerPosition )
		{
			if ( !player.Controller.IsValid() ) return end;

			var playerLine = playerPosition;

			var nearest = ClosestPointOnLine( end, playerLine, playerLine + Vector3.Up * player.Controller.CurrentHeight );
			var offset = end - nearest;
			var length = offset.Length;
			if ( length >= radius ) return end;

			var direction = length > 0.001f ? offset / length : forward;
			return nearest + direction * radius;
		}

		private static Vector3 ClosestPointOnLine( Vector3 point, Vector3 start, Vector3 end )
		{
			var line = end - start;
			var lengthSquared = line.LengthSquared;
			if ( lengthSquared <= 0.0f ) return start;

			var fraction = Vector3.Dot( point - start, line ) / lengthSquared;
			fraction = fraction.Clamp( 0.0f, 1.0f );
			return start + line * fraction;
		}
	}
}