Merge branch 'v3_testMerge' of https://github.com/pandamicro/cocos2d-x into v3_assetsmanager

Conflicts:
	build/cocos2d_libs.xcodeproj/project.pbxproj
	cocos/platform/CCFileUtils.cpp
	tests/lua-tests/project/CMakeLists.txt
	tests/lua-tests/project/Classes/AppDelegate.cpp
	tests/lua-tests/project/proj.android/jni/Android.mk
	tests/lua-tests/project/proj.win32/lua-tests.win32.vcxproj
This commit is contained in:
samuele3hu 2014-10-15 13:41:27 +08:00
commit 064e159c70
45 changed files with 4097 additions and 348 deletions

View File

@ -700,8 +700,8 @@
1AC35D7A18CEE59900F37B72 /* cocosbuilderRes in Resources */ = {isa = PBXBuildFile; fileRef = 1AC35D7818CEE59900F37B72 /* cocosbuilderRes */; };
1AC35D8118CEE5B100F37B72 /* AppDelegate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC35D7D18CEE5B100F37B72 /* AppDelegate.cpp */; };
1AC35D8218CEE5B100F37B72 /* AppDelegate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC35D7D18CEE5B100F37B72 /* AppDelegate.cpp */; };
1AC35D8318CEE5B100F37B72 /* lua_assetsmanager_test_sample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC35D7F18CEE5B100F37B72 /* lua_assetsmanager_test_sample.cpp */; };
1AC35D8418CEE5B100F37B72 /* lua_assetsmanager_test_sample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC35D7F18CEE5B100F37B72 /* lua_assetsmanager_test_sample.cpp */; };
1AC35D8318CEE5B100F37B72 /* lua_assetsmanagerex_test_sample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC35D7F18CEE5B100F37B72 /* lua_assetsmanagerex_test_sample.cpp */; };
1AC35D8418CEE5B100F37B72 /* lua_assetsmanagerex_test_sample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC35D7F18CEE5B100F37B72 /* lua_assetsmanagerex_test_sample.cpp */; };
1AC35D9818CEE5D100F37B72 /* AppController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1AC35D8718CEE5D100F37B72 /* AppController.mm */; };
1AC35D9918CEE5D100F37B72 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1AC35D8818CEE5D100F37B72 /* Default-568h@2x.png */; };
1AC35D9A18CEE5D100F37B72 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 1AC35D8918CEE5D100F37B72 /* Default.png */; };
@ -957,6 +957,12 @@
B609E67419C18DAD003D0074 /* BillBoardTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B609E67119C18DAD003D0074 /* BillBoardTest.cpp */; };
B6C039D919C95D83007207DC /* LightTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6C039D719C95D83007207DC /* LightTest.cpp */; };
B6C039DA19C95D83007207DC /* LightTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6C039D719C95D83007207DC /* LightTest.cpp */; };
BA4B67D219E6699200BAF8F9 /* AssetsManagerExTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BA4B67D019E6699200BAF8F9 /* AssetsManagerExTest.cpp */; };
BA4B67D319E6699200BAF8F9 /* AssetsManagerExTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BA4B67D019E6699200BAF8F9 /* AssetsManagerExTest.cpp */; };
BAF402E219E675F30060A895 /* Manifests in Resources */ = {isa = PBXBuildFile; fileRef = BAF402E119E675F30060A895 /* Manifests */; };
BAF402E319E675F30060A895 /* Manifests in Resources */ = {isa = PBXBuildFile; fileRef = BAF402E119E675F30060A895 /* Manifests */; };
BAF402E419E676370060A895 /* Manifests in Resources */ = {isa = PBXBuildFile; fileRef = BAF402E119E675F30060A895 /* Manifests */; };
BAF402E519E6764A0060A895 /* Manifests in Resources */ = {isa = PBXBuildFile; fileRef = BAF402E119E675F30060A895 /* Manifests */; };
C04F935A1941B05400E9FEAB /* TileMapTest2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C04F93581941B05400E9FEAB /* TileMapTest2.cpp */; };
C04F935B1941B05400E9FEAB /* TileMapTest2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C04F93581941B05400E9FEAB /* TileMapTest2.cpp */; };
C08689C118D370C90093E810 /* background.caf in Resources */ = {isa = PBXBuildFile; fileRef = C08689C018D370C90093E810 /* background.caf */; };
@ -2782,8 +2788,8 @@
1AC35D7818CEE59900F37B72 /* cocosbuilderRes */ = {isa = PBXFileReference; lastKnownFileType = folder; name = cocosbuilderRes; path = "../tests/lua-tests/res/cocosbuilderRes"; sourceTree = "<group>"; };
1AC35D7D18CEE5B100F37B72 /* AppDelegate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppDelegate.cpp; sourceTree = "<group>"; };
1AC35D7E18CEE5B100F37B72 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
1AC35D7F18CEE5B100F37B72 /* lua_assetsmanager_test_sample.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_assetsmanager_test_sample.cpp; sourceTree = "<group>"; };
1AC35D8018CEE5B100F37B72 /* lua_assetsmanager_test_sample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lua_assetsmanager_test_sample.h; sourceTree = "<group>"; };
1AC35D7F18CEE5B100F37B72 /* lua_assetsmanagerex_test_sample.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_assetsmanagerex_test_sample.cpp; sourceTree = "<group>"; };
1AC35D8018CEE5B100F37B72 /* lua_assetsmanagerex_test_sample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lua_assetsmanagerex_test_sample.h; sourceTree = "<group>"; };
1AC35D8618CEE5D100F37B72 /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = "<group>"; };
1AC35D8718CEE5D100F37B72 /* AppController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AppController.mm; sourceTree = "<group>"; };
1AC35D8818CEE5D100F37B72 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
@ -2986,6 +2992,9 @@
B609E67219C18DAD003D0074 /* BillBoardTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BillBoardTest.h; path = BillBoardTest/BillBoardTest.h; sourceTree = "<group>"; };
B6C039D719C95D83007207DC /* LightTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LightTest.cpp; path = LightTest/LightTest.cpp; sourceTree = "<group>"; };
B6C039D819C95D83007207DC /* LightTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LightTest.h; path = LightTest/LightTest.h; sourceTree = "<group>"; };
BA4B67D019E6699200BAF8F9 /* AssetsManagerExTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AssetsManagerExTest.cpp; sourceTree = "<group>"; };
BA4B67D119E6699200BAF8F9 /* AssetsManagerExTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AssetsManagerExTest.h; sourceTree = "<group>"; };
BAF402E119E675F30060A895 /* Manifests */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Manifests; path = "../tests/cpp-tests/Resources/Manifests"; sourceTree = "<group>"; };
C04F93581941B05400E9FEAB /* TileMapTest2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TileMapTest2.cpp; sourceTree = "<group>"; };
C04F93591941B05400E9FEAB /* TileMapTest2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TileMapTest2.h; sourceTree = "<group>"; };
C08689C018D370C90093E810 /* background.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = background.caf; path = "../tests/cpp-tests/Resources/background.caf"; sourceTree = "<group>"; };
@ -5805,6 +5814,7 @@
1AC359B418CECF0B00F37B72 /* ExtensionsTest */ = {
isa = PBXGroup;
children = (
BA4B67CF19E6699200BAF8F9 /* AssetsManagerExTest */,
38FA2E70194AEBE100FF2BE4 /* CocoStudioActionTimelineTest */,
1AC359B518CECF0B00F37B72 /* CocosBuilderTest */,
1AC359DC18CECF0B00F37B72 /* CocoStudioArmatureTest */,
@ -6502,6 +6512,7 @@
1AC35CBA18CED84500F37B72 /* fonts */,
1AC35CBC18CED84500F37B72 /* hd */,
1AC35CBE18CED84500F37B72 /* Images */,
BAF402E119E675F30060A895 /* Manifests */,
1AC35CC118CED84500F37B72 /* Misc */,
1AC35CC318CED84500F37B72 /* Particles */,
1AC35CC618CED84500F37B72 /* Shaders */,
@ -6631,8 +6642,8 @@
15427B76198B750300DC375D /* lua_module_register.h */,
1AC35D7D18CEE5B100F37B72 /* AppDelegate.cpp */,
1AC35D7E18CEE5B100F37B72 /* AppDelegate.h */,
1AC35D7F18CEE5B100F37B72 /* lua_assetsmanager_test_sample.cpp */,
1AC35D8018CEE5B100F37B72 /* lua_assetsmanager_test_sample.h */,
1AC35D7F18CEE5B100F37B72 /* lua_assetsmanagerex_test_sample.cpp */,
1AC35D8018CEE5B100F37B72 /* lua_assetsmanagerex_test_sample.h */,
);
name = Classes;
path = "../tests/lua-tests/project/Classes";
@ -7207,6 +7218,15 @@
name = LightTest;
sourceTree = "<group>";
};
BA4B67CF19E6699200BAF8F9 /* AssetsManagerExTest */ = {
isa = PBXGroup;
children = (
BA4B67D019E6699200BAF8F9 /* AssetsManagerExTest.cpp */,
BA4B67D119E6699200BAF8F9 /* AssetsManagerExTest.h */,
);
path = AssetsManagerExTest;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -7654,6 +7674,7 @@
15D1FCF11998637C00302043 /* Cocos2d.lua in Resources */,
3E2F27BC19D00D7200E7C490 /* audio in Resources */,
1AC35DC318CEE65100F37B72 /* Misc in Resources */,
BAF402E419E676370060A895 /* Manifests in Resources */,
1AC35DC618CEE65100F37B72 /* Shaders in Resources */,
1529F05C19ED88830064B9B1 /* tp.lua in Resources */,
15D1FD141998637C00302043 /* extern.lua in Resources */,
@ -7739,6 +7760,7 @@
15D1FD111998637C00302043 /* DrawPrimitives.lua in Resources */,
15D1FD1B1998637C00302043 /* json.lua in Resources */,
1AC35DD618CEE65200F37B72 /* Misc in Resources */,
BAF402E519E6764A0060A895 /* Manifests in Resources */,
15D1FD3E199863CA00302043 /* DeprecatedCocosDenshionClass.lua in Resources */,
1AC35DF718CEE65B00F37B72 /* effect1.wav in Resources */,
C08689C418D370C90093E810 /* background.caf in Resources */,
@ -7835,6 +7857,7 @@
1AC35CFA18CED84500F37B72 /* Misc in Resources */,
38FA2E76194AECF800FF2BE4 /* ActionTimeline in Resources */,
1AC35D0418CED84500F37B72 /* Shaders in Resources */,
BAF402E219E675F30060A895 /* Manifests in Resources */,
3E2F27BA19CFF52300E7C490 /* audio in Resources */,
1AC35CD818CED84500F37B72 /* CocosBuilderExample.ccbresourcelog in Resources */,
B2507B6B192589AF00FA4972 /* Shaders3D in Resources */,
@ -7914,6 +7937,7 @@
3E2BDAD219BEA3E20055CDCD /* audio in Resources */,
C08689C318D370C90093E810 /* background.caf in Resources */,
1AC35C9518CECF1400F37B72 /* Icon-72.png in Resources */,
BAF402E319E675F30060A895 /* Manifests in Resources */,
1AC35D0B18CED84500F37B72 /* zwoptex in Resources */,
1AC35CF518CED84500F37B72 /* Images in Resources */,
1AC35C9118CECF1400F37B72 /* Icon-40.png in Resources */,
@ -8030,7 +8054,7 @@
1AC35DB518CEE5DA00F37B72 /* LuaObjectCBridgeTest.mm in Sources */,
150F918819DA409E00B89F57 /* lua_test_bindings.cpp in Sources */,
1AC35DB618CEE5DA00F37B72 /* main.cpp in Sources */,
1AC35D8318CEE5B100F37B72 /* lua_assetsmanager_test_sample.cpp in Sources */,
1AC35D8318CEE5B100F37B72 /* lua_assetsmanagerex_test_sample.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -8044,7 +8068,7 @@
1AC35D9818CEE5D100F37B72 /* AppController.mm in Sources */,
1AC35D8218CEE5B100F37B72 /* AppDelegate.cpp in Sources */,
1AC35DA618CEE5D100F37B72 /* RootViewController.mm in Sources */,
1AC35D8418CEE5B100F37B72 /* lua_assetsmanager_test_sample.cpp in Sources */,
1AC35D8418CEE5B100F37B72 /* lua_assetsmanagerex_test_sample.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -8209,6 +8233,7 @@
1AC35C4B18CECF0C00F37B72 /* ShaderTest2.cpp in Sources */,
38FA2E73194AEBE100FF2BE4 /* ActionTimelineTestScene.cpp in Sources */,
1AC35C6518CECF0C00F37B72 /* UnitTest.cpp in Sources */,
BA4B67D219E6699200BAF8F9 /* AssetsManagerExTest.cpp in Sources */,
29080DC9191B595E0066F8DF /* UISceneManager_Editor.cpp in Sources */,
1AC35B3F18CECF0C00F37B72 /* Bug-458.cpp in Sources */,
3E2F27B919CFF4AF00E7C490 /* NewAudioEngineTest.cpp in Sources */,
@ -8353,6 +8378,7 @@
1AC35B7C18CECF0C00F37B72 /* GameOverScene.cpp in Sources */,
1AC35BF418CECF0C00F37B72 /* ExtensionsTest.cpp in Sources */,
1AC35B3618CECF0C00F37B72 /* TestEntries.cpp in Sources */,
BA4B67D319E6699200BAF8F9 /* AssetsManagerExTest.cpp in Sources */,
1AC35B2E18CECF0C00F37B72 /* Box2dTest.cpp in Sources */,
29080DCA191B595E0066F8DF /* UISceneManager_Editor.cpp in Sources */,
1AC35C1218CECF0C00F37B72 /* LabelTestNew.cpp in Sources */,

View File

@ -184,6 +184,11 @@ xcopy /Y /Q "$(ProjectDir)..\..\external\chipmunk\prebuilt\win32\release-lib\*.*
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\extensions\assets-manager\AssetsManager.cpp" />
<ClCompile Include="..\..\extensions\assets-manager\AssetsManagerEx.cpp" />
<ClCompile Include="..\..\extensions\assets-manager\CCEventAssetsManagerEx.cpp" />
<ClCompile Include="..\..\extensions\assets-manager\CCEventListenerAssetsManagerEx.cpp" />
<ClCompile Include="..\..\extensions\assets-manager\Downloader.cpp" />
<ClCompile Include="..\..\extensions\assets-manager\Manifest.cpp" />
<ClCompile Include="..\..\extensions\GUI\CCControlExtension\CCControl.cpp" />
<ClCompile Include="..\..\extensions\GUI\CCControlExtension\CCControlButton.cpp" />
<ClCompile Include="..\..\extensions\GUI\CCControlExtension\CCControlColourPicker.cpp" />
@ -529,6 +534,11 @@ xcopy /Y /Q "$(ProjectDir)..\..\external\chipmunk\prebuilt\win32\release-lib\*.*
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\extensions\assets-manager\AssetsManager.h" />
<ClInclude Include="..\..\extensions\assets-manager\AssetsManagerEx.h" />
<ClInclude Include="..\..\extensions\assets-manager\CCEventAssetsManagerEx.h" />
<ClInclude Include="..\..\extensions\assets-manager\CCEventListenerAssetsManagerEx.h" />
<ClInclude Include="..\..\extensions\assets-manager\Downloader.h" />
<ClInclude Include="..\..\extensions\assets-manager\Manifest.h" />
<ClInclude Include="..\..\extensions\cocos-ext.h" />
<ClInclude Include="..\..\extensions\ExtensionExport.h" />
<ClInclude Include="..\..\extensions\ExtensionMacros.h" />

View File

@ -1177,6 +1177,21 @@
<ClCompile Include="..\ui\UIEditBox\UIEditBoxImpl-win32.cpp">
<Filter>ui\UIWidgets\EditBox</Filter>
</ClCompile>
<ClCompile Include="..\..\extensions\assets-manager\AssetsManagerEx.cpp">
<Filter>extension\AssetsManager</Filter>
</ClCompile>
<ClCompile Include="..\..\extensions\assets-manager\CCEventAssetsManagerEx.cpp">
<Filter>extension\AssetsManager</Filter>
</ClCompile>
<ClCompile Include="..\..\extensions\assets-manager\CCEventListenerAssetsManagerEx.cpp">
<Filter>extension\AssetsManager</Filter>
</ClCompile>
<ClCompile Include="..\..\extensions\assets-manager\Downloader.cpp">
<Filter>extension\AssetsManager</Filter>
</ClCompile>
<ClCompile Include="..\..\extensions\assets-manager\Manifest.cpp">
<Filter>extension\AssetsManager</Filter>
</ClCompile>
<ClCompile Include="..\ui\UIWebViewImpl-win32.cpp">
<Filter>ui\UIWidgets</Filter>
</ClCompile>
@ -2375,6 +2390,21 @@
<ClInclude Include="..\ui\UIEditBox\UIEditBoxImpl-win32.h">
<Filter>ui\UIWidgets\EditBox</Filter>
</ClInclude>
<ClInclude Include="..\..\extensions\assets-manager\AssetsManagerEx.h">
<Filter>extension\AssetsManager</Filter>
</ClInclude>
<ClInclude Include="..\..\extensions\assets-manager\CCEventAssetsManagerEx.h">
<Filter>extension\AssetsManager</Filter>
</ClInclude>
<ClInclude Include="..\..\extensions\assets-manager\CCEventListenerAssetsManagerEx.h">
<Filter>extension\AssetsManager</Filter>
</ClInclude>
<ClInclude Include="..\..\extensions\assets-manager\Downloader.h">
<Filter>extension\AssetsManager</Filter>
</ClInclude>
<ClInclude Include="..\..\extensions\assets-manager\Manifest.h">
<Filter>extension\AssetsManager</Filter>
</ClInclude>
<ClInclude Include="..\ui\UIWebViewImpl-win32.h">
<Filter>ui\UIWidgets</Filter>
</ClInclude>

View File

@ -195,7 +195,8 @@ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) \
$(LOCAL_PATH)/../external/unzip \
$(LOCAL_PATH)/../external/chipmunk/include/chipmunk \
$(LOCAL_PATH)/../external/xxhash \
$(LOCAL_PATH)/../external/nslog
$(LOCAL_PATH)/../external/nslog \
$(LOCAL_PATH)/base
LOCAL_C_INCLUDES := $(LOCAL_PATH) \
$(LOCAL_PATH)/. \

View File

@ -1,27 +1,27 @@
/****************************************************************************
Copyright (c) 2010-2013 cocos2d-x.org
Copyright (c) 2013-2014 Chukong Technologies Inc.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
Copyright (c) 2010-2013 cocos2d-x.org
Copyright (c) 2013-2014 Chukong Technologies Inc.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#ifndef __CC_FILEUTILS_H__
#define __CC_FILEUTILS_H__
@ -49,18 +49,18 @@ public:
* Gets the instance of FileUtils.
*/
static FileUtils* getInstance();
/**
* Destroys the instance of FileUtils.
*/
static void destroyInstance();
/** @deprecated Use getInstance() instead */
CC_DEPRECATED_ATTRIBUTE static FileUtils* sharedFileUtils() { return getInstance(); }
/** @deprecated Use destroyInstance() instead */
CC_DEPRECATED_ATTRIBUTE static void purgeFileUtils() { destroyInstance(); }
/**
* The destructor of FileUtils.
* @js NA
@ -99,7 +99,7 @@ public:
* @warning Recall: you are responsible for calling free() on any Non-NULL pointer returned.
*/
CC_DEPRECATED_ATTRIBUTE virtual unsigned char* getFileData(const std::string& filename, const char* mode, ssize_t *size);
/**
* Gets resource file data from a zip file.
*
@ -109,7 +109,7 @@ public:
* @warning Recall: you are responsible for calling free() on any Non-nullptr pointer returned.
*/
virtual unsigned char* getFileDataFromZip(const std::string& zipFilePath, const std::string& filename, ssize_t *size);
/** Returns the fullpath for a given filename.
@ -119,50 +119,50 @@ public:
The file search is based on the array element order of search paths and resolution directories.
For instance:
We set two elements("/mnt/sdcard/", "internal_dir/") to search paths vector by setSearchPaths,
and set three elements("resources-ipadhd/", "resources-ipad/", "resources-iphonehd")
to resolutions vector by setSearchResolutionsOrder. The "internal_dir" is relative to "Resources/".
If we have a file named 'sprite.png', the mapping in fileLookup dictionary contains `key: sprite.png -> value: sprite.pvr.gz`.
Firstly, it will replace 'sprite.png' with 'sprite.pvr.gz', then searching the file sprite.pvr.gz as follows:
/mnt/sdcard/resources-ipadhd/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/resources-ipad/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/resources-iphonehd/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/sprite.pvr.gz (if not found, search next)
internal_dir/resources-ipadhd/sprite.pvr.gz (if not found, search next)
internal_dir/resources-ipad/sprite.pvr.gz (if not found, search next)
internal_dir/resources-iphonehd/sprite.pvr.gz (if not found, search next)
internal_dir/sprite.pvr.gz (if not found, return "sprite.png")
If the filename contains relative path like "gamescene/uilayer/sprite.png",
and the mapping in fileLookup dictionary contains `key: gamescene/uilayer/sprite.png -> value: gamescene/uilayer/sprite.pvr.gz`.
The file search order will be:
/mnt/sdcard/gamescene/uilayer/resources-ipadhd/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/gamescene/uilayer/resources-ipad/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/gamescene/uilayer/resources-iphonehd/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/gamescene/uilayer/sprite.pvr.gz (if not found, search next)
internal_dir/gamescene/uilayer/resources-ipadhd/sprite.pvr.gz (if not found, search next)
internal_dir/gamescene/uilayer/resources-ipad/sprite.pvr.gz (if not found, search next)
internal_dir/gamescene/uilayer/resources-iphonehd/sprite.pvr.gz (if not found, search next)
internal_dir/gamescene/uilayer/sprite.pvr.gz (if not found, return "gamescene/uilayer/sprite.png")
We set two elements("/mnt/sdcard/", "internal_dir/") to search paths vector by setSearchPaths,
and set three elements("resources-ipadhd/", "resources-ipad/", "resources-iphonehd")
to resolutions vector by setSearchResolutionsOrder. The "internal_dir" is relative to "Resources/".
If we have a file named 'sprite.png', the mapping in fileLookup dictionary contains `key: sprite.png -> value: sprite.pvr.gz`.
Firstly, it will replace 'sprite.png' with 'sprite.pvr.gz', then searching the file sprite.pvr.gz as follows:
/mnt/sdcard/resources-ipadhd/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/resources-ipad/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/resources-iphonehd/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/sprite.pvr.gz (if not found, search next)
internal_dir/resources-ipadhd/sprite.pvr.gz (if not found, search next)
internal_dir/resources-ipad/sprite.pvr.gz (if not found, search next)
internal_dir/resources-iphonehd/sprite.pvr.gz (if not found, search next)
internal_dir/sprite.pvr.gz (if not found, return "sprite.png")
If the filename contains relative path like "gamescene/uilayer/sprite.png",
and the mapping in fileLookup dictionary contains `key: gamescene/uilayer/sprite.png -> value: gamescene/uilayer/sprite.pvr.gz`.
The file search order will be:
/mnt/sdcard/gamescene/uilayer/resources-ipadhd/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/gamescene/uilayer/resources-ipad/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/gamescene/uilayer/resources-iphonehd/sprite.pvr.gz (if not found, search next)
/mnt/sdcard/gamescene/uilayer/sprite.pvr.gz (if not found, search next)
internal_dir/gamescene/uilayer/resources-ipadhd/sprite.pvr.gz (if not found, search next)
internal_dir/gamescene/uilayer/resources-ipad/sprite.pvr.gz (if not found, search next)
internal_dir/gamescene/uilayer/resources-iphonehd/sprite.pvr.gz (if not found, search next)
internal_dir/gamescene/uilayer/sprite.pvr.gz (if not found, return "gamescene/uilayer/sprite.png")
If the new file can't be found on the file system, it will return the parameter filename directly.
This method was added to simplify multiplatform support. Whether you are using cocos2d-js or any cross-compilation toolchain like StellaSDK or Apportable,
you might need to load different resources for a given file in the different platforms.
@since v2.1
*/
virtual std::string fullPathForFilename(const std::string &filename);
/**
* Loads the filenameLookup dictionary from the contents of a filename.
*
*
* @note The plist file name should follow the format below:
*
*
* @code
* <?xml version="1.0" encoding="UTF-8"?>
* <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@ -193,7 +193,7 @@ public:
*/
virtual void loadFilenameLookupDictionaryFromFile(const std::string &filename);
/**
/**
* Sets the filenameLookup dictionary.
*
* @param pFilenameLookupDict The dictionary for replacing filename.
@ -211,8 +211,8 @@ public:
*
*/
virtual std::string fullPathFromRelativeFile(const std::string &filename, const std::string &relativeFile);
/**
/**
* Sets the array that contains the search order of the resources.
*
* @param searchResolutionsOrder The source array that contains the search order of the resources.
@ -222,14 +222,14 @@ public:
* @lua NA
*/
virtual void setSearchResolutionsOrder(const std::vector<std::string>& searchResolutionsOrder);
/**
* Append search order of the resources.
*
* @see setSearchResolutionsOrder(), fullPathForFilename().
* @since v2.1
*/
virtual void addSearchResolutionsOrder(const std::string &order,const bool front=false);
* Append search order of the resources.
*
* @see setSearchResolutionsOrder(), fullPathForFilename().
* @since v2.1
*/
virtual void addSearchResolutionsOrder(const std::string &order, const bool front=false);
/**
* Gets the array that contains the search order of the resources.
@ -240,9 +240,9 @@ public:
*/
virtual const std::vector<std::string>& getSearchResolutionsOrder();
/**
/**
* Sets the array of search paths.
*
*
* You can use this array to modify the search path of the resources.
* If you want to use "themes" or search resources in the "cache", you can do it easily by adding new entries in this array.
*
@ -262,21 +262,21 @@ public:
virtual void setSearchPaths(const std::vector<std::string>& searchPaths);
/**
* Add search path.
*
* @since v2.1
*/
* Add search path.
*
* @since v2.1
*/
void addSearchPath(const std::string & path, const bool front=false);
/**
* Gets the array of search paths.
*
*
* @return The array of search paths.
* @see fullPathForFilename(const char*).
* @lua NA
*/
virtual const std::vector<std::string>& getSearchPaths() const;
/**
* Gets the writable path.
* @return The path that can be write/read a file in
@ -386,7 +386,7 @@ public:
/** Returns the full path cache */
const std::unordered_map<std::string, std::string>& getFullPathCache() const { return _fullPathCache; }
protected:
/**
* The default constructor.
@ -468,7 +468,7 @@ protected:
*/
ValueMap _filenameLookupDict;
/**
/**
* The vector contains resolution folders.
* The lower index of the element in this vector, the higher priority for this resolution directory.
*/
@ -490,7 +490,7 @@ protected:
std::string _defaultResRootPath;
/**
* The full path cache. When a file is found, it will be added into this cache.
* The full path cache. When a file is found, it will be added into this cache.
* This variable is used for improving the performance of file search.
*/
std::unordered_map<std::string, std::string> _fullPathCache;

View File

@ -770,11 +770,11 @@ int LuaEngine::handleEvent(ScriptHandlerMgr::HandlerType type,void* data)
return handleTableViewEvent(type, data);
}
break;
case ScriptHandlerMgr::HandlerType::ASSETSMANAGER_PROGRESS:
case ScriptHandlerMgr::HandlerType::ASSETSMANAGER_ERROR:
case ScriptHandlerMgr::HandlerType::ASSETSMANAGER_SUCCESS:
case ScriptHandlerMgr::HandlerType::ASSETSMANAGEREX_PROGRESS:
case ScriptHandlerMgr::HandlerType::ASSETSMANAGEREX_ERROR:
case ScriptHandlerMgr::HandlerType::ASSETSMANAGEREX_SUCCESS:
{
return handleAssetsManagerEvent(type, data);
return handleAssetsManagerExEvent(type, data);
}
break;
case ScriptHandlerMgr::HandlerType::ARMATURE_EVENT:
@ -947,7 +947,7 @@ int LuaEngine::handleTableViewEvent(ScriptHandlerMgr::HandlerType handlerType,vo
return ret;
}
int LuaEngine::handleAssetsManagerEvent(ScriptHandlerMgr::HandlerType type,void* data)
int LuaEngine::handleAssetsManagerExEvent(ScriptHandlerMgr::HandlerType type,void* data)
{
if (nullptr == data)
return 0;
@ -956,35 +956,35 @@ int LuaEngine::handleAssetsManagerEvent(ScriptHandlerMgr::HandlerType type,void*
if (nullptr == eventData->nativeObject || nullptr == eventData->value)
return 0;
LuaAssetsManagerEventData* assetsManagerData = static_cast<LuaAssetsManagerEventData*>(eventData->value);
// LuaAssetsManagerEventData* assetsManagerData = static_cast<LuaAssetsManagerEventData*>(eventData->value);
//
// int handler = ScriptHandlerMgr::getInstance()->getObjectHandler((void*)eventData->nativeObject, type);
//
// if (0 == handler)
// return 0;
//
// int ret = 0;
// switch (type)
// {
// case ScriptHandlerMgr::HandlerType::ASSETSMANAGER_PROGRESS:
// case ScriptHandlerMgr::HandlerType::ASSETSMANAGER_ERROR:
// {
// _stack->pushInt(assetsManagerData->value);
// ret = _stack->executeFunctionByHandler(handler, 1);
// }
// break;
//
// case ScriptHandlerMgr::HandlerType::ASSETSMANAGER_SUCCESS:
// {
// ret = _stack->executeFunctionByHandler(handler, 0);
// }
// break;
//
// default:
// break;
// }
int handler = ScriptHandlerMgr::getInstance()->getObjectHandler((void*)eventData->nativeObject, type);
if (0 == handler)
return 0;
int ret = 0;
switch (type)
{
case ScriptHandlerMgr::HandlerType::ASSETSMANAGER_PROGRESS:
case ScriptHandlerMgr::HandlerType::ASSETSMANAGER_ERROR:
{
_stack->pushInt(assetsManagerData->value);
ret = _stack->executeFunctionByHandler(handler, 1);
}
break;
case ScriptHandlerMgr::HandlerType::ASSETSMANAGER_SUCCESS:
{
ret = _stack->executeFunctionByHandler(handler, 0);
}
break;
default:
break;
}
return ret;
return 0;
}
int LuaEngine::handleArmatureWrapper(ScriptHandlerMgr::HandlerType type,void* data)

View File

@ -146,7 +146,7 @@ private:
int handleTouchesEvent(void* data);
int handlerControlEvent(void* data);
int handleEvenCustom(void* data);
int handleAssetsManagerEvent(ScriptHandlerMgr::HandlerType type,void* data);
int handleAssetsManagerExEvent(ScriptHandlerMgr::HandlerType type,void* data);
int handleTableViewEvent(ScriptHandlerMgr::HandlerType type,void* data);
int handleTableViewEvent(ScriptHandlerMgr::HandlerType type,void* data, int numResults, const std::function<void(lua_State*,int)>& func);
int handleArmatureWrapper(ScriptHandlerMgr::HandlerType type,void* data);

View File

@ -126,9 +126,9 @@ public:
XMLHTTPREQUEST_READY_STATE_CHANGE,
ASSETSMANAGER_PROGRESS,
ASSETSMANAGER_SUCCESS,
ASSETSMANAGER_ERROR,
ASSETSMANAGEREX_PROGRESS,
ASSETSMANAGEREX_SUCCESS,
ASSETSMANAGEREX_ERROR,
STUDIO_EVENT_LISTENER,
ARMATURE_EVENT,

View File

@ -366,35 +366,35 @@ public:
virtual void onProgress(int percent) override
{
int handler = ScriptHandlerMgr::getInstance()->getObjectHandler((void*)this, ScriptHandlerMgr::HandlerType::ASSETSMANAGER_PROGRESS);
if (0 != handler)
{
LuaAssetsManagerEventData eventData(percent);
BasicScriptData data((void*)this,&eventData);
LuaEngine::getInstance()->handleEvent(ScriptHandlerMgr::HandlerType::ASSETSMANAGER_PROGRESS, (void*)&data);
}
// int handler = ScriptHandlerMgr::getInstance()->getObjectHandler((void*)this, ScriptHandlerMgr::HandlerType::ASSETSMANAGER_PROGRESS);
// if (0 != handler)
// {
// LuaAssetsManagerEventData eventData(percent);
// BasicScriptData data((void*)this,&eventData);
// LuaEngine::getInstance()->handleEvent(ScriptHandlerMgr::HandlerType::ASSETSMANAGEREX_PROGRESS, (void*)&data);
// }
}
virtual void onSuccess() override
{
int handler = ScriptHandlerMgr::getInstance()->getObjectHandler((void*)this, ScriptHandlerMgr::HandlerType::ASSETSMANAGER_SUCCESS);
if (0 != handler)
{
LuaAssetsManagerEventData eventData;
BasicScriptData data((void*)this,&eventData);
LuaEngine::getInstance()->handleEvent(ScriptHandlerMgr::HandlerType::ASSETSMANAGER_SUCCESS, (void*)&data);
}
// int handler = ScriptHandlerMgr::getInstance()->getObjectHandler((void*)this, ScriptHandlerMgr::HandlerType::ASSETSMANAGER_SUCCESS);
// if (0 != handler)
// {
// LuaAssetsManagerEventData eventData;
// BasicScriptData data((void*)this,&eventData);
// LuaEngine::getInstance()->handleEvent(ScriptHandlerMgr::HandlerType::ASSETSMANAGEREX_SUCCESS, (void*)&data);
// }
}
virtual void onError(AssetsManager::ErrorCode errorCode) override
{
int handler = ScriptHandlerMgr::getInstance()->getObjectHandler((void*)this, ScriptHandlerMgr::HandlerType::ASSETSMANAGER_ERROR);
if (0 != handler)
{
LuaAssetsManagerEventData eventData((int)errorCode);
BasicScriptData data((void*)this,&eventData);
LuaEngine::getInstance()->handleEvent(ScriptHandlerMgr::HandlerType::ASSETSMANAGER_ERROR, (void*)&data);
}
// int handler = ScriptHandlerMgr::getInstance()->getObjectHandler((void*)this, ScriptHandlerMgr::HandlerType::ASSETSMANAGER_ERROR);
// if (0 != handler)
// {
// LuaAssetsManagerEventData eventData((int)errorCode);
// BasicScriptData data((void*)this,&eventData);
// LuaEngine::getInstance()->handleEvent(ScriptHandlerMgr::HandlerType::ASSETSMANAGEREX_ERROR, (void*)&data);
// }
}
};
@ -445,7 +445,7 @@ static int lua_cocos2dx_AssetsManager_setDelegate(lua_State* L)
}
LUA_FUNCTION handler = toluafix_ref_function(L, 2, 0);
ScriptHandlerMgr::HandlerType handlerType = (ScriptHandlerMgr::HandlerType) ((int)tolua_tonumber(L,3,0) + (int)ScriptHandlerMgr::HandlerType::ASSETSMANAGER_PROGRESS);
ScriptHandlerMgr::HandlerType handlerType = (ScriptHandlerMgr::HandlerType) ((int)tolua_tonumber(L,3,0) + (int)ScriptHandlerMgr::HandlerType::ASSETSMANAGEREX_PROGRESS);
ScriptHandlerMgr::getInstance()->addObjectHandler((void*)delegate, handler, handlerType);
return 0;
@ -939,12 +939,81 @@ static void extendTableView(lua_State* L)
lua_pop(L, 1);
}
static void extendManifest(lua_State* L)
{
lua_pushstring(L, "cc.Manifest");
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pop(L, 1);
}
static int lua_cocos2dx_Extension_EventListenerAssetsManagerEx_create(lua_State* L)
{
if (nullptr == L)
return 0;
int argc = 0;
#if COCOS2D_DEBUG >= 1
tolua_Error tolua_err;
if (!tolua_isusertable(L,1,"cc.EventListenerAssetsManagerEx",0,&tolua_err)) goto tolua_lerror;
#endif
argc = lua_gettop(L)-1;
if (argc == 2)
{
#if COCOS2D_DEBUG >= 1
if (!tolua_isusertype(L, 2, "cc.AssetsManagerEx", 0, &tolua_err) ||
!toluafix_isfunction(L,3,"LUA_FUNCTION",0,&tolua_err))
goto tolua_lerror;
#endif
cocos2d::extension::AssetsManagerEx* assetManager = static_cast<cocos2d::extension::AssetsManagerEx*>(tolua_tousertype(L,2,nullptr));
LUA_FUNCTION handler = toluafix_ref_function(L,3,0);
cocos2d::extension::EventListenerAssetsManagerEx* ret = cocos2d::extension::EventListenerAssetsManagerEx::create(assetManager, [=](EventAssetsManagerEx* event){
int id = event? (int)event->_ID : -1;
int* luaID = event? &event->_luaID : nullptr;
toluafix_pushusertype_ccobject(L, id, luaID, (void*)event,"cc.EventAssetsManagerEx");
LuaEngine::getInstance()->getLuaStack()->executeFunctionByHandler(handler, 1);
});
int id = (ret) ? (int)ret->_ID : -1;
int* luaID = (ret) ? &ret->_luaID : nullptr;
toluafix_pushusertype_ccobject(L, id, luaID, (void*)ret,"cc.EventListenerAssetsManagerEx");
return 1;
}
CCLOG("%s has wrong number of arguments: %d, was expecting %d \n", "create",argc, 2);
return 0;
#if COCOS2D_DEBUG >= 1
tolua_lerror:
tolua_error(L,"#ferror in function 'lua_cocos2dx_Extension_EventListenerAssetsManagerEx_create'.",&tolua_err);
return 0;
#endif
}
static void extendEventListenerAssetsManagerEx(lua_State* L)
{
lua_pushstring(L, "cc.EventListenerAssetsManagerEx");
lua_rawget(L, LUA_REGISTRYINDEX);
if (lua_istable(L,-1))
{
tolua_function(L, "create", lua_cocos2dx_Extension_EventListenerAssetsManagerEx_create);
}
lua_pop(L, 1);
}
int register_all_cocos2dx_extension_manual(lua_State* tolua_S)
{
extendControl(tolua_S);
extendAssetsManager(tolua_S);
extendScrollView(tolua_S);
extendTableView(tolua_S);
extendManifest(tolua_S);
extendEventListenerAssetsManagerEx(tolua_S);
return 0;
}

View File

@ -35,15 +35,6 @@ extern "C" {
TOLUA_API int register_all_cocos2dx_extension_manual(lua_State* tolua_S);
TOLUA_API int register_extension_module(lua_State* tolua_S);
struct LuaAssetsManagerEventData
{
int value;
LuaAssetsManagerEventData(int _value = 0):value(_value)
{
}
};
struct LuaTableViewEventData
{
void* value;

View File

@ -208,6 +208,39 @@ cc.NODE_ON_ENTER_TRANSITION_DID_FINISH = 2
cc.NODE_ON_EXIT_TRANSITION_DID_START = 3
cc.NODE_ON_CLEAN_UP = 4
cc.CONTROL_STEPPER_PART_MINUS = 0
cc.CONTROL_STEPPER_PART_PLUS = 1
cc.CONTROL_STEPPER_PART_NONE = 2
cc.TABLEVIEW_FILL_TOPDOWN = 0
cc.TABLEVIEW_FILL_BOTTOMUP = 1
cc.WEBSOCKET_OPEN = 0
cc.WEBSOCKET_MESSAGE = 1
cc.WEBSOCKET_CLOSE = 2
cc.WEBSOCKET_ERROR = 3
cc.WEBSOCKET_STATE_CONNECTING = 0
cc.WEBSOCKET_STATE_OPEN = 1
cc.WEBSOCKET_STATE_CLOSING = 2
cc.WEBSOCKET_STATE_CLOSED = 3
cc.XMLHTTPREQUEST_RESPONSE_STRING = 0
cc.XMLHTTPREQUEST_RESPONSE_ARRAY_BUFFER = 1
cc.XMLHTTPREQUEST_RESPONSE_BLOB = 2
cc.XMLHTTPREQUEST_RESPONSE_DOCUMENT = 3
cc.XMLHTTPREQUEST_RESPONSE_JSON = 4
cc.ASSETSMANAGEREX_CREATE_FILE = 0
cc.ASSETSMANAGEREX_NETWORK = 1
cc.ASSETSMANAGEREX_NO_NEW_VERSION = 2
cc.ASSETSMANAGEREX_UNCOMPRESS = 3
cc.ASSETSMANAGEREX_PROTOCOL_PROGRESS = 0
cc.ASSETSMANAGEREX_PROTOCOL_SUCCESS = 1
cc.ASSETSMANAGEREX_PROTOCOL_ERROR = 2
cc.Handler = cc.Handler or {}
cc.Handler.NODE = 0
cc.Handler.MENU_CLICKED = 1
@ -477,7 +510,6 @@ cc.KeyCodeKey =
cc.KeyCode =
{
}
for k,v in ipairs(cc.KeyCodeKey) do
@ -486,6 +518,28 @@ end
cc.KeyCode.KEY_BACK = cc.KeyCode.KEY_ESCAPE
cc.EventAssetsManagerEx =
{
EventCode =
{
ERROR_NO_LOCAL_MANIFEST = 0,
ERROR_DOWNLOAD_MANIFEST = 1,
ERROR_PARSE_MANIFEST = 2,
NEW_VERSION_FOUND = 3,
ALREADY_UP_TO_DATE = 4,
UPDATE_PROGRESSION = 5,
ASSET_UPDATED = 6,
ERROR_UPDATING = 7,
UPDATE_FINISHED = 8,
},
}
cc.AssetsManagerExStatic =
{
VERSION_ID = "@version",
MANIFEST_ID = "@manifest",
}
cc.EventCode =
{
BEGAN = 0,

View File

@ -7,6 +7,11 @@ LOCAL_MODULE_FILENAME := libextension
LOCAL_SRC_FILES := \
assets-manager/AssetsManager.cpp \
assets-manager/Downloader.cpp \
assets-manager/Manifest.cpp \
assets-manager/AssetsManagerEx.cpp \
assets-manager/CCEventAssetsManagerEx.cpp \
assets-manager/CCEventListenerAssetsManagerEx.cpp \
GUI/CCControlExtension/CCControl.cpp \
GUI/CCControlExtension/CCControlButton.cpp \
GUI/CCControlExtension/CCControlColourPicker.cpp \

View File

@ -22,6 +22,11 @@ include_directories(
set(COCOS_EXTENSIONS_SRC
../extensions/assets-manager/AssetsManager.cpp
../extensions/assets-manager/AssetsManagerEx.cpp
../extensions/assets-manager/CCEventAssetsManagerEx.cpp
../extensions/assets-manager/CCEventListenerAssetsManagerEx.cpp
../extensions/assets-manager/Downloader.cpp
../extensions/assets-manager/Manifest.cpp
../extensions/GUI/CCControlExtension/CCControl.cpp
../extensions/GUI/CCControlExtension/CCControlButton.cpp
../extensions/GUI/CCControlExtension/CCControlColourPicker.cpp

View File

@ -0,0 +1,877 @@
/****************************************************************************
Copyright (c) 2014 cocos2d-x.org
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "AssetsManagerEx.h"
#include "CCEventListenerAssetsManagerEx.h"
#include "cocos2d.h"
#include <curl/curl.h>
#include <curl/easy.h>
#include <stdio.h>
#include "unzip.h"
NS_CC_EXT_BEGIN
#define VERSION_FILENAME "version.manifest"
#define TEMP_MANIFEST_FILENAME "project.manifest.temp"
#define MANIFEST_FILENAME "project.manifest"
#define BUFFER_SIZE 8192
#define MAX_FILENAME 512
#define DEFAULT_CONNECTION_TIMEOUT 8
const std::string AssetsManagerEx::VERSION_ID = "@version";
const std::string AssetsManagerEx::MANIFEST_ID = "@manifest";
const std::string AssetsManagerEx::BATCH_UPDATE_ID = "@batch_update";
// Implementation of AssetsManagerEx
AssetsManagerEx::AssetsManagerEx(const std::string& manifestUrl, const std::string& storagePath)
: _updateState(State::UNCHECKED)
, _waitToUpdate(false)
, _totalToDownload(0)
, _totalWaitToDownload(0)
, _percent(0)
, _percentByFile(0)
, _manifestUrl(manifestUrl)
, _storagePath("")
, _cacheVersionPath("")
, _cacheManifestPath("")
, _tempManifestPath("")
, _assets(nullptr)
, _localManifest(nullptr)
, _tempManifest(nullptr)
, _remoteManifest(nullptr)
{
// Init variables
_eventDispatcher = Director::getInstance()->getEventDispatcher();
std::string pointer = StringUtils::format("%p", this);
_eventName = EventListenerAssetsManagerEx::LISTENER_ID + pointer;
_fileUtils = FileUtils::getInstance();
_updateState = State::UNCHECKED;
_downloader = std::make_shared<Downloader>();
_downloader->setConnectionTimeout(DEFAULT_CONNECTION_TIMEOUT);
_downloader->_onError = std::bind(&AssetsManagerEx::onError, this, std::placeholders::_1);
_downloader->_onProgress = std::bind(&AssetsManagerEx::onProgress,
this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4);
_downloader->_onSuccess = std::bind(&AssetsManagerEx::onSuccess, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
setStoragePath(storagePath);
_cacheVersionPath = _storagePath + VERSION_FILENAME;
_cacheManifestPath = _storagePath + MANIFEST_FILENAME;
_tempManifestPath = _storagePath + TEMP_MANIFEST_FILENAME;
// Init and load local manifest
_localManifest = new Manifest();
loadLocalManifest(manifestUrl);
// Init and load temporary manifest
_tempManifest = new Manifest();
_tempManifest->parse(_tempManifestPath);
if (!_tempManifest->isLoaded())
_fileUtils->removeFile(_tempManifestPath);
// Init remote manifest for future usage
_remoteManifest = new Manifest();
}
AssetsManagerEx::~AssetsManagerEx()
{
_downloader->_onError = nullptr;
_downloader->_onSuccess = nullptr;
_downloader->_onProgress = nullptr;
CC_SAFE_RELEASE(_localManifest);
// _tempManifest could share a ptr with _remoteManifest or _localManifest
if (_tempManifest != _localManifest && _tempManifest != _remoteManifest)
CC_SAFE_RELEASE(_tempManifest);
CC_SAFE_RELEASE(_remoteManifest);
}
AssetsManagerEx* AssetsManagerEx::create(const std::string& manifestUrl, const std::string& storagePath)
{
AssetsManagerEx* ret = new AssetsManagerEx(manifestUrl, storagePath);
if (ret)
{
ret->autorelease();
}
else
{
CC_SAFE_DELETE(ret);
}
return ret;
}
void AssetsManagerEx::prepareLocalManifest()
{
// An alias to assets
_assets = &(_localManifest->getAssets());
// Add search paths
_localManifest->prependSearchPaths();
}
void AssetsManagerEx::loadLocalManifest(const std::string& manifestUrl)
{
// Prefer to use the cached manifest file, if not found use user configured manifest file
if (_fileUtils->isFileExist(_cacheManifestPath))
{
_localManifest->parse(_cacheManifestPath);
if (_localManifest->isLoaded())
prepareLocalManifest();
else
_fileUtils->removeFile(_cacheManifestPath);
}
// Fail to found or load cached manifest file
if (!_localManifest->isLoaded())
{
_localManifest->parse(_manifestUrl);
if (_localManifest->isLoaded())
prepareLocalManifest();
}
// Fail to load local manifest
if (!_localManifest->isLoaded())
{
CCLOG("AssetsManagerEx : No local manifest file found error.\n");
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
}
}
std::string AssetsManagerEx::basename(const std::string& path) const
{
size_t found = path.find_last_of("/\\");
if (std::string::npos != found)
{
return path.substr(0, found);
}
else
{
return path;
}
}
std::string AssetsManagerEx::get(const std::string& key) const
{
auto it = _assets->find(key);
if (it != _assets->cend()) {
return _storagePath + it->second.path;
}
else return "";
}
const Manifest* AssetsManagerEx::getLocalManifest() const
{
return _localManifest;
}
const Manifest* AssetsManagerEx::getRemoteManifest() const
{
return _remoteManifest;
}
const std::string& AssetsManagerEx::getStoragePath() const
{
return _storagePath;
}
void AssetsManagerEx::setStoragePath(const std::string& storagePath)
{
if (_storagePath.size() > 0)
_fileUtils->removeDirectory(_storagePath);
_storagePath = storagePath;
adjustPath(_storagePath);
_fileUtils->createDirectory(_storagePath);
}
void AssetsManagerEx::adjustPath(std::string &path)
{
if (path.size() > 0 && path[path.size() - 1] != '/')
{
path.append("/");
}
}
bool AssetsManagerEx::decompress(const std::string &zip)
{
// Find root path for zip file
size_t pos = zip.find_last_of("/\\");
if (pos == std::string::npos)
{
CCLOG("AssetsManagerEx : no root path specified for zip file %s\n", zip.c_str());
return false;
}
const std::string rootPath = zip.substr(0, pos+1);
// Open the zip file
unzFile zipfile = unzOpen(zip.c_str());
if (! zipfile)
{
CCLOG("AssetsManagerEx : can not open downloaded zip file %s\n", zip.c_str());
return false;
}
// Get info about the zip file
unz_global_info global_info;
if (unzGetGlobalInfo(zipfile, &global_info) != UNZ_OK)
{
CCLOG("AssetsManagerEx : can not read file global info of %s\n", zip.c_str());
unzClose(zipfile);
return false;
}
// Buffer to hold data read from the zip file
char readBuffer[BUFFER_SIZE];
// Loop to extract all files.
uLong i;
for (i = 0; i < global_info.number_entry; ++i)
{
// Get info about current file.
unz_file_info fileInfo;
char fileName[MAX_FILENAME];
if (unzGetCurrentFileInfo(zipfile,
&fileInfo,
fileName,
MAX_FILENAME,
NULL,
0,
NULL,
0) != UNZ_OK)
{
CCLOG("AssetsManagerEx : can not read compressed file info\n");
unzClose(zipfile);
return false;
}
const std::string fullPath = rootPath + fileName;
// Check if this entry is a directory or a file.
const size_t filenameLength = strlen(fileName);
if (fileName[filenameLength-1] == '/')
{
//There are not directory entry in some case.
//So we need to create directory when decompressing file entry
if ( !_fileUtils->createDirectory(basename(fullPath)) )
{
// Failed to create directory
CCLOG("AssetsManagerEx : can not create directory %s\n", fullPath.c_str());
unzClose(zipfile);
return false;
}
}
else
{
// Entry is a file, so extract it.
// Open current file.
if (unzOpenCurrentFile(zipfile) != UNZ_OK)
{
CCLOG("AssetsManagerEx : can not extract file %s\n", fileName);
unzClose(zipfile);
return false;
}
// Create a file to store current file.
FILE *out = fopen(fullPath.c_str(), "wb");
if (!out)
{
CCLOG("AssetsManagerEx : can not create decompress destination file %s\n", fullPath.c_str());
unzCloseCurrentFile(zipfile);
unzClose(zipfile);
return false;
}
// Write current file content to destinate file.
int error = UNZ_OK;
do
{
error = unzReadCurrentFile(zipfile, readBuffer, BUFFER_SIZE);
if (error < 0)
{
CCLOG("AssetsManagerEx : can not read zip file %s, error code is %d\n", fileName, error);
fclose(out);
unzCloseCurrentFile(zipfile);
unzClose(zipfile);
return false;
}
if (error > 0)
{
fwrite(readBuffer, error, 1, out);
}
} while(error > 0);
fclose(out);
}
unzCloseCurrentFile(zipfile);
// Goto next entry listed in the zip file.
if ((i+1) < global_info.number_entry)
{
if (unzGoToNextFile(zipfile) != UNZ_OK)
{
CCLOG("AssetsManagerEx : can not read next file for decompressing\n");
unzClose(zipfile);
return false;
}
}
}
unzClose(zipfile);
return true;
}
void AssetsManagerEx::decompressDownloadedZip()
{
// Decompress all compressed files
for (auto it = _compressedFiles.begin(); it != _compressedFiles.end(); ++it) {
std::string zipfile = *it;
if (!decompress(zipfile))
{
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DECOMPRESS, "", "Unable to decompress file " + zipfile);
}
_fileUtils->removeFile(zipfile);
}
_compressedFiles.clear();
}
void AssetsManagerEx::dispatchUpdateEvent(EventAssetsManagerEx::EventCode code, const std::string &assetId/* = ""*/, const std::string &message/* = ""*/, int curle_code/* = CURLE_OK*/, int curlm_code/* = CURLM_OK*/)
{
EventAssetsManagerEx event(_eventName, this, code, _percent, _percentByFile, assetId, message, curle_code, curlm_code);
_eventDispatcher->dispatchEvent(&event);
}
AssetsManagerEx::State AssetsManagerEx::getState() const
{
return _updateState;
}
void AssetsManagerEx::downloadVersion()
{
if (_updateState > State::PREDOWNLOAD_VERSION)
return;
std::string versionUrl = _localManifest->getVersionFileUrl();
if (versionUrl.size() > 0)
{
_updateState = State::DOWNLOADING_VERSION;
// Download version file asynchronously
_downloader->downloadAsync(versionUrl, _cacheVersionPath, VERSION_ID);
}
// No version file found
else
{
CCLOG("AssetsManagerEx : No version file found, step skipped\n");
_updateState = State::PREDOWNLOAD_MANIFEST;
downloadManifest();
}
}
void AssetsManagerEx::parseVersion()
{
if (_updateState != State::VERSION_LOADED)
return;
_remoteManifest->parse(_cacheVersionPath);
if (!_remoteManifest->isVersionLoaded())
{
CCLOG("AssetsManagerEx : Fail to parse version file, step skipped\n");
_updateState = State::PREDOWNLOAD_MANIFEST;
downloadManifest();
}
else
{
if (_localManifest->versionEquals(_remoteManifest))
{
_updateState = State::UP_TO_DATE;
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
}
else
{
_updateState = State::NEED_UPDATE;
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND);
// Wait to update so continue the process
if (_waitToUpdate)
{
_updateState = State::PREDOWNLOAD_MANIFEST;
downloadManifest();
}
}
}
}
void AssetsManagerEx::downloadManifest()
{
if (_updateState != State::PREDOWNLOAD_MANIFEST)
return;
std::string manifestUrl = _localManifest->getManifestFileUrl();
if (manifestUrl.size() > 0)
{
_updateState = State::DOWNLOADING_MANIFEST;
// Download version file asynchronously
_downloader->downloadAsync(manifestUrl, _tempManifestPath, MANIFEST_ID);
}
// No manifest file found
else
{
CCLOG("AssetsManagerEx : No manifest file found, check update failed\n");
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST);
_updateState = State::UNCHECKED;
}
}
void AssetsManagerEx::parseManifest()
{
if (_updateState != State::MANIFEST_LOADED)
return;
_remoteManifest->parse(_tempManifestPath);
if (!_remoteManifest->isLoaded())
{
CCLOG("AssetsManagerEx : Error parsing manifest file\n");
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_PARSE_MANIFEST);
_updateState = State::UNCHECKED;
}
else
{
if (_localManifest->versionEquals(_remoteManifest))
{
_updateState = State::UP_TO_DATE;
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
}
else
{
_updateState = State::NEED_UPDATE;
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND);
if (_waitToUpdate)
{
startUpdate();
}
}
}
}
void AssetsManagerEx::startUpdate()
{
if (_updateState != State::NEED_UPDATE)
return;
_updateState = State::UPDATING;
// Clean up before update
_failedUnits.clear();
_downloadUnits.clear();
_compressedFiles.clear();
_totalWaitToDownload = _totalToDownload = 0;
_percent = _percentByFile = _sizeCollected = _totalSize = 0;
_downloadedSize.clear();
_totalEnabled = false;
// Temporary manifest exists, resuming previous download
if (_tempManifest->isLoaded() && _tempManifest->versionEquals(_remoteManifest))
{
_tempManifest->genResumeAssetsList(&_downloadUnits);
_totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size();
_downloader->batchDownloadAsync(_downloadUnits, BATCH_UPDATE_ID);
std::string msg = StringUtils::format("Resuming from previous unfinished update, %d files remains to be finished.", _totalToDownload);
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "", msg);
}
// Check difference
else
{
// Temporary manifest not exists,
// it will be used to register the download states of each asset,
// in this case, it equals remote manifest.
if(!_tempManifest->isLoaded()) {
_tempManifest->release();
_tempManifest = _remoteManifest;
}
std::unordered_map<std::string, Manifest::AssetDiff> diff_map = _localManifest->genDiff(_remoteManifest);
if (diff_map.size() == 0)
{
_updateState = State::UP_TO_DATE;
// Rename temporary manifest to valid manifest
_fileUtils->renameFile(_storagePath, TEMP_MANIFEST_FILENAME, MANIFEST_FILENAME);
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
}
else
{
// Generate download units for all assets that need to be updated or added
std::string packageUrl = _remoteManifest->getPackageUrl();
for (auto it = diff_map.begin(); it != diff_map.end(); ++it)
{
Manifest::AssetDiff diff = it->second;
if (diff.type == Manifest::DiffType::DELETED)
{
_fileUtils->removeFile(_storagePath + diff.asset.path);
}
else
{
std::string path = diff.asset.path;
// Create path
_fileUtils->createDirectory(basename(_storagePath + path));
Downloader::DownloadUnit unit;
unit.customId = it->first;
unit.srcUrl = packageUrl + path;
unit.storagePath = _storagePath + path;
unit.resumeDownload = false;
_downloadUnits.emplace(unit.customId, unit);
}
}
// Set other assets' downloadState to SUCCESSED
auto assets = _remoteManifest->getAssets();
for (auto it = assets.cbegin(); it != assets.cend(); ++it)
{
const std::string &key = it->first;
auto diffIt = diff_map.find(key);
if (diffIt == diff_map.end())
{
_tempManifest->setAssetDownloadState(key, Manifest::DownloadState::SUCCESSED);
}
}
_totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size();
_downloader->batchDownloadAsync(_downloadUnits, BATCH_UPDATE_ID);
std::string msg = StringUtils::format("Start to update %d files from remote package.", _totalToDownload);
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "", msg);
}
}
_waitToUpdate = false;
}
void AssetsManagerEx::updateSucceed()
{
// Every thing is correctly downloaded, do the following
// 1. rename temporary manifest to valid manifest
_fileUtils->renameFile(_storagePath, TEMP_MANIFEST_FILENAME, MANIFEST_FILENAME);
// 2. swap the localManifest
if (_localManifest != nullptr)
_localManifest->release();
_localManifest = _remoteManifest;
_remoteManifest = nullptr;
// 3. make local manifest take effect
prepareLocalManifest();
// 4. decompress all compressed files
decompressDownloadedZip();
// 5. Set update state
_updateState = State::UP_TO_DATE;
// 6. Notify finished event
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_FINISHED);
}
void AssetsManagerEx::checkUpdate()
{
if (!_localManifest->isLoaded())
{
CCLOG("AssetsManagerEx : No local manifest file found error.\n");
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
return;
}
switch (_updateState) {
case State::UNCHECKED:
case State::PREDOWNLOAD_VERSION:
{
downloadVersion();
}
break;
case State::UP_TO_DATE:
{
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
}
break;
case State::FAIL_TO_UPDATE:
case State::NEED_UPDATE:
{
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND);
}
break;
default:
break;
}
}
void AssetsManagerEx::update()
{
if (!_localManifest->isLoaded())
{
CCLOG("AssetsManagerEx : No local manifest file found error.\n");
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
return;
}
_waitToUpdate = true;
switch (_updateState) {
case State::UNCHECKED:
{
_updateState = State::PREDOWNLOAD_VERSION;
}
case State::PREDOWNLOAD_VERSION:
{
downloadVersion();
}
break;
case State::VERSION_LOADED:
{
parseVersion();
}
break;
case State::PREDOWNLOAD_MANIFEST:
{
downloadManifest();
}
break;
case State::MANIFEST_LOADED:
{
parseManifest();
}
break;
case State::FAIL_TO_UPDATE:
case State::NEED_UPDATE:
{
// Manifest not loaded yet
if (!_remoteManifest->isLoaded())
{
_waitToUpdate = true;
_updateState = State::PREDOWNLOAD_MANIFEST;
downloadManifest();
}
else
{
startUpdate();
}
}
break;
case State::UP_TO_DATE:
case State::UPDATING:
_waitToUpdate = false;
break;
default:
break;
}
}
void AssetsManagerEx::updateAssets(const Downloader::DownloadUnits& assets)
{
if (_updateState != State::UPDATING && _localManifest->isLoaded() && _remoteManifest->isLoaded())
{
int size = (int)(assets.size());
if (size > 0)
{
_updateState = State::UPDATING;
_downloadUnits.clear();
_downloadUnits = assets;
_downloader->batchDownloadAsync(_downloadUnits, BATCH_UPDATE_ID);
}
else if (size == 0 && _totalWaitToDownload == 0)
{
updateSucceed();
}
}
}
const Downloader::DownloadUnits& AssetsManagerEx::getFailedAssets() const
{
return _failedUnits;
}
void AssetsManagerEx::downloadFailedAssets()
{
CCLOG("AssetsManagerEx : Start update %lu failed assets.\n", _failedUnits.size());
updateAssets(_failedUnits);
}
void AssetsManagerEx::onError(const Downloader::Error &error)
{
// Skip version error occured
if (error.customId == VERSION_ID)
{
CCLOG("AssetsManagerEx : Fail to download version file, step skipped\n");
_updateState = State::PREDOWNLOAD_MANIFEST;
downloadManifest();
}
else if (error.customId == MANIFEST_ID)
{
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST, error.customId, error.message, error.curle_code, error.curlm_code);
}
else
{
auto unitIt = _downloadUnits.find(error.customId);
// Found unit and add it to failed units
if (unitIt != _downloadUnits.end())
{
Downloader::DownloadUnit unit = unitIt->second;
_failedUnits.emplace(unit.customId, unit);
}
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_UPDATING, error.customId, error.message, error.curle_code, error.curlm_code);
}
}
void AssetsManagerEx::onProgress(double total, double downloaded, const std::string &url, const std::string &customId)
{
if (customId == VERSION_ID || customId == MANIFEST_ID)
{
_percent = 100 * (total - downloaded) / total;
// Notify progression event
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, customId);
return;
}
else
{
// Calcul total downloaded
bool found = false;
double totalDownloaded = 0;
for (auto it = _downloadedSize.begin(); it != _downloadedSize.end(); ++it)
{
if (it->first == customId)
{
it->second = downloaded;
found = true;
}
totalDownloaded += it->second;
}
// Collect information if not registed
if (!found)
{
// Set download state to DOWNLOADING, this will run only once in the download process
_tempManifest->setAssetDownloadState(customId, Manifest::DownloadState::DOWNLOADING);
// Register the download size information
_downloadedSize.emplace(customId, downloaded);
_totalSize += total;
_sizeCollected++;
// All collected, enable total size
if (_sizeCollected == _totalToDownload)
{
_totalEnabled = true;
}
}
if (_totalEnabled && _updateState == State::UPDATING)
{
float currentPercent = 100 * totalDownloaded / _totalSize;
// Notify at integer level change
if ((int)currentPercent != (int)_percent) {
_percent = currentPercent;
// Notify progression event
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "");
}
}
}
}
void AssetsManagerEx::onSuccess(const std::string &srcUrl, const std::string &storagePath, const std::string &customId)
{
if (customId == VERSION_ID)
{
_updateState = State::VERSION_LOADED;
parseVersion();
}
else if (customId == MANIFEST_ID)
{
_updateState = State::MANIFEST_LOADED;
parseManifest();
}
else if (customId == BATCH_UPDATE_ID)
{
// Finished with error check
if (_failedUnits.size() > 0 || _totalWaitToDownload > 0)
{
// Save current download manifest information for resuming
_tempManifest->saveToFile(_tempManifestPath);
decompressDownloadedZip();
_updateState = State::FAIL_TO_UPDATE;
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_FAILED);
}
else
{
updateSucceed();
}
}
else
{
auto assets = _remoteManifest->getAssets();
auto assetIt = assets.find(customId);
if (assetIt != assets.end())
{
// Set download state to SUCCESSED
_tempManifest->setAssetDownloadState(customId, Manifest::DownloadState::SUCCESSED);
// Add file to need decompress list
if (assetIt->second.compressed) {
_compressedFiles.push_back(storagePath);
}
}
auto unitIt = _downloadUnits.find(customId);
if (unitIt != _downloadUnits.end())
{
// Reduce count only when unit found in _downloadUnits
_totalWaitToDownload--;
_percentByFile = 100 * (float)(_totalToDownload - _totalWaitToDownload) / _totalToDownload;
// Notify progression event
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "");
}
// Notify asset updated event
dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ASSET_UPDATED, customId);
unitIt = _failedUnits.find(customId);
// Found unit and delete it
if (unitIt != _failedUnits.end())
{
// Remove from failed units list
_failedUnits.erase(unitIt);
}
}
}
void AssetsManagerEx::destroyDownloadedVersion()
{
_fileUtils->removeFile(_cacheVersionPath);
_fileUtils->removeFile(_cacheManifestPath);
}
NS_CC_EXT_END

View File

@ -0,0 +1,266 @@
/****************************************************************************
Copyright (c) 2013 cocos2d-x.org
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#ifndef __AssetsManagerEx__
#define __AssetsManagerEx__
#include "base/CCEventDispatcher.h"
#include "platform/CCFileUtils.h"
#include "CCEventAssetsManagerEx.h"
#include "Downloader.h"
#include "Manifest.h"
#include "extensions/ExtensionMacros.h"
#include "extensions/ExtensionExport.h"
#include "json/document.h"
#include <string>
#include <unordered_map>
#include <vector>
NS_CC_EXT_BEGIN
/**
* @brief This class is used to auto update resources, such as pictures or scripts.
*/
class CC_EX_DLL AssetsManagerEx : public Ref
{
public:
friend class Downloader;
friend int downloadProgressFunc(Downloader::ProgressData *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded);
//! Update states
enum class State
{
UNCHECKED,
PREDOWNLOAD_VERSION,
DOWNLOADING_VERSION,
VERSION_LOADED,
PREDOWNLOAD_MANIFEST,
DOWNLOADING_MANIFEST,
MANIFEST_LOADED,
NEED_UPDATE,
UPDATING,
UP_TO_DATE,
FAIL_TO_UPDATE
};
const static std::string VERSION_ID;
const static std::string MANIFEST_ID;
const static std::string BATCH_UPDATE_ID;
/** @brief Create function for creating a new AssetsManagerEx
@param manifestUrl The url for the local manifest file
@param storagePath The storage path for downloaded assetes
@warning The cached manifest in your storage path have higher priority and will be searched first,
only if it doesn't exist, AssetsManagerEx will use the given manifestUrl.
*/
static AssetsManagerEx* create(const std::string &manifestUrl, const std::string &storagePath);
/** @brief Check out if there is a new version of manifest.
* You may use this method before updating, then let user determine whether
* he wants to update resources.
*/
void checkUpdate();
/** @brief Update with the current local manifest.
*/
void update();
/** @brief Reupdate all failed assets under the current AssetsManagerEx context
*/
void downloadFailedAssets();
/** @brief Gets the current update state.
*/
State getState() const;
/** @brief Gets storage path.
*/
const std::string& getStoragePath() const;
/** @brief Function for retrieve the local manifest object
*/
const Manifest* getLocalManifest() const;
/** @brief Function for retrieve the remote manifest object
*/
const Manifest* getRemoteManifest() const;
CC_CONSTRUCTOR_ACCESS:
AssetsManagerEx(const std::string& manifestUrl, const std::string& storagePath);
virtual ~AssetsManagerEx();
protected:
std::string basename(const std::string& path) const;
std::string get(const std::string& key) const;
void loadLocalManifest(const std::string& manifestUrl);
void prepareLocalManifest();
void setStoragePath(const std::string& storagePath);
void adjustPath(std::string &path);
void dispatchUpdateEvent(EventAssetsManagerEx::EventCode code, const std::string &message = "", const std::string &assetId = "", int curle_code = 0, int curlm_code = 0);
void downloadVersion();
void parseVersion();
void downloadManifest();
void parseManifest();
void startUpdate();
void updateSucceed();
bool decompress(const std::string &filename);
void decompressDownloadedZip();
/** @brief Update a list of assets under the current AssetsManagerEx context
*/
void updateAssets(const Downloader::DownloadUnits& assets);
/** @brief Retrieve all failed assets during the last update
*/
const Downloader::DownloadUnits& getFailedAssets() const;
/** @brief Function for destorying the downloaded version file and manifest file
*/
void destroyDownloadedVersion();
/** @brief Call back function for error handling,
the error will then be reported to user's listener registed in addUpdateEventListener
@param error The error object contains ErrorCode, message, asset url, asset key
@warning AssetsManagerEx internal use only
* @js NA
* @lua NA
*/
virtual void onError(const Downloader::Error &error);
/** @brief Call back function for recording downloading percent of the current asset,
the progression will then be reported to user's listener registed in addUpdateProgressEventListener
@param total Total size to download for this asset
@param downloaded Total size already downloaded for this asset
@param url The url of this asset
@param customId The key of this asset
@warning AssetsManagerEx internal use only
* @js NA
* @lua NA
*/
virtual void onProgress(double total, double downloaded, const std::string &url, const std::string &customId);
/** @brief Call back function for success of the current asset
the success event will then be send to user's listener registed in addUpdateEventListener
@param srcUrl The url of this asset
@param customId The key of this asset
@warning AssetsManagerEx internal use only
* @js NA
* @lua NA
*/
virtual void onSuccess(const std::string &srcUrl, const std::string &storagePath, const std::string &customId);
private:
//! The event of the current AssetsManagerEx in event dispatcher
std::string _eventName;
//! Reference to the global event dispatcher
EventDispatcher *_eventDispatcher;
//! Reference to the global file utils
FileUtils *_fileUtils;
//! State of update
State _updateState;
//! Downloader
std::shared_ptr<Downloader> _downloader;
//! The reference to the local assets
const std::unordered_map<std::string, Manifest::Asset> *_assets;
//! The path to store downloaded resources.
std::string _storagePath;
//! The local path of cached version file
std::string _cacheVersionPath;
//! The local path of cached manifest file
std::string _cacheManifestPath;
//! The local path of cached temporary manifest file
std::string _tempManifestPath;
//! The path of local manifest file
std::string _manifestUrl;
//! Local manifest
Manifest *_localManifest;
//! Local temporary manifest for download resuming
Manifest *_tempManifest;
//! Remote manifest
Manifest *_remoteManifest;
//! Whether user have requested to update
bool _waitToUpdate;
//! All assets unit to download
Downloader::DownloadUnits _downloadUnits;
//! All failed units
Downloader::DownloadUnits _failedUnits;
//! All files to be decompressed
std::vector<std::string> _compressedFiles;
//! Download percent
float _percent;
//! Download percent by file
float _percentByFile;
//! Indicate whether the total size should be enabled
int _totalEnabled;
//! Indicate the number of file whose total size have been collected
int _sizeCollected;
//! Total file size need to be downloaded (sum of all file)
double _totalSize;
//! Downloaded size for each file
std::unordered_map<std::string, double> _downloadedSize;
//! Total number of assets to download
int _totalToDownload;
//! Total number of assets still waiting to be downloaded
int _totalWaitToDownload;
};
NS_CC_EXT_END
#endif /* defined(__AssetsManagerEx__) */

View File

@ -0,0 +1,46 @@
/****************************************************************************
Copyright (c) 2014 Chukong Technologies Inc.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "CCEventAssetsManagerEx.h"
#include "base/ccMacros.h"
#include <functional>
#include "AssetsManagerEx.h"
NS_CC_EXT_BEGIN
EventAssetsManagerEx::EventAssetsManagerEx(const std::string& eventName, cocos2d::extension::AssetsManagerEx *manager, const EventCode &code, float percent/* = 0 */, float percentByFile/* = 0*/, const std::string& assetId/* = "" */, const std::string& message/* = "" */, int curle_code/* = CURLE_OK*/, int curlm_code/* = CURLM_OK*/)
: EventCustom(eventName)
, _manager(manager)
, _code(code)
, _curle_code(curle_code)
, _curlm_code(curlm_code)
, _percent(percent)
, _percentByFile(percentByFile)
, _assetId(assetId)
, _message(message)
{
}
NS_CC_EXT_END

View File

@ -0,0 +1,99 @@
/****************************************************************************
Copyright (c) 2014 Chukong Technologies Inc.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#ifndef __cocos2d_libs__CCEventAssetsManagerEx__
#define __cocos2d_libs__CCEventAssetsManagerEx__
#include "base/CCEvent.h"
#include "base/CCEventCustom.h"
#include "extensions/ExtensionMacros.h"
#include "extensions/ExtensionExport.h"
NS_CC_EXT_BEGIN
class AssetsManagerEx;
class CC_EX_DLL EventAssetsManagerEx : public cocos2d::EventCustom
{
public:
friend class AssetsManagerEx;
//! Update events code
enum class EventCode
{
ERROR_NO_LOCAL_MANIFEST,
ERROR_DOWNLOAD_MANIFEST,
ERROR_PARSE_MANIFEST,
NEW_VERSION_FOUND,
ALREADY_UP_TO_DATE,
UPDATE_PROGRESSION,
ASSET_UPDATED,
ERROR_UPDATING,
UPDATE_FINISHED,
UPDATE_FAILED,
ERROR_DECOMPRESS
};
inline EventCode getEventCode() const { return _code; };
inline int getCURLECode() const { return _curle_code; };
inline int getCURLMCode() const { return _curlm_code; };
inline std::string getMessage() const { return _message; };
inline std::string getAssetId() const { return _assetId; };
inline cocos2d::extension::AssetsManagerEx *getAssetsManagerEx() const { return _manager; };
inline float getPercent() const { return _percent; };
inline float getPercentByFile() const { return _percentByFile; };
CC_CONSTRUCTOR_ACCESS:
/** Constructor */
EventAssetsManagerEx(const std::string& eventName, cocos2d::extension::AssetsManagerEx *manager, const EventCode &code, float percent = 0, float percentByFile = 0, const std::string& assetId = "", const std::string& message = "", int curle_code = 0, int curlm_code = 0);
private:
EventCode _code;
cocos2d::extension::AssetsManagerEx *_manager;
std::string _message;
std::string _assetId;
int _curle_code;
int _curlm_code;
float _percent;
float _percentByFile;
};
NS_CC_EXT_END
#endif /* defined(__cocos2d_libs__CCEventAssetsManagerEx__) */

View File

@ -0,0 +1,98 @@
/****************************************************************************
Copyright (c) 2014 Chukong Technologies Inc.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "CCEventListenerAssetsManagerEx.h"
#include "CCEventAssetsManagerEx.h"
#include "AssetsManagerEx.h"
#include "cocos2d.h"
NS_CC_EXT_BEGIN
const std::string EventListenerAssetsManagerEx::LISTENER_ID = "__cc_assets_manager_";
EventListenerAssetsManagerEx::EventListenerAssetsManagerEx()
: _onAssetsManagerExEvent(nullptr)
, _AssetsManagerEx(nullptr)
{
}
EventListenerAssetsManagerEx* EventListenerAssetsManagerEx::create(cocos2d::extension::AssetsManagerEx *AssetsManagerEx, const std::function<void(EventAssetsManagerEx*)>& callback)
{
EventListenerAssetsManagerEx* ret = new EventListenerAssetsManagerEx();
if (ret && ret->init(AssetsManagerEx, callback))
{
ret->autorelease();
}
else
{
CC_SAFE_DELETE(ret);
}
return ret;
}
bool EventListenerAssetsManagerEx::init(const AssetsManagerEx *AssetsManagerEx, const std::function<void(EventAssetsManagerEx*)>& callback)
{
bool ret = false;
_AssetsManagerEx = AssetsManagerEx;
_onAssetsManagerExEvent = callback;
auto func = [this](EventCustom *event) -> void
{
EventAssetsManagerEx *eventAssetsManagerEx = dynamic_cast<EventAssetsManagerEx*>(event);
_onAssetsManagerExEvent(eventAssetsManagerEx);
};
std::string pointer = StringUtils::format("%p", AssetsManagerEx);
if (EventListenerCustom::init(LISTENER_ID + pointer, func))
{
ret = true;
}
return ret;
}
EventListenerAssetsManagerEx* EventListenerAssetsManagerEx::clone()
{
EventListenerAssetsManagerEx* ret = new EventListenerAssetsManagerEx();
if (ret && ret->init(_AssetsManagerEx, _onAssetsManagerExEvent))
{
ret->autorelease();
}
else
{
CC_SAFE_DELETE(ret);
}
return ret;
}
bool EventListenerAssetsManagerEx::checkAvailable()
{
bool ret = false;
if (EventListener::checkAvailable() && _AssetsManagerEx != nullptr && _onAssetsManagerExEvent != nullptr)
{
ret = true;
}
return ret;
}
NS_CC_EXT_END

View File

@ -0,0 +1,86 @@
/****************************************************************************
Copyright (c) 2014 Chukong Technologies Inc.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#ifndef __cocos2d_libs__CCEventListenerAssetsManagerEx__
#define __cocos2d_libs__CCEventListenerAssetsManagerEx__
#include "base/CCEventListener.h"
#include "base/CCEventListenerCustom.h"
#include "extensions/ExtensionMacros.h"
#include "extensions/ExtensionExport.h"
NS_CC_EXT_BEGIN
class EventAssetsManagerEx;
class AssetsManagerEx;
/**
* Usage:
* auto dispatcher = Director::getInstance()->getEventDispatcher();
* auto manager = AssetsManagerEx::create(manifestUrl, storagePath);
* Adds a listener:
*
* auto callback = [](EventAssetsManagerEx* event){ do_some_thing(); };
* auto listener = EventListenerAssetsManagerEx::create(manager, callback);
* dispatcher->addEventListenerWithSceneGraphPriority(listener, one_node);
*
* Removes a listener
*
* dispatcher->removeEventListener(listener);
*/
class CC_EX_DLL EventListenerAssetsManagerEx : public cocos2d::EventListenerCustom
{
public:
friend class AssetsManagerEx;
/** Creates an event listener with type and callback.
* @param eventType The type of the event.
* @param callback The callback function when the specified event was emitted.
*/
static EventListenerAssetsManagerEx* create(AssetsManagerEx *AssetsManagerEx, const std::function<void(EventAssetsManagerEx*)>& callback);
/// Overrides
virtual bool checkAvailable() override;
virtual EventListenerAssetsManagerEx* clone() override;
CC_CONSTRUCTOR_ACCESS:
/** Constructor */
EventListenerAssetsManagerEx();
/** Initializes event with type and callback function */
bool init(const AssetsManagerEx *AssetsManagerEx, const std::function<void(EventAssetsManagerEx*)>& callback);
protected:
static const std::string LISTENER_ID;
std::function<void(EventAssetsManagerEx*)> _onAssetsManagerExEvent;
const AssetsManagerEx *_AssetsManagerEx;
//friend class luaEventListenerAssetsManagerEx;
};
NS_CC_EXT_END
#endif /* defined(__cocos2d_libs__CCEventListenerAssetsManagerEx__) */

View File

@ -0,0 +1,680 @@
/****************************************************************************
Copyright (c) 2013 cocos2d-x.org
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "Downloader.h"
#include "cocos2d.h"
#include <curl/curl.h>
#include <curl/easy.h>
#include <cstdio>
#include <cerrno>
NS_CC_EXT_BEGIN
#define LOW_SPEED_LIMIT 1L
#define LOW_SPEED_TIME 5L
#define MAX_REDIRS 2
#define DEFAULT_TIMEOUT 5
#define HTTP_CODE_SUPPORT_RESUME 206
#define TEMP_EXT ".temp"
size_t fileWriteFunc(void *ptr, size_t size, size_t nmemb, void *userdata)
{
FILE *fp = (FILE*)userdata;
size_t written = fwrite(ptr, size, nmemb, fp);
return written;
}
size_t bufferWriteFunc(void *ptr, size_t size, size_t nmemb, void *userdata)
{
Downloader::StreamData *streamBuffer = (Downloader::StreamData *)userdata;
size_t written = size * nmemb;
// Avoid pointer overflow
if (streamBuffer->offset + written <= streamBuffer->total)
{
memcpy(streamBuffer->buffer + streamBuffer->offset, ptr, written);
streamBuffer->offset += written;
return written;
}
else return 0;
}
// This is only for batchDownload process, will notify file succeed event in progress function
int batchDownloadProgressFunc(Downloader::ProgressData *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded)
{
if (ptr->totalToDownload == 0)
{
ptr->totalToDownload = totalToDownload;
}
if (ptr->downloaded != nowDownloaded)
{
ptr->downloaded = nowDownloaded;
Downloader::ProgressData data = *ptr;
if (nowDownloaded == totalToDownload)
{
Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{
if (!data.downloader.expired())
{
std::shared_ptr<Downloader> downloader = data.downloader.lock();
auto progressCB = downloader->getProgressCallback();
if (progressCB != nullptr)
{
progressCB(totalToDownload, nowDownloaded, data.url, data.customId);
}
auto successCB = downloader->getSuccessCallback();
if (successCB != nullptr)
{
successCB(data.url, data.path + data.name, data.customId);
}
}
});
}
else
{
Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{
if (!data.downloader.expired())
{
std::shared_ptr<Downloader> downloader = data.downloader.lock();
auto callback = downloader->getProgressCallback();
if (callback != nullptr)
{
callback(totalToDownload, nowDownloaded, data.url, data.customId);
}
}
});
}
}
return 0;
}
// Compare to batchDownloadProgressFunc, this only handles progress information notification
int downloadProgressFunc(Downloader::ProgressData *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded)
{
if (ptr->totalToDownload == 0)
{
ptr->totalToDownload = totalToDownload;
}
if (ptr->downloaded != nowDownloaded)
{
ptr->downloaded = nowDownloaded;
Downloader::ProgressData data = *ptr;
Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{
if (!data.downloader.expired())
{
std::shared_ptr<Downloader> downloader = data.downloader.lock();
auto callback = downloader->getProgressCallback();
if (callback != nullptr)
{
callback(totalToDownload, nowDownloaded, data.url, data.customId);
}
}
});
}
return 0;
}
Downloader::Downloader()
: _onError(nullptr)
, _onProgress(nullptr)
, _onSuccess(nullptr)
, _connectionTimeout(DEFAULT_TIMEOUT)
, _supportResuming(false)
{
_fileUtils = FileUtils::getInstance();
}
Downloader::~Downloader()
{
}
int Downloader::getConnectionTimeout()
{
return _connectionTimeout;
}
void Downloader::setConnectionTimeout(int timeout)
{
if (timeout >= 0)
_connectionTimeout = timeout;
}
void Downloader::notifyError(ErrorCode code, const std::string &msg/* ="" */, const std::string &customId/* ="" */, int curle_code/* = CURLE_OK*/, int curlm_code/* = CURLM_OK*/)
{
std::weak_ptr<Downloader> ptr = shared_from_this();
Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{
if (!ptr.expired())
{
std::shared_ptr<Downloader> downloader = ptr.lock();
if (downloader->_onError != nullptr)
{
Error err;
err.code = code;
err.curle_code = curle_code;
err.curlm_code = curlm_code;
err.message = msg;
err.customId = customId;
downloader->_onError(err);
}
}
});
}
void Downloader::notifyError(const std::string &msg, int curlm_code, const std::string &customId/* = ""*/)
{
notifyError(ErrorCode::CURL_MULTI_ERROR, msg, customId, CURLE_OK, curlm_code);
}
void Downloader::notifyError(const std::string &msg, const std::string &customId, int curle_code)
{
notifyError(ErrorCode::CURL_EASY_ERROR, msg, customId, curle_code);
}
std::string Downloader::getFileNameFromUrl(const std::string &srcUrl)
{
// Find file name and file extension
std::string filename;
unsigned long found = srcUrl.find_last_of("/\\");
if (found != std::string::npos)
filename = srcUrl.substr(found+1);
return filename;
}
void Downloader::clearBatchDownloadData()
{
while (_progDatas.size() != 0) {
delete _progDatas.back();
_progDatas.pop_back();
}
while (_files.size() != 0) {
delete _files.back();
_files.pop_back();
}
}
void Downloader::prepareDownload(const std::string &srcUrl, const std::string &storagePath, const std::string &customId, bool resumeDownload, FileDescriptor *fDesc, ProgressData *pData)
{
std::shared_ptr<Downloader> downloader = shared_from_this();
pData->customId = customId;
pData->url = srcUrl;
pData->downloader = downloader;
pData->downloaded = 0;
pData->totalToDownload = 0;
fDesc->fp = nullptr;
fDesc->curl = nullptr;
Error err;
err.customId = customId;
// Asserts
// Find file name and file extension
unsigned long found = storagePath.find_last_of("/\\");
if (found != std::string::npos)
{
pData->name = storagePath.substr(found+1);
pData->path = storagePath.substr(0, found+1);
}
else
{
err.code = ErrorCode::INVALID_URL;
err.message = "Invalid url or filename not exist error: " + srcUrl;
if (this->_onError) this->_onError(err);
return;
}
// Create a file to save file.
const std::string outFileName = storagePath + TEMP_EXT;
if (_supportResuming && resumeDownload && _fileUtils->isFileExist(outFileName))
{
fDesc->fp = fopen(outFileName.c_str(), "ab");
}
else
{
fDesc->fp = fopen(outFileName.c_str(), "wb");
}
if (!fDesc->fp)
{
err.code = ErrorCode::CREATE_FILE;
err.message = StringUtils::format("Can not create file %s: errno %d", outFileName.c_str(), errno);
if (this->_onError) this->_onError(err);
}
}
bool Downloader::prepareHeader(void *curl, const std::string &srcUrl) const
{
curl_easy_setopt(curl, CURLOPT_URL, srcUrl.c_str());
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
if (curl_easy_perform(curl) == CURLE_OK)
return true;
else
return false;
}
long Downloader::getContentSize(const std::string &srcUrl) const
{
double contentLength = -1;
CURL *header = curl_easy_init();
if (prepareHeader(header, srcUrl))
{
curl_easy_getinfo(header, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &contentLength);
}
curl_easy_cleanup(header);
return contentLength;
}
void Downloader::downloadToBufferAsync(const std::string &srcUrl, unsigned char *buffer, const long &size, const std::string &customId/* = ""*/)
{
if (buffer != nullptr)
{
std::shared_ptr<Downloader> downloader = shared_from_this();
ProgressData pData;
pData.customId = customId;
pData.url = srcUrl;
pData.downloader = downloader;
pData.downloaded = 0;
pData.totalToDownload = 0;
StreamData streamBuffer;
streamBuffer.buffer = buffer;
streamBuffer.total = size;
streamBuffer.offset = 0;
auto t = std::thread(&Downloader::downloadToBuffer, this, srcUrl, customId, streamBuffer, pData);
t.detach();
}
}
void Downloader::downloadToBufferSync(const std::string &srcUrl, unsigned char *buffer, const long &size, const std::string &customId/* = ""*/)
{
if (buffer != nullptr)
{
std::shared_ptr<Downloader> downloader = shared_from_this();
ProgressData pData;
pData.customId = customId;
pData.url = srcUrl;
pData.downloader = downloader;
pData.downloaded = 0;
pData.totalToDownload = 0;
StreamData streamBuffer;
streamBuffer.buffer = buffer;
streamBuffer.total = size;
streamBuffer.offset = 0;
downloadToBuffer(srcUrl, customId, streamBuffer, pData);
}
}
void Downloader::downloadToBuffer(const std::string &srcUrl, const std::string &customId, const StreamData &buffer, const ProgressData &data)
{
std::weak_ptr<Downloader> ptr = shared_from_this();
CURL *curl = curl_easy_init();
if (!curl)
{
this->notifyError(ErrorCode::CURL_EASY_ERROR, "Can not init curl with curl_easy_init", customId);
return;
}
// Download pacakge
curl_easy_setopt(curl, CURLOPT_URL, srcUrl.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, bufferWriteFunc);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, downloadProgressFunc);
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &data);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, true);
if (_connectionTimeout) curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, _connectionTimeout);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, LOW_SPEED_LIMIT);
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, LOW_SPEED_TIME);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
_fileUtils->removeFile(data.path + data.name + TEMP_EXT);
std::string msg = StringUtils::format("Unable to download file: [curl error]%s", curl_easy_strerror(res));
this->notifyError(msg, customId, res);
}
curl_easy_cleanup(curl);
Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{
if (!ptr.expired())
{
std::shared_ptr<Downloader> downloader = ptr.lock();
auto successCB = downloader->getSuccessCallback();
if (successCB != nullptr)
{
successCB(data.url, "", data.customId);
}
}
});
}
void Downloader::downloadAsync(const std::string &srcUrl, const std::string &storagePath, const std::string &customId/* = ""*/)
{
FileDescriptor fDesc;
ProgressData pData;
prepareDownload(srcUrl, storagePath, customId, false, &fDesc, &pData);
if (fDesc.fp != NULL)
{
auto t = std::thread(&Downloader::download, this, srcUrl, customId, fDesc, pData);
t.detach();
}
}
void Downloader::downloadSync(const std::string &srcUrl, const std::string &storagePath, const std::string &customId/* = ""*/)
{
FileDescriptor fDesc;
ProgressData pData;
prepareDownload(srcUrl, storagePath, customId, false, &fDesc, &pData);
if (fDesc.fp != NULL)
{
download(srcUrl, customId, fDesc, pData);
}
}
void Downloader::download(const std::string &srcUrl, const std::string &customId, const FileDescriptor &fDesc, const ProgressData &data)
{
std::weak_ptr<Downloader> ptr = shared_from_this();
CURL *curl = curl_easy_init();
if (!curl)
{
this->notifyError(ErrorCode::CURL_EASY_ERROR, "Can not init curl with curl_easy_init", customId);
return;
}
// Download pacakge
curl_easy_setopt(curl, CURLOPT_URL, srcUrl.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fileWriteFunc);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fDesc.fp);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, downloadProgressFunc);
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &data);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, true);
if (_connectionTimeout) curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, _connectionTimeout);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, LOW_SPEED_LIMIT);
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, LOW_SPEED_TIME);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
_fileUtils->removeFile(data.path + data.name + TEMP_EXT);
std::string msg = StringUtils::format("Unable to download file: [curl error]%s", curl_easy_strerror(res));
this->notifyError(msg, customId, res);
}
fclose(fDesc.fp);
curl_easy_cleanup(curl);
// This can only be done after fclose
if (res == CURLE_OK)
{
_fileUtils->renameFile(data.path, data.name + TEMP_EXT, data.name);
}
Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{
if (!ptr.expired())
{
std::shared_ptr<Downloader> downloader = ptr.lock();
auto successCB = downloader->getSuccessCallback();
if (successCB != nullptr)
{
successCB(data.url, data.path + data.name, data.customId);
}
}
});
}
void Downloader::batchDownloadAsync(const DownloadUnits &units, const std::string &batchId/* = ""*/)
{
auto t = std::thread(&Downloader::batchDownloadSync, this, units, batchId);
t.detach();
}
void Downloader::batchDownloadSync(const DownloadUnits &units, const std::string &batchId/* = ""*/)
{
if (units.size() == 0)
{
return;
}
// Make sure downloader won't be released
std::weak_ptr<Downloader> ptr = shared_from_this();
// Test server download resuming support with the first unit
_supportResuming = false;
CURL *header = curl_easy_init();
// Make a resume request
curl_easy_setopt(header, CURLOPT_RESUME_FROM_LARGE, 0);
if (prepareHeader(header, units.begin()->second.srcUrl))
{
long responseCode;
curl_easy_getinfo(header, CURLINFO_RESPONSE_CODE, &responseCode);
if (responseCode == HTTP_CODE_SUPPORT_RESUME)
{
_supportResuming = true;
}
}
curl_easy_cleanup(header);
int count = 0;
DownloadUnits group;
for (auto it = units.cbegin(); it != units.cend(); ++it, ++count)
{
if (count == FOPEN_MAX)
{
groupBatchDownload(group);
group.clear();
count = 0;
}
const std::string &key = it->first;
const DownloadUnit &unit = it->second;
group.emplace(key, unit);
}
if (group.size() > 0)
{
groupBatchDownload(group);
}
Director::getInstance()->getScheduler()->performFunctionInCocosThread([ptr, batchId]{
if (!ptr.expired()) {
std::shared_ptr<Downloader> downloader = ptr.lock();
auto callback = downloader->getSuccessCallback();
if (callback != nullptr)
{
callback("", "", batchId);
}
}
});
_supportResuming = false;
}
void Downloader::groupBatchDownload(const DownloadUnits &units)
{
CURLM* multi_handle = curl_multi_init();
int still_running = 0;
for (auto it = units.cbegin(); it != units.cend(); ++it)
{
DownloadUnit unit = it->second;
std::string srcUrl = unit.srcUrl;
std::string storagePath = unit.storagePath;
std::string customId = unit.customId;
FileDescriptor *fDesc = new FileDescriptor();
ProgressData *data = new ProgressData();
prepareDownload(srcUrl, storagePath, customId, unit.resumeDownload, fDesc, data);
if (fDesc->fp != NULL)
{
CURL* curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, srcUrl.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fileWriteFunc);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fDesc->fp);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, batchDownloadProgressFunc);
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, data);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, true);
if (_connectionTimeout) curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, _connectionTimeout);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, LOW_SPEED_LIMIT);
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, LOW_SPEED_TIME);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true);
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, MAX_REDIRS);
// Resuming download support
if (_supportResuming && unit.resumeDownload)
{
// Check already downloaded size for current download unit
long size = _fileUtils->getFileSize(storagePath + TEMP_EXT);
if (size != -1)
{
curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, size);
}
}
fDesc->curl = curl;
CURLMcode code = curl_multi_add_handle(multi_handle, curl);
if (code != CURLM_OK)
{
// Avoid memory leak
fclose(fDesc->fp);
delete data;
delete fDesc;
std::string msg = StringUtils::format("Unable to add curl handler for %s: [curl error]%s", customId.c_str(), curl_multi_strerror(code));
this->notifyError(msg, code, customId);
}
else
{
// Add to list for tracking
_progDatas.push_back(data);
_files.push_back(fDesc);
}
}
}
// Query multi perform
CURLMcode curlm_code = CURLM_CALL_MULTI_PERFORM;
while(CURLM_CALL_MULTI_PERFORM == curlm_code) {
curlm_code = curl_multi_perform(multi_handle, &still_running);
}
if (curlm_code != CURLM_OK) {
std::string msg = StringUtils::format("Unable to continue the download process: [curl error]%s", curl_multi_strerror(curlm_code));
this->notifyError(msg, curlm_code);
}
else
{
bool failed = false;
while (still_running > 0 && !failed)
{
// set a suitable timeout to play around with
struct timeval select_tv;
long curl_timeo = -1;
select_tv.tv_sec = 1;
select_tv.tv_usec = 0;
curl_multi_timeout(multi_handle, &curl_timeo);
if(curl_timeo >= 0) {
select_tv.tv_sec = curl_timeo / 1000;
if(select_tv.tv_sec > 1)
select_tv.tv_sec = 1;
else
select_tv.tv_usec = (curl_timeo % 1000) * 1000;
}
int rc;
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
int maxfd = -1;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);
curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &select_tv);
switch(rc)
{
case -1:
failed = true;
break;
case 0:
default:
curlm_code = CURLM_CALL_MULTI_PERFORM;
while(CURLM_CALL_MULTI_PERFORM == curlm_code) {
curlm_code = curl_multi_perform(multi_handle, &still_running);
}
if (curlm_code != CURLM_OK) {
std::string msg = StringUtils::format("Unable to continue the download process: [curl error]%s", curl_multi_strerror(curlm_code));
this->notifyError(msg, curlm_code);
}
break;
}
}
}
// Clean up and close files
curl_multi_cleanup(multi_handle);
for (auto it = _files.begin(); it != _files.end(); ++it)
{
FILE *f = (*it)->fp;
fclose(f);
auto single = (*it)->curl;
curl_multi_remove_handle(multi_handle, single);
curl_easy_cleanup(single);
}
// Check unfinished files and notify errors, succeed files will be renamed from temporary file name to real name
for (auto it = _progDatas.begin(); it != _progDatas.end(); ++it) {
ProgressData *data = *it;
if (data->downloaded < data->totalToDownload || data->totalToDownload == 0)
{
this->notifyError(ErrorCode::NETWORK, "Unable to download file", data->customId);
}
else
{
_fileUtils->renameFile(data->path, data->name + TEMP_EXT, data->name);
}
}
clearBatchDownloadData();
}
NS_CC_EXT_END

View File

@ -0,0 +1,196 @@
/****************************************************************************
Copyright (c) 2013 cocos2d-x.org
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#ifndef __Downloader__
#define __Downloader__
#include "platform/CCFileUtils.h"
#include "extensions/ExtensionMacros.h"
#include "extensions/ExtensionExport.h"
#include <unordered_map>
#include <string>
#include <functional>
#include <memory>
NS_CC_EXT_BEGIN
class CC_EX_DLL Downloader : public std::enable_shared_from_this<Downloader>
{
public:
friend class AssetsManagerEx;
enum class ErrorCode
{
CREATE_FILE,
NETWORK,
NO_NEW_VERSION,
UNCOMPRESS,
CURL_UNINIT,
CURL_MULTI_ERROR,
CURL_EASY_ERROR,
INVALID_URL,
INVALID_STORAGE_PATH
};
struct Error
{
ErrorCode code;
int curlm_code;
int curle_code;
std::string message;
std::string customId;
std::string url;
};
struct ProgressData
{
std::weak_ptr<Downloader> downloader;
std::string customId;
std::string url;
std::string path;
std::string name;
double downloaded;
double totalToDownload;
};
struct DownloadUnit
{
std::string srcUrl;
std::string storagePath;
std::string customId;
bool resumeDownload;
};
struct StreamData
{
long offset;
long total;
unsigned char *buffer;
};
typedef std::unordered_map<std::string, DownloadUnit> DownloadUnits;
typedef std::function<void(const Downloader::Error &)> ErrorCallback;
typedef std::function<void(double, double, const std::string &, const std::string &)> ProgressCallback;
typedef std::function<void(const std::string &, const std::string &, const std::string &)> SuccessCallback;
int getConnectionTimeout();
void setConnectionTimeout(int timeout);
void setErrorCallback(const ErrorCallback &callback) { _onError = callback; };
void setProgressCallback(const ProgressCallback &callback) { _onProgress = callback; };
void setSuccessCallback(const SuccessCallback &callback) { _onSuccess = callback; };
ErrorCallback getErrorCallback() const { return _onError; };
ProgressCallback getProgressCallback() const { return _onProgress; };
SuccessCallback getSuccessCallback() const { return _onSuccess; };
long getContentSize(const std::string &srcUrl) const;
void downloadToBufferAsync(const std::string &srcUrl, unsigned char *buffer, const long &size, const std::string &customId = "");
void downloadToBufferSync(const std::string &srcUrl, unsigned char *buffer, const long &size, const std::string &customId = "");
void downloadAsync(const std::string &srcUrl, const std::string &storagePath, const std::string &customId = "");
void downloadSync(const std::string &srcUrl, const std::string &storagePath, const std::string &customId = "");
void batchDownloadAsync(const DownloadUnits &units, const std::string &batchId = "");
void batchDownloadSync(const DownloadUnits &units, const std::string &batchId = "");
/**
* The default constructor.
*/
Downloader();
~Downloader();
protected:
struct FileDescriptor
{
FILE *fp;
void *curl;
};
void prepareDownload(const std::string &srcUrl, const std::string &storagePath, const std::string &customId, bool resumeDownload, FileDescriptor *fDesc, ProgressData *pData);
bool prepareHeader(void *curl, const std::string &srcUrl) const;
void downloadToBuffer(const std::string &srcUrl, const std::string &customId, const StreamData &buffer, const ProgressData &data);
void download(const std::string &srcUrl, const std::string &customId, const FileDescriptor &fDesc, const ProgressData &data);
void groupBatchDownload(const DownloadUnits &units);
void notifyError(ErrorCode code, const std::string &msg = "", const std::string &customId = "", int curle_code = 0, int curlm_code = 0);
void notifyError(const std::string &msg, int curlm_code, const std::string &customId = "");
void notifyError(const std::string &msg, const std::string &customId, int curle_code);
private:
int _connectionTimeout;
ErrorCallback _onError;
ProgressCallback _onProgress;
SuccessCallback _onSuccess;
std::string getFileNameFromUrl(const std::string &srcUrl);
void clearBatchDownloadData();
std::vector<FileDescriptor *> _files;
std::vector<ProgressData *> _progDatas;
FileUtils *_fileUtils;
bool _supportResuming;
};
int downloadProgressFunc(Downloader::ProgressData *ptr, double totalToDownload, double nowDownloaded, double totalToUpLoad, double nowUpLoaded);
NS_CC_EXT_END
#endif /* defined(__Downloader__) */

View File

@ -0,0 +1,481 @@
/****************************************************************************
Copyright (c) 2014 cocos2d-x.org
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "Manifest.h"
#include "json/filestream.h"
#include "json/prettywriter.h"
#include "json/stringbuffer.h"
#include <fstream>
#define KEY_VERSION "version"
#define KEY_PACKAGE_URL "packageUrl"
#define KEY_MANIFEST_URL "remoteManifestUrl"
#define KEY_VERSION_URL "remoteVersionUrl"
#define KEY_GROUP_VERSIONS "groupVersions"
#define KEY_ENGINE_VERSION "engineVersion"
#define KEY_ASSETS "assets"
#define KEY_COMPRESSED_FILES "compressedFiles"
#define KEY_SEARCH_PATHS "searchPaths"
#define KEY_PATH "path"
#define KEY_MD5 "md5"
#define KEY_GROUP "group"
#define KEY_COMPRESSED "compressed"
#define KEY_COMPRESSED_FILE "compressedFile"
#define KEY_DOWNLOAD_STATE "downloadState"
NS_CC_EXT_BEGIN
Manifest::Manifest(const std::string& manifestUrl/* = ""*/)
: _versionLoaded(false)
, _loaded(false)
, _manifestRoot("")
, _remoteManifestUrl("")
, _remoteVersionUrl("")
, _version("")
, _engineVer("")
{
// Init variables
_fileUtils = FileUtils::getInstance();
if (manifestUrl.size() > 0)
parse(manifestUrl);
}
void Manifest::parse(const std::string& manifestUrl)
{
clear();
std::string content;
if (_fileUtils->isFileExist(manifestUrl))
{
// Load file content
content = _fileUtils->getStringFromFile(manifestUrl);
if (content.size() == 0)
{
CCLOG("Fail to retrieve local file content: %s\n", manifestUrl.c_str());
}
else
{
// Parse file with rapid json
_json.Parse<0>(content.c_str());
// Print error
if (_json.HasParseError()) {
size_t offset = _json.GetErrorOffset();
if (offset > 0)
offset--;
std::string errorSnippet = content.substr(offset, 10);
CCLOG("File parse error %s at <%s>\n", _json.GetParseError(), errorSnippet.c_str());
}
}
}
if (_json.IsObject())
{
// Register the local manifest root
size_t found = manifestUrl.find_last_of("/\\");
if (found != std::string::npos)
{
_manifestRoot = manifestUrl.substr(0, found+1);
}
loadManifest(_json);
}
}
bool Manifest::isVersionLoaded() const
{
return _versionLoaded;
}
bool Manifest::isLoaded() const
{
return _loaded;
}
bool Manifest::versionEquals(const Manifest *b) const
{
// Check manifest version
if (_version != b->getVersion())
{
return false;
}
// Check group versions
else
{
std::vector<std::string> bGroups = b->getGroups();
std::unordered_map<std::string, std::string> bGroupVer = b->getGroupVerions();
// Check group size
if (bGroups.size() != _groups.size())
return false;
// Check groups version
for (int i = 0; i < _groups.size(); ++i) {
std::string gid =_groups[i];
// Check group name
if (gid != bGroups[i])
return false;
// Check group version
if (_groupVer.at(gid) != bGroupVer.at(gid))
return false;
}
}
return true;
}
std::unordered_map<std::string, Manifest::AssetDiff> Manifest::genDiff(const Manifest *b) const
{
std::unordered_map<std::string, AssetDiff> diff_map;
std::unordered_map<std::string, Asset> bAssets = b->getAssets();
std::string key;
Asset valueA;
Asset valueB;
std::unordered_map<std::string, Asset>::const_iterator valueIt, it;
for (it = _assets.begin(); it != _assets.end(); ++it)
{
key = it->first;
valueA = it->second;
// Deleted
valueIt = bAssets.find(key);
if (valueIt == bAssets.cend()) {
AssetDiff diff;
diff.asset = valueA;
diff.type = DiffType::DELETED;
diff_map.emplace(key, diff);
continue;
}
// Modified
valueB = valueIt->second;
if (valueA.md5 != valueB.md5) {
AssetDiff diff;
diff.asset = valueB;
diff.type = DiffType::MODIFIED;
diff_map.emplace(key, diff);
}
}
for (it = bAssets.begin(); it != bAssets.end(); ++it)
{
key = it->first;
valueB = it->second;
// Added
valueIt = _assets.find(key);
if (valueIt == _assets.cend()) {
AssetDiff diff;
diff.asset = valueB;
diff.type = DiffType::ADDED;
diff_map.emplace(key, diff);
}
}
return diff_map;
}
void Manifest::genResumeAssetsList(Downloader::DownloadUnits *units) const
{
for (auto it = _assets.begin(); it != _assets.end(); ++it)
{
Asset asset = it->second;
if (asset.downloadState != DownloadState::SUCCESSED)
{
Downloader::DownloadUnit unit;
unit.customId = it->first;
unit.srcUrl = _packageUrl + asset.path;
unit.storagePath = _manifestRoot + asset.path;
if (asset.downloadState == DownloadState::DOWNLOADING)
{
unit.resumeDownload = true;
}
else
{
unit.resumeDownload = false;
}
units->emplace(unit.customId, unit);
}
}
}
void Manifest::prependSearchPaths()
{
std::vector<std::string> searchPaths = FileUtils::getInstance()->getSearchPaths();
std::vector<std::string>::iterator iter = searchPaths.begin();
searchPaths.insert(iter, _manifestRoot);
for (int i = (int)_searchPaths.size()-1; i >= 0; i--)
{
std::string path = _searchPaths[i];
if (path.size() > 0 && path[path.size() - 1] != '/')
path.append("/");
path = _manifestRoot + path;
iter = searchPaths.begin();
searchPaths.insert(iter, path);
}
FileUtils::getInstance()->setSearchPaths(searchPaths);
}
const std::string& Manifest::getPackageUrl() const
{
return _packageUrl;
}
const std::string& Manifest::getManifestFileUrl() const
{
return _remoteManifestUrl;
}
const std::string& Manifest::getVersionFileUrl() const
{
return _remoteVersionUrl;
}
const std::string& Manifest::getVersion() const
{
return _version;
}
const std::vector<std::string>& Manifest::getGroups() const
{
return _groups;
}
const std::unordered_map<std::string, std::string>& Manifest::getGroupVerions() const
{
return _groupVer;
}
const std::string& Manifest::getGroupVersion(const std::string &group) const
{
return _groupVer.at(group);
}
const std::unordered_map<std::string, Manifest::Asset>& Manifest::getAssets() const
{
return _assets;
}
void Manifest::setAssetDownloadState(const std::string &key, const Manifest::DownloadState &state)
{
auto valueIt = _assets.find(key);
if (valueIt != _assets.end())
{
valueIt->second.downloadState = state;
// Update json object
if(_json.IsObject())
{
if ( _json.HasMember(KEY_ASSETS) )
{
rapidjson::Value &assets = _json[KEY_ASSETS];
if (assets.IsObject())
{
for (rapidjson::Value::MemberIterator itr = assets.MemberonBegin(); itr != assets.MemberonEnd(); ++itr)
{
std::string jkey = itr->name.GetString();
if (jkey == key) {
rapidjson::Value &entry = itr->value;
rapidjson::Value &value = entry[KEY_DOWNLOAD_STATE];
if (value.IsInt())
{
value.SetInt((int)state);
}
else
{
entry.AddMember<int>(KEY_DOWNLOAD_STATE, (int)state, _json.GetAllocator());
}
}
}
}
}
}
}
}
void Manifest::clear()
{
if (_versionLoaded || _loaded)
{
_groups.clear();
_groupVer.clear();
_remoteManifestUrl = "";
_remoteVersionUrl = "";
_version = "";
_engineVer = "";
_versionLoaded = false;
}
if (_loaded)
{
_assets.clear();
_searchPaths.clear();
_loaded = false;
}
}
Manifest::Asset Manifest::parseAsset(const std::string &path, const rapidjson::Value &json)
{
Asset asset;
asset.path = path;
if ( json.HasMember(KEY_MD5) && json[KEY_MD5].IsString() )
{
asset.md5 = json[KEY_MD5].GetString();
}
else asset.md5 = "";
if ( json.HasMember(KEY_PATH) && json[KEY_PATH].IsString() )
{
asset.path = json[KEY_PATH].GetString();
}
if ( json.HasMember(KEY_COMPRESSED) && json[KEY_COMPRESSED].IsBool() )
{
asset.compressed = json[KEY_COMPRESSED].GetBool();
}
else asset.compressed = false;
if ( json.HasMember(KEY_DOWNLOAD_STATE) && json[KEY_DOWNLOAD_STATE].IsInt() )
{
asset.downloadState = (DownloadState)(json[KEY_DOWNLOAD_STATE].GetInt());
}
else asset.downloadState = DownloadState::UNSTARTED;
return asset;
}
void Manifest::loadVersion(const rapidjson::Document &json)
{
// Retrieve remote manifest url
if ( json.HasMember(KEY_MANIFEST_URL) && json[KEY_MANIFEST_URL].IsString() )
{
_remoteManifestUrl = json[KEY_MANIFEST_URL].GetString();
}
// Retrieve remote version url
if ( json.HasMember(KEY_VERSION_URL) && json[KEY_VERSION_URL].IsString() )
{
_remoteVersionUrl = json[KEY_VERSION_URL].GetString();
}
// Retrieve local version
if ( json.HasMember(KEY_VERSION) && json[KEY_VERSION].IsString() )
{
_version = json[KEY_VERSION].GetString();
}
// Retrieve local group version
if ( json.HasMember(KEY_GROUP_VERSIONS) )
{
const rapidjson::Value& groupVers = json[KEY_GROUP_VERSIONS];
if (groupVers.IsObject())
{
for (rapidjson::Value::ConstMemberIterator itr = groupVers.MemberonBegin(); itr != groupVers.MemberonEnd(); ++itr)
{
std::string group = itr->name.GetString();
std::string version = "0";
if (itr->value.IsString())
{
version = itr->value.GetString();
}
_groups.push_back(group);
_groupVer.emplace(group, version);
}
}
}
// Retrieve local engine version
if ( json.HasMember(KEY_ENGINE_VERSION) && json[KEY_ENGINE_VERSION].IsString() )
{
_engineVer = json[KEY_ENGINE_VERSION].GetString();
}
_versionLoaded = true;
}
void Manifest::loadManifest(const rapidjson::Document &json)
{
loadVersion(json);
// Retrieve package url
if ( json.HasMember(KEY_PACKAGE_URL) && json[KEY_PACKAGE_URL].IsString() )
{
_packageUrl = json[KEY_PACKAGE_URL].GetString();
// Append automatically "/"
if (_packageUrl.size() > 0 && _packageUrl[_packageUrl.size() - 1] != '/')
{
_packageUrl.append("/");
}
}
// Retrieve all assets
if ( json.HasMember(KEY_ASSETS) )
{
const rapidjson::Value& assets = json[KEY_ASSETS];
if (assets.IsObject())
{
for (rapidjson::Value::ConstMemberIterator itr = assets.MemberonBegin(); itr != assets.MemberonEnd(); ++itr)
{
std::string key = itr->name.GetString();
Asset asset = parseAsset(key, itr->value);
_assets.emplace(key, asset);
}
}
}
// Retrieve all search paths
if ( json.HasMember(KEY_SEARCH_PATHS) )
{
const rapidjson::Value& paths = json[KEY_SEARCH_PATHS];
if (paths.IsArray())
{
for (rapidjson::SizeType i = 0; i < paths.Size(); ++i)
{
if (paths[i].IsString()) {
_searchPaths.push_back(paths[i].GetString());
}
}
}
}
_loaded = true;
}
void Manifest::saveToFile(const std::string &filepath)
{
rapidjson::StringBuffer buffer;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
_json.Accept(writer);
std::ofstream output(filepath, std::ofstream::out);
if(!output.bad())
output << buffer.GetString() << std::endl;
}
NS_CC_EXT_END

View File

@ -0,0 +1,207 @@
/****************************************************************************
Copyright (c) 2013 cocos2d-x.org
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#ifndef __Manifest__
#define __Manifest__
#include "extensions/ExtensionMacros.h"
#include "extensions/ExtensionExport.h"
#include "Downloader.h"
#include <string>
#include <unordered_map>
#include <vector>
#include "json/document.h"
NS_CC_EXT_BEGIN
class CC_EX_DLL Manifest : public Ref
{
public:
friend class AssetsManagerEx;
//! The type of difference
enum class DiffType {
ADDED,
DELETED,
MODIFIED
};
enum class DownloadState {
UNSTARTED,
DOWNLOADING,
SUCCESSED
};
//! Asset object
struct Asset {
std::string md5;
std::string path;
bool compressed;
DownloadState downloadState;
};
//! Object indicate the difference between two Assets
struct AssetDiff {
Asset asset;
DiffType type;
};
/** @brief Check whether the version informations have been fully loaded
*/
bool isVersionLoaded() const;
/** @brief Check whether the manifest have been fully loaded
*/
bool isLoaded() const;
/** @brief Gets remote package url.
*/
const std::string& getPackageUrl() const;
/** @brief Gets remote manifest file url.
*/
const std::string& getManifestFileUrl() const;
/** @brief Gets remote version file url.
*/
const std::string& getVersionFileUrl() const;
/** @brief Gets manifest version.
*/
const std::string& getVersion() const;
protected:
/** @brief Constructor for Manifest class
@param manifestUrl Url of the local manifest
*/
Manifest(const std::string& manifestUrl = "");
/** @brief Parse the manifest file information into this manifest
* @param manifestUrl Url of the local manifest
*/
void parse(const std::string& manifestUrl);
/** @brief Check whether the version of this manifest equals to another.
* @param b The other manifest
*/
bool versionEquals(const Manifest *b) const;
/** @brief Generate difference between this Manifest and another.
* @param b The other manifest
*/
std::unordered_map<std::string, AssetDiff> genDiff(const Manifest *b) const;
/** @brief Generate resuming download assets list
* @param units The download units reference to be modified by the generation result
*/
void genResumeAssetsList(Downloader::DownloadUnits *units) const;
/** @brief Prepend all search paths to the FileUtils.
*/
void prependSearchPaths();
void loadVersion(const rapidjson::Document &json);
void loadManifest(const rapidjson::Document &json);
void saveToFile(const std::string &filepath);
Asset parseAsset(const std::string &path, const rapidjson::Value &json);
void clear();
/** @brief Gets all groups.
*/
const std::vector<std::string>& getGroups() const;
/** @brief Gets all groups version.
*/
const std::unordered_map<std::string, std::string>& getGroupVerions() const;
/** @brief Gets version for the given group.
* @param group Key of the requested group
*/
const std::string& getGroupVersion(const std::string &group) const;
/** @brief Gets assets.
*/
const std::unordered_map<std::string, Asset>& getAssets() const;
/** @brief Set the download state for an asset
* @param key Key of the asset to set
* @param state The current download state of the asset
*/
void setAssetDownloadState(const std::string &key, const DownloadState &state);
private:
//! Indicate whether the version informations have been fully loaded
bool _versionLoaded;
//! Indicate whether the manifest have been fully loaded
bool _loaded;
//! Reference to the global file utils
FileUtils *_fileUtils;
//! The local manifest root
std::string _manifestRoot;
//! The remote package url
std::string _packageUrl;
//! The remote path of manifest file
std::string _remoteManifestUrl;
//! The remote path of version file [Optional]
std::string _remoteVersionUrl;
//! The version of local manifest
std::string _version;
//! All groups exist in manifest [Optional]
std::vector<std::string> _groups;
//! The versions of all local group [Optional]
std::unordered_map<std::string, std::string> _groupVer;
//! The version of local engine
std::string _engineVer;
//! Full assets list
std::unordered_map<std::string, Asset> _assets;
//! All search paths
std::vector<std::string> _searchPaths;
rapidjson::Document _json;
};
NS_CC_EXT_END
#endif /* defined(__Manifest__) */

View File

@ -13,6 +13,10 @@
#include "physics-nodes/CCPhysicsSprite.h"
#include "assets-manager/AssetsManager.h"
#include "assets-manager/AssetsManagerEx.h"
#include "assets-manager/CCEventAssetsManagerEx.h"
#include "assets-manager/CCEventListenerAssetsManagerEx.h"
#include "assets-manager/Manifest.h"
#include "ExtensionDeprecated.h"
#endif /* __COCOS2D_EXT_H__ */

View File

@ -1171,6 +1171,14 @@
"extensions/GUI/CCScrollView/CCTableViewCell.h",
"extensions/assets-manager/AssetsManager.cpp",
"extensions/assets-manager/AssetsManager.h",
"extensions/assets-manager/CCEventAssetsManager.cpp",
"extensions/assets-manager/CCEventAssetsManager.h",
"extensions/assets-manager/CCEventListenerAssetsManager.cpp",
"extensions/assets-manager/CCEventListenerAssetsManager.h",
"extensions/assets-manager/Downloader.cpp",
"extensions/assets-manager/Downloader.h",
"extensions/assets-manager/Manifest.cpp",
"extensions/assets-manager/Manifest.h",
"extensions/cocos-ext.h",
"extensions/physics-nodes/CCPhysicsDebugNode.cpp",
"extensions/physics-nodes/CCPhysicsDebugNode.h",

View File

@ -49,6 +49,7 @@ set(TESTS_SRC
Classes/DrawPrimitivesTest/DrawPrimitivesTest.cpp
Classes/EffectsAdvancedTest/EffectsAdvancedTest.cpp
Classes/EffectsTest/EffectsTest.cpp
Classes/ExtensionsTest/AssetsManagerExTest/AssetsManagerExTest.cpp
Classes/ExtensionsTest/CocosBuilderTest/ButtonTest/ButtonTestLayer.cpp
Classes/ExtensionsTest/CocosBuilderTest/CocosBuilderTest.cpp
Classes/ExtensionsTest/CocosBuilderTest/HelloCocosBuilder/HelloCocosBuilderLayer.cpp

View File

@ -96,6 +96,7 @@ bool AppDelegate::applicationDidFinishLaunching()
searchPaths.push_back("ccs-res/hd/scenetest/UIComponentTest");
searchPaths.push_back("ccs-res/hd/scenetest/TriggerTest");
searchPaths.push_back("ccs-res");
searchPaths.push_back("Manifests");
director->setContentScaleFactor(resourceSize.height/designSize.height);
}
else

View File

@ -0,0 +1,212 @@
#include "AssetsManagerExTest.h"
#include "../../testResource.h"
#include "cocos2d.h"
const char* sceneManifests[] = {"AMTestScene1/project.manifest", "AMTestScene2/project.manifest", "AMTestScene3/project.manifest"};
const char* storagePaths[] = {"CppTests/AssetsManagerExTest/scene1/", "CppTests/AssetsManagerExTest/scene2/", "CppTests/AssetsManagerExTest/scene3"};
const char* backgroundPaths[] = {"Images/background1.jpg", "Images/background2.jpg", "Images/background3.png"};
AssetsManagerExTestLayer::AssetsManagerExTestLayer(const std::string& spritePath)
: _spritePath(spritePath)
{
}
AssetsManagerExTestLayer::~AssetsManagerExTestLayer(void)
{
}
std::string AssetsManagerExTestLayer::title() const
{
return "AssetsManagerExTest";
}
void AssetsManagerExTestLayer::onEnter()
{
BaseTest::onEnter();
_background = Sprite::create(_spritePath);
if (_background)
{
addChild(_background, 1);
_background->setPosition( VisibleRect::center() );
}
}
void AssetsManagerExTestLayer::restartCallback(Ref* sender)
{
}
void AssetsManagerExTestLayer::nextCallback(Ref* sender)
{
if (AssetsManagerExLoaderScene::currentScene < 2)
{
AssetsManagerExLoaderScene::currentScene++;
}
else
{
AssetsManagerExLoaderScene::currentScene = 0;
}
auto scene = new AssetsManagerExLoaderScene();
scene->runThisTest();
scene->release();
}
void AssetsManagerExTestLayer::backCallback(Ref* sender)
{
if (AssetsManagerExLoaderScene::currentScene > 0)
{
AssetsManagerExLoaderScene::currentScene--;
}
else AssetsManagerExLoaderScene::currentScene = 2;
auto scene = new AssetsManagerExLoaderScene();
scene->runThisTest();
scene->release();
}
AssetsManagerExTestScene::AssetsManagerExTestScene(std::string background)
{
auto layer = new AssetsManagerExTestLayer(background);
addChild(layer);
layer->release();
}
void AssetsManagerExTestScene::runThisTest()
{
}
int AssetsManagerExLoaderScene::currentScene = 0;
AssetsManagerExLoaderScene::AssetsManagerExLoaderScene()
: _progress(nullptr)
, _amListener(nullptr)
{
}
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);
_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);
}
}
void AssetsManagerExLoaderScene::onExit()
{
_eventDispatcher->removeEventListener(_amListener);
_am->release();
Scene::onExit();
}

View File

@ -0,0 +1,53 @@
#ifndef __AssetsManagerEx_Test_H__
#define __AssetsManagerEx_Test_H__
#include "extensions/cocos-ext.h"
#include "../../testBasic.h"
#include "../../BaseTest.h"
USING_NS_CC;
USING_NS_CC_EXT;
class AssetsManagerExTestLayer : public BaseTest
{
public:
AssetsManagerExTestLayer(const std::string& spritePath);
~AssetsManagerExTestLayer(void);
virtual std::string title() const;
void onEnter();
virtual void restartCallback(Ref* sender);
virtual void nextCallback(Ref* sender);
virtual void backCallback(Ref* sender);
private:
Sprite *_background;
std::string _spritePath;
};
class AssetsManagerExTestScene : public TestScene
{
public:
AssetsManagerExTestScene(std::string background);
virtual void runThisTest() override;
};
class AssetsManagerExLoaderScene : public TestScene
{
public:
AssetsManagerExLoaderScene();
virtual void runThisTest() override;
virtual void onExit() override;
static int currentScene;
private:
AssetsManagerEx *_am;
Label *_progress;
EventListenerAssetsManagerEx* _amListener;
};
#endif /* defined(__AssetsManagerEx_Test_H__) */

View File

@ -1,5 +1,6 @@
#include "ExtensionsTest.h"
#include "../testResource.h"
#include "AssetsManagerExTest/AssetsManagerExTest.h"
#include "NotificationCenterTest/NotificationCenterTest.h"
#include "ControlExtensionTest/CCControlSceneManager.h"
#include "CocosBuilderTest/CocosBuilderTest.h"
@ -29,6 +30,10 @@ static struct {
const char *name;
std::function<void(Ref* sender)> callback;
} g_extensionsTests[] = {
{ "AssetsManagerExTest", [](Ref* sender) {
AssetsManagerExLoaderScene *scene = new AssetsManagerExLoaderScene();
scene->runThisTest();
} },
{ "NotificationCenterTest", [](Ref* sender) { runNotificationCenterTest(); }
},
{ "CCControlButtonTest", [](Ref *sender){

View File

@ -0,0 +1,16 @@
{
"packageUrl" : "http://tools.itharbors.com/assets_manager/AMTestScene1/",
"remoteManifestUrl" : "http://tools.itharbors.com/assets_manager/AMTestScene1/project.manifest",
"remoteVersionUrl" : "http://tools.itharbors.com/assets_manager/AMTestScene1/version.manifest",
"version" : "1.0.0",
"engineVersion" : "3.0 beta",
"assets" : {
"Images/background1.jpg" : {
"md5" : "..."
}
},
"searchPaths" : [
]
}

View File

@ -0,0 +1,15 @@
{
"packageUrl" : "http://tools.itharbors.com/assets_manager/AMTestScene2/",
"remoteManifestUrl" : "http://tools.itharbors.com/assets_manager/AMTestScene2/project.manifest",
"version" : "1.0.0",
"engineVersion" : "3.0 beta",
"assets" : {
"Images/background2.jpg" : {
"md5" : "..."
}
},
"searchPaths" : [
]
}

View File

@ -0,0 +1,16 @@
{
"packageUrl" : "http://tools.itharbors.com/assets_manager/AMTestScene3/",
"remoteManifestUrl" : "http://tools.itharbors.com/assets_manager/AMTestScene3/project.manifest",
"remoteVersionUrl" : "http://tools.itharbors.com/assets_manager/AMTestScene3/version.manifest",
"version" : "1.0.0",
"engineVersion" : "3.0 beta",
"assets" : {
"Images/background3.png" : {
"md5" : "..."
}
},
"searchPaths" : [
]
}

View File

@ -49,6 +49,7 @@ LOCAL_SRC_FILES := main.cpp \
../../Classes/EffectsAdvancedTest/EffectsAdvancedTest.cpp \
../../Classes/EffectsTest/EffectsTest.cpp \
../../Classes/ExtensionsTest/ExtensionsTest.cpp \
../../Classes/ExtensionsTest/AssetsManagerExTest/AssetsManagerExTest.cpp \
../../Classes/ExtensionsTest/CocosBuilderTest/CocosBuilderTest.cpp \
../../Classes/ExtensionsTest/CocosBuilderTest/AnimationsTest/AnimationsTestLayer.cpp \
../../Classes/ExtensionsTest/CocosBuilderTest/ButtonTest/ButtonTestLayer.cpp \

View File

@ -145,6 +145,7 @@
<ClCompile Include="..\Classes\ConfigurationTest\ConfigurationTest.cpp" />
<ClCompile Include="..\Classes\ConsoleTest\ConsoleTest.cpp" />
<ClCompile Include="..\Classes\DataVisitorTest\DataVisitorTest.cpp" />
<ClCompile Include="..\Classes\ExtensionsTest\AssetsManagerExTest\AssetsManagerExTest.cpp" />
<ClCompile Include="..\Classes\ExtensionsTest\CocosBuilderTest\AnimationsTest\AnimationsTestLayer.cpp" />
<ClCompile Include="..\Classes\ExtensionsTest\CocosBuilderTest\TimelineCallbackTest\TimelineCallbackTestLayer.cpp" />
<ClCompile Include="..\Classes\ExtensionsTest\CocoStudioActionTimelineTest\ActionTimelineTestScene.cpp" />
@ -334,6 +335,7 @@
<ClInclude Include="..\Classes\ConfigurationTest\ConfigurationTest.h" />
<ClInclude Include="..\Classes\ConsoleTest\ConsoleTest.h" />
<ClInclude Include="..\Classes\DataVisitorTest\DataVisitorTest.h" />
<ClInclude Include="..\Classes\ExtensionsTest\AssetsManagerExTest\AssetsManagerExTest.h" />
<ClInclude Include="..\Classes\ExtensionsTest\CocosBuilderTest\AnimationsTest\AnimationsLayerLoader.h" />
<ClInclude Include="..\Classes\ExtensionsTest\CocosBuilderTest\AnimationsTest\AnimationsTestLayer.h" />
<ClInclude Include="..\Classes\ExtensionsTest\CocosBuilderTest\TimelineCallbackTest\TimelineCallbackLayerLoader.h" />

View File

@ -331,6 +331,9 @@
<Filter Include="Classes\BillBoardTest">
<UniqueIdentifier>{54a30b92-ddfb-420e-908b-886c23c21cf1}</UniqueIdentifier>
</Filter>
<Filter Include="Classes\ExtensionsTest\AssetsManagerExTest">
<UniqueIdentifier>{f6c2eb6d-ad25-4287-a2a4-1c0d7382a49f}</UniqueIdentifier>
</Filter>
<Filter Include="Classes\UITest\CocostudioGUISceneTest\UIWebViewTest">
<UniqueIdentifier>{a0b90b93-5575-4729-9afc-8a3839b378ac}</UniqueIdentifier>
</Filter>
@ -876,6 +879,9 @@
<ClCompile Include="..\Classes\BillBoardTest\BillBoardTest.cpp">
<Filter>Classes\BillBoardTest</Filter>
</ClCompile>
<ClCompile Include="..\Classes\ExtensionsTest\AssetsManagerExTest\AssetsManagerExTest.cpp">
<Filter>Classes\ExtensionsTest\AssetsManagerExTest</Filter>
</ClCompile>
<ClCompile Include="..\Classes\LightTest\LightTest.cpp">
<Filter>Classes\LightTest</Filter>
</ClCompile>
@ -1622,6 +1628,9 @@
<ClInclude Include="..\Classes\BillBoardTest\BillBoardTest.h">
<Filter>Classes\BillBoardTest</Filter>
</ClInclude>
<ClInclude Include="..\Classes\ExtensionsTest\AssetsManagerExTest\AssetsManagerExTest.h">
<Filter>Classes\ExtensionsTest\AssetsManagerExTest</Filter>
</ClInclude>
<ClInclude Include="..\Classes\LightTest\LightTest.h">
<Filter>Classes\LightTest</Filter>
</ClInclude>

View File

@ -1,17 +0,0 @@
#ifndef COCOS2DX_COCOS_SCRIPTING_LUA_BINDINGS_LUA_ASSETSMANAGER_TEST_SAMPLE_H
#define COCOS2DX_COCOS_SCRIPTING_LUA_BINDINGS_LUA_ASSETSMANAGER_TEST_SAMPLE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "tolua++.h"
#ifdef __cplusplus
}
#endif
/**
* The apis which are bound in this file are temporary for the assetsmanager test sample.After the completion of some systems like fileutils,these apis will be deprecated
*/
TOLUA_API int register_assetsmanager_test_sample(lua_State* tolua_S);
#endif // #ifndef COCOS2DX_COCOS_SCRIPTING_LUA_BINDINGS_LUA_ASSETSMANAGER_TEST_SAMPLE_H

View File

@ -1,4 +1,4 @@
#include "lua_assetsmanager_test_sample.h"
#include "lua_assetsmanagerex_test_sample.h"
#ifdef __cplusplus
extern "C" {
@ -141,7 +141,7 @@ tolua_lerror:
#endif
}
int register_assetsmanager_test_sample(lua_State* L)
int register_assetsmanagerex_test_sample(lua_State* L)
{
tolua_open(L);
tolua_module(L, NULL, 0);

View File

@ -0,0 +1,17 @@
#ifndef COCOS2DX_COCOS_SCRIPTING_LUA_BINDINGS_LUA_ASSETSMANAGEREX_TEST_SAMPLE_H
#define COCOS2DX_COCOS_SCRIPTING_LUA_BINDINGS_LUA_ASSETSMANAGEREX_TEST_SAMPLE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "tolua++.h"
#ifdef __cplusplus
}
#endif
/**
* The apis which are bound in this file are temporary for the assetsmanagerex test sample.After the completion of some systems like fileutils,these apis will be deprecated
*/
TOLUA_API int register_assetsmanagerex_test_sample(lua_State* tolua_S);
#endif // #ifndef COCOS2DX_COCOS_SCRIPTING_LUA_BINDINGS_LUA_ASSETSMANAGEREX_TEST_SAMPLE_H

View File

@ -15,7 +15,7 @@
<ClInclude Include="main.h">
<Filter>win32</Filter>
</ClInclude>
<ClInclude Include="..\Classes\lua_assetsmanager_test_sample.h">
<ClInclude Include="..\Classes\lua_assetsmanagerex_test_sample.h">
<Filter>Classes</Filter>
</ClInclude>
<ClInclude Include="..\Classes\lua_module_register.h">
@ -32,7 +32,7 @@
<ClCompile Include="main.cpp">
<Filter>win32</Filter>
</ClCompile>
<ClCompile Include="..\Classes\lua_assetsmanager_test_sample.cpp">
<ClCompile Include="..\Classes\lua_assetsmanagerex_test_sample.cpp">
<Filter>Classes</Filter>
</ClCompile>
<ClCompile Include="..\Classes\lua_test_bindings.cpp">

View File

@ -0,0 +1,336 @@
local targetPlatform = cc.Application:getInstance():getTargetPlatform()
local sceneID =
{
"AMTestScene1",
"AMTestScene2",
"AMTestScene3",
}
local sceneManifests =
{
"Manifests/AMTestScene1/project.manifest",
"Manifests/AMTestScene2/project.manifest",
"Manifests/AMTestScene3/project.manifest"
}
--UNCHECK
local storagePaths =
{
"LuaTests/AssetsManagerExTest/scene1",
"LuaTests/AssetsManagerExTest/scene2",
"LuaTests/AssetsManagerExTest/scene3",
}
local backgroundPaths =
{
"Images/background1.jpg",
"Images/background2.jpg",
"Images/background3.png"
}
-------------------------------------
-- AssetsManagerEx1 Test
-------------------------------------
local AMTestScene1 = {}
AMTestScene1.__index = AMTestScene1
function AMTestScene1.create()
local layer = cc.Layer:create()
local am = nil
local function onEnter()
Helper.initWithLayer(layer)
Helper.titleLabel:setString("AssetsManagerExTest1")
local sprite = cc.Sprite:create("Images/Icon.png")
layer:addChild(sprite)
sprite:setPosition(cc.p(VisibleRect:center().x, VisibleRect:center().y))
local ttfConfig = {}
ttfConfig.fontFilePath = "fonts/arial.ttf"
ttfConfig.fontSize = 40
local progress = cc.Label:createWithTTF(ttfConfig, "0%", cc.VERTICAL_TEXT_ALIGNMENT_CENTER)
progress:setPosition(cc.p(VisibleRect:center().x, VisibleRect:center().y + 50))
layer:addChild(progress)
am = cc.AssetsManagerEx:create("Manifests/AMTestScene1/project.manifest", "LuaTests/AssetsManagerExTest/scene1")
am:retain()
if not am:getLocalManifest():isLoaded() then
print("Fail to update assets, step skipped.")
local background = cc.Sprite:create("Images/background1.jpg")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
else
local function onUpdateEvent(event)
local eventCode = event:getEventCode()
if eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_NO_LOCAL_MANIFEST then
print("No local manifest file found, skip assets update.")
local background = cc.Sprite:create("Images/background1.jpg")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
elseif eventCode == cc.EventAssetsManagerEx.EventCode.UPDATE_PROGRESSION then
local assetId = event:getAssetId()
local percent = event:getPercent()
local strInfo = ""
if assetId == cc.AssetsManagerExStatic.VERSION_ID then
strInfo = string.format("Version file: %d%%", percent)
elseif assetId == cc.AssetsManagerExStatic.MANIFEST_ID then
strInfo = string.format("Manifest file: %d%%", percent)
else
strInfo = string.format("%d%%", percent)
end
progress:setString(strInfo)
elseif eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_DOWNLOAD_MANIFEST or
eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_PARSE_MANIFEST then
print("Fail to download manifest file, update skipped.")
local background = cc.Sprite:create("Images/background1.jpg")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
elseif eventCode == cc.EventAssetsManagerEx.EventCode.ALREADY_UP_TO_DATE or
eventCode == cc.EventAssetsManagerEx.EventCode.UPDATE_FINISHED then
print("Update finished.")
local background = cc.Sprite:create("Images/background1.jpg")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
elseif eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_UPDATING then
print("Asset ", event:getAssetId(), ", ", event:getMessage())
local background = cc.Sprite:create("Images/background1.jpg")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
end
end
local listener = cc.EventListenerAssetsManagerEx:create(am,onUpdateEvent)
cc.Director:getInstance():getEventDispatcher():addEventListenerWithFixedPriority(listener, 1)
am:update()
end
end
local function onNodeEvent(event)
if "enter" == event then
onEnter()
elseif "exit" == event then
am:release()
end
end
layer:registerScriptHandler(onNodeEvent)
return layer
end
-------------------------------------
-- AssetsManagerEx2 Test
-------------------------------------
local AMTestScene2 = {}
AMTestScene2.__index = AMTestScene2
function AMTestScene2.create()
local layer = cc.Layer:create()
local am = nil
local function onEnter()
Helper.initWithLayer(layer)
Helper.titleLabel:setString("AssetsManagerExTest2")
local sprite = cc.Sprite:create("Images/Icon.png")
layer:addChild(sprite)
sprite:setPosition(cc.p(VisibleRect:center().x, VisibleRect:center().y))
local ttfConfig = {}
ttfConfig.fontFilePath = "fonts/arial.ttf"
ttfConfig.fontSize = 40
local progress = cc.Label:createWithTTF(ttfConfig, "0%", cc.VERTICAL_TEXT_ALIGNMENT_CENTER)
progress:setPosition(cc.p(VisibleRect:center().x, VisibleRect:center().y + 50))
layer:addChild(progress)
am = cc.AssetsManagerEx:create("Manifests/AMTestScene2/project.manifest", "LuaTests/AssetsManagerExTest/scene2")
am:retain()
if not am:getLocalManifest():isLoaded() then
print("Fail to update assets, step skipped.")
local background = cc.Sprite:create("Images/background2.jpg")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
else
local function onUpdateEvent(event)
local eventCode = event:getEventCode()
if eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_NO_LOCAL_MANIFEST then
print("No local manifest file found, skip assets update.")
local background = cc.Sprite:create("Images/background2.jpg")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
elseif eventCode == cc.EventAssetsManagerEx.EventCode.UPDATE_PROGRESSION then
local assetId = event:getAssetId()
local percent = event:getPercent()
local strInfo = ""
if assetId == cc.AssetsManagerExStatic.VERSION_ID then
strInfo = string.format("Version file: %d%%", percent)
elseif assetId == cc.AssetsManagerExStatic.MANIFEST_ID then
strInfo = string.format("Manifest file: %d%%", percent)
else
strInfo = string.format("%d%%", percent)
end
progress:setString(strInfo)
elseif eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_DOWNLOAD_MANIFEST or
eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_PARSE_MANIFEST then
print("Fail to download manifest file, update skipped.")
local background = cc.Sprite:create("Images/background2.jpg")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
elseif eventCode == cc.EventAssetsManagerEx.EventCode.ALREADY_UP_TO_DATE or
eventCode == cc.EventAssetsManagerEx.EventCode.UPDATE_FINISHED then
print("Update finished.")
local background = cc.Sprite:create("Images/background2.jpg")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
elseif eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_UPDATING then
print("Asset ", event:getAssetId(), ", ", event:getMessage())
local background = cc.Sprite:create("Images/background2.jpg")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
end
end
local listener = cc.EventListenerAssetsManagerEx:create(am,onUpdateEvent)
cc.Director:getInstance():getEventDispatcher():addEventListenerWithFixedPriority(listener, 1)
am:update()
end
end
local function onNodeEvent(event)
if "enter" == event then
onEnter()
elseif "exit" == event then
am:release()
end
end
layer:registerScriptHandler(onNodeEvent)
return layer
end
-------------------------------------
-- AssetsManagerEx3 Test
-------------------------------------
local AMTestScene3 = {}
AMTestScene3.__index = AMTestScene3
function AMTestScene3.create()
local layer = cc.Layer:create()
local am = nil
local function onEnter()
Helper.initWithLayer(layer)
Helper.titleLabel:setString("AssetsManagerExTest3")
local sprite = cc.Sprite:create("Images/Icon.png")
layer:addChild(sprite)
sprite:setPosition(cc.p(VisibleRect:center().x, VisibleRect:center().y))
local ttfConfig = {}
ttfConfig.fontFilePath = "fonts/arial.ttf"
ttfConfig.fontSize = 40
local progress = cc.Label:createWithTTF(ttfConfig, "0%", cc.VERTICAL_TEXT_ALIGNMENT_CENTER)
progress:setPosition(cc.p(VisibleRect:center().x, VisibleRect:center().y + 50))
layer:addChild(progress)
am = cc.AssetsManagerEx:create("Manifests/AMTestScene3/project.manifest", "LuaTests/AssetsManagerExTest/scene3")
am:retain()
if not am:getLocalManifest():isLoaded() then
print("Fail to update assets, step skipped.")
local background = cc.Sprite:create("Images/background3.png")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
else
local function onUpdateEvent(event)
local eventCode = event:getEventCode()
if eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_NO_LOCAL_MANIFEST then
print("No local manifest file found, skip assets update.")
local background = cc.Sprite:create("Images/background3.png")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
elseif eventCode == cc.EventAssetsManagerEx.EventCode.UPDATE_PROGRESSION then
local assetId = event:getAssetId()
local percent = event:getPercent()
local strInfo = ""
if assetId == cc.AssetsManagerExStatic.VERSION_ID then
strInfo = string.format("Version file: %d%%", percent)
elseif assetId == cc.AssetsManagerExStatic.MANIFEST_ID then
strInfo = string.format("Manifest file: %d%%", percent)
else
strInfo = string.format("%d%%", percent)
end
progress:setString(strInfo)
elseif eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_DOWNLOAD_MANIFEST or
eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_PARSE_MANIFEST then
print("Fail to download manifest file, update skipped.")
local background = cc.Sprite:create("Images/background3.png")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
elseif eventCode == cc.EventAssetsManagerEx.EventCode.ALREADY_UP_TO_DATE or
eventCode == cc.EventAssetsManagerEx.EventCode.UPDATE_FINISHED then
print("Update finished.")
local background = cc.Sprite:create("Images/background3.png")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
elseif eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_UPDATING then
print("Asset ", event:getAssetId(), ", ", event:getMessage())
local background = cc.Sprite:create("Images/background3.png")
layer:addChild(background, 1)
background:setPosition( cc.p(VisibleRect:center().x, VisibleRect:center().y ))
end
end
local listener = cc.EventListenerAssetsManagerEx:create(am,onUpdateEvent)
cc.Director:getInstance():getEventDispatcher():addEventListenerWithFixedPriority(listener, 1)
am:update()
end
end
local function onNodeEvent(event)
if "enter" == event then
onEnter()
elseif "exit" == event then
am:release()
end
end
layer:registerScriptHandler(onNodeEvent)
return layer
end
-------------------------------------
-- AssetsManagerEx Test
-------------------------------------
function AssetsManagerExTestMain()
local scene = cc.Scene:create()
Helper.createFunctionTable =
{
AMTestScene1.create,
AMTestScene2.create,
AMTestScene3.create,
}
scene:addChild(AMTestScene1.create())
scene:addChild(CreateBackMenuItem())
return scene
end

View File

@ -1,160 +0,0 @@
local targetPlatform = cc.Application:getInstance():getTargetPlatform()
local lineSpace = 40
local itemTagBasic = 1000
local menuItemNames =
{
"enter",
"reset",
"update",
}
local winSize = cc.Director:getInstance():getWinSize()
local function updateLayer()
local layer = cc.Layer:create()
local support = false
if (cc.PLATFORM_OS_IPHONE == targetPlatform) or (cc.PLATFORM_OS_IPAD == targetPlatform)
or (cc.PLATFORM_OS_WINDOWS == targetPlatform) or (cc.PLATFORM_OS_ANDROID == targetPlatform)
or (cc.PLATFORM_OS_MAC == targetPlatform) then
support = true
end
if not support then
print("Platform is not supported!")
return layer
end
local isUpdateItemClicked = false
local assetsManager = nil
local pathToSave = ""
local menu = cc.Menu:create()
menu:setPosition(cc.p(0, 0))
cc.MenuItemFont:setFontName("Arial")
cc.MenuItemFont:setFontSize(24)
local progressLable = cc.Label:createWithTTF("",s_arialPath,30)
progressLable:setAnchorPoint(cc.p(0.5, 0.5))
progressLable:setPosition(cc.p(140,50))
layer:addChild(progressLable)
pathToSave = createDownloadDir()
local function onError(errorCode)
if errorCode == cc.ASSETSMANAGER_NO_NEW_VERSION then
progressLable:setString("no new version")
elseif errorCode == cc.ASSETSMANAGER_NETWORK then
progressLable:setString("network error")
end
end
local function onProgress( percent )
local progress = string.format("downloading %d%%",percent)
progressLable:setString(progress)
end
local function onSuccess()
progressLable:setString("downloading ok")
end
local function getAssetsManager()
if nil == assetsManager then
assetsManager = cc.AssetsManager:new("https://raw.github.com/samuele3hu/AssetsManagerTest/master/package.zip",
"https://raw.github.com/samuele3hu/AssetsManagerTest/master/version",
pathToSave)
assetsManager:retain()
assetsManager:setDelegate(onError, cc.ASSETSMANAGER_PROTOCOL_ERROR )
assetsManager:setDelegate(onProgress, cc.ASSETSMANAGER_PROTOCOL_PROGRESS)
assetsManager:setDelegate(onSuccess, cc.ASSETSMANAGER_PROTOCOL_SUCCESS )
assetsManager:setConnectionTimeout(3)
end
return assetsManager
end
local function update(sender)
progressLable:setString("")
getAssetsManager():update()
end
local function reset(sender)
progressLable:setString("")
deleteDownloadDir(pathToSave)
getAssetsManager():deleteVersion()
createDownloadDir()
end
local function reloadModule( moduleName )
package.loaded[moduleName] = nil
return require(moduleName)
end
local function enter(sender)
if not isUpdateItemClicked then
local realPath = pathToSave .. "/package"
addSearchPath(realPath,true)
end
assetsManagerModule = reloadModule("src/AssetsManagerTest/AssetsManagerModule")
assetsManagerModule.newScene(AssetsManagerTestMain)
end
local callbackFuncs =
{
enter,
reset,
update,
}
local function menuCallback(tag, menuItem)
local scene = nil
local nIdx = menuItem:getLocalZOrder() - itemTagBasic
local ExtensionsTestScene = CreateExtensionsTestScene(nIdx)
if nil ~= ExtensionsTestScene then
cc.Director:getInstance():replaceScene(ExtensionsTestScene)
end
end
for i = 1, table.getn(menuItemNames) do
local item = cc.MenuItemFont:create(menuItemNames[i])
item:registerScriptTapHandler(callbackFuncs[i])
item:setPosition(winSize.width / 2, winSize.height - i * lineSpace)
if not support then
item:setEnabled(false)
end
menu:addChild(item, itemTagBasic + i)
end
local function onNodeEvent(msgName)
if nil ~= assetsManager then
assetsManager:release()
assetsManager = nil
end
end
layer:registerScriptHandler(onNodeEvent)
layer:addChild(menu)
return layer
end
-------------------------------------
-- AssetsManager Test
-------------------------------------
function AssetsManagerTestMain()
local scene = cc.Scene:create()
scene:addChild(updateLayer())
scene:addChild(CreateBackMenuItem())
return scene
end

View File

@ -14,6 +14,7 @@ require "src/ActionManagerTest/ActionManagerTest"
require "src/ActionsEaseTest/ActionsEaseTest"
require "src/ActionsProgressTest/ActionsProgressTest"
require "src/ActionsTest/ActionsTest"
require "src/AssetsManagerExTest/AssetsManagerExTest"
require "src/AssetsManagerTest/AssetsManagerTest"
require "src/BillBoardTest/BillBoardTest"
require "src/BugsTest/BugsTest"
@ -78,6 +79,7 @@ local _allTests = {
{ isSupported = true, name = "ActionsEaseTest" , create_func = EaseActionsTest },
{ isSupported = true, name = "ActionsProgressTest" , create_func = ProgressActionsTest },
{ isSupported = true, name = "ActionsTest" , create_func = ActionsTest },
{ isSupported = true, name = "AssetsManagerExTest" , create_func = AssetsManagerExTestMain },
{ isSupported = true, name = "AssetsManagerTest" , create_func = AssetsManagerTestMain },
{ isSupported = audioEndineSupported, name = "AudioEngineTest", create_func = AudioEngineTest},
{ isSupported = false, name = "Box2dTest" , create_func= Box2dTestMain },

View File

@ -13,7 +13,7 @@ android_flags = -D_SIZE_T_DEFINED_
clang_headers = -I%(clangllvmdir)s/lib/clang/3.3/include
clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__
cocos_headers = -I%(cocosdir)s -I%(cocosdir)s/cocos/editor-support -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/platform/android
cocos_headers = -I%(cocosdir)s -I%(cocosdir)s/cocos/editor-support -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/platform/android -I%(cocosdir)s/external -I%(cocosdir)s/external/json
cocos_flags = -DANDROID
@ -27,7 +27,7 @@ headers = %(cocosdir)s/extensions/cocos-ext.h
# what classes to produce code for. You can use regular expressions here. When testing the regular
# expression, it will be enclosed in "^$", like this: "^Menu*$".
classes = AssetsManager.* Control.* ControlButton.* ScrollView$ TableView$ TableViewCell$
classes = Control.* ControlButton.* ScrollView$ TableView$ TableViewCell$ AssetsManager Manifest EventAssetsManager EventListenerAssetsManager
# what should we skip? in the format ClassName::[function function]
# ClassName is a regular expression, but will be used like this: "^ClassName$" functions are also
@ -39,13 +39,14 @@ classes = AssetsManager.* Control.* ControlButton.* ScrollView$ TableView$ Tabl
skip = .*Delegate::[*],
.*Loader.*::[*],
*::[^visit$ copyWith.* onEnter.* onExit.* ^description$ getObjectType (g|s)etDelegate .*HSV],
AssetsManager::[(g|s)etDelegate],
AssetsManagerDelegateProtocol::[*],
EditBox::[(g|s)etDelegate ^keyboard.* touchDownAction getScriptEditBoxHandler registerScriptEditBoxHandler unregisterScriptEditBoxHandler],
Control::[removeHandleOfControlEvent addHandleOfControlEvent],
ControlUtils::[*],
ControlSwitchSprite::[*],
ScrollView::[(g|s)etDelegate$],
TableView::[create (g|s)etDataSource$ (g|s)etDelegate]
TableView::[create (g|s)etDataSource$ (g|s)etDelegate],
Manifest::[getAssets getAsset],
EventListenerAssetsManager::[create]
rename_functions =
@ -63,7 +64,7 @@ base_classes_to_skip =
# classes that create no constructor
# Set is special and we will use a hand-written constructor
abstract_classes =
abstract_classes = ArmatureDataManager Manifest
# Determining whether to use script object(js object) to control the lifecycle of native(cpp) object or the other way around. Supported values are 'yes' or 'no'.
script_control_cpp = no