# 事件机制EventSystem  
ECS最重要的特性一是数据跟逻辑分离，二是数据驱动逻辑。什么是数据驱动逻辑呢？不太好理解，我们举个例子
一个moba游戏，英雄都有血条，血条会在人物头上显示，也会在左上方头像UI上显示。这时候服务端发来一个扣血消息。我们怎么处理这个消息？第一种方法，在消息处理函数中修改英雄的血数值，修改头像上血条显示，同时修改头像UI的血条。这种方式很明显造成了模块间的耦合。第二种方法，扣血消息处理函数中只是改变血值，血值的改变抛出一个hpchange的事件，人物头像模块跟UI模块都订阅血值改变事件，在订阅的方法中分别处理自己的逻辑，这样各个模块负责自己的逻辑，没有耦合。
ET提供了多种事件，事件都是可以多次订阅的:  
1. AwakeSystem，组件工厂创建组件后抛出，只抛出一次，可以带参数
```csharp
    Player player = ComponentFactory.Create<Player>();

    // 订阅Player的Awake事件
    public class PlayerAwakeSystem: AwakeSystem<Player>
    {
        public override void Awake(Player self)
        {
        }
    }
```
2. StartSystem，组件UpdateSystem调用前抛出
```csharp
    // 订阅Player的Start事件
    public class PlayerStartSystem: StartSystem<Player>
    {
        public override void Start(Player self)
        {
        }
    }
```
3. UpdateSystem，组件每帧抛出
```csharp
    // 订阅Player的Update事件
    public class PlayerUpdateSystem: UpdateSystem<Player>
    {
        public override void Update(Player self)
        {
        }
    }
```
4. DestroySystem，组件删除时抛出
```csharp
    // 订阅Player的Destroy事件
    public class PlayerDestroySystem: DestroySystem<Player>
    {
        public override void Destroy(Player self)
        {
        }
    }

    Player player = ComponentFactory.Create<Player>();
    // 这里会触发Destroy事件
    player.Dispose();
```
5. ChangeSystem，组件内容改变时抛出，需要开发者手动触发
```csharp
    // 订阅Player的Destroy事件
    public class PlayerChangeSystem: ChangeSystem<Player>
    {
        public override void Change(Player self)
        {
        }
    }

    Player player = ComponentFactory.Create<Player>();
    // 需要手动触发ChangeSystem
    Game.EventSystem.Change(player);
```
6. DeserializeSystem，组件反序列化之后抛出
```csharp
    // 订阅Player的Deserialize事件
    public class PlayerDeserializeSystem: DeserializeSystem<Player>
    {
        public override void Deserialize(Player self)
        {
        }
    }

    // 这里player2会触发Deserialize事件
    Player player2 = MongoHelper.FromBson<Player>(player.ToBson());
```
7. LoadSystem，EventSystem加载dll时抛出，用于服务端热更新，重新加载dll做一些处理，比如重新注册handler
```csharp
    // 订阅Player的Load事件
    public class PlayerLoadSystem: LoadSystem<Player>
    {
        public override void Load(Player self)
        {
        }
    }
```
8. 普通的Event，由开发者自己抛出，可以最多带三个参数。另外客户端热更层也可以订阅mono层的Event事件
```csharp
    int oldhp = 10;
    int newhp = 5;
    // 抛出hp改变事件
    Game.EventSystem.Run("HpChange", oldhp, newhp);

    // UI订阅hp改变事件
    [Event("HpChange")]
    public class HpChange_ShowUI: AEvent<int, int>
    {
        public override void Run(int a, int b)
        {
            throw new NotImplementedException();
        }
    }

    // 模型头顶血条模块也订阅hp改变事件
    [Event("HpChange")]
    public class HpChange_ModelHeadChange: AEvent<int, int>
    {
        public override void Run(int a, int b)
        {
            throw new NotImplementedException();
        }
    }
```

9. 除此之外还有很多事件，例如消息事件。消息事件使用MessageHandler来声明，可以带参数指定哪种服务器需要订阅。
```csharp
	[MessageHandler(AppType.Gate)]
	public class C2G_LoginGateHandler : AMRpcHandler<C2G_LoginGate, G2C_LoginGate>
	{
		protected override void Run(Session session, C2G_LoginGate message, Action<G2C_LoginGate> reply)
		{
			G2C_LoginGate response = new G2C_LoginGate();
			reply(response);
		}
	}
```
更具体的消息事件等到讲消息的时候再细细讲解了  
10. 数值事件，数值模块再讲解  
......, 更多的事件由自己去开发。

ET框架的逻辑就是由以上各种事件来驱动的。


