您的位置:首页 > 其它

ET框架---ClientDispatcher学习笔记

2018-04-07 23:11 302 查看

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层调用热更层中的方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息