server-master/srcs/_plugins/WingsEmu.Plugins.BasicImplementation/Event/Characters/CharacterPreLoadEventHandler.cs
2026-02-10 18:21:30 +01:00

146 lines
No EOL
6.1 KiB
C#

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<CharacterPreLoadEvent>
{
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();
}
}
}