Developers Manual > Cocos2d-x > Modules > Assets manager

Assets Manager Extension

This document will introduce the new extension assets manager in Cocos2d-x. This extension is designed for hot update of images, audio files and game scripts used in your game. You will be able to update a new version of resources on your apps, your game can keep track your remote resources and download them into the device. An entier new design, new experience or even new contents could be instantly available without needing to update your application on every app store.

Use case

Imagine you have your game already released on app stores, however you are not satisfied with some designs or some negative feedback are reported by users. Ordinarily, you can only repackage your game and submit it to every app store and wait... until it pass the verification, or not. I mean, it's a very painful procedure, and during the process, many users may have already gone.

Other cases:

  • When you want to organise an in game activity for the saint valentin day, you surely don't want to miss the timing.
  • If you found a critcal bug in your game which will strongly damage the balance in your game.
  • When you want to add a new package of levels or scenes in your game to extend its playable time.
  • and many more...

For all of this, if you have a chance to make things happen overnight, wouldn't it be great? Assets manager is exactly designed for these purposes.

Features

The assets manager in Cocos2d-x have many useful features to help you make the hot update very convenient and efficient.

  • Multi thread downloading support
  • Two levels progression support: File level progression and byte level progression
  • Zip compressed file support
  • Download resuming
  • Detailed progression informations and error informations
  • Possibility to retry failed assets

Usage

It's quite simple to use the assets manager, firstly, you need an initial manifest file in JSON format in your app package.

In the manifest file, you can describe the online address of the remote manifest file, the current version and a set of resources, then you will be able to use the jsb.AssetsManager class to update it during the game process.

Manifest files

Here is an example of the manifest file in json format:

{
    "packageUrl" : "http://example.com/assets_manager/TestScene/",
    "remoteVersionUrl" : "http://example.com/assets_manager/TestScene/version.manifest",
    "remoteManifestUrl" : "http://example.com/assets_manager/TestScene/project.manifest",
    "version" : "1.0.0",
    "engineVersion" : "Cocos2d-JS v3.0 RC0",

    "assets" : {
        "Images/background.jpg" : {
            "md5" : "..."
        },
        "Images/icon.png" : {
            "md5" : "..."
        },
        "Images/button.png" : {
            "md5" : "..."
        },
        "src/game.lua" : {
            "md5" : "..."
        },
        "src/layer.lua" : {
            "md5" : "..."
        },
        "compressed.zip" : {
            "md5" : "...",
            "compressed" : true
        }
    },

    "searchPaths" : [
        "res/"
    ]
}
  • packageUrl : The url where the assets manager will try to request and download all the assets.
  • remoteVersionUrl : The remote version file url which permit to check the remote version to determine whether a new version has been uploaded to the server.
  • remoteManifestUrl : The remote manifest file url which contains all the assets informations.
  • version : The version of this manifest file.
  • engineVersion : Engine version used by the manifest file.
  • assets : All assets informations.
    • key : The key of each represents the relative path of the asset.
    • md5 : The md5 field represents the version information of the asset.
    • compressed : [optional] When compressed field is true, the downloaded file will be decompressed. automatically. Only zip format is supported.
  • searchPaths : The search paths that should be added to cocos2d engine.

The version.manifest file should contain exact same informations with the first five fields of manifest file. It is optional, if it can't be found, the assets manager will download directly the complete manifest file. But it can be very useful if your manifest file is very large so that it can greatly save the time for comparison of version information.

Usage of AssetsManager

Here is an example of usage:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
void AssetsManagerExLoaderScene::runThisTest()
{
    int currentId = currentScene;
    std::string manifestPath = sceneManifests[currentId], storagePath = FileUtils::getInstance()->getWritablePath() + storagePaths[currentId];
    CCLOG("Storage path for this test : %s", storagePath.c_str());

    Sprite *sprite = Sprite::create("Images/Icon.png");
    auto layer = Layer::create();
    addChild(layer);
    layer->addChild(sprite);
    sprite->setPosition( VisibleRect::center() );

    TTFConfig config("fonts/tahoma.ttf", 30);
    _progress = Label::createWithTTF(config, "0%", TextHAlignment::CENTER);
    _progress->setPosition( Vec2(VisibleRect::center().x, VisibleRect::center().y + 50) );
    layer->addChild(_progress);

    _am = AssetsManagerEx::create(manifestPath, storagePath);
 // As the process is asynchronies, you need to retain the assets manager to make sure it won't be released before the process is ended.
   _am->retain();

    if (!_am->getLocalManifest()->isLoaded())
    {
        CCLOG("Fail to update assets, step skipped.");
        AssetsManagerExTestScene *scene = new AssetsManagerExTestScene(backgroundPaths[currentId]);
        Director::getInstance()->replaceScene(scene);
        scene->release();
    }
    else
    {
        _amListener = cocos2d::extension::EventListenerAssetsManagerEx::create(_am, [currentId, this](EventAssetsManagerEx* event){
            static int failCount = 0;
            AssetsManagerExTestScene *scene;
            switch (event->getEventCode())
            {
                case EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST:
                {
                    CCLOG("No local manifest file found, skip assets update.");
                    scene = new AssetsManagerExTestScene(backgroundPaths[currentId]);
                    Director::getInstance()->replaceScene(scene);
                    scene->release();
                }
                    break;
                case EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION:
                {
                    std::string assetId = event->getAssetId();
                    float percent = event->getPercent();
                    std::string str;
                    if (assetId == AssetsManagerEx::VERSION_ID)
                    {
                        str = StringUtils::format("Version file: %.2f", percent) + "%";
                    }
                    else if (assetId == AssetsManagerEx::MANIFEST_ID)
                    {
                        str = StringUtils::format("Manifest file: %.2f", percent) + "%";
                    }
                    else
                    {
                        str = StringUtils::format("%.2f", percent) + "%";
                        CCLOG("%.2f Percent", percent);
                    }
                    if (this->_progress != nullptr)
                        this->_progress->setString(str);
                }
                    break;
                case EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST:
                case EventAssetsManagerEx::EventCode::ERROR_PARSE_MANIFEST:
                {
                    CCLOG("Fail to download manifest file, update skipped.");
                    scene = new AssetsManagerExTestScene(backgroundPaths[currentId]);
                    Director::getInstance()->replaceScene(scene);
                    scene->release();
                }
                    break;
                case EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE:
                case EventAssetsManagerEx::EventCode::UPDATE_FINISHED:
                {
                    CCLOG("Update finished. %s", event->getMessage().c_str());
                    scene = new AssetsManagerExTestScene(backgroundPaths[currentId]);
                    Director::getInstance()->replaceScene(scene);
                    scene->release();
                }
                    break;
                case EventAssetsManagerEx::EventCode::UPDATE_FAILED:
                {
                    CCLOG("Update failed. %s", event->getMessage().c_str());

                    failCount ++;
                    if (failCount < 5)
                    {
                        _am->downloadFailedAssets();
                    }
                    else
                    {
                        CCLOG("Reach maximum fail count, exit update process");
                        failCount = 0;
                        scene = new AssetsManagerExTestScene(backgroundPaths[currentId]);
                        Director::getInstance()->replaceScene(scene);
                        scene->release();
                    }
                }
                    break;
                case EventAssetsManagerEx::EventCode::ERROR_UPDATING:
                {
                    CCLOG("Asset %s : %s", event->getAssetId().c_str(), event->getMessage().c_str());
                }
                    break;
                case EventAssetsManagerEx::EventCode::ERROR_DECOMPRESS:
                {
                    CCLOG("%s", event->getMessage().c_str());
                }
                    break;
                default:
                    break;
            }
        });
        Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_amListener, 1);

        _am->update();

        Director::getInstance()->replaceScene(this);
    }
}

You can also refer to the test case Extensions/AssetsManagerTest in our js-tests project. Other public APIs of jsb.AssetsManager is listed below:

  • checkUpdate()
  • getState()
  • getStoragePath()
  • getLocalManifest()
  • getRemoteManifest()

Known issue

Assets manager may fail to create and download files on windows and iOS simulator, we will try to fix it very soon, please test on real iOS devices in the meantime.

Sign up for our newsletter to keep up with the latest developments, releases and updates for Cocos2d-x.