GameFramework 底层解析
对GF的源码解析,学习设计思路,学习代码规范 GF官网 GF-API
看了GF的源码,感觉自己之前写的代码都是一堆垃圾!!!
源码阅读建议:与StarForce项目一同阅读
Base层
数据处理器,序列化工具,Log,事件池,引用池,任务代理池,其他扩展:Action,Func,变量封装(用于自定义数据结构),自定义链表
DataProvider 数据处理器
主要细节只需要看IDataProvider,IDataProviderHelper的实现上
IDataProvider,IDataProviderHelper主要实现2个接口:ReadData,ParseData
- IDataProvider 从ResourceManager中读取资源,为数据提供者
- IDataProviderHelper负责对具体数据的解析,为数据提供者帮助接口,用户使用上只需要实现帮助类即可
对于IDataProviderHelper可能会引起误区,这里的ReadData是在IDataProvider读取资源成功时调用,这时已经拿到了需要的资源,可以直接使用或者再主动调用ParseData解析数据再使用。 - 执行顺序如:
ConfigManager.ReadData()->IDataProvider.ReadData()->读取成功后->IDataProviderHelper.ReadData(),
这时主动调用ConfigManager.ParseData()->IDataProvider.ParseData()->IDataProviderHelper.ParseData()
1 | IDataProvider |
EventPool 事件池
实现事件接口:订阅,取消订阅,抛出事件,立即抛出事件
- Fire 抛出事件:线程安全,将待执行事件放入队列,下一帧执行
- FireNow 立即抛出事件:线程不安全
1 | // |
Log
对Log进行封装,ILogHelper对Log的具体实现
ReferencePool 引用池
为了降低因大量产生类对象而导致的内存分配,设计了引用池的概念,来将用完的对象清理并缓存起来,供后续使用。
实现IReference接口,通过ReferencePool.Acquire
TaskPool 任务池
这个任务池主要做资源异步加载,下载等异步操作的任务
- TaskBase:只是任务数据
- ITaskAgent:任务代理,处理任务的具体行为
如DownloadAgent.cs处的使用,Agent只处理该Task中数据,并在执行中通知对应Helper执行具体下载逻辑 - TaskInfo:用于Debug等展示的信息
- TaskPool:任务池,管理ITaskAgent并执行
Variable 变量
变量封装
Version 版本号
方便版本号管理,版本号在资源更新时需要使用,判断旧资源与新资源的版本号。
封装的基础类型
类 | 注释 |
---|---|
GaneFrameworkAction | 封装多参数委托 |
GameFrameworkFunc | 封装多参数委托 |
GameFrameworkEntry | 游戏入口 |
GameFrameworkEventArgs | 事件数据封装 |
GameFrameworkException | 异常抛出封装 |
GameFrameworkLinkedList | 带缓存的LinkedList(链表) |
GameFrameworkLinkedListRange | 有范围的链表,即理解为LinkedList中的一小段 |
GameFrameworkModule | 模块的封装基类,统一管理各类模块Manager |
GameFrameworkMultiDictionary | 多值字典,Value为链表 |
GameFrameworkSerializer | 序列化器, |
Config
经过了对Base层的理解,Config层就很轻松弄明白了。
主要封装了数据读取,解析,获取。
执行顺序:
ConfigManager.ReadData()->IDataProvider.ReadData()->读取成功后->IDataProviderHelper.ReadData(),
ConfigManager.ParseData()->IDataProvider.ParseData()->IDataProviderHelper.ParseData()
使用上只需要:修改对应Helper即可
DataNode
树状数据节点,个人使用最多就是GetOrAddNode(string)
DataTable
- 使用DataTable,扩展一下可以很方便与excel使用
- 实现Helper类解析Excel产生的bytes数据即可
接口 | 注释 |
---|---|
IDataTable | 表(数据容器,管理多条数据) |
IDataRow | 数据项(一条数据) |
IDataHelper | 数据解析帮助类 |
IDataTableManager | 管理所有表 |
Debugger
运行时的Debugger界面,使用上很方便,具体就是打印多种不同信息
Download
下载任务都是异步操作,因此需要等待,这时Base层定义好的TaskPool就有了作用
下载步骤:
- DownloadTask携带下载数据:下载路径,保存路径,下载状态,缓冲区大小等
- DownloadAgent处理任务数据,监听下载状态变化:下载数据更新,下载长度更新,下载完成,下载失败
- IDownloadAgentHelper实现实际下载逻辑,如UnityWebRequestDownloadAgentHelper为例,使用UnityWebRequest发送实际下载请求,DownloadHandler抛出下载数据更新事件
- DownloadCounter计算下载速度
- IDownloadManager即下载管理器,管理任务池以及开放对应下载接口
Entity
Entity即实体
EntityManager->EntityGroup->Entity
每个Entity有独一无二的id,Manager通过字典存储,方便管理Entity
每个EntityManager管理EntityGroup,EntityGroup只管理组内的Entity
每个Entity实际生成时通过EntityGroup中的对象池子管理
ShowEntity流程:ReourcesManager加载资源->IEntityHelper实例化->注册进EntityGroup的对象池中->调用Entity生命周期函数OnInit->OnShow
Event
对Base层的EventPool的一层封装
FileSystem
- FileSystem对应一个物理文件,其中保存多个文件数据,每个文件数据可理解为一个数据类型的二进制数据,加载时解析成对应类型的数据
其中有一个概念数据块,即每一个文件数据都是一个数据块,但是当同名数据更新时,文件数据会更换一个空闲块进行存储。 - IFileSystem fileSystem = fileSystemComponent.CreateFileSystem(fullPath, FileSystemAccess.ReadWrite, maxFileCount, maxBlockCount);
创建文件系统时,输入的maxFileCount,以及maxBlockCount对应最大文件个数以及最大数据块个数,目前FileSystem还不支持文件系统自动扩容,需一开始设定好,且maxFileCount <= maxBlockCount,在更新文件数据时会更换数据块,因此更新越频繁的数据maxBlockCount需要越大,以保证数据更新有足够的碎片空间进行修改。
FSM
有限状态机
Localization
本地化语言,实现上与Config类似,只是在不同Language下读取不同的文件下存储的keyValue
Network
接口 | 注释 |
---|---|
INetworkManager | 管理NetworkChannel |
INetworkChannel | 建立链接,处理消息接收发送 |
INetworkChannelHelper | 消息序列化反序列化帮助类 |
IPacketHandler | 处理协议,每个协议有其ID,通过ID区分 |
IPacketHeader | 消息头部信息主要记录长度,可自行添加头部信息携带数据,实际消息存在长度,发包是存在数据的粘包以及分包,这时需要头部信息判断消息是否接收完毕 |
- 使用上,客户端需要链接几处服务器就创建几个INetworkChannel分别链接,发消息也是同样每个链接处理各自的消息如:实际服务器一般存在:Gate服务器,Game服务器,Chat服务器,Friend服务器等等,使用NetworkManager可以很方便管理这种分布式服务器的链接
- 使用网络通信的数据结构最好使用protobuf,是目前最适合用于网络通信的数据结构,可以参考StarForce中Network模块心跳包实现
- 发送以及接收消息都是异步的,且客户端收到消息在非主线程,需要事件系统通过线程安全方式抛出
ObjectPool
对象池,其中有提供CreateSingleSpawnObjectPool,CreateMultiSpawnObjectPool
理解为:池子里的资源能够同时被使用一次或使用多次,缓存资源在Spawn后以及Release前都算是在使用下,MultiSpawnObjectPool能多次Spawn同一资源(目前还没使用过,感觉没什么作用,我目前理解为这个池子只管理了一个缓存资源,在任何情况下都能Spawn出来使用),SingleSpawnObjectPool是我们通常情况下的对象池。
Procedure
游戏进程管理,是FSM的实现,可以参考StarForce的游戏启动流程
Resource
- 资源管理模块设计整个框架,几乎每个模块都使用到资源管理器,普通的资源管理只是提供资源打包,加载,卸载等操作,这个强大的资源管理器还提供了可视化操作界面,资源使用分析,以及资源更新处理。
- 资源模式一共有三种:单机模式,预下载的可更新模式,使用时下载的可更新模式。 关于三种模式的使用方法参考StarForce的启动流程,非常详细。
- 关于资源组的思想,资源组类似于Unity中的AssetBundle包即压缩包,一个包里包含多个资源文件,方便管理,资源还可以设置文件系统,多个资源组放进一个文件中。
编辑器中的使用方式
- 使用前需要先设置ResourceEditor.xml文件配置,是ResourceEditor的过滤配置,再导入GF框架后可以直接复制StarForce中的配置
- 关于ResourceEditor有些无法过滤的文件:如bytes文件,atlas文件(将图片打成一个包并不会自动生成图集,Load出来还是Texture2D格式)等,可以手动扩展ResourceEditor的过滤配置修改脚本ResourceEditorController.cs过滤文件设置
- 进行第一步后就可看到设置路径下的所有合法资源文件了
- Resource Builder:选择打包平台,以及路径,还可以选择打包事件处理器,如StarForce将打完的包复制了一份到StreamingAssets路径下,具体查看接口IBuildEventHandler.cs
实际运行中检查并更新资源流程
1 | // 根据StarForce启动流程 |
dll源码解析
Scene
场景加载,卸载管理,对ResourceManager的LoadScene,UnLoadScene封装了一层
Setting
游戏设置,与Config实现类似
Sound
非常好用的音效管理器,高效,简洁,功能强大
接口 | 注释 |
---|---|
ISoundAgent | 一个音效有一个代理,内部逻辑代理接口,主要负责处理声音开启暂停等 |
ISoundAgentHelper | 声音播放实际逻辑 |
ISoundGroup | 声音组 |
ISoundGroupHelper | 声音组帮助器,StarForce提供默认用于处理混音的组 |
ISoundHelper | 释放资源 |
ISoundManager | 管理音效播放,暂停,恢复以及音效组 |
UI
设计思路与Sound以及Entity类似,UIGroup组管理UIForm,UIManager一起管理,需要注意的是同类型UIForm可以开启多个,只单个存在的界面需要自己判断是否再次开启,可以参考Demo中的写法
Utility
提供了各种通用函数,方便使用
WebRequest
Web请求是异步的,通过TaskPool来代理Web请求,使用上带来的好处是可以不需要使用协程,监听成功失败事件即可。