101 lines
4.9 KiB
C#
101 lines
4.9 KiB
C#
using NB.Gate.System;
|
||
using Fantasy;
|
||
using Fantasy.Async;
|
||
using Fantasy.Network;
|
||
using Fantasy.Network.Interface;
|
||
|
||
namespace NB.Gate.Handler;
|
||
|
||
public sealed class C2G_LoginRequestHandler : MessageRPC<C2G_LoginRequest, G2C_LoginResponse>
|
||
{
|
||
protected override async FTask Run(Session session, C2G_LoginRequest request, G2C_LoginResponse response,
|
||
Action reply)
|
||
{
|
||
if (string.IsNullOrEmpty(request.ToKen))
|
||
{
|
||
// 1、客户端漏传了 response.ErrorCode = 1;
|
||
// 2、恶意攻击导致的 session.Dispose();
|
||
session.Dispose();
|
||
return;
|
||
}
|
||
|
||
var scene = session.Scene;
|
||
// Log.Info($"网关服场景 {scene.Id} {scene.RouteId} {scene.SceneConfigId} {scene.RouteId} {session.RouteId}");
|
||
if (!GateJWTHelper.ValidateToken(scene, request.ToKen, out var accountId))
|
||
{
|
||
// 如果失败,表示肯定是恶意攻击、所以毫不犹疑,直接断开当前会话。
|
||
session.Dispose();
|
||
return;
|
||
}
|
||
|
||
// 在缓存中检查该账号是否存在
|
||
var gameAccountManageComponent = scene.GetComponent<PlayerManageComponent>();
|
||
Log.Debug("检查账号是否在缓存中");
|
||
if (!gameAccountManageComponent.TryGet(accountId, out var account))
|
||
{
|
||
// 首先要先到数据库中查询是否有这个账号
|
||
account = await PlayerHelper.LoadDataBase(scene, accountId);
|
||
// 如果有的话,就直接加入在缓存中就可以了
|
||
if (account == null)
|
||
{
|
||
Log.Debug("检查到账号没有在数据库中,需要创建一个新的账号并且保存到数据库中");
|
||
// 如果没有,就要创建一个新的并且保存到数据库。
|
||
// 如果不存在,表示这是一个新的账号,需要创建一下这个账号。
|
||
account = await PlayerFactory.Create(scene, accountId);
|
||
}
|
||
else
|
||
{
|
||
Log.Debug("检查到账号在数据库中");
|
||
}
|
||
|
||
Log.Debug("把当前账号添加到缓存中");
|
||
// 把创建完成的Account放入到缓存中
|
||
gameAccountManageComponent.Add(account);
|
||
}
|
||
else
|
||
{
|
||
Log.Debug("检测到当前账号已经在缓存中了");
|
||
// 如果有延迟下线的计划任务,那就先取消一下。
|
||
account.CancelTimeout();
|
||
// 如果在Gate的缓存中已经存在了该账号那只能以下几种可能:
|
||
// 1、同一客户端发送了重复登录的请求数据。
|
||
// 2、客户端经历的断线然后又重新连接到这个服务器上了(断线重连)。
|
||
// 3、多个客户端同时登录了这个账号(顶号)。
|
||
|
||
if (session.RuntimeId == account.SessionRunTimeId)
|
||
{
|
||
// 如果执行到这里,说明是客户端发送了多次登录的请求,这样的情况下,直接返回就可以了,不需要做任何操作。
|
||
return;
|
||
}
|
||
|
||
Log.Debug("检测到当前账号的Session不是同一个");
|
||
if (scene.TryGetEntity<Session>(account.SessionRunTimeId, out var oldSession))
|
||
{
|
||
Log.Debug("当前账号的Session在当前的系统中,所以需要发送一个重复登录的命令,并且要断开这个Session");
|
||
// 如果这个Session在当前框架中可以查询到。
|
||
// 那表示就是当前的会话还是在存在的,有如下几个可能:
|
||
// 1、客户端断线重连,要给这个Session发送一个消息,通知它有人登录了。
|
||
// 2、其他的客户端登录了这个账号,要给这个Session发送一个消息,通知它有人登录了。
|
||
|
||
var gameAccountFlagComponent = oldSession.GetComponent<PlayerFlagComponent>();
|
||
gameAccountFlagComponent.AccountID = 0;
|
||
gameAccountFlagComponent.Player = null;
|
||
// 给客户端发送一个重复登录的消息,如果当前客户端是自己上次登录的,发送也不会收到。
|
||
oldSession.Send(new G2C_RepeatLogin());
|
||
// 给当前Session做一个定时销毁的任务,因为不做这个定时销毁,直接销毁的话,有可能消息还没有发送过去就销毁了
|
||
oldSession.SetTimeout(3000);
|
||
}
|
||
}
|
||
|
||
// 给当前Session添加一个组件,当Session销毁的时候会销毁这个组件。
|
||
var accountFlagComponent = session.AddComponent<PlayerFlagComponent>();
|
||
accountFlagComponent.AccountID = accountId;
|
||
accountFlagComponent.Player = account;
|
||
|
||
account.SessionRunTimeId = session.RuntimeId;
|
||
response.GameAccountInfo = account.GetGameAccountInfo();
|
||
Log.Debug($"当前的Gate服务器:{session.Scene.SceneConfigId} accountId:{accountId}");
|
||
|
||
//连接到游戏中心服
|
||
}
|
||
} |