ET框架---ClientDispatcher学习笔记

ClientDispatcher学习笔记

请大家关注我的微博:@NormanLin_BadPixel坏像素


public class ClientDispatcher: IMessageDispatcher
{
    // 热更层消息回调
    public Action<Session, PacketInfo> HotfixCallback;

    public void Dispatch(Session session, PacketInfo packetInfo)
    {
        if (OpcodeHelper.IsClientHotfixMessage(packetInfo.Opcode))
        {
            HotfixCallback.Invoke(session, packetInfo);
            return;
        }

        Type messageType = Game.Scene.GetComponent<OpcodeTypeComponent>().GetType(packetInfo.Opcode);
        IMessage message = (IMessage)session.Network.MessagePacker.DeserializeFrom(messageType, packetInfo.Bytes, packetInfo.Index, packetInfo.Length);

        // 如果是帧同步消息,交给ClientFrameComponent处理
        FrameMessage frameMessage = message as FrameMessage;
        if (frameMessage != null)
        {
            Game.Scene.GetComponent<ClientFrameComponent>().Add(session, frameMessage);
            return;
        }

        // 普通消息或者是Rpc请求消息
        MessageInfo messageInfo = new MessageInfo(packetInfo.RpcId, packetInfo.Opcode, message);
        Game.Scene.GetComponent<MessageDispatherComponent>().Handle(session, messageInfo);
    }
}

我们先看看普通的消息是怎么处理的。传入的参数是SessionPacketInfo,这在我们之前都讲过了。在Seesion学习笔记里有。
我们知道,通过网络传过来的消息在接收过来后会被封装成PacketInfo,这里,我们需要对PacketInfo进行解析,获取到里面的消息。之前怎么打包的,我们也就怎么解包。先是通过Opcode获取到消息的类型,根据类型再反序列换为IMessage相对应的派生类,所有的消息都会继承这个类。

// 如果是帧同步消息,交给ClientFrameComponent处理

因为如果是帧同步消息,则需要根据帧同步决定它什么时候被处理,所以我们把它传给ClientFrameComponent,这个我们之前也讲过哦。

而如果是普通消息或者是Rpc请求消息,我们需要立马对其进行处理。先是根据消息内容创建MessageInfo,然后直接交给MessageDispatherComponent处理。这里我们也知道为什么在3.0里把MessageDispatherComponent移除了热更新消息的调度,因为热更的消息在3.0根本就不会传入MessageDispatherComponent,而是在HotfixCallback里调用。而热更新的消息则会传入HotfixMessageDispatcher,因为热更的消息有自己的一套OpcodeTypeComponentMessageDispatherComponent

HotFix的OpcodeTypeComponent

HotFix的OpcodeTypeComponent跟Model的相差无几,但是在储存Opcode的时候,把有MEssageAttribute特性的类存入了ProtoBuf.PType。这个类,在原生Protobuf-net中是没有的。它用自己的CreateInstance取代了原生Protobuf-net中的RuntimeTypeModelTypeSerializer中的Activator.CreateInstance。为什么要这么做呢?为什么呢?

我也很疑惑,所以去问了,不过大概是周末,大家都不在,没有人为我解惑。所以我就不断的去看,看这些代码的源头在哪,又是在什么地方被调用的。终于,功夫不负有心人,终于给我找着了,这里我就给大家解惑一下。(可花了我半个多小时!)

如上面介绍的,我们的消息会分为热更新消息和普通消息,但是不管是什么消息,我们都需要在Unity主程序层通过Protobuf-net反序列化成对应的类。反序列化其实就是根据一定结构的数据实例化一个类。但是,我们知道,在ILRuntime中的反射,是不允许我们直接实例化热更层的类的,而是要调用AppDomain来创建实例。这里是说明。所以为了区分需要反序列化的类是热更层dll中的还是Unity主程序的,引入了这个PType

public static object CreateInstance(Type type){
    if (Type.GetType (type.FullName) == null) {
        if (CreateInstanceFunc != null) {
            return CreateInstanceFunc.Invoke(type.FullName);
        }
    }
    return Activator.CreateInstance (type
        #if !(CF || SILVERLIGHT || WINRT || PORTABLE || NETSTANDARD1_3 || NETSTANDARD1_4)
        , nonPublic: true
        #endif
    );
}

通过这个方法创建实例,会判断是否属于热更层的类,如果是,则通过特殊的方法实例化,这里是ILRuntime的appDomain.Instantiate方法。否则,则通过普通的Activator.CreateInstance

HotFix的MessageDispatherComponent

热更层的消息调度器跟Model层的差不多,也是获取热更层的程序集,找到里面有MessageHandlerAttribute特性的类,然后根据opcode注册里面的处理器。但是这里多了一个步骤,它会尝试注册到mono层。为什么还要注册到mono层呢?我的理解是,有些消息,可能需要mono层和热更层同时处理。瞎编个例子,一个移动的消息,我的位置变化可能写在mono层,是不变的,但是我的动画播放写在热更层,可能会变。而注册到mono层,则要通过中间层MessageProxy,这个其实就是用委托代理的方法让mono层调用热更层中的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值