public void FixedUpdate()
{
    Vector3 movementDirection = new Vector3(_playerActions.CurrentMovementDirection.x, 0, _playerActions.CurrentMovementDirection.y);
    Vector3 movementVelocity = movementDirection * _context.Config.GroundControlMult;
    Vector3 movementDisplacement = movementVelocity * Time.fixedDeltaTime;

    Vector3 currentPosition = _context.Rigidbody.position;
    float colliderRadius = _context.Collider.radius;
    float colliderHeight = _context.Collider.height;

    Vector3 lastNormal = Vector3.zero;

    // Implementation of https://arxiv.org/ftp/arxiv/papers/1211/1211.0059.pdf
    for (int i = 0; i < 3; i++)
    {
        if (KCCUtils.CheckWillBeAgainstWall(currentPosition, colliderRadius, colliderHeight, movementDisplacement.normalized, movementDisplacement.magnitude, out RaycastHit hit))
        {
            float distanceToWall = Mathf.Max(hit.distance - 0.01f, 0);

            Vector3 movementToWall = movementDisplacement.normalized * distanceToWall;
            Vector3 movementInsideWall = movementDisplacement - movementToWall;

            currentPosition += movementToWall;

            // We've hit 1 plane. Slide along it.
            if (i == 0)
            {
                movementDisplacement = Vector3.ProjectOnPlane(movementInsideWall, hit.normal);
            }
            
            // We've hit 2 planes. The only movement is along their intersection.
            if (i == 1)
            {
                float angleBetweenNormals = Vector3.Angle(lastNormal, hit.normal);

                // If the angle is small, the planes are almost parallel. We can presumably just slide along the other.
                if (angleBetweenNormals < 10f)
                {
                    movementDisplacement = Vector3.ProjectOnPlane(movementInsideWall, hit.normal);
                }
                // Otherwise we gotta stop.
                else
                {
                    Vector3 crossProduct = Vector3.Cross(lastNormal, hit.normal);
                    Vector3 creaseVector = crossProduct.normalized;

                    movementDisplacement = Vector3.Project(movementInsideWall, creaseVector);
                }
            }

            // We've hit 3 planes. The only movement is away from all 3.
            if (i == 2)
            {
                movementDisplacement = Vector3.zero;
            }

            lastNormal = hit.normal;
        }
        else
        {
            // Since there are 3 max iterations, this will only be reached if we've hit at most 2 planes.
            currentPosition += movementDisplacement;
            break;
        }
    }

    _context.Rigidbody.MovePosition(currentPosition);
}




        public static bool CheckWillBeAgainstWall(Vector3 startPosition, float radius, float height, Vector3 movementDirection, float maxDistance, out RaycastHit hit)
        {
            Vector3 topSphereOrigin = startPosition + Vector3.up * ((height / 2) - radius);
            Vector3 bottomSphereOrigin = startPosition + Vector3.down * ((height / 2) - radius);

            return Physics.CapsuleCast(topSphereOrigin, bottomSphereOrigin, radius, movementDirection, out hit, maxDistance);
        }