GameFramework框架——StarForce案例之游戏流程大体知识总结

目录

一、 ProcedureLaunch流程

二、ProcedureSplash流程

三、ProcedureCheckVersion流程

*四、ProcedureUpdateVersion流程

五、ProcedureCheckResources流程

六、ProcedureUpdateResources流程

七、ProcedurePreload流程【预加载流程】

八、ProcedureChangeScene流程

九、ProcedureMenu流程

十、ProcedureMain流程


一、 ProcedureLaunch流程

OnEnter
    1、加载 BuildInfo.txt,该文件提供游戏版本号、补丁号、服务器的version.txt地址、各种平台的整包更新url
        version.txt是客户端一份、服务器一份的,热更新模式时,每次启动游戏客户端会比对一下服务器的version.txt的信息
        信息主要包括:是否强制整包更新、内部版本号、内部补丁号、内部资源版本号、服务器资源目录地址、资源包字节大小、资源包HashCode、
        压缩资源包字节大小、压缩资源包HashCode(资源包都是同一份,只有一个资源包)
        热更新流程博客:https://blog.csdn.net/qq_39574690/article/details/109234506
        问题:version.txt会放在客户端哪?与服务器的version.txt如何比对判定是否需热更?

    2、 多语言初始化(编辑器直接使用系统语言:简体中文)
    若使用GameEntry.Setting.SetString(Constant.Setting.Language, language.ToString());保存指定语言,且GF框架支持该语言则使用它。
    若不支持则临时使用英语替代。具体代码位于ProcedureLaunch的80行,默认支持英语、简体中文、繁体中文、韩语
    默认加载GameMain/Localization/xxx/Dictionaries/yyy.zzz,其中xxx是语言目录、yyy是文件名、zzz是后缀(.bytes or .xml)
    例如:大陆地址:GameMain/Localization/ChineseSimplified/Dictionaries/Default.xml (Default是默认文件)

     多语言使用Localization Component脚本指定的Localization helper脚本的解析方法ParseData进行解析,例如StarForce.XmlLocalizationHelper类专门解析xml格式参考Default.xml
     【多语言配置文件加载方法】:GameEntry.Localization.ReadData("Asset/.../Default.xml", this);  加载多语言字典xml格式文件并解析到LocalizationComponent里

    在ProcedurePreload流程执行PreloadResources方法会加载指定语言的Default.xml多语言文件
    用法例如:GameEntry.Localization.GetString("Dialog.ConfirmButton");  
    'Dialog.ConfirmButton' 是key,返回字符串string
    【待测试:新增多语言(日文)】

    若需要更改当前多语言,都需要重新加载框架所在的场景即StarForce Launcher (框架指Game Framework物体)

    3、变体配置:根据使用的语言,通知底层加载对应的资源变体 【???好像和资源加载有关联,又和多语言有关联, 例如:"zh-cn” 是 中文简体变体 国际化本地化?】

    4、声音配置:根据用户配置数据,设置即将使用的声音选项(设置音乐组是否静音、音量)
    设置是否静音:GameEntry.Sound.Mute("Music", GameEntry.Setting.GetBool(Constant.Setting.MusicMuted, false)); 
    设置音量:GameEntry.Sound.SetVolume("Music", GameEntry.Setting.GetFloat(Constant.Setting.MusicVolume, 0.3f));

    ProcedurePreload流程会进行加载“Music”、“UISound”、“Sound”音乐组的表格形式配置文件.
    加载方法:GameEntry.DataTable.LoadDataTable(dataTableName, dataTableAssetName, this);
    其中,dataTableName 是 配置表名、 dataTableAssetName 是 配置表文件相对Assets路径 , "Assets/GameMain/DataTables/Sound.txt"

    播放/停止/暂停Music音乐组的音乐:
    int musicId = GameEntry.Sound.PlayMusic(id)
    GameEntry.Sound.StopMusic()
    GameEntry.Sound.PauseSound(musicId); //待测试

    播放/停止/暂停播放Sound音乐组的音乐:
    int soundId = GameEntry.Sound.PlaySound(id);
    GameEntry.Sound.StopSound(soundId);
    GameEntry.Sound.PauseSound(soundId);
    
    播放/停止/暂停UISound音乐组的音乐
    int uiSoundId = GameEntry.Sound.PlayUISound(id);
    GameEntry.Sound.StopSound(uiSoundId);  //待测
    GameEntry.Sound.PauseSound(uiSoundId);//待测

    5、加载热更新模块所使用的多语言配置文件Assets/GameMain/Configs/DefaultDictionary.xml (该文件不可热更,因为热更前就要用到的。)
    它是一个GameEntry.Localization.ParseData直接解析由BuiltinDataComponent完成加载的配置文件text,解析后放入多语言字典。
    关于Xml的格式和解析,它只会进行识别<Dictionary Language='xxx'>是你当前设置语言的内容进行解析,其他的语言的会过滤掉,
    所以实际是可以写成DefaultDictionary那样的,但实际我们热更新的多语言文本,还是分开文件写了,因为占空间啊..这里它不占作者就懒得分开了。

OnUpdate    
    立即切换到ProcedureSplash流程

二、ProcedureSplash流程

OnEnter
    //TODO 可播放一个进场动画再执行以下逻辑
    1、检查BaseComponent(Builtin物体挂载的脚本)的Editor Resource Mode为true,则直接进入ProcedurePreload流程【预加载流程】——编辑器模式
    2、检查ResourceComponent(Resource物体挂载的脚本)的Resource Mode为Package,则直接进入ProcedureInitResources流程【初始化游戏资源流程】——单机模式
    3、若1、2都无法通过,则是可热更模式,进入ProcedureCheckVersion流程【检查版本流程】——可更新模式  【重点】

——————————————————————————————————————————————
可更新模式:

三、ProcedureCheckVersion流程

OnEnter
    1、注册网络请求失败、成功事件:
        GameEntry.Event.Subscribe(WebRequestSuccessEventArgs.EventId, OnWebRequestSuccess);
                    GameEntry.Event.Subscribe(WebRequestFailureEventArgs.EventId, OnWebRequestFailure);

    2、发起网络请求:GameEntry.WebRequest.AddWebRequest(服务器version.txt地址, this);
    StarForce案例:请求下载BuildInfo文件的CheckVersionUrl地址指定的version.txt文件
    *地址:Utility.Text.Format(GameEntry.BuiltinData.BuildInfo.CheckVersionUrl, GetPlatformPath()) 内容 待测 应该是要加上平台名称的.【*待测】
    
    3、OnWebRequestSuccess 网络请求成功回调
        将GameEventArgs e 转为 WebRequestSuccessEventArgs 类对象ne
        通过ne.GetWebResponseBytes() 获取byte[] 字节数组
        Utility.Json.ToObject<VersionInfo>(byte[]) 转为VersionInfo类型对象m_VersionInfo
            若不存在,则报错:“Parse VersionInfo failure.”
        打印“Latest game version is '{0} ({1})', local game version is '{2} ({3})'.” 
        {0}({1})是服务器版本号(服务器补丁号) ,{2}({3})是当前版本号和补丁号

        当m_VersionInfo.ForceUpdateGame为true时,进行强制更新游戏应用(整包更新)
        弹窗提示用户点击跳转到官网下载,否则退出游戏。
        官网地址是BuildInfo.txt设置的那些WindowsAppUrl、AndroidAppUrl、iOS...
        
        否则,设置资源更新下载地址即m_VersionInfo.UpdatePrefixUri地址
        一般为:"http://localhost/Windows"地址, localhost改为服务器IP地址,这是Windows平台的热更新。
        Windows文件夹是从AB打包目录下的Full\x_x_x_x\平台英文名称获取的,AB打包后直接放到服务器上即可,
        然后将这个文件夹的地址作为version.txt的UpdatePrefixUri内容。

        m_CheckVersionComplete设置为true

        * m_NeedUpdateVersion = GameEntry.Resource.CheckVersionList(m_VersionInfo.InternalResourceVersion) == CheckVersionListResult.NeedUpdate;
        检查资源是否有变化,有变化则需要进行热更新, m_NeedUpdateVersion设为true。

        这里估计是判断【服务器资源版本号】与【本地资源版本号】不同则需更新Version【版本信息】。

OnUpdate
    当m_CheckVersionComplete为true时
        当m_NeedUpdateVersion为true时,需要更新版本信息
        将VersionListLength、VersionListHashCode、VersionListZipLength、VersionListZipHashCode内容【这些是版本资源相关的信息】
        携带以上信息包进入【ProcedureUpdateVersion流程】【版本更新流程】

        否则,不需要更新版本信息,进入ProcedureCheckResources流程【检查资源流程】

    否则,游戏逻辑不会再进行下一个流程了 会在OnUpdate卡主不动。
        1、解析VersionInfo报错:Parse VersionInfo failure
        2、处于整包更新流程,玩家会打开官网 或 退出游戏

*四、ProcedureUpdateVersion流程

OnEnter
    获取传入的VersionListLength、VersionListHashCode、VersionListZipLength、VersionListZipHashCode。
    四个变量传入GameEntry.Resource.UpdateVersionList进行更新version list【版本列表, 可能是md5 + filepath 文件那个东西】
    
    更新版本文件成功:OnUpdateVersionListSuccess回调,设置m_UpdateVersionComplete为true

OnUpdate
    检查m_UpdateVersionComplete为true,则进入ProcedureCheckResources流程【检查资源流程】
    即更新版本文件完毕后,进行检查一遍资源, 上面不需要更新版本是直接走到检查资源流程的。

【*问题】它是更新Version.txt?? 这个文件更新好后,再进行检查游戏资源? 
目前搞不懂UpdateVersionList到底是更新的内容具体是什么。

五、ProcedureCheckResources流程

OnEnter
    直接调用GameEntry.Resource.CheckResources方法检查资源,对比游戏资源文件,检查出需更新的文件数、大小等信息
    OnCheckResourcesComplete 检查完成回调
        回调传回参数:
            movedCount 已移动的资源数量
            removedCount 已移除的资源数量
            updateCount 可更新的资源数量,大于0时则表示需热更资源
            updateTotalLength 可更新的资源总大小
            updateTotalZipLength 可更新的压缩后总大小
OnUpdate
    若检查资源成功,则进行如下逻辑:
      1、若需更新资源(updateCount > 0)
        将updateCount和updateTotalZipLength打包,携带进入ProcedureUpdateResources流程【更新资源流程】 。
    
      2、否则,不需要更新资源,进入ProcedurePreload流程【预加载流程】

六、ProcedureUpdateResources流程

OnEnter
    监听资源更新开始、更新后、成功、失败事件
    若网络处于使用网络数据,会询问是否使用网络数据进行更新(也就是你没连wifi会问一下是否真的花流量去更新)
    若点确定更新,或使用wifi会进入StartUpdateResources开始更新下载资源。
        首先加载出UpdateResourceForm热更新面板,显示热更进度
        接着调用GameEntry.Resource.UpdateResources进行更新资源,
        资源更细完毕回调 OnUpdateResourcesComplete,更新资源成功/失败会打印
            Update resources complete with no errors. 成功 并设置完成标记为true
            Update resources complete with errors.   失败

        资源更新细节:注意以下回调是以单个资源文件为对象而言的,
            1、开始更新资源时回调 OnResourceUpdateStart
                传入将开始热更的资源文件对象,若已存在更新列表则把文件更新进度置为0,不放入更新列表;
                若不存在于更新列表,则封装为一个UpdateLengthData对象放入更新列表。
                UpdateLengthData只有Name和Length变量,Name是资源名,Length是进度.
            2、正在更新的资源改变后回调OnResourceUpdateChanged
                刷新与这个资源文件相关的UpdateLengthData对象的Length进度变量为新的进度,并更新进度条。
            3、资源更新成功后回调 OnResourceUpdateSuccess
                将对应的资源对象的Length设为完成值,并更新完成数+1,刷新进度条。
            4、资源更新失败后回调 OnResourceUpdateFailure,
                若重试次数大于总共重试次数,报错并退出;
                否则, 报错 并 从更新列表移除报错的文件对象, 更新进度条。
                报错信息:“Update resource '{0}' failure from '{1}' with error message '{2}', retry count '{3}'”
                {0} 资源名,{1} 路径,{2} 错误信息,{3} 重试次数
            【注意】关于2和3、4时,如果从更新列表找不到该资源,都会报错"Update resource '{0}' is invalid." {0}是资源名
            
            更新进度条:
                显示的{0}/{1}, {2}/{3}, {4:P0}, {5}/s
                即更新成功数量/总数量,当前更新字节/总需更新字节,更新百分比,当前下载速度/s
                在资源更新失败后,直接从更新列表移除后,会尝试重新下载,如果超出一定次数失败就真的失败了。
                此时,进度条会卡死,可在OnUpdateResourcesComplete的else块处理失败流程。
                

OnUpdate
    更新成功后,进入ProcedurePreload流程【预加载流程】
    否则,卡死游戏逻辑,提示更新失败 Update resources complete with errors.  可在这里优化下处理失败后的流程。

七、ProcedurePreload流程【预加载流程】

OnEnter
    监听Config配表表加载成功、失败事件
    监听DataTable数据表加载成功、失败事件
    监听多语言字典加载成功、失败事件
    1、使用GameEntry.Config.ReadData, 加载Assets/GameMain/Configs/DefaultConfig.txt文件【全局配置文件】
    具体:DataProvider的ReadData加载资源文件,加载优先级为0,加载完成后由Config Component指定的Config Helper类进行ReadData读取
    一般读取的是object, ParseData是解析byte[]或string的. 最终变成一个<key, value>键值对存储在ConfigManager里.
    可通过GetString(key,defaultValue)根据key获取value,类似PlayerPref类 具体参考IConfigManager.cs内部接口

    2、使用GameEntry.DataTable.LoadDataTable(dataTableName, dataTableAssetName, this)
    在介绍音乐初始化时讲过,参数1是表名,参数2是表文件路径
        例如:加载GameMain/DataTables/Sound.txt
        需为表格新建一个脚本作为表格对应的序列化类DRSound,它放于GameMain/Scripts/DataTable下。
        DRSound类命名空间必须是StarForce,你想改的话可以去DataTableExtension类修改DataRowClassPrefixName变量指定的"StarForce.DR"
        例如:改为"MyGame.",那么Sound.txt表格对应的序列化类名为Sound,命名空间为MyGame。
        加载还是使用DataProvider进行加载资源文件,再通过DataTableComponent的Data Table Helper进行解析。
        即DefaultDataTableHelper类进行ReadData(读资源文件object)和ParseData(解析资源文件的byte[]或string)
        ReadData后接着就是直接到ParseData的.
        
        最终,Sound.txt会变成一个以lua来形容:
        ["Sound"] = {
           [id] = { id , 其他成员 },
           [id] = { id , 其他成员 },
           ...
        }
        存储于DataTableComponent里
        
        类似:Sound.txt命名的,它只允许有一个存在。
        可以用Sound_sound1.txt命名的,它代表Sound类型的表格名为sound1,可以存在名为sound2的Sound类型表格..
        
        可使用IDataTable<DRSound> table = GameEntry.DataTable.GetDataTable<DRSound>() 获取表格对象。
        DRSound drSound = table.GetDataRow(id) 根据id获取具体内容 其他方式可看具体源码

        若有命名的则可通过GameEntry.DataTable.GetDataTable<DRSound>("sound1") 获取表格对象。

    3、LoadDictionary("Default"); 多语言字典加载,已介绍过
    DataProvider加载, 再使用Localization Component的Localization Helper类 (XmlLocalizationHelper类) 进行解析
    以<key,value>形式保存在Localization Component的字典对象里。
    可通过GameEntry.Localization.GetString(string key)方法获取
    支持GameEntry.Localization.GetString传递多个参数作为格式化字符串
    例如:  
        存在键值对:["A"] = "{0}_{1}"
     GameEntry.Localization.GetString("A",  "hello", "world") 输出 hello_world
    
    4、LoadFont("MainFont")
    加载字体资源:Assets\GameMain\Fonts\MainFont.ttf
    使用GameEntry.Resource.LoadAsset(path, 優先級,成功回調, 失败回调)
    成功时设置UGuiForm.SetMainFont((Font)) 可能是UI的主字体设置为Font,优先选用这个字体.

OnUpdate
    等预加载资源都加载完毕后,通过GameEntry.Config.GetInt("Scene.Menu") 获取DefaultConfig配置表的对应key内容
    将其内容作为NextSceneId字段值传入ProcedureChangeScene流程【更新场景流程】

八、ProcedureChangeScene流程

    专门用于切换场景,只要设置NextSceneId传入流程即可。
    例如这样
    procedureOwner.SetData<VarInt>("NextSceneId", GameEntry.Config.GetInt("Scene.Menu"));
    ChangeState<ProcedureChangeScene>(procedureOwner);
    这个NextSceneId是和Scene配置表和 DefaultConfig表格有关。

    监听场景加载成功、失败、进行中、加载场景依赖资源事件
    1、停止所有声音
    2、隐藏所有实体
    3、卸载所有场景
    4、还原游戏速度
    5、根据NextSceneId从Scene配置表搜出场景资源文件名,获取场景相对路径Assets/.../Menu
    使用GameEntry.Scene.LoadScene(AssetUtility.GetSceneAsset(drScene.AssetName), Constant.AssetPriority.SceneAsset, this);同步加载追加场景
    其中drScene是从Scene配置表根据id找出的DRScene对象, AssetName是资源名
    
    加载成功:播放DRScene的BackgroundMusicId音乐,使用GameEntry.Sound.PlayMusic(id)播放,并设置加载成功标记 【传回LoadSceneSuccessEventArgs对象】
    加载失败:打印Load scene '{0}' failure, error message '{1}'." {0} =  ne.SceneAssetName, {1} = ne.ErrorMessage    【传回LoadSceneFailureEventArgs对象ne】
    加载中:打印Load scene '{0}' update, progress '{1}'. {0} = ne.SceneAssetName, {1} = ne.Progress.ToString("P2") 【传回LoadSceneUpdateEventArgs对象ne】
    加载依赖资源完成:打印Load scene '{0}' dependency asset '{1}', count '{2}/{3}'.",  【传回LoadSceneDependencyAssetEventArgs对象ne】
    {0} = ne.SceneAssetName, {1} = ne.DependencyAssetName, {2} = ne.LoadedCount.ToString(), {3} = ne.TotalCount.ToString()
    关于事件监听是每一个事件都有一个Id和一个XXXEventArgs类对象继承与GameEventArgs类,它就是个专门用于传递一些参数的,一般有个叫Create的静态方法拷贝自身。
    例如:m_EventComponent.Fire(this, LoadSceneSuccessEventArgs.Create(e)); 这个e是LoadSceneSuccessEventArgs对象!这样传给加载成功回调..

    目前仅有2个场景可去
    1、Menu
    2、Main
    上面的NextSceneId是Menu的Id,所以等加载场景完毕后,跳转到ProcedureMenu流程

九、ProcedureMenu流程

    监听OpenUIFormSuccessEventArgs事件【打开UI成功事件】
    GameEntry.UI.OpenUIForm(UIFormId.MenuForm, this); 打开MenuForm面板
    这个Id是在GameMain/DataTables/UIForm.txt表格的Id,表格序列化类为DRUIForm
    DRUIForm内容:id、资源名、界面组GroupName、是否允许存在多个同样的UI出现、是否会被其覆盖的UI暂停
    当前加载的UI资源名是MenuForm。

    使用UIComponent类的方法OpenUIForm(资源相对路径,界面组GroupName, 优先级, 是否会被覆盖的UI所暂停, userData)进行打开UI
    关于GF的UI系统的界面组其实是一个Canvas,然后设置指定的层级,把创建的UI放到界面组Canvas下。但个人觉得UI系统不是很好,可以不用。

    加载回调OnOpenUIFormSuccess传递回的OpenUIFormSuccessEventArgs内带UIForm,它是预制体挂载的一个脚本基类。
    UIForm内写有各种UI生命周期方法,它其实是在创建UI时用代码添加到物体上的。
    UI预制体原本挂载有MenuForm、创建后动态添加UIForm脚本
    继承关系:MenuForm -> UGuiForm -> UIFormLogic -> MonoBehaviour
    
    UGuiForm脚本: 有一些控制关闭面板、播放UI音乐、设置字体等公用方法,在初始化时它会添加一个CanvasGroup,用它来在OnOpen和OnClose时做一些渐隐渐显的效果..
    设置RectTransform为全屏适配,获得/添加GraphicRaycaster组件接收射线,并初始化所有Text的字体和内容,原本预制体上Text的内容是key,它会使用如下代码:
    texts[i].text = GameEntry.Localization.GetString(texts[i].text); 将key转为当前多语言的对应内容。 也就是说策划看预览界面时的文本全都是key(体验感不好)
    
    UIFormLogic会获取身上的UIForm对象,并声明了一堆UI生命周期虚方法,由MenuForm实现.
    在MenuForm的OnOpen(useData),useData其实是在ProcedureMenu流程对象,它在调用GameEntry.UI.OpenUIForm(UIFormId.MenuForm, this);时传入的第二个参数this就是它。
    将useData转为ProcedureMenu对象后,调用ProcedureMenu的StartGame公共方法,m_StartGame设置为true.

OnUpdate
    当m_StartGame为true时,切到ProcedureChangeScene流程,加载Scene.Main配置对应的场景显示,等加载完毕后进入ProcedureMain流程。
    procedureOwner.SetData<VarInt>("NextSceneId", GameEntry.Config.GetInt("Scene.Main")); 下一个场景为Main场景
                procedureOwner.SetData<VarByte>("GameMode", (byte)GameMode.Survival);  这个GameMode并没有在ProcedureChangeScene使用,但是在ProcedureMain流程就用到了。

十、ProcedureMain流程

OnInit
    初始化一个字典, [GameMode.Survival] = new SurvivalGame();
OnEnter
    获取procedureOwner里存储的VarByte类型数据"GameMode" , 它对应地获取到了字典[GameMode.Survival]的内容: SurvivalGame对象
    执行SurvivalGame对象的Initialize方法, m_CurrentGame为SurvivalGame对象。

OnUpdate
    当检查到m_CurrentGame存在且m_CurrentGame.GameOver==false时,执行m_CurrentGame.Update(elapseSeconds, realElapseSeconds); 
    elapseSeconds是帧时间,realElapseSeconds是不受Time.timeScale影响的帧时间

    否则,2f后跳转回Menu场景, 如下逻辑:
    procedureOwner.SetData<VarInt>("NextSceneId", GameEntry.Config.GetInt("Scene.Menu"));
                ChangeState<ProcedureChangeScene>(procedureOwner);

至此基本结束流程的讲解,关于战斗逻辑部分,暂时不看。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值