// WingsEmu // // Developed by NosWings Team using System; using System.Linq; using System.Threading; using System.Threading.Tasks; using PhoenixLib.DAL; using PhoenixLib.Events; using PhoenixLib.Logging; using Polly; using Polly.Retry; using WingsAPI.Communication; using WingsAPI.Communication.DbServer.AccountService; using WingsAPI.Communication.DbServer.CharacterService; using WingsAPI.Data.Account; using WingsAPI.Data.Character; using WingsEmu.Game; using WingsEmu.Game.Characters; using WingsEmu.Game.Characters.Events; using WingsEmu.Packets.Enums; namespace WingsEmu.Plugins.BasicImplementations.Event.Characters; public class SessionSaveEventHandler : IAsyncEventProcessor { private readonly IAccountService _accountService; private readonly ICharacterService _characterService; private readonly IMapper _mapper; private readonly IPlayerEntityFactory _playerEntityFactory; public SessionSaveEventHandler(IPlayerEntityFactory playerEntityFactory, ICharacterService characterService, IAccountService accountService, IMapper mapper) { _playerEntityFactory = playerEntityFactory; _characterService = characterService; _accountService = accountService; _mapper = mapper; } public async Task HandleAsync(SessionSaveEvent e, CancellationToken cancellation) { IPlayerEntity playerEntity = e.Sender.PlayerEntity; AccountDTO account = _mapper.Map(e.Sender.Account); long accountId = account.Id; AsyncRetryPolicy policy = Policy.Handle().RetryAsync(3, (exception, i1) => Log.Error($"[CHARACTER_SAVE][ACCOUNT_ID: '{accountId.ToString()}'] Failed to save characters, try {i1.ToString()}. ", exception)); AccountSaveResponse response = null; try { response = await policy.ExecuteAsync(() => _accountService.SaveAccount(new AccountSaveRequest { AccountDto = account })); } catch (Exception ex) { Log.Error($"[CHARACTER_SAVE][ACCOUNT_ID: '{account.Id.ToString()}'] Unexpected error: ", ex); } if (response?.ResponseType != RpcResponseType.SUCCESS) { Log.Warn($"[CHARACTER_SAVE][ACCOUNT_ID: '{account.Id.ToString()}'] Failed to save account"); } CharacterDTO characterDto = _playerEntityFactory.CreateCharacterDto(playerEntity); DbServerSaveCharacterResponse response2 = null; try { response2 = await _characterService.SaveCharacter(new DbServerSaveCharacterRequest { Character = characterDto }); } catch (Exception ex) { Log.Error($"[CHARACTER_SAVE][CHARACTER_ID: '{characterDto.Id.ToString()}'] Unexpected error: ", ex); } if (response2?.RpcResponseType != RpcResponseType.SUCCESS) { Log.Warn($"[CHARACTER_SAVE][CHARACTER_ID: '{characterDto.Id.ToString()}'] Failed to save character"); } Log.Warn($"{characterDto.Name} was saved"); CheckPlayerMute(playerEntity); AccountPenaltyMultiSaveResponse response3 = null; try { response3 = await _accountService.SaveAccountPenalties(new AccountPenaltyMultiSaveRequest { AccountPenaltyDtos = e.Sender.Account.Logs }); } catch (Exception ex) { Log.Error($"[CHARACTER_SAVE][ACCOUNT_ID: '{account.Id.ToString()}'] Unexpected error: ", ex); } if (response3?.ResponseType != RpcResponseType.SUCCESS) { Log.Warn($"[CHARACTER_SAVE][ACCOUNT_ID: '{account.Id.ToString()}'] Failed to save account's penalties"); } } private void CheckPlayerMute(IPlayerEntity playerEntity) { if (!playerEntity.MuteRemainingTime.HasValue) { return; } AccountPenaltyDto penalty = playerEntity.Session.Account.Logs.FirstOrDefault(x => x.PenaltyType == PenaltyType.Muted && x.RemainingTime.HasValue); if (penalty == null) { return; } if (playerEntity.MuteRemainingTime.Value.TotalMilliseconds > 0) { penalty.RemainingTime = (int?)playerEntity.MuteRemainingTime.Value.TotalSeconds; } else { penalty.RemainingTime = null; } } }