ET游戏框架整理笔记1: 从main函数说起

写这个主要是给自己梳理下这个框架  省的看一遍回头又忘了

加载dll都干了啥

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

代码不贴了  这里简单记下 

遍历程序集 =>遍历所有类 =>找到所有标记了BaseAttribute及其子Attribute的类型 添加到types字典中 key=attributetype value =type

下面是目前框架内的所有标记有BaseAttribute的类型

image

然后遍历types =>找到标记了ObjectSystem的类 =>根据其实现的不同接口 添加到不同的字典中 key=type value=类的实例

比如下面这个

[ObjectSystem]
public class AppManagerComponentAwakeSystem : AwakeSystem<AppManagerComponent>
{
     public override void Awake(AppManagerComponent self)
     {
         self.Awake();
     }
}



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;

                }

AwakeSystem 是实现了IAwakeSystem 接口的

同理找到所有标记 EventAttribute的type 添加到字典中  这个就一个类标记有该标签 暂时忽略

这些字典是挂在 Game上面的 算是全局变量 把标记了ObjectSystemAttribute标签的类的实例缓存起来做什么? 这里还看不出来


Game.Scene 挂载组件

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

挂载组件会先创建一个component对象 然后添加到组件字典中 key=type value=component实例

创建component代码贴下

//创建组件

K component = ComponentFactory.CreateWithParent<K, P1>(this, p1, this.IsFromPool);


public static T CreateWithParent<T, A>(Component parent, A a, bool fromPool = true) where T : Component
{
     Type type = typeof (T);
    
     T component;
     if (fromPool)
     {
         component = (T)Game.ObjectPool.Fetch(type);
     }
     else
     {
         component = (T)Activator.CreateInstance(type);   
     }
    
     Game.EventSystem.Add(component);
    
     component.Parent = parent;
     if (component is ComponentWithId componentWithId)
     {
         componentWithId.Id = component.InstanceId;
     }
     Game.EventSystem.Awake(component, a);
     return component;
}

注意这一句 Game.EventSystem.Add(component);

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);
     }
}

这里用到了上面缓存的类型,把挂载的组件的instanceid根据分类添加到了不同队列中   那这个队列中的缓存这些组件instanceid干嘛呢  这里不知道


最后一个操作  Game.EventSystem.Awake(component, a);

下面根据之前加载dll时候 缓存的类的实例  比如 上面贴的 AppManagerComponentAwakeSystem  然后调用 IAwake接口

所以所有 标记了ObjectSystem特性标签 && 实现IAwake接口的类  都会在实例化时候 调用它的Awake方法

public void Awake<P1>(Component component, P1 p1)
         {
             List<IAwakeSystem> iAwakeSystems = this.awakeSystems[component.GetType()];
             if (iAwakeSystems == null)
             {
                 return;
             }

            foreach (IAwakeSystem aAwakeSystem in iAwakeSystems)
             {
                 if (aAwakeSystem == null)
                 {
                     continue;
                 }
                
                 IAwake<P1> iAwake = aAwakeSystem as IAwake<P1>;
                 if (iAwake == null)
                 {
                     continue;
                 }

                try
                 {
                     iAwake.Run(component, p1);
                 }
                 catch (Exception e)
                 {
                     Log.Error(e);
                 }
             }
         }

之后再把刚刚创建的组件添加到component字典中


根据不同的应用程序类型加载不同组件

服务器类型大概分为 realm gate map location 等

每种服务器需要挂载的组件不同  根据配置文件配置  挂载不同组件

然后死循环调用 update方法

while (true)
{
     try
     {
         Thread.Sleep(1);
         OneThreadSynchronizationContext.Instance.Update();
         Game.EventSystem.Update();
     }
     catch (Exception e)
     {
         Log.Error(e);
     }
}

还记得上面标记绿色的疑问吗

下面就把之前缓存的instanceid取出去组件字典中获取组件

然后获取之前缓存的实现了IUpdateSystem 接口的实例 调用update方法

比如下面这个

[ObjectSystem]
public class TimerComponentUpdateSystem : UpdateSystem<TimerComponent>
{
     public override void Update(TimerComponent self)
     {
         self.Update();
     }
}


public void Update()
         {
             this.Start();
            
             while (this.updates.Count > 0)
             {
                 long instanceId = this.updates.Dequeue();
                 Component 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
                     {
                         iUpdateSystem.Run(component);
                     }
                     catch (Exception e)
                     {
                         Log.Error(e);
                     }
                 }
             }

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


在此前 会调用this.Start();方法

这里不贴了 和update逻辑一样的  就是在update前 调用component实现的IStartSystem接口方法

然后把instanceid放到了另一个队列中 this.updates2.Enqueue(instanceId);  为什么放到新队列中 不知道

 框架每隔一毫秒就调用一次 标记有ObjectSystem标签 并实现了IUpdateSystem接口的类方法  并在此调用IStartSystem接口方法(如果有的话)

posted @ 2019-07-10 23:34  小谭行天下  阅读(772)  评论(0编辑  收藏  举报