ET服务器框架学习笔记(三)

217 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

ET服务器框架学习笔记(三)

文章目录


前言

上一篇简单了解了EventSystem大致的功能与原理,这一篇完善一下EventSystem之后,回到Program,继续深入。


一、EventSystem相关

-public void Add(Component component):添加一个组件(当然派生类,entity等也算的),然后根据component的类型信息,找到之前实例化完毕且注册好的各个与这个component组件关联的System,再调用相关方法,这样一个完整的ECS基础就有了。

public void Add(Component component)
		{
			this.allComponents.Add(component.InstanceId, component);

			Type type = component.GetType();

			if (this.loadSystems.ContainsKey(type))
			{
				this.loaders.Enqueue(component.InstanceId);
			}

			if (this.updateSystems.ContainsKey(type))
			{
				this.updates.Enqueue(component.InstanceId);
			}

			if (this.startSystems.ContainsKey(type))
			{
				this.starts.Enqueue(component.InstanceId);
			}

			if (this.lateUpdateSystems.ContainsKey(type))
			{
				this.lateUpdates.Enqueue(component.InstanceId);
			}
		}
  • public void Deserialize(Component component):这里需要注意的是调用的地方在component的EndInit方法,而这个方法是由标记了Bson反序列化完毕的时调用的。然后也有注释写了这个系统要谨慎使用。因为数据到数据库里,也会走这个方法,如果在System写的东西不对,那么会出现问题。
    -在这里插入图片描述

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

二、Program

1.添加OptionComponent组件

Options options = Game.Scene.AddComponent<OptionComponent, string[]>(args).Options;

调用到Enity的AddComponent(),再调用到ComponentFactory.CreateWithParent,这里会调用到Game.EventSystem.Add(component);从而回到前面说的,system流程,及会调用OptionComponentSystem的Awake,进而调用到OptionComponent自身的Awake

K component = ComponentFactory.CreateWithParent<K, P1>(this, p1, this.IsFromPool);
Game.EventSystem.Add(component);
[ObjectSystem]
	public class OptionComponentSystem : AwakeSystem<OptionComponent, string[]>
	{
		public override void Awake(OptionComponent self, string[] a)
		{
			self.Awake(a);
		}
	}
public class OptionComponent : Component
	{
		public Options Options { get; set; }

		public void Awake(string[] args)
		{
			Parser.Default.ParseArguments<Options>(args)
				.WithNotParsed(error => throw new Exception($"命令行格式错误!"))
				.WithParsed(options => { Options = options; });
		}
	}

这个组件主要用来获取服务器启动时的命令行参数,具体的参数来源于配置。
在这里插入图片描述

2.StartConfigComponent组件

StartConfigComponent存储了服务器启动所需的各类配置,并且通过配置里面的AppType类型,赋予不同的服务启动参数(示例):

public static StartConfigComponent Instance { get; private set; }
		
		private Dictionary<int, StartConfig> configDict;
		
		private Dictionary<int, IPEndPoint> innerAddressDict = new Dictionary<int, IPEndPoint>();
		
		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; }

该处使用的url网络请求的数据。


3.IdGenerater.AppId

初始化IdGenerater.AppId,用于给各个component产生唯一的id,包括各个服务之间的component也能有唯一ID,便于做分布式服务器,各个component进行访问,核心方式就是通过不同的appid以及自增的实例id产生唯一的id(示例):

public long ToLong()
		{
			ulong result = 0;
			result |= (uint)this.AppId;
			result |= this.Value << 18;
			return (long)result;
		}

4.LogManager

对于服务器而言,日志极为重要,用于定位问题,追溯问题相当有用。ET使用Nlog作为日志系统,方便打印保存日志

  • 根据配置修改打印的title,用于看日志的时候,有各类信息,知道是哪个服,哪个appId出问题
				LogManager.Configuration.Variables["appType"] = $"{startConfig.AppType}";
				LogManager.Configuration.Variables["appId"] = $"{startConfig.AppId}";
				LogManager.Configuration.Variables["appTypeFormat"] = $"{startConfig.AppType, -8}";
				LogManager.Configuration.Variables["appIdFormat"] = $"{startConfig.AppId:0000}";

得到的打印结果类似:
在这里插入图片描述
第一行就是代码:Log.Info($“server start… {startConfig.AppId} {startConfig.AppType}”);打印出来的。

5.TimerComponent

时间组件,时间组件是个单例组件。主要用于做一些延时回调,类似于计时器功能,这个类里面涉及的东西比较多,下篇单独来记录一下。

总结

通过配置的启动项,设置appid,这样能设置各个组件的唯一ID用于互相通信,再设置日志系统,日志系统使用的Nlog,简单方便,拿来即用,ET都帮我们配置好了,基本不需要修改。下篇单独对TimerComponent进行分析记录,感觉又是一个难点。