ET框架:Server底层主逻辑循环(2)--EventSystem

7 篇文章 0 订阅
6 篇文章 0 订阅

之前Server的主逻辑循环中
除了异步处理,还有一个EventSystem.Update()
因为异步处理搜索引用后,只发现网络逻辑中有使用,因此,可以猜测Game.EventSystem就囊括了所有游戏的逻辑了

while (true)
{
	try
	{
		Thread.Sleep(1);
		OneThreadSynchronizationContext.Instance.Update(); // 处理异步回调
		Game.EventSystem.Update();
	}
	catch (Exception e)
	{
		Log.Error(e);
	}
}

Main方法中try{}中一开始,就发现这两句:

Game.EventSystem.Add(DLLType.Model, typeof(Game).Assembly);
Game.EventSystem.Add(DLLType.Hotfix, DllHelper.GetHotfixAssembly());

出现Assembly,表示这个EventSystem很可能通过反射来调用接口。
看看Add 方法做了什么?

		/// <summary>
        /// 添加一个程序集
        /// 每调用一次,所有表都会重置一次,并且load系统会执行一次
        /// </summary>
        /// <param name="dllType"></param>
        /// <param name="assembly"></param>
		public void Add(DLLType dllType, Assembly assembly)
		{
			// 这个表在运行过程中只覆盖,不重置。其他所有表或队列将被重置掉
			this.assemblies[dllType] = assembly;
 			
			// types实际上是个Dict<AttributeType, List<ClassType>>的结构
			// AttributeType应用了特性(Attribute),向程序类添加声明性信息
			// 在类、方法等的声明上一行用中括号[]引用
			// 继承 Attribute 的子类名字如果以 “Attribute” 结尾,则声明时是可以简化这个结尾的
			// 这里将 “继承自 BaseAttribute 的 Attribute” 来声明的类都找到。
			// 按照 AttributeType 来分类保存在types中
			this.types.Clear();
			foreach (Assembly value in this.assemblies.Values)
			{
				foreach (Type type in value.GetTypes())
				{
					if (type.IsAbstract)
					{
						continue;
					}

					object[] objects = type.GetCustomAttributes(typeof(BaseAttribute), true);
					if (objects.Length == 0)
					{
						continue;
					}

					BaseAttribute baseAttribute = (BaseAttribute) objects[0];
					this.types.Add(baseAttribute.AttributeType, type);
				}
			}

			// 一堆System,主力逻辑,最重要的system是update
			// 这里的system表结构是Dict<ComponentType, List<ISystem>>
			this.awakeSystems.Clear();
			this.lateUpdateSystems.Clear();
			this.updateSystems.Clear();
			this.startSystems.Clear();
			this.loadSystems.Clear();
			this.changeSystems.Clear();
			this.destroySystems.Clear();
			this.deserializeSystems.Clear();

			// 把所有特性是 ObjectSystem 的类实例化,并将实例对象放入对应的表中
			// 不同的接口放到不同的系统表中,系统表中按照处理的组件类型来分组
			foreach (Type type in this.GetTypes(typeof(ObjectSystemAttribute)))
			{
				object obj = Activator.CreateInstance(type); // 实例化

				switch (obj)
				{
					case IAwakeSystem objectSystem:
						this.awakeSystems.Add(objectSystem.Type(), objectSystem);
						break;
					case IUpdateSystem updateSystem:
						this.updateSystems.Add(updateSystem.Type(), updateSystem);
						break;
					case ILateUpdateSystem lateUpdateSystem:
						this.lateUpdateSystems.Add(lateUpdateSystem.Type(), lateUpdateSystem);
						break;
					case IStartSystem startSystem:
						this.startSystems.Add(startSystem.Type(), startSystem);
						break;
					case IDestroySystem destroySystem:
						this.destroySystems.Add(destroySystem.Type(), destroySystem);
						break;
					case ILoadSystem loadSystem:
						this.loadSystems.Add(loadSystem.Type(), loadSystem);
						break;
					case IChangeSystem changeSystem:
						this.changeSystems.Add(changeSystem.Type(), changeSystem);
						break;
					case IDeserializeSystem deserializeSystem:
						this.deserializeSystems.Add(deserializeSystem.Type(), deserializeSystem);
						break;
				}
			}

			// 事件分发器表,所有声明了EventAttribute的类都是监听器
			// 监听的事件类型在声明EventAttribute时候定义,例如:
			// ...../ET/Unity/Assets/Model/Module/Numeric/NumericChangeEvent_NotifyWatcher.cs (4, 3):	[Event(EventIdType.NumbericChange)]
			// EventIdType文件中定义了各种事件,注意,server 和 client 有各自的EventIdType文件
			// EventSystem 的 Run 方法就是用来通知Watcher有事件触发
			this.allEvents.Clear();
			if (this.types.ContainsKey(typeof (EventAttribute)))
			{
				foreach (Type type in types[typeof(EventAttribute)])
				{
					object[] attrs = type.GetCustomAttributes(typeof(EventAttribute), false);

					foreach (object attr in attrs)
					{
						EventAttribute aEventAttribute = (EventAttribute)attr;
						object obj = Activator.CreateInstance(type);
						IEvent iEvent = obj as IEvent;
						if (iEvent == null)
						{
							Log.Error($"{obj.GetType().Name} 没有继承IEvent");
						}
						// 注册事件监听器,按事件类型分
						this.RegisterEvent(aEventAttribute.Type, iEvent);
					}
				}
			}


			// 所有系统实例化完成,现在跑一次loadSystem逻辑
			this.Load();
		}

再看看Update逻辑,
Update的逻辑中用了双队列交替遍历,可以在一次循环中遍历所有新增的update组件。

		/// <summary>
        /// EventSystem 的 Update 逻辑
        /// 注意写法有可能导致的问题
        /// </summary>
		public void Update()
		{
			// update前先start
			// 但start的执行并不一定在update前
			this.Start();

            // 这里执行到所有update运行过为止
            // 死循环可能:假设update中不断增加一个新的update组件
            // 执行逻辑错误可能: 假设某个update中注册一个新的Entity,其带有一个update组件和一个start组件
            //   那么这个Entity的 update 会比 start 先执行
            // 最简单的解决方法是:
            //int count = this.updates.Count;
            while (this.updates.Count > 0)
			{
                // 从队列中获取一个实体ID
                // 如果这个实体已经被删除,就不会再添加回去队列中
				// 从而清理掉已经删除的实体
                long instanceId = this.updates.Dequeue();
				// 死循环和执行逻辑错误的解决方法:
				// 如果计数器到了,直接把instanceId添加回队列中
				//if (count <= 0)
				//{
				//	this.updates2.Enqueue(instanceId);
				//	continue;
				//}
				//count--;
		
				Entity component;
				if (!this.allComponents.TryGetValue(instanceId, out component))
				{
					continue;
				}
				if (component.IsDisposed)
				{
					continue;
				}
				
				List<IUpdateSystem> iUpdateSystems = this.updateSystems[component.GetType()];
				if (iUpdateSystems == null)
				{
					continue;
				}

				this.updates2.Enqueue(instanceId);

				foreach (IUpdateSystem iUpdateSystem in iUpdateSystems)
				{
					try
					{
						// 执行update
						iUpdateSystem.Run(component);
					}
					catch (Exception e)
					{
						Log.Error(e);
					}
				}
			}

			ObjectHelper.Swap(ref this.updates, ref this.updates2);
		}

其他系统遍历都有类似问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值