大厅子游戏实现指引,creator2.0以上

关于大厅+子游戏的实现方案,很早就想做了,也参考了论坛中的实现方案,看了很多的帖子,也查了很多的资料,发现所有的实现方案都一样,简单说下我对于他们的实现方案的理解。

APP启动的时候会在main.js里初始化好所有的资源列表,加载资源的时候只能加载列表中存在的资源,现有方案的实现都是通过修改main实现,并且每一个子游戏 和 大厅都是一个独立项目,也就是每个游戏都是独立的运行环境,相互之前也无法共享资源,简单说下我认为这种方案的弊端:

  1. **运行环境独立,资源无法共享。**导致公共资源只能放在大厅中预加载才能在子游戏中使用(因为资源加载过后会有缓存,所以可以在子游戏中使用)。 再举个列子,如果你有5款麻将,普通话的语音文件肯定是都一样的吧,难道发包要把这份资源拷贝5份?每次更新1款麻将都要更新1遍这个语音资源?这么做我觉得无法忍受。

  2. **公共代码无法共用。**最基本的,网络层的代码需要在每个项目中拷贝一份,再加上其他自己框架性的代码,如果你的子游戏有十几二十个,想想你的公共代码要怎么处理。

  3. **开发维护困难。**不知道使用这种方案的是将所有资源放到1个项目里开发,还是每个项目独立开发,如果是前者,开发完还需要将子游戏拷贝到相应项目构建资源,如果是后者也挺麻烦的。

  4. 之前看资料,好像还要解决uuid冲突问题,具体没尝试,不太清楚

以上是个人对现有大厅子游戏实现方案的理解,看到这里,我果断地放弃的这种做法


最近花了点时间,仔细推敲了下,自己实现了另一种方案

先说下自己对分包方案的理解和要求:

  1. 所谓大厅+子游戏 其实应该是一种资源管理,想要实现对特定资源的更新管理。

  2. 分包要实现 所有资源可以共用,所有代码可以共用。

  3. 开发维护要简单便捷,将大厅+所有子游戏 作为一个项目进行开发。

基于以上的要求,我们可以这么做:

  1. 将所谓大厅子游戏看作是1个完整项目。这样就可以使用公共资源和代码了

  2. 自己记录资源所属的 子游戏模块(比如上述5个麻将语音资源的实现,我们也可以将1份资源记录为属于N个子游戏模块)

  3. 每次构建所有的完整资源,构建完成后,根据自己的记录 将构建后的资源 按子游戏模块筛选出来

  4. 根据筛选的模块资源 生成每个模块的资源更新列表,即 project.manifest 和 version.manifest文件。

  5. 自己实现更新逻辑,更新某个特定模块资源。


以上就是大致的实现思路,下面说下我自己的做法 (此方案依赖编辑器提供的打包函数,仅适用于creator2.0以上)

  1. 写一份配置文件,以路径记录所属模块,可以将1份资源记录属于1个或多个模块

  2. 自己写一个扩展插件,利用编辑器构建API onBuildFinish函数, 在这个函数里 我们可以拿到所有的构建后的资源

    这里可以获取所有构建资源的uuid,通过uuid得到资源路径,通过之前的配置文件,得到uuid所属的模块,然后自己记录下来。
    可能用到的函数有
    Editor.assetdb.uuidToUrl 通过uuid得到路径
    buildResults.getDependencies(asset.uuid) 获取资源的依赖资源
    Editor.assetdb.isMountByUuid 是否为系统内置资源

  3. 修改version_generator.js文件,根据之前得到的 uuid所属模块 的配置文件,分别生成每个模块的 project.manifest 和 version.manifest 文件。
    其实这一步可以灵活的配置,比如我做了一个将大厅的资源包含在每个子游戏中,这样在更新子游戏时 就同时更新了大厅,省去了大厅的单独更新。 当然你也可以单独更新大厅,怎么做,你可以随意配置。

  4. 根据官方提供的热更新脚本,实现热更功能,这个脚本几乎不用做什么改动,只有1点需要注意:官方提供的热更机制,更新完成后,会生成名为 project.manifest 文件,我们需要将此文件改名为 对应模块的文件名, 子游戏_project.manifest。 因为热更新管理器的缓存机制,如果你不更改此文件,可能会导致其他子游戏无法更新。例如,更新完pdk,版本为1.0,更新完成后, 这时候再更新mj,版本同样为1.0,热更管理器会直接认为已经更新完了,因为本地存在的那份 project.manifest文件导致的。


这个方案的实现 不涉及到更改 main.js 文件。
有1点不好的地方是,更新完子游戏时,可能需要重启APP,当然,如果你确定你的子游戏中不包含公共部分的资源代码,也是可以不用重启的。

这些是我目前的想法,自己也是做了测试demo,成功的实现相关功能,但目前尚未用于生成环境(预计1个月内,我们自己的项目就要使用了),有兴趣的,可以参照这个思路,自己尝试实现看看。

0314补充:关于更新管理器的缓存机制,理解有些偏差,在下面12楼做出更正

13赞

求共享demo

demo先不发了,毕竟还没用于生产环境,而且我的本意也只是提供一个思路,让真正有需要的人通过思考解决问题。
这几天我们的产品要开始用了,等到上线后再考虑要不要给demo吧。

mark

mark~~~~~~

楼主思路确实可行,但是代码就存在一份么?子项目只管资源么?那这样岂不是每次子游戏一改动 就要大厅热更?

代码只有1份,这样才叫代码共用啊。
这种设计 每次更新其实就把所有的代码都更到最新了。
我自己的想法是,把大厅的资源包含在每个子游戏中,这样就不必单独去更新大厅了,因为每次更新子游戏都会将大厅更新,当然大厅也作为一个独立更新的模块,可以同时兼容的。

哈哈哈, 思路不谋而合. 我们现在也是这样的

嗯,我们也是这样的,我们的子游戏使用包含了公共代码和资源可以做到更新下载子游戏不重启

热更新完成后想要更改project的文件名,却找不到文件,重启游戏就找到了。安卓上测试有问题,模拟器正常。请问楼主用的什么方法解决的,我的版本2.1.0

  1. 请问下,这种情况在安卓上是必现吗? 我测试时并未发现这种情况。
  2. 经实践发现,热更功能有时候会返回更新失败,但其实是更新成功了,所以建议 在UPDATE_FINISHED,UPDATE_FAILED,ALREADY_UP_TO_DATE 都做下处理。
  3. 我最近在测试更新失败的问题,就是怕不同游戏交替更新时,导致模块判断错了。所以我打算在project文件中加个模块字段,更新完成后如果字段一致,就更改本地project.manifest文件,否则删掉它。

如果后续测试有别的发现,可以在这里交流下!

这里需要更正下,关于热更缓存,我之前的理解有点偏差,这里更正下

  1. 热更管理器会在更新目录(命名为xx)的同级目录生成一个xx_temp的目录,首先会从服务器下载project.manifest文件并存放于xx_temp目录下,名称为 project.minifest.temp,更新成功后 xx_temp目录会被删除,并且在xx目录生成project.manifest文件。

  2. 所以每次更新时热更管理器会先查找 xx_temp/project.manifest.temp文件,比对要更新的manifest文件,如果temp文件存在且版本号一致,则会接着更新,否则会从服务器下载新的project.manifest文件,重新更新。

基于上面的更新机制,我的方案需要做以下处理

  1. 更新之前需要检测 xx_temp/project.manifest.temp文件是否存在,如果存在,需要比对模块是否一致,不一致则删除此文件重新更新。
  2. 更新完成后需要将 xx/project.manifest文件更名为对应的模块名。
    (官方的更新是基于project.manifest文件判断的,即使本地存在A资源,与服务器A资源完全一致,而本地的project.manifest文件中不存在A的记录,那下次更新时,还会更新一遍A资源)

整个dome吧,学习一下

mark~~~~~~

过几天我试试楼主的思路封装一个框架试试

mark

弄一个简单的demo看看,这两天研究这个东西,给整的脑袋都大了。

mark,大佬可以给个demo参考一下么,我大框架写完了,就差更新一块不知道怎么搞了

因为和我们的开发项目在一起,且经过不断完善,改了好多,现在没时间剥离出来一个demo,我把所用到的东西都拷贝了一份,上传供你参考下,这里面的东西可以组成一个功能完整的更新方案了。等后面有时间的话,再整理一个能跑的demo吧。
代码基本上都有注释,再加上这片文章,仔细读过的,应该可以拿来就用了。
packages/assetlist/main.js 构建插件,资源的处理分析,都在这里了
pack_generator.js 生成版本资源(使用pack_gen.bat运行)
TTUpgrade.js 热更逻辑入口文件(check_update)
TTHotUpdate.js 热更插件文件
more.zip (434.8 KB)

3赞

2.0 之前 这个 分包是非常好做的。 2.0 之后 稍微麻烦点。