ET5 MailBoxComponent 简单介绍

根据ET5文档介绍,MailBoxComponent组件一般与Actor搭配使用,挂载该组件后,就可以通过Actor发送消息。

官方demo主要有两种使用方式:

session.AddComponent<MailBoxComponent, string>(MailboxType.GateSession);
await unit.AddComponent<MailBoxComponent>().AddLocation();
await unit.AddComponent<MailBoxComponent>()

1、这里拆分一下服务端的实体(客户端):
  玩家在客户端有Player和Unit:Player有
id,只有一个自己。Unit会有多个,自己和其他人。
  玩家在服务端:
    Realm:只负责注册,查询和验证等功能,不会有长链接的相关处理
    Gate:在网关上有Player实体:有IId,Account和UnitId--关联Map服的Unit实体。Player绑定了Session。
    Map:玩家在Map服务器上有Unit实体有唯一ID,挂载UnitGateComponent组件关联GateSessionId。

2、客户端,各服务器都是不同的端,都不在一台设备上。只是用相同的UnitID,分别在这些端创建Player和Unit实例,实例上存着需要的id号来识别谁是谁和找到连接session。
session就是在不同端建立的持续通信的连接。

Client与Gate通信,网关上存着Player绑定了session,有UnitID就能找到连接session进行通信。

服务端之间,你可以在每个服务端定义一个构建和获取与其它服务端的连接session的方法。

非网关服务器=》客户端,可以用ActorId,构建ActorMessageSender通信。

 

3、举例看看

在InnerMessageDispatcher中添加注释,方便查看内网中的Actor消息传递

HandleIActorMessage函数中:Log.Info("InnerMessageDispatcher内网消息转发:" + message.ActorId + "---" + entity);
 

  

 3.1:Gate服务器不处理消息,直接转发消息

      注意:C2G_LoginGateHandler中 session.AddComponent<MailBoxComponent, string>(MailboxType.GateSession);当其他服务器消息发送到Gate的Session上时,消息会自动转发给前端,Gate服务器不会有相应的Handler处理该信息。

  1、先注释寻路消息:G2M_CreateUnitHandler 中注释掉  await unit.AddComponent<MailBoxComponent>().AddLocation();

      编译运行,

    参考前端,有小人出现。说明创建小人消息发送到了前端,

 

  3.2:Gate服务器处理消息--不直接转发。

     1、调整代码 C2G_LoginGateHandler ,给Player添加个MailBox组件。

            Player player = ComponentFactory.Create<Player, string>(account);
            player.AddComponent<MailBoxComponent>(); //新加入的代码
            
            Game.Scene.GetComponent<PlayerComponent>().Add(player);
            session.AddComponent<SessionPlayerComponent>().Player = player;
            session.AddComponent<MailBoxComponent, string>(MailboxType.GateSession);

 

  2、在Gate服务器中添加一个消息处理Handler

using System.Threading.Tasks;
using ETModel;

namespace ETHotfix
{
    [ActorMessageHandler(AppType.Gate)]
    public class Actor_MatchSucess_NttHandler: AMActorHandler<Player, Actor_MatchSucess_Ntt>
    {
        protected override async ETTask Run(Player entity, Actor_MatchSucess_Ntt message)
        {
            Log.Info($"-------收到Map服务器发送的Actor消息---玩家{entity.Id}收到消息---:" + message.GamerID);
            await Task.CompletedTask;
        }
    }
}

 

3、在内网中添加信息 InnerMessage.proto
在InnerMessage.proto中添加


message Actor_MatchSucess_Ntt // IActorMessage
{
    int32 RpcId = 90;
    int64 ActorId = 94;
    int64 GamerID = 1;
}

 4、在Map中向Gate的Player中发送消息。G2M_CreateUnitHandler 中添加代码。

注意:这个添加的代码,ActorMessageSender 发送消息时往Player中发送,不是Session中。

 

            await unit.AddComponent<MailBoxComponent>().AddLocation();
            unit.AddComponent<UnitGateComponent, long>(request.GateSessionId);
            Game.Scene.GetComponent<UnitComponent>().Add(unit);
            response.UnitId = unit.Id;

            /**********添加测试代码 ********/
            //测试给Gate服务器发送Actor消息
            // 注意,Gate中Player必须 await player.AddComponent<MailBoxComponent>().AddLocation();
             ActorMessageSenderComponent actorLocationSenderComponent = Game.Scene.GetComponent<ActorMessageSenderComponent>();
             //这里是发送到Session实体,会直接转发到前端--需要调整Actor_MatchSucess_Ntt,OuterMessage.proto中添加消息体
             // ActorMessageSender actorMessageSender = actorLocationSenderComponent.Get(request.GateSessionId);
             //这里是发送到Player,Gate有相关Handler处理,不会直接转发
             ActorMessageSender actorMessageSender = actorLocationSenderComponent.Get(request.PlayerId);
             actorMessageSender.Send(new Actor_MatchSucess_Ntt(){GamerID = 32435});
             /**********添加测试代码 ********/
    5、编辑运行

 

4、总结

  同样是Actor消息,有的是发送给Gate,有的是发送给前端。其实都是发送给了Gate,当信息发送给Session时,Gate会直接转发给前端,因为Session挂载MailBox时添加了MailBoxType.GateSession类型,使用会直接转发。Player挂载MailBox时,没有加类型,使用会转发到相关Handler里进行处理。

  至于Player挂载MailBox两种方式  player.AddComponent<MailBoxComponent>(); 和 await player.AddComponent<MailBoxComponent>().AddLocation();  个人理解:后面加AddLocation,会将实体加入到Location服务器中,方便发送 IActorLocationMessage 这种带 Location的消息--这种消息可能会在Location服务器中查询用户。

  所以不论多少个端,Client,Gate,Map,Realm,只是在每个端都创建了同样UnitId的Player实例,和用同样UnitD创建的Unit实例,每一个玩家就像在每个端都有分身或影子,玩家的分身之间把消息传来传去,改变着玩家的状态。

  另外,各类服务器(主要指map)也可以通过网关上客户端与网关的session连接,给一群玩家的本尊客户端广播消息。

  注:Realm只需要认证账号,不需要分身

  Demo中的这几大实例id,就是几种实体(Entity)的InstanceId

    Player,Session,Unit

    • actorsender在构建时,传入一个实体的实例id,就可以给这个实体的实例发消息,不论他在哪个服务器。--例子中player加MailBox
    • 只要有session,player,unit 的实例id就能给他们发actor消息。
    • 而通过session的实例id给用户的网关session发actor消息,session会给你转发给客户端(用户的网关sesion正是网关与客户端的连接session)。

 

 

参考内容:https://www.taikr.com/course/1053/task/30966/show

               https://github.com/egametang/ET/blob/master/Book/5.4Actor%E6%A8%A1%E5%9E%8B.md 

               https://www.lfzxb.top/etbook/#54-actor%E6%A8%A1%E5%9E%8B

            

 

 

 
posted @ 2021-03-08 11:58  Foto_CShow  阅读(399)  评论(0编辑  收藏  举报