using System.Threading; using System.Threading.Tasks; using PhoenixLib.Events; using PhoenixLib.Logging; using WingsAPI.Communication; using WingsAPI.Communication.DbServer.CharacterService; using WingsAPI.Communication.Sessions; using WingsAPI.Communication.Sessions.Model; using WingsAPI.Communication.Sessions.Request; using WingsAPI.Communication.Sessions.Response; using WingsEmu.Game.Characters.Events; using WingsEmu.Game.Managers; using WingsEmu.Game.Networking; namespace WingsEmu.Plugins.BasicImplementations.Event.Characters; public class CharacterPreLoadEventHandler : IAsyncEventProcessor { private static readonly SemaphoreSlim _semaphoreSlim = new(1, 1); private readonly ICharacterService _characterService; private readonly IServerManager _serverManager; private readonly ISessionManager _sessionManager; private readonly ISessionService _sessionService; public CharacterPreLoadEventHandler(ISessionService sessionService, ICharacterService characterService, IServerManager serverManager, ISessionManager sessionManager) { _sessionService = sessionService; _characterService = characterService; _serverManager = serverManager; _sessionManager = sessionManager; } public async Task HandleAsync(CharacterPreLoadEvent e, CancellationToken cancellation) { await _semaphoreSlim.WaitAsync(cancellation); try { IClientSession session = e.Sender; if (session?.Account == null || session.HasSelectedCharacter) { return; } SessionResponse sessionResponse = await _sessionService.GetSessionByAccountId(new GetSessionByAccountIdRequest { AccountId = session.Account.Id }); if (sessionResponse is not { ResponseType: RpcResponseType.SUCCESS }) { session.ForceDisconnect(); return; } Session sharedSession = sessionResponse.Session; if (sharedSession.State != SessionState.CharacterSelection) { session.ForceDisconnect(); return; } if (sharedSession.ChannelId != _serverManager.ChannelId) { await session.NotifyStrangeBehavior(StrangeBehaviorSeverity.DANGER, $"[POTENTIAL_DUPE][PRE_LOAD] Wrong Channel: {sharedSession.AccountId} - {session.Account.MasterAccountId} - {sharedSession.HardwareId}"); session.ForceDisconnect(); return; } if (session.SessionId != sharedSession.EncryptionKey) { await session.NotifyStrangeBehavior(StrangeBehaviorSeverity.DANGER, $"[POTENTIAL_DUPE][PRE_LOAD] Wrong Encryption Key: {sharedSession.AccountId} - {session.Account.MasterAccountId} - {sharedSession.HardwareId}"); session.ForceDisconnect(); return; } DbServerGetCharacterResponse response = await _characterService.GetCharacterBySlot(new DbServerGetCharacterFromSlotRequest { AccountId = session.Account.Id, Slot = e.Slot }); if (response.RpcResponseType != RpcResponseType.SUCCESS) { Log.Warn("[CHARACTER_SCREEN] Selected a character that does not exist"); session.ForceDisconnect(); return; } SessionResponse tmp = await _sessionService.ConnectCharacter(new ConnectCharacterRequest { AccountId = session.Account.Id, ChannelId = _serverManager.ChannelId, CharacterId = response.CharacterDto.Id }); if (tmp.ResponseType != RpcResponseType.SUCCESS) { await session.NotifyStrangeBehavior(StrangeBehaviorSeverity.DANGER, $"[POTENTIAL_DUPE][PRE_LOAD] Looks like {response.CharacterDto.Name} - {session.Account.MasterAccountId} - {sharedSession.HardwareId} was already connected and tried to connect to {_serverManager.ChannelId}"); session.ForceDisconnect(); return; } if (sharedSession.State == SessionState.CrossChannelAuthentication && _serverManager.ChannelId != sharedSession.AllowedCrossChannelId) { session.ForceDisconnect(); return; } if (sharedSession.State != SessionState.CharacterSelection) { await session.NotifyStrangeBehavior(StrangeBehaviorSeverity.DANGER, $"[POTENTIAL_DUPE][PRE_LOAD] Looks like accountId: {sharedSession.AccountId} - {response.CharacterDto.Name} - {sharedSession.HardwareId} was already connected on the channel while being on {_serverManager.ChannelId}"); session.ForceDisconnect(); return; } if (_sessionManager.IsOnline(response.CharacterDto.Id)) { session.ForceDisconnect(); return; } IClientSession alreadyConnectedSession = _sessionManager.GetSessionByCharacterId(response.CharacterDto.Id); if (alreadyConnectedSession != null) { await alreadyConnectedSession.NotifyStrangeBehavior(StrangeBehaviorSeverity.DANGER, $"[POTENTIAL_DUPE][PRE_LOAD] Looks like {alreadyConnectedSession.PlayerEntity.Name} was already connected on the channel while being on {_serverManager.ChannelId}"); alreadyConnectedSession.ForceDisconnect(); await session.NotifyStrangeBehavior(StrangeBehaviorSeverity.DANGER, $"[POTENTIAL_DUPE][PRE_LOAD] Looks like {response.CharacterDto.Name} - {sharedSession.HardwareId} was already connected on the channel while being on {_serverManager.ChannelId}"); session.ForceDisconnect(); return; } session.SelectedCharacterSlot = e.Slot; session.SendPacket("OK"); } finally { _semaphoreSlim.Release(); } } }