1.4.2热更下载第一个文件时如果中断,则再次进入热更时,热更会失效

您好,我发现在AssetsManagerEx.cpp的逻辑中,是通过Manifest->saveToFile保存manifest文件中热更内容的下载状态的。AssetsManagerEx.cpp中共有5处saveToFile,如果是第一次热更新,AssetsManagerEx.cpp的startUpdate第三处的saveToFile会将远程manifest保存到本地,但是这个manifest不带任何文件的下载状态。

之后的逻辑_tempManifest->setAssetDownloadState(it->first, Manifest::DownloadState::UNSTARTED);
会更新下载状态,但是没有及时保存到本地,而是等到AssetsManagerEx::queueDowload中的_percentByFile / 100 > _nextSavePoint条件满足时,才能调用saveToFile保存文件的下载状态。

在第一个文件下载完之前,_percentByFile一直为0,不会调用saveToFile,如果此时关掉应用再次打开,会调用
_tempManifest->genResumeAssetsList(&_downloadUnits);
但是因为之前的待下载文件的状态DownloadState::UNSTARTED都没能保存,所以genResumeAssetsList就得不到下载列表,热更就直接完成了。

我的临时改法是,改成_percentByFile / 100 >= _nextSavePoint,因为一开始_percentByFile为0,所以在下载第一个文件之前调用queueDowload()里面的saveToFile会把待下载文件的状态写入到本地的manifest文件中,使得再次热更时genResumeAssetsList能收集到待热更的文件。

但是我感觉这样还是有一点风险,就是AssetsManagerEx::startUpdate()中的第三个saveToFile保存了无下载状态的文件列表,之后的queueDowload中再保存一个有状态的下载列表,如果这中间除了什么问题,导致有状态的列表没有保存,那么热更就失效了。所以能不能第一次保存的时候就是保存有状态的下载列表呢?

不知道我理解的热更流程对不对,谢谢!

Creator 版本号:1.4.2
运行时目标平台:(Web/iOS/Android/模拟器)
手机浏览器平台:(机型,浏览器)
操作系统:(编辑器错误)
详细报错信息,包含调用堆栈:
编辑器之前是否有其它报错:
做了什么操作引起的 Bug:
偶发 bug 的概率和额外线索:(重现几率/场景节点规模/项目资源规模)

3赞

非常感谢你这么详细的测试!!!
你的理解都完全正确,我看了才发现确实是有问题!我的设计初衷是在 remote manifest 和 local manfiest 的 diff_map 计算出来之后,就应该做第一次保存,但是顺序写错了。。。 AssetsManagerEx::startUpdate 中正确的逻辑是这样的

...
// Generate download units for all assets that need to be updated or added
std::string packageUrl = _remoteManifest->getPackageUrl();
// Preprocessing local files in previous version and creating download folders
for (auto it = diff_map.begin(); it != diff_map.end(); ++it)
{
    Manifest::AssetDiff diff = it->second;
    if (diff.type != Manifest::DiffType::DELETED)
    {
        std::string path = diff.asset.path;
        DownloadUnit unit;
        unit.customId = it->first;
        unit.srcUrl = packageUrl + path;
        unit.storagePath = _tempStoragePath + path;
        unit.size = diff.asset.size;
        _downloadUnits.emplace(unit.customId, unit);
        _tempManifest->setAssetDownloadState(it->first, Manifest::DownloadState::UNSTARTED);
    }
}
// Save current download manifest information for resuming
_tempManifest->saveToFile(_tempManifestPath);
...

这样的话就不需要修改 nextSavePoint 判断了。

你的第二个疑问也有道理,如果在 tempManifest 下载成功后,出现问题导致中断,没有进行到 diff map 的比较,就会出现下一次进入游戏时,genResumeAssetsList 出来的列表为空,这个问题我会考虑下,可能会添加一个字段:可恢复下载,在生成 diff map 之后,才会设置这个状态为 true 并 saveToFile,只有这个字段为 true 才会使用 temp manifest,否则当作 temp manifest 无效。

2赞

赞一个。

太客气啦!你们免费提供引擎给大家开发游戏,才是特别要感谢的呢!!

这个问题在下一版里面会修正吗?

已经修复了

https://github.com/cocos-creator/cocos2d-x-lite/pull/630

1.5 正式版中不会有这个问题

1赞

这个bug也把我坑了,cocos2dx上至今未修复