SessionUserComponent
请大家关注我的微博:@NormanLin_BadPixel坏像素
我们一眼就看到了作者的注释。
/// <summary>
/// Session关联User对象组件
/// 用于Session断开时触发下线
/// </summary>
public class SessionUserComponent : Component
{
// User对象
public User User { get; set; }
...
}
这个User属性会在添加这个组件的时候赋值。既在客户端发送登陆请求,在Gate服务器登陆时创建的User对象。同时会创建Gate服务器与客户端之间的会话Session,在这个Session上会添加这个组件并把前面创建的User对象赋值给SessionUserComponent.User。具体过程可以看通过注册登陆请求走一遍简单的消息传输
//释放User对象时将User对象从管理组件中移除
Game.Scene.GetComponent<UserComponent>()?.Remove(this.User.UserID);
之前创建User对象的时候把它记录在UserComponent里面,现在玩家退出,要把这条记录移除。
//正在匹配中发送玩家退出匹配请求
if (this.User.IsMatching)
{
IPEndPoint matchIPEndPoint = config.MatchConfig.GetComponent<InnerConfig>().IPEndPoint;
Session matchSession = Game.Scene.GetComponent<NetInnerComponent>().Get(matchIPEndPoint);
await matchSession.Call(new G2M_PlayerExitMatch_Req() { UserID = this.User.UserID });
}
嗯,向匹配服务器发送玩家退出匹配的请求。我们去看看怎么处理。
protected override void Run(Session session, G2M_PlayerExitMatch_Req message, Action<M2G_PlayerExitMatch_Ack> reply)
{
M2G_PlayerExitMatch_Ack response = new M2G_PlayerExitMatch_Ack();
try
{
Matcher matcher = Game.Scene.GetComponent<MatcherComponent>().Remove(message.UserID);
matcher?.Dispose();
Log.Info($"玩家{message.UserID}退出匹配队列");
reply(response);
}
catch (Exception e)
{
ReplyError(response, e, reply);
}
}
不深究了,MatcherComponent我们学习过了。
//正在游戏中发送玩家退出房间请求
if(this.User.ActorID != 0)
{
ActorProxy actorProxy = actorProxyComponent.Get(this.User.ActorID);
await actorProxy.Call(new Actor_PlayerExitRoom_Req() { UserID = this.User.UserID });
}
之前我们把消息发送给匹配服务器,现在我们要把消息发送给指定的玩家角色。不过这个玩家角色具体在那个服务器上,我们不知道,所以我们通过ActorProxy去发送消息。
而接收Actor消息的服务器,是用NetInnerComponent监听接收端口的,并且用InnerMessageDispatcher处理消息。
// 收到actor rpc request
if (message is ActorRequest actorRpcRequest)
{
Entity entity = Game.Scene.GetComponent<ActorManagerComponent>().Get(actorRpcRequest.Id);
if (entity == null)
{
Log.Warning($"not found actor: {actorRpcRequest.Id}");
ActorResponse response = new ActorResponse
{
Error = ErrorCode.ERR_NotFoundActor
};
session.Reply(packetInfo.RpcId, response);
return;
}
entity.GetComponent<ActorComponent>().Add(new ActorMessageInfo() { Session = session, RpcId = packetInfo.RpcId, Message = actorRpcRequest });
return;
}
我们看到,它会通过ID精准找到需要处理消息的对象,并把消息添加入ActorComponent内的任务待办任务队列中。
我们可以在Actor_PlayerExitRoom_ReqHandler里面找到对这个消息的处理,我们就不深究了。
//向登录服务器发送玩家下线消息
IPEndPoint realmIPEndPoint = config.RealmConfig.GetComponent<InnerConfig>().IPEndPoint;
Session realmSession = Game.Scene.GetComponent<NetInnerComponent>().Get(realmIPEndPoint);
realmSession.Send(new G2R_PlayerOffline_Ntt() { UserID = this.User.UserID });
this.User.Dispose();
this.User = null;
我们看看登陆服务器的处理。
protected override void Run(Session session, G2R_PlayerOffline_Ntt message)
{
//玩家下线
Game.Scene.GetComponent<OnlineComponent>().Remove(message.UserID);
Log.Info($"玩家{message.UserID}下线");
}
很简单。