<commit_before>﻿using EndlessClient.GameExecution;
using EndlessClient.HUD;
using EOLib;
using EOLib.Domain.Character;
using EOLib.Domain.Extensions;
using EOLib.Domain.Map;
using EOLib.IO.Map;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;

namespace EndlessClient.Rendering.Character
{
    public class CharacterAnimator : GameComponent, ICharacterAnimator
    {
        public const int WALK_FRAME_TIME_MS = 120;
        public const int ATTACK_FRAME_TIME_MS = 100;

        private readonly ICharacterRepository _characterRepository;
        private readonly ICurrentMapStateRepository _currentMapStateRepository;
        private readonly ICurrentMapProvider _currentMapProvider;
        private readonly ICharacterActions _characterActions;
        private readonly IWalkValidationActions _walkValidationActions;
        private readonly IPathFinder _pathFinder;

        private readonly Dictionary<int, EODirection> _queuedDirections;
        private readonly Dictionary<int, MapCoordinate> _queuedPositions;
        private readonly Dictionary<int, RenderFrameActionTime> _otherPlayerStartWalkingTimes;
        private readonly Dictionary<int, RenderFrameActionTime> _otherPlayerStartAttackingTimes;
        private readonly Dictionary<int, RenderFrameActionTime> _otherPlayerStartSpellCastTimes;

        private Queue<MapCoordinate> _walkPath;
        private MapCoordinate? _targetCoordinate;

        public CharacterAnimator(IEndlessGameProvider gameProvider,
                                 ICharacterRepository characterRepository,
                                 ICurrentMapStateRepository currentMapStateRepository,
                                 ICurrentMapProvider currentMapProvider,
                                 ICharacterActions characterActions,
                                 IWalkValidationActions walkValidationActions,
                                 IPathFinder pathFinder)
            : base((Game) gameProvider.Game)
        {
            _characterRepository = characterRepository;
            _currentMapStateRepository = currentMapStateRepository;
            _currentMapProvider = currentMapProvider;
            _characterActions = characterActions;
            _walkValidationActions = walkValidationActions;
            _pathFinder = pathFinder;
            _queuedDirections = new Dictionary<int, EODirection>();
            _queuedPositions = new Dictionary<int, MapCoordinate>();
            _otherPlayerStartWalkingTimes = new Dictionary<int, RenderFrameActionTime>();
            _otherPlayerStartAttackingTimes = new Dictionary<int, RenderFrameActionTime>();
            _otherPlayerStartSpellCastTimes = new Dictionary<int, RenderFrameActionTime>();
            _walkPath = new Queue<MapCoordinate>();
        }

        public override void Update(GameTime gameTime)
        {
            AnimateCharacterWalking();
            AnimateCharacterAttacking();
            AnimateCharacterSpells();

            base.Update(gameTime);
        }

        public void MainCharacterFace(EODirection direction)
        {
            if (_otherPlayerStartWalkingTimes.ContainsKey(_characterRepository.MainCharacter.ID))
            {
                _queuedDirections[_characterRepository.MainCharacter.ID] = direction;
                return;
            }

            var renderProperties = _characterRepository.MainCharacter.RenderProperties.WithDirection(direction);
            var newMainCharacter = _characterRepository.MainCharacter.WithRenderProperties(renderProperties);
            _characterRepository.MainCharacter = newMainCharacter;

            _characterActions.Face(direction);
        }

        public void StartMainCharacterWalkAnimation(MapCoordinate? targetCoordinate = null)
        {
            _walkPath.Clear();
            if (targetCoordinate.HasValue)
            {
                _targetCoordinate = targetCoordinate;

                var rp = _characterRepository.MainCharacter.RenderProperties;
                var characterCoord = new MapCoordinate(rp.MapX, rp.MapY);

                _walkPath = _pathFinder.FindPath(characterCoord, _targetCoordinate.Value);

                if (!_otherPlayerStartWalkingTimes.ContainsKey(_characterRepository.MainCharacter.ID))
                {
                    rp = FaceTarget(characterCoord, _walkPath.Peek(), rp);
                    _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithRenderProperties(rp);
                }
            }

            if (_otherPlayerStartWalkingTimes.ContainsKey(_characterRepository.MainCharacter.ID))
            {
                _otherPlayerStartWalkingTimes[_characterRepository.MainCharacter.ID].Replay = true;
                return;
            }<commit_msg>Fix crash in click to walk<commit_after>﻿using EndlessClient.GameExecution;
using EndlessClient.HUD;
using EOLib;
using EOLib.Domain.Character;
using EOLib.Domain.Extensions;
using EOLib.Domain.Map;
using EOLib.IO.Map;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;

namespace EndlessClient.Rendering.Character
{
    public class CharacterAnimator : GameComponent, ICharacterAnimator
    {
        public const int WALK_FRAME_TIME_MS = 120;
        public const int ATTACK_FRAME_TIME_MS = 100;

        private readonly ICharacterRepository _characterRepository;
        private readonly ICurrentMapStateRepository _currentMapStateRepository;
        private readonly ICurrentMapProvider _currentMapProvider;
        private readonly ICharacterActions _characterActions;
        private readonly IWalkValidationActions _walkValidationActions;
        private readonly IPathFinder _pathFinder;

        private readonly Dictionary<int, EODirection> _queuedDirections;
        private readonly Dictionary<int, MapCoordinate> _queuedPositions;
        private readonly Dictionary<int, RenderFrameActionTime> _otherPlayerStartWalkingTimes;
        private readonly Dictionary<int, RenderFrameActionTime> _otherPlayerStartAttackingTimes;
        private readonly Dictionary<int, RenderFrameActionTime> _otherPlayerStartSpellCastTimes;

        private Queue<MapCoordinate> _walkPath;
        private MapCoordinate? _targetCoordinate;

        public CharacterAnimator(IEndlessGameProvider gameProvider,
                                 ICharacterRepository characterRepository,
                                 ICurrentMapStateRepository currentMapStateRepository,
                                 ICurrentMapProvider currentMapProvider,
                                 ICharacterActions characterActions,
                                 IWalkValidationActions walkValidationActions,
                                 IPathFinder pathFinder)
            : base((Game) gameProvider.Game)
        {
            _characterRepository = characterRepository;
            _currentMapStateRepository = currentMapStateRepository;
            _currentMapProvider = currentMapProvider;
            _characterActions = characterActions;
            _walkValidationActions = walkValidationActions;
            _pathFinder = pathFinder;
            _queuedDirections = new Dictionary<int, EODirection>();
            _queuedPositions = new Dictionary<int, MapCoordinate>();
            _otherPlayerStartWalkingTimes = new Dictionary<int, RenderFrameActionTime>();
            _otherPlayerStartAttackingTimes = new Dictionary<int, RenderFrameActionTime>();
            _otherPlayerStartSpellCastTimes = new Dictionary<int, RenderFrameActionTime>();
            _walkPath = new Queue<MapCoordinate>();
        }

        public override void Update(GameTime gameTime)
        {
            AnimateCharacterWalking();
            AnimateCharacterAttacking();
            AnimateCharacterSpells();

            base.Update(gameTime);
        }

        public void MainCharacterFace(EODirection direction)
        {
            if (_otherPlayerStartWalkingTimes.ContainsKey(_characterRepository.MainCharacter.ID))
            {
                _queuedDirections[_characterRepository.MainCharacter.ID] = direction;
                return;
            }

            var renderProperties = _characterRepository.MainCharacter.RenderProperties.WithDirection(direction);
            var newMainCharacter = _characterRepository.MainCharacter.WithRenderProperties(renderProperties);
            _characterRepository.MainCharacter = newMainCharacter;

            _characterActions.Face(direction);
        }

        public void StartMainCharacterWalkAnimation(MapCoordinate? targetCoordinate = null)
        {
            _walkPath.Clear();
            if (targetCoordinate.HasValue)
            {
                _targetCoordinate = targetCoordinate;

                var rp = _characterRepository.MainCharacter.RenderProperties;
                var characterCoord = new MapCoordinate(rp.MapX, rp.MapY);

                _walkPath = _pathFinder.FindPath(characterCoord, _targetCoordinate.Value);

                if (!_otherPlayerStartWalkingTimes.ContainsKey(_characterRepository.MainCharacter.ID) && _walkPath.Any())
                {
                    rp = FaceTarget(characterCoord, _walkPath.Peek(), rp);
                    _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithRenderProperties(rp);
                }
            }

            if (_otherPlayerStartWalkingTimes.ContainsKey(_characterRepository.MainCharacter.ID))
            {
                _otherPlayerStartWalkingTimes[_characterRepository.MainCharacter.ID].Replay = true;
                return;
            }
{'fraction_non_alphanumeric': 0.057365145228215765, 'fraction_numerical': 0.0012448132780082987, 'mean_word_length': 2.6394865987164966, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '672664', 'n_tokens_mistral': 2205, 'n_tokens_neox': 2159, 'n_words': 420}