coco2dx-lua_热更新_AssetsManagerEx(转)



1.概述
AssetsManagerEx的特点:
按文件更新
更新失败的时候,只更新失败的文件
更新失败的情况下,下次重新启动,只更新上次更新的错误文件


原理
本地会存在一个配置文件,网络中(你的服务器中也会存在一个配置文件)。
通过本地配置文件与网络的配置文件进行比对。发现差异化数据然后,将网络数据拉取到本地。


2.实例
2.1.创建AssetsManagerEx
_assets_manager_ex = AssetsManagerEx::create(
"Config/project.manifest", 
FileUtils::getInstance()->getWritablePath() + "DownLoad");
_assets_manager_ex->retain();


参数上第一个是本地的配置文件地地址,第二个参数是你从网络上拉取的数据的本地保存地址。


2.2.本地配置文件
{
    "packageUrl" : "http://tools.itharbors.com/assets_manager/AMTestScene1/",
    "remoteManifestUrl" : "http://7xs6k4.com1.z0.glb.clouddn.com/project.manifest",
    "remoteVersionUrl" : "http://tools.itharbors.com/assets_manager/AMTestScene1/version_dev.manifest",
    "version" : "1.0.0",
    "engineVersion" : "3.0 beta",


    "assets" : {
        "Images/background1.jpg" : {
            "md5" : "..."
        }
    },


    "searchPaths" : [
    ]
}


这是一个Json的数据格式
packageUrl是你要下载具体内容的地址,程序允许的时候会将你的资源名称比如Image/xxx.png
  添加到packageUrl的后边组成完整的连接,相对于我们刚才举得例子的位置就是
  http://tools.itharbors.com/assets_manager/AMTestScene1/Image/xxx.png。
  然后从这个连接中拉取数据到本地并且保存为Image/xxx.png
remoteManifestUrl是远程的配置文件地址,与你本地的配置文件做为对应。就是最前边原理里
  边提到的拉取远程数据跟本地数据做对比的远程数据
remoteVersionUrl 因为配置文件中可能存在很多需要更新的配置文件的信息,所以频发的拉取
  这个数据是非常要命的。所以AssetsManagerEx提供了一个让你只拉取版本信息的连接,具体
  内容跟远程配置文件格式相似,只是没有了文件的相关配置
  
(1)远程版本文件
{
    "packageUrl": "http://tools.itharbors.com/assets_manager/AMTestScene1/",
    "remoteManifestUrl": "http://tools.itharbors.com/assets_manager/AMTestScene1/project_dev.manifest",
    "remoteVersionUrl": "http://tools.itharbors.com/assets_manager/AMTestScene1/version_dev.manifest",
    "version": "1.2.0",
    "engineVersion": "3.0 dev"
}
(2)远程配置文件
{
    "packageUrl" : "http://tools.itharbors.com/assets_manager/AMTestScene1/",
    "remoteManifestUrl" : "http://7xs6k4.com1.z0.glb.clouddn.com/project_dev.manifest",
    "remoteVersionUrl" : "http://tools.itharbors.com/assets_manager/AMTestScene1/version_dev.manifest",
    "version" : "1.2.0",
    "engineVersion" : "3.x dev",


    "assets" : {
        "Images/assetMgrBackground1.jpg" : {
            "md5" : "....."
        },
        "Images/ball.png" : {
            "md5" : "..."
        },
        "Images/blocks.png" : {
            "md5" : "..."
        },
        "compressed.zip" : {
            "md5" : "...",
            "compressed" : true
        },
        "Images/Bird.jpg" : {
            "md5" : "..."
        },
        "Images/Daisy_Flower.jpg" : {
            "md5" : "..."
        },
        "Images/Mountain_Reflections.jpg" : {
            "md5" : "..."
        },
        "Images/Plitvice_National_Park.jpg" : {
            "md5" : "..."
        },
        "Images/sakountala.jpg" : {
            "md5" : "..."
        },
        "Images/Snake_River.jpg" : {
            "md5" : "..."
        },
        "Images/Thunder.jpg" : {
            "md5" : "..."
        },
        "Images/Tranquil_Lagoon.jpg" : {
            "md5" : "..."
        },
        "Images/Tyrol.jpg" : {
            "md5" : "..."
        },
        "Images/univ-lille1.jpg" : {
            "md5" : "..."
        },
        "Images/Yellow_Garden_Flowers.jpg" : {
            "md5" : "..."
        },
        "Images/Yellow_Lilly.jpg" : {
            "md5" : "..."
        },
        "Images/Yellow_Tulips.jpg" : {
            "md5" : "..."
        }
    },


    "searchPaths" : [
    ]
}


(3)业务相关的代码
if (!_assets_manager_ex->getLocalManifest()->isLoaded()){
onLoadSuccess();
}else{
_assets_manager_listener = cocos2d::extension::EventListenerAssetsManagerEx::create(_assets_manager_ex, [this](EventAssetsManagerEx * event){
switch (event->getEventCode()) {
case cocos2d::extension::EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST:
case cocos2d::extension::EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST:
case cocos2d::extension::EventAssetsManagerEx::EventCode::ERROR_PARSE_MANIFEST:
case cocos2d::extension::EventAssetsManagerEx::EventCode::ERROR_DECOMPRESS:
case cocos2d::extension::EventAssetsManagerEx::EventCode::UPDATE_FAILED:
{
this->onLoadError((int)event->getEventCode());
break;
}
case cocos2d::extension::EventAssetsManagerEx::EventCode::ERROR_UPDATING:
{   
tryDownloadFaildAssets();


break;
}
case cocos2d::extension::EventAssetsManagerEx::EventCode::ASSET_UPDATED:
{
tryDownloadFaildAssets();


break;
}
case cocos2d::extension::EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE:
{
CCLOG("已经是最新版本,直接进入主界面");
this->onAllFileIsNew();
break;
}
case cocos2d::extension::EventAssetsManagerEx::EventCode::UPDATE_FINISHED:
{
CCLOG("更新完成重新加载");
this->onLoadSuccess();
break;
}
case cocos2d::extension::EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION:
{
//                    this->onLoadPercent(event->getPercent());
this->onLoadPercent(event->getPercentByFile());
break;
}
case cocos2d::extension::EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND:
{
CCLOG("发现新本版开始升级");
break;
}
default:
break;
}
});


Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_assets_manager_listener, 1);
_assets_manager_ex->update();
}


其实意思已经很明显了,就是查看一下当前是不是已经加载完成了。如果已经加载完成了,那么
直接跳过,进入游戏就好了。
如果没有加载完成就需要添加上监听器,然后启动下载,等待回调就好了。


3.问题
(1)进行比对
拉取配置文件到本地,然后添加.temp后缀作为临时文件
然后将临时文件跟本地文件进行比对,得出差异结果集,然后操作本地文件
这个文件比对是拿md5数据进行确定这个文件是否正常的。不过这个md5是指配置文件里边的md5而
不是这个文件实际的md5
请你不要认为这套md5是文件的md5校验,把它认为是一个文件的版本号可能更容易理解一些
之所以文件用md5进行比对,应该是方便后台在构建这个文件时有一个可靠的依据


(2)怎样进行不修改代码的情况下替换资源
通过添加SearchPath进行文件替换
其实组件并没有直接替换掉你包里边的文件,而只是添加了优先搜索目录来进行文件的优先查找的权限


(3)下载文件的确立过程
这个组件会修改他自己下载的.temp组件,其实就是添加上下载的状态,然后重新保存一边
重新保存的时机在所有的文件尝试下载过一边之后
下载一边的意思是说成功和失败都算
但是下载过程中,软件意外退出或者主动退出,是不会保存状态的,如果需要,则需要业务进行手动
的保存调用


(4)如何做到重启之后,依然沿着上次的下载过程继续下载的
如果程序检测到存在.temp文件,并且.temp文件与远程文件的版本是一样的话,那么直接认为.temp
文件是最新版本,尝试从.temp文件中尝试重新加载上一次的数据
也就是说,只有所有的文件下载过一遍之后,系统主动保存到.temp文件之后。再重新启动能够重新复盘
或者下载到一半,你觉得用户可能要退出的情况下保存了这个文件也能够复盘成功


4.修订
AssetsManagerEx在3.9的Demo上根本跑不起来
3.10没有测试过,我看了下源码的地方貌似也没有修改


BUG的表现
在任何一个资源下载失败的情况下,你会发现更新已经卡住再也不动了。


修复
将AssetsManagerEx::onError方法修改成下边这个样子
void AssetsManagerEx::onError(const network::DownloadTask& task,
                              int errorCode,
                              int errorCodeInternal,
                              const std::string& errorStr)
{
    // Skip version error occured
    if (task.identifier == VERSION_ID){
        CCLOG("AssetsManagerEx : Fail to download version file, step skipped\n");
        _updateState = State::PREDOWNLOAD_MANIFEST;
        downloadManifest();
    }else if (task.identifier == MANIFEST_ID){
        dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST, task.identifier, errorStr, errorCode, errorCodeInternal);
    }else{
        auto unitIt = _downloadUnits.find(task.identifier);
        // Found unit and add it to failed units
        if (unitIt != _downloadUnits.end()){
            --_totalWaitToDownload;


            DownloadUnit unit = unitIt->second;
            _failedUnits.emplace(unit.customId, unit);
        }
        dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_UPDATING, task.identifier, errorStr, errorCode, errorCodeInternal);
    }
}


别以为下载了就好用,去看看修订这一章节然后你才能成功(仅限3.9)



















































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值