private static void SetLoopSounds(
            ICharacter character,
            BaseCharacterClientState clientState,
            AppliedCharacterInput appliedInput,
            ProtoCharacterSkeleton protoSkeleton,
            bool isIdle)
        {
            CharacterSound soundKey;

            if (isIdle)
            {
                soundKey = CharacterSound.LoopIdle;
            }
            else
            {
                var isRunningMode = (appliedInput.MoveModes & CharacterMoveModes.ModifierRun) != 0;
                soundKey = isRunningMode ? CharacterSound.LoopRun : CharacterSound.LoopWalk;
            }

            var(soundPresetCharacter, soundPresetMovement)           = protoSkeleton.GetSoundPresets(character);
            clientState.SoundEmitterLoopCharacter.NextSoundResource  = soundPresetCharacter.GetSound(soundKey);
            clientState.SoundEmitterLoopMovemement.NextSoundResource = soundPresetMovement.GetSound(soundKey);

            // ensure the sounds are played
            clientState.SoundEmitterLoopCharacter.Play();
            clientState.SoundEmitterLoopMovemement.Play();
        }
        private static double GetCurrentRotationAngleRadInterpolated(
            ICharacter character,
            BaseCharacterClientState clientState,
            AppliedCharacterInput appliedInput)
        {
            double rotationAngleRad = appliedInput.RotationAngleRad;

            if (!clientState.LastInterpolatedRotationAngleRad.HasValue)
            {
                // current character or first time - simply use current angle
                clientState.LastInterpolatedRotationAngleRad = rotationAngleRad;
                return(rotationAngleRad);
            }

            var oldAngle = clientState.LastInterpolatedRotationAngleRad.Value;

            if (Math.Abs(MathHelper.GetShortestAngleDist(oldAngle, rotationAngleRad))
                < Math.PI / 2)
            {
                // small difference - allow to interpolate
                // smooth interpolation for remote players is required to better deal with the network update rate
                // for local player it's much more fast and just improves overall smoothness of the character rotation
                var rate = character.IsCurrentClientCharacter
                               ? RotationAngleRadInterpolationRateCurrentCharacter
                               : RotationAngleRadInterpolationRateRemoteCharacter;

                rotationAngleRad = MathHelper.LerpAngle(
                    oldAngle,
                    rotationAngleRad,
                    Api.Client.Core.DeltaTime,
                    rate);
            }

            clientState.LastInterpolatedRotationAngleRad = rotationAngleRad;
            return(rotationAngleRad);
        }