上一节说道 挂载组件的几个步骤
1. 组件工厂创建组件
2. 如果有泛型类以组件为参数 并且实现了IUpdateSystem接口的话会调用它的update方法
如下面这个类
[ObjectSystem]
public class TimerComponentUpdateSystem : UpdateSystem<TimerComponent>
{
public override void Update(TimerComponent self)
{
self.Update();
}
}
3. 组件添加到父组件字典中
-------------------------------------------------------上一节分界线-------------------------------------------------------
main函数中加载完dll就是 挂载这两个组件 OptionComponent StartConfigComponent
Options options = Game.Scene.AddComponent<OptionComponent, string[]>(args).Options;
StartConfig startConfig = Game.Scene.AddComponent<StartConfigComponent, string, int>(options.Config, options.AppId).StartConfig;
这两个组件干嘛用的 上一节有说道创建组件时候会判断 ,会把 dotnet后面的参数序列化到组件的options属性中
startconfig组件根据上面的文件路径加载配置 根据apptype初始化组件的各类配置文件 如下面这些
public StartConfig StartConfig { get; private set; }
public StartConfig DBConfig { get; private set; }
public StartConfig RealmConfig { get; private set; }
public StartConfig LocationConfig { get; private set; }
public List<StartConfig> MapConfigs { get; private set; }
public List<StartConfig> GateConfigs { get; private set; }
消息分发组件 MessageDispatcherComponent
[ObjectSystem]
public class MessageDispatcherComponentAwakeSystem : AwakeSystem<MessageDispatcherComponent>
{
public override void Awake(MessageDispatcherComponent self)
{
self.Load();
}
}
创建该组件时调用load方法
/// <summary>
/// 消息分发组件
/// </summary>
public static class MessageDispatcherComponentHelper
{
public static void Load(this MessageDispatcherComponent self)
{
self.Handlers.Clear();AppType appType = StartConfigComponent.Instance.StartConfig.AppType;
List<Type> types = Game.EventSystem.GetTypes(typeof(MessageHandlerAttribute));
foreach (Type type in types)
{
object[] attrs = type.GetCustomAttributes(typeof(MessageHandlerAttribute), false);
if (attrs.Length == 0)
{
continue;
}MessageHandlerAttribute messageHandlerAttribute = attrs[0] as MessageHandlerAttribute;
if (!messageHandlerAttribute.Type.Is(appType))
{
continue;
}IMHandler iMHandler = Activator.CreateInstance(type) as IMHandler;
if (iMHandler == null)
{
Log.Error($"message handle {type.Name} 需要继承 IMHandler");
continue;
}Type messageType = iMHandler.GetMessageType();
ushort opcode = Game.Scene.GetComponent<OpcodeTypeComponent>().GetOpcode(messageType);
if (opcode == 0)
{
Log.Error($"消息opcode为0: {messageType.Name}");
continue;
}
self.RegisterHandler(opcode, iMHandler);
}
}public static void RegisterHandler(this MessageDispatcherComponent self, ushort opcode, IMHandler handler)
{
if (!self.Handlers.ContainsKey(opcode))
{
self.Handlers.Add(opcode, new List<IMHandler>());
}
self.Handlers[opcode].Add(handler);
}
}
}
这个方法会从所有组件中找到 标记有MessageHandlerAttribute的类遍历 => 反射创建该类的实例A => 获取该Message的类型B,如下图的R2C_Ping => 把B的编码作为key 实例A作为value 缓存到 ActorMessageDispatcherComponent 组件的ActorMessageHandlers字典中
如下面这个就是一个消息处理类
[MessageHandler(AppType.AllServer)]
public class C2R_PingHandler : AMRpcHandler<C2R_Ping, R2C_Ping>
{
protected override async ETTask Run(Session session, C2R_Ping request, R2C_Ping response, Action reply)
{
reply();
await ETTask.CompletedTask;
}
}
缓存的这些消息处理类在后面收发协议时候回用到
内网通信组件 NetInnerComponent
顾名思义 这个是内网通信用的 添加组件时候传入了内网的地址
Game.Scene.AddComponent<NetInnerComponent, string>(innerConfig.Address);
添加组件后会自动调用awake方法 看一下这个方法干了啥
public static void Awake(this NetInnerComponent self, string address)
{
self.Awake(NetworkProtocol.TCP, address, Packet.PacketSizeLength4);
self.MessagePacker = new MongoPacker();
self.MessageDispatcher = new InnerMessageDispatcher();
self.AppType = StartConfigComponent.Instance.StartConfig.AppType;
}
标黄的方法是父组件 NetworkComponent的方法 根据协议类型创建不同的通信类
public void Awake(NetworkProtocol protocol, string address, int packetSize = Packet.PacketSizeLength2)
{
IPEndPoint ipEndPoint;
switch (protocol)
{
case NetworkProtocol.KCP:
ipEndPoint = NetworkHelper.ToIPEndPoint(address);
this.Service = new KService(ipEndPoint, this.OnAccept) { Parent = this };
break;
case NetworkProtocol.TCP:
ipEndPoint = NetworkHelper.ToIPEndPoint(address);
this.Service = new TService(packetSize, ipEndPoint, this.OnAccept) { Parent = this };
break;
case NetworkProtocol.WebSocket:
string[] prefixs = address.Split(';');
this.Service = new WService(prefixs, this.OnAccept) { Parent = this };
break;
}
}
这里公司用的是websocket
然后就是开启websocket监听 配置文件中InnerConfig地址 127.0.0.1:20002
websocket通讯服务端大概这样的
*******************websocket服务端****************************************
第一步:创建HttpListener类,并启动监听:
var listener = new HttpListener();
listener.Prefixes.Add("http://10.10.13.140:8080/");
listener.Start();
第二步:等待连接var context = listener.GetContext();
第三步:接收websocketvar wsContext = await context.AcceptWebSocketAsync(null);
var ws = wsContext.WebSocket;
Console.WriteLine("WebSocket connect");
第四步:开始异步接收数据//接收数据
var wsdata = await ws.ReceiveAsync(abuf, cancel);
Console.WriteLine(wsdata.Count);
byte[] bRec = new byte[wsdata.Count];
Array.Copy(buf, bRec, wsdata.Count);
Console.WriteLine(Encoding.Default.GetString(bRec));
第五步:释放资源//注意,使用完,记得释放,不然会有内存泄漏
ws.Dispose();
ET不一样的是在接收到websocket消息后 ,调用一个OnAccept方法 创建session组件 然后调用start方法
public void OnAccept(AChannel channel)
{
Session session = ComponentFactory.CreateWithParent<Session, AChannel>(this, channel);
this.sessions.Add(session.Id, session);
session.Start();
}