// unity on animator ik
        void OnAnimatorIK(int layerIndex)
        {
#if DEBUG_INFO
            if (!m_initialized)
            {
                Debug.LogError("component not initialized! " + " < " + this.ToString() + ">");
                return;
            }
#endif



            //// doing it this way because must prevent any way of locking in m_takingstep mode
            //// so m_stepTime is always incrementing
            m_steptime += Time.deltaTime * 3.9f;
            if (m_steptime > m_stepmaxtime)
            {
                // reset from ik stepping
                if (m_takingstep)
                {
                    m_Character.disableGroundPull     = false;
                    m_Character.capsule.isTrigger     = false;
                    m_Character.rigidBody.isKinematic = false;
                    m_Character.rigidBody.useGravity  = true;
                    m_Character.disableCapsuleScale   = false;
                    m_Character.disableMove           = false;
                    transform.position = m_stepEndPosition;

                    m_leftIK    = true;
                    m_rightIK   = true;
                    m_CurPointL = null;
                    m_CurPointR = null;
                }
                m_takingstep = false;
            }
            if (m_takingstep)
            {
                float lerpvalue = m_steptime / m_stepmaxtime;
                lerpvalue          = lerpvalue * lerpvalue;
                transform.position = Vector3.Lerp(m_stepStartPosition, m_stepEndPosition, lerpvalue);
            }

            bool isBumpInFront = false;

            if (!m_takingstep)
            {
                bool isOnLayer = Utils.DoesMaskContainsLayer(IKSteppingLayers.value, m_Character.getCurrentGroundLayer());

                // if ik stepping enabled and character is grounded
                // do ik stepping check
                if (EnableIKStepping && m_Character.isGroundMode && isOnLayer)
                {
                    // reset values
                    left_ikActive       = false;
                    right_ikActive      = false;
                    m_IkHit             = false;
                    m_LeftHeightOffset  = new Vector3(-float.MaxValue, -float.MaxValue, -float.MaxValue);
                    m_RightHeightOffset = new Vector3(-float.MaxValue, -float.MaxValue, -float.MaxValue);

                    Vector3 currentDirection = m_Character.moveWS;
                    if (m_Character.moveWS == Vector3.zero) // character not moving
                    {
                        return;
                    }

                    // check if it is wall in front
                    bool    isWallInFront      = false;
                    float   sphereChecksRadius = m_Character.capsule.radius * 0.95f;
                    Vector3 startPos           = transform.position;
                    Ray     ray             = new Ray(startPos + Vector3.up * (MaxStepHeight + sphereChecksRadius * 0.51f), currentDirection);
                    float   wall_dist_check = m_Character.capsule.radius * 1.25f;

                    // little up
                    ray.origin += new Vector3(0f, sphereChecksRadius * 0.525f, 0f);

#if DEBUG_INFO
                    WALL_COLOR = Color.blue;
                    BUMP_COLOR = Color.white;
                    WALL_START = ray.origin;
                    WALL_END   = WALL_START + ray.direction * wall_dist_check;
#endif
                    RaycastHit hit;
                    float      currAngle = 0.0f;
                    int        mask      = IKSteppingLayers.value;
                    if (Physics.SphereCast(ray, sphereChecksRadius, out hit,
                                           wall_dist_check, mask))
                    {
#if DEBUG_INFO
                        WALL_COLOR = Color.red;
#endif
                        isWallInFront = true;
                        currAngle     = Vector3.Angle(Vector3.up, hit.normal);
                    }

                    //// if wall in front do nothing and return
                    if (!isWallInFront)
                    {
                        // do legs ik
                        if (m_leftIK)
                        {
                            _leftLegIK(m_CurPointL);
                        }
                        if (m_rightIK)
                        {
                            _rightLegIK(m_CurPointR);
                        }

                        // check if there are bumps in front of feet and slope
                        float halfishHeight = MaxStepHeight * 0.4f;
                        ray = new Ray(startPos + Vector3.up * halfishHeight, currentDirection);
                        float bump_dist_check = wall_dist_check * 1.5f;

#if DEBUG_INFO
                        BUMP_START = ray.origin;
                        BUMP_END   = BUMP_START + ray.direction * bump_dist_check;
#endif

                        bool bump_hit = Physics.SphereCast(ray, halfishHeight * 0.5f, out hit, bump_dist_check, mask);
                        if (bump_hit)
                        {
#if DEBUG_INFO
                            BUMP_COLOR = Color.red;
#endif
                            isBumpInFront = true;
                            currAngle     = Vector3.Angle(Vector3.up, hit.normal);
                        }
                        bool bumpAngleTooLow = currAngle < MaxSlopeAngle;

                        m_Character.capsule.isTrigger = false;
                        if (isBumpInFront && !bumpAngleTooLow)
                        {
                            // if character is running just jump a little and return
                            if (m_Character.forwardAmount > 0.75f)
                            {
                                m_Character.rigidBody.velocity += m_Character.rigidBody.mass * Vector3.up * bumpJump;
                                return;
                            }

                            if ((m_IkHit))
                            {
                                // which is higher of left and right foot
                                Vector3 higher = m_LeftHeightOffset;
                                m_leftIK  = true;
                                m_rightIK = false;

                                if (m_LeftHeightOffset.y < m_RightHeightOffset.y)
                                {
                                    higher    = m_RightHeightOffset;
                                    m_leftIK  = false;
                                    m_rightIK = true;
                                }

                                Vector3 higherLocalToXform = transform.InverseTransformPoint(higher);

                                // check of step is higher and in front of current direction
                                bool    inFrontDirection = false;
                                Vector3 toHigher         = higher - transform.position;
                                float   dot = Vector3.Dot(currentDirection, toHigher);
                                if (dot > 0)                                      // if in front
                                {
                                    inFrontDirection = higherLocalToXform.y > 0f; // higher than transform position
                                }

                                if (inFrontDirection)
                                {
                                    // additional checks
                                    if ((m_rightIK && m_RightSteppingForward) ||
                                        (m_leftIK && m_LeftSteppingForward))
                                    {
                                        // ik stepping setup
                                        Vector3 m_FootOffset = higher - transform.position;

                                        m_stepStartPosition = transform.position;
                                        m_stepEndPosition   = transform.position + m_FootOffset;

                                        m_steptime   = 00.0f;
                                        m_takingstep = true;
                                        m_Character.disableGroundPull     = true;
                                        m_Character.capsule.isTrigger     = true;
                                        m_Character.rigidBody.isKinematic = true;
                                        m_Character.rigidBody.useGravity  = false;
                                        m_Character.disableCapsuleScale   = true;
                                        m_Character.disableMove           = true;

                                        if (m_leftIK)
                                        {
                                            m_CurPointL = m_stepEndPosition; m_CurPointR = null;
                                        }
                                        if (m_rightIK)
                                        {
                                            m_CurPointL = null; m_CurPointR = m_stepEndPosition;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    left_ikActive  = false;
                    right_ikActive = false;
                    _leftLegIK();
                    _rightLegIK();
                }
            }



            // do animator ik
            if (layerIndex == 0)
            {
                if (left_ikActive)
                {
                    m_lweight += m_weightspeed * Time.deltaTime;
                    m_lweight  = Mathf.Min(m_lweight, 1.0f);
                    m_Animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot, m_lweight);
                    m_Animator.SetIKPosition(AvatarIKGoal.LeftFoot, m_leftIKTarget);
                }
                else
                {
                    m_lweight -= m_weightspeed * Time.deltaTime;
                    m_lweight  = Mathf.Max(0.0f, m_lweight);
                    m_Animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot, m_lweight);
                    m_Animator.SetIKPosition(AvatarIKGoal.LeftFoot, m_leftIKTarget);
                }
                if (right_ikActive)
                {
                    m_rweight += m_weightspeed * Time.deltaTime;
                    m_rweight  = Mathf.Min(m_rweight, 1.0f);
                    m_Animator.SetIKPositionWeight(AvatarIKGoal.RightFoot, m_rweight);
                    m_Animator.SetIKPosition(AvatarIKGoal.RightFoot, m_rightIKTarget);
                }
                else
                {
                    m_rweight -= m_weightspeed * Time.deltaTime;
                    m_rweight  = Mathf.Max(0.0f, m_rweight);
                    m_Animator.SetIKPositionWeight(AvatarIKGoal.RightFoot, m_rweight);
                    m_Animator.SetIKPosition(AvatarIKGoal.RightFoot, m_rightIKTarget);
                }
            }
        }
        /// <summary>
        /// slope control function
        /// </summary>
        private void _slopeControl()
        {
            m_Character.slopeMultiplier = 1.0f;
            m_Character.jumpAllowed     = true;

            bool isOnLayer = Utils.DoesMaskContainsLayer(layers.value, m_Character.getCurrentGroundLayer());

            if (!isOnLayer)
            {
                return;
            }
            if (m_Character.distanceFromGround > 0.1f)
            {
                return;
            }



            m_GroundNormal = m_Character.groundNormal; // character is checking ground normal already


            Vector3 thisPos = transform.position;
            Vector3 moveDir = m_Character.moveWS;

            if (moveDir == Vector3.zero)
            {
                moveDir = m_Character.transform.forward;
            }
            Vector3 nextPos = thisPos + moveDir.normalized * (m_Character.capsule.radius * 0.99f);
            bool    goingUp = _isGoingUp(thisPos, nextPos);

            if (goingUp)
            {
                float slopeStart = Mathf.Max(MaxSlope - 10.0f, 0.0f);
                float angle      = Vector3.Angle(m_GroundNormal, Vector3.up);
                float amt0       = 0.0f;
                float angDiff    = angle - slopeStart;
                amt0 = angDiff / (MaxSlope - slopeStart);
                amt0 = Mathf.Max(0.0f, amt0);
                float   velocityMultiplier = Mathf.Lerp(1.0f, 0.5f, amt0);
                float   downForce          = Mathf.Lerp(0.0f, downVelocityStrength, amt0);
                Vector3 down = Vector3.down * downForce;

                if (angle > MaxSlope)
                {
                    m_Character.capsule.material = m_defines.zeroFrictionMaterial;
                    m_Character.slopeMultiplier *= Mathf.Max(0.5f, velocityMultiplier);
                    if (m_Character.isDiving)
                    {
                        m_Character.simulateRootMotion = false;
                    }

                    if (disableJumpOnHighSlope)
                    {
                        m_Character.jumpAllowed = false;
                        Vector3 velocity = m_Character.rigidBody.velocity;
                        velocity *= velocityMultiplier;
                        m_Character.rigidBody.velocity = velocity + down;
                    }
                    else
                    {
                        Vector3 velocity = m_Character.rigidBody.velocity;
                        velocity.x *= velocityMultiplier;
                        velocity.z *= velocityMultiplier;
                        m_Character.rigidBody.velocity = velocity + down;
                    }
                }
                else if (angle > slopeStart)
                {
                    m_Character.capsule.material = m_defines.zeroFrictionMaterial;
                    m_Character.slopeMultiplier *= Mathf.Max(0.5f, velocityMultiplier);
                    Vector3 velocity = m_Character.rigidBody.velocity;
                    velocity.x *= velocityMultiplier;
                    velocity.z *= velocityMultiplier;
                    m_Character.rigidBody.velocity = velocity + down;
                }
            }
        }