private static void SkeletonOnAnimationEventFootstep(
            ICharacter character,
            IComponentSkeleton skeleton,
            SkeletonEventData e)
        {
            if (e.EventName != "Footstep")
            {
                return;
            }

            // play footstep sound
            GroundSoundMaterial groundSoundMaterial;

            var tile = character.Tile;

            // find the latest proto ground object with sound
            IProtoObjectWithGroundSoundMaterial protoGroundObject = null;

            foreach (var worldObject in tile.StaticObjects)
            {
                if (worldObject.ProtoStaticWorldObject is IProtoObjectWithGroundSoundMaterial proto)
                {
                    protoGroundObject = proto;
                }
            }

            if (protoGroundObject is not null)
            {
                // get sound material of proto ground object
                groundSoundMaterial = protoGroundObject.SharedGetGroundSoundMaterial();
            }
            else
            {
                // get sound material of proto tile
                var protoTile = (ProtoTile)tile.ProtoTile;
                groundSoundMaterial = protoTile.GroundSoundMaterial;
            }

            ReadOnlySoundPreset <GroundSoundMaterial> soundPresetMovement = null;
            var protoCharacter = character.ProtoCharacter;

            if (protoCharacter is PlayerCharacter &&
                PlayerCharacter.GetPublicState(character).CurrentVehicle is null)
            {
                // try get movement sound preset override
                foreach (var item in character.SharedGetPlayerContainerEquipment().Items)
                {
                    if (item.ProtoItem is IProtoItemEquipmentArmor protoItemEquipmentArmor)
                    {
                        soundPresetMovement = protoItemEquipmentArmor.SoundPresetFootstepsOverride;
                        break;
                    }
                }
            }

            var protoSkeleton = (ProtoCharacterSkeleton)protoCharacter.ClientGetCurrentProtoSkeleton(character);

            if (soundPresetMovement is null)
            {
                // movement sound preset is not overridden - use from this skeleton
                soundPresetMovement = protoSkeleton.SoundPresetFootsteps;
            }

            // use some pitch variation
            var pitch = RandomHelper.Range(protoSkeleton.FootstepsPitchVariationRange.From,
                                           protoSkeleton.FootstepsPitchVariationRange.To);

            var volume = protoSkeleton.VolumeFootsteps;

            // apply some volume variation
            volume *= RandomHelper.Range(protoSkeleton.FootstepsVolumeVariationRange.From,
                                         protoSkeleton.FootstepsVolumeVariationRange.To);
            // apply constant volume multiplier
            volume *= SoundConstants.VolumeFootstepsMultiplier;

            soundPresetMovement.PlaySound(
                groundSoundMaterial,
                character,
                volume: (float)volume,
                pitch: (float)pitch);
        }
 public static GroundSoundMaterial SharedGetGroundSoundMaterial(
     this IProtoObjectWithGroundSoundMaterial protoFloor)
 {
     return(protoFloor.GroundSoundMaterial);
 }