From a26e91f839e5849f38784da19a241e7ea8758b28 Mon Sep 17 00:00:00 2001 From: pandamicro Date: Thu, 9 Oct 2014 18:30:39 +0800 Subject: [PATCH 1/2] no message --- build/cocos2d_libs.xcodeproj/project.pbxproj | 60 ++ build/cocos2d_tests.xcodeproj/project.pbxproj | 42 +- cocos/2d/libcocos2d.vcxproj | 10 + cocos/2d/libcocos2d.vcxproj.filters | 30 + cocos/Android.mk | 3 +- cocos/platform/CCFileUtils.cpp | 157 ++-- cocos/platform/CCFileUtils.h | 166 ++-- .../lua-bindings/manual/CCLuaEngine.cpp | 66 +- .../lua-bindings/manual/CCLuaEngine.h | 2 +- .../manual/cocos2d/LuaScriptHandlerMgr.h | 6 +- .../lua_cocos2dx_extension_manual.cpp | 113 ++- .../extension/lua_cocos2dx_extension_manual.h | 9 - .../script/cocos2d/Cocos2dConstants.lua | 56 +- extensions/Android.mk | 5 + extensions/CMakeLists.txt | 5 + extensions/assets-manager/AssetsManagerEx.cpp | 877 ++++++++++++++++++ extensions/assets-manager/AssetsManagerEx.h | 266 ++++++ .../assets-manager/CCEventAssetsManagerEx.cpp | 46 + .../assets-manager/CCEventAssetsManagerEx.h | 99 ++ .../CCEventListenerAssetsManagerEx.cpp | 98 ++ .../CCEventListenerAssetsManagerEx.h | 86 ++ extensions/assets-manager/Downloader.cpp | 680 ++++++++++++++ extensions/assets-manager/Downloader.h | 196 ++++ extensions/assets-manager/Manifest.cpp | 481 ++++++++++ extensions/assets-manager/Manifest.h | 207 +++++ extensions/cocos-ext.h | 4 + templates/cocos2dx_files.json | 8 + tests/cpp-tests/CMakeLists.txt | 1 + tests/cpp-tests/Classes/AppDelegate.cpp | 1 + .../AssetsManagerExTest.cpp | 212 +++++ .../AssetsManagerExTest/AssetsManagerExTest.h | 53 ++ .../Classes/ExtensionsTest/ExtensionsTest.cpp | 5 + .../Manifests/AMTestScene1/project.manifest | 16 + .../Manifests/AMTestScene2/project.manifest | 15 + .../Manifests/AMTestScene3/project.manifest | 16 + tests/cpp-tests/proj.android/jni/Android.mk | 1 + tests/cpp-tests/proj.win32/cpp-tests.vcxproj | 2 + .../proj.win32/cpp-tests.vcxproj.filters | 9 + tests/lua-tests/project/CMakeLists.txt | 2 +- .../lua-tests/project/Classes/AppDelegate.cpp | 12 +- .../Classes/lua_assetsmanager_test_sample.h | 17 - ...pp => lua_assetsmanagerex_test_sample.cpp} | 4 +- .../Classes/lua_assetsmanagerex_test_sample.h | 17 + .../project/proj.android/jni/Android.mk | 2 +- .../proj.win32/lua-tests.win32.vcxproj | 4 +- .../lua-tests.win32.vcxproj.filters | 4 +- .../AssetsManagerExModule.lua} | 0 .../AssetsManagerExTest.lua | 336 +++++++ .../AssetsManagerTest/AssetsManagerTest.lua | 160 ---- tests/lua-tests/src/mainMenu.lua | 2 + tools/tolua/cocos2dx_extension.ini | 13 +- 51 files changed, 4247 insertions(+), 435 deletions(-) create mode 100644 extensions/assets-manager/AssetsManagerEx.cpp create mode 100644 extensions/assets-manager/AssetsManagerEx.h create mode 100644 extensions/assets-manager/CCEventAssetsManagerEx.cpp create mode 100644 extensions/assets-manager/CCEventAssetsManagerEx.h create mode 100644 extensions/assets-manager/CCEventListenerAssetsManagerEx.cpp create mode 100644 extensions/assets-manager/CCEventListenerAssetsManagerEx.h create mode 100644 extensions/assets-manager/Downloader.cpp create mode 100644 extensions/assets-manager/Downloader.h create mode 100644 extensions/assets-manager/Manifest.cpp create mode 100644 extensions/assets-manager/Manifest.h create mode 100644 tests/cpp-tests/Classes/ExtensionsTest/AssetsManagerExTest/AssetsManagerExTest.cpp create mode 100644 tests/cpp-tests/Classes/ExtensionsTest/AssetsManagerExTest/AssetsManagerExTest.h create mode 100644 tests/cpp-tests/Resources/Manifests/AMTestScene1/project.manifest create mode 100644 tests/cpp-tests/Resources/Manifests/AMTestScene2/project.manifest create mode 100644 tests/cpp-tests/Resources/Manifests/AMTestScene3/project.manifest delete mode 100644 tests/lua-tests/project/Classes/lua_assetsmanager_test_sample.h rename tests/lua-tests/project/Classes/{lua_assetsmanager_test_sample.cpp => lua_assetsmanagerex_test_sample.cpp} (97%) create mode 100644 tests/lua-tests/project/Classes/lua_assetsmanagerex_test_sample.h rename tests/lua-tests/src/{AssetsManagerTest/AssetsManagerModule.lua => AssetsManagerExTest/AssetsManagerExModule.lua} (100%) create mode 100644 tests/lua-tests/src/AssetsManagerExTest/AssetsManagerExTest.lua delete mode 100644 tests/lua-tests/src/AssetsManagerTest/AssetsManagerTest.lua diff --git a/build/cocos2d_libs.xcodeproj/project.pbxproj b/build/cocos2d_libs.xcodeproj/project.pbxproj index 4164e3cd82..b3522b9400 100644 --- a/build/cocos2d_libs.xcodeproj/project.pbxproj +++ b/build/cocos2d_libs.xcodeproj/project.pbxproj @@ -1813,6 +1813,26 @@ B60C5BD519AC68B10056FBDE /* CCBillBoard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B60C5BD219AC68B10056FBDE /* CCBillBoard.cpp */; }; B60C5BD619AC68B10056FBDE /* CCBillBoard.h in Headers */ = {isa = PBXBuildFile; fileRef = B60C5BD319AC68B10056FBDE /* CCBillBoard.h */; }; B60C5BD719AC68B10056FBDE /* CCBillBoard.h in Headers */ = {isa = PBXBuildFile; fileRef = B60C5BD319AC68B10056FBDE /* CCBillBoard.h */; }; + BAF92D5E19C89D6D003BCFEF /* AssetsManagerEx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BAF92D5419C89D6D003BCFEF /* AssetsManagerEx.cpp */; }; + BAF92D5F19C89D6D003BCFEF /* AssetsManagerEx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BAF92D5419C89D6D003BCFEF /* AssetsManagerEx.cpp */; }; + BAF92D6019C89D6D003BCFEF /* AssetsManagerEx.h in Headers */ = {isa = PBXBuildFile; fileRef = BAF92D5519C89D6D003BCFEF /* AssetsManagerEx.h */; }; + BAF92D6119C89D6D003BCFEF /* AssetsManagerEx.h in Headers */ = {isa = PBXBuildFile; fileRef = BAF92D5519C89D6D003BCFEF /* AssetsManagerEx.h */; }; + BAF92D6219C89D6D003BCFEF /* CCEventAssetsManagerEx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BAF92D5619C89D6D003BCFEF /* CCEventAssetsManagerEx.cpp */; }; + BAF92D6319C89D6D003BCFEF /* CCEventAssetsManagerEx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BAF92D5619C89D6D003BCFEF /* CCEventAssetsManagerEx.cpp */; }; + BAF92D6419C89D6D003BCFEF /* CCEventAssetsManagerEx.h in Headers */ = {isa = PBXBuildFile; fileRef = BAF92D5719C89D6D003BCFEF /* CCEventAssetsManagerEx.h */; }; + BAF92D6519C89D6D003BCFEF /* CCEventAssetsManagerEx.h in Headers */ = {isa = PBXBuildFile; fileRef = BAF92D5719C89D6D003BCFEF /* CCEventAssetsManagerEx.h */; }; + BAF92D6619C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BAF92D5819C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.cpp */; }; + BAF92D6719C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BAF92D5819C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.cpp */; }; + BAF92D6819C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.h in Headers */ = {isa = PBXBuildFile; fileRef = BAF92D5919C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.h */; }; + BAF92D6919C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.h in Headers */ = {isa = PBXBuildFile; fileRef = BAF92D5919C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.h */; }; + BAF92D6A19C89D6D003BCFEF /* Downloader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BAF92D5A19C89D6D003BCFEF /* Downloader.cpp */; }; + BAF92D6B19C89D6D003BCFEF /* Downloader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BAF92D5A19C89D6D003BCFEF /* Downloader.cpp */; }; + BAF92D6C19C89D6D003BCFEF /* Downloader.h in Headers */ = {isa = PBXBuildFile; fileRef = BAF92D5B19C89D6D003BCFEF /* Downloader.h */; }; + BAF92D6D19C89D6D003BCFEF /* Downloader.h in Headers */ = {isa = PBXBuildFile; fileRef = BAF92D5B19C89D6D003BCFEF /* Downloader.h */; }; + BAF92D6E19C89D6D003BCFEF /* Manifest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BAF92D5C19C89D6D003BCFEF /* Manifest.cpp */; }; + BAF92D6F19C89D6D003BCFEF /* Manifest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BAF92D5C19C89D6D003BCFEF /* Manifest.cpp */; }; + BAF92D7019C89D6D003BCFEF /* Manifest.h in Headers */ = {isa = PBXBuildFile; fileRef = BAF92D5D19C89D6D003BCFEF /* Manifest.h */; }; + BAF92D7119C89D6D003BCFEF /* Manifest.h in Headers */ = {isa = PBXBuildFile; fileRef = BAF92D5D19C89D6D003BCFEF /* Manifest.h */; }; ED9C6A9418599AD8000A5232 /* CCNodeGrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED9C6A9218599AD8000A5232 /* CCNodeGrid.cpp */; }; ED9C6A9518599AD8000A5232 /* CCNodeGrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED9C6A9218599AD8000A5232 /* CCNodeGrid.cpp */; }; ED9C6A9618599AD8000A5232 /* CCNodeGrid.h in Headers */ = {isa = PBXBuildFile; fileRef = ED9C6A9318599AD8000A5232 /* CCNodeGrid.h */; }; @@ -2799,6 +2819,16 @@ B3AF019F1842FBA400A98B85 /* b2MotorJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2MotorJoint.h; sourceTree = ""; }; B60C5BD219AC68B10056FBDE /* CCBillBoard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CCBillBoard.cpp; sourceTree = ""; }; B60C5BD319AC68B10056FBDE /* CCBillBoard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCBillBoard.h; sourceTree = ""; }; + BAF92D5419C89D6D003BCFEF /* AssetsManagerEx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AssetsManagerEx.cpp; sourceTree = ""; }; + BAF92D5519C89D6D003BCFEF /* AssetsManagerEx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AssetsManagerEx.h; sourceTree = ""; }; + BAF92D5619C89D6D003BCFEF /* CCEventAssetsManagerEx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CCEventAssetsManagerEx.cpp; sourceTree = ""; }; + BAF92D5719C89D6D003BCFEF /* CCEventAssetsManagerEx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCEventAssetsManagerEx.h; sourceTree = ""; }; + BAF92D5819C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CCEventListenerAssetsManagerEx.cpp; sourceTree = ""; }; + BAF92D5919C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCEventListenerAssetsManagerEx.h; sourceTree = ""; }; + BAF92D5A19C89D6D003BCFEF /* Downloader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Downloader.cpp; sourceTree = ""; }; + BAF92D5B19C89D6D003BCFEF /* Downloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Downloader.h; sourceTree = ""; }; + BAF92D5C19C89D6D003BCFEF /* Manifest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Manifest.cpp; sourceTree = ""; }; + BAF92D5D19C89D6D003BCFEF /* Manifest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Manifest.h; sourceTree = ""; }; B67C624319D4186F00F11FC6 /* ccShader_3D_ColorNormal.frag */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = ccShader_3D_ColorNormal.frag; sourceTree = ""; }; B67C624419D4186F00F11FC6 /* ccShader_3D_ColorNormalTex.frag */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = ccShader_3D_ColorNormalTex.frag; sourceTree = ""; }; B67C624519D4186F00F11FC6 /* ccShader_3D_PositionNormalTex.vert */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = ccShader_3D_PositionNormalTex.vert; sourceTree = ""; }; @@ -3617,6 +3647,16 @@ 1AAF5350180E305F000584C8 /* assets-manager */ = { isa = PBXGroup; children = ( + BAF92D5419C89D6D003BCFEF /* AssetsManagerEx.cpp */, + BAF92D5519C89D6D003BCFEF /* AssetsManagerEx.h */, + BAF92D5619C89D6D003BCFEF /* CCEventAssetsManagerEx.cpp */, + BAF92D5719C89D6D003BCFEF /* CCEventAssetsManagerEx.h */, + BAF92D5819C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.cpp */, + BAF92D5919C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.h */, + BAF92D5A19C89D6D003BCFEF /* Downloader.cpp */, + BAF92D5B19C89D6D003BCFEF /* Downloader.h */, + BAF92D5C19C89D6D003BCFEF /* Manifest.cpp */, + BAF92D5D19C89D6D003BCFEF /* Manifest.h */, 1AAF5351180E3060000584C8 /* AssetsManager.cpp */, 1AAF5352180E3060000584C8 /* AssetsManager.h */, ); @@ -4851,6 +4891,7 @@ 15AE1A2219AAD3D500C27E9E /* Box2D.h in Headers */, 15AE191419AAD35000C27E9E /* CCSGUIReader.h in Headers */, 15AE196D19AAD35700C27E9E /* CCActionTimeline.h in Headers */, + BAF92D6019C89D6D003BCFEF /* AssetsManagerEx.h in Headers */, 15AE1A6D19AAD40300C27E9E /* b2ChainAndPolygonContact.h in Headers */, 3E2F27A719CFBFE400E7C490 /* AudioEngine.h in Headers */, 15AE183A19AAD2F700C27E9E /* CCRay.h in Headers */, @@ -4865,6 +4906,7 @@ 50ABBE871925AB6F00A911A9 /* ccMacros.h in Headers */, 50ABBE731925AB6F00A911A9 /* CCEventListenerMouse.h in Headers */, 1A570063180BC5A10088DEC7 /* CCAction.h in Headers */, + BAF92D6819C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.h in Headers */, 1A570067180BC5A10088DEC7 /* CCActionCamera.h in Headers */, 15AE1AD919AAD41000C27E9E /* b2Rope.h in Headers */, 15AE187B19AAD33D00C27E9E /* CCBAnimationManager.h in Headers */, @@ -5136,6 +5178,7 @@ 1A01C69418F57BE800EFE3A6 /* CCFloat.h in Headers */, 1A57034D180BD09B0088DEC7 /* tinyxml2.h in Headers */, 15AE18F519AAD35000C27E9E /* CCArmatureDefine.h in Headers */, + BAF92D6C19C89D6D003BCFEF /* Downloader.h in Headers */, 15AE188219AAD33D00C27E9E /* CCBReader.h in Headers */, 1A570356180BD0B00088DEC7 /* ioapi.h in Headers */, 15AE19C319AAD3A700C27E9E /* BoundingBoxAttachment.h in Headers */, @@ -5179,6 +5222,7 @@ 15AE1B9E19AADFDF00C27E9E /* UIVBox.h in Headers */, 15AE192319AAD35000C27E9E /* DictionaryHelper.h in Headers */, B257B4501989D5E800D9A687 /* CCPrimitive.h in Headers */, + BAF92D6419C89D6D003BCFEF /* CCEventAssetsManagerEx.h in Headers */, 50ABBE6B1925AB6F00A911A9 /* CCEventListenerFocus.h in Headers */, 50ABBDA51925AB4100A911A9 /* CCQuadCommand.h in Headers */, 15AE197319AAD35700C27E9E /* CCNodeReader.h in Headers */, @@ -5279,6 +5323,7 @@ 50ABC0171926664800A911A9 /* CCImage.h in Headers */, 50ABBDA91925AB4100A911A9 /* CCRenderCommand.h in Headers */, 50ABBD951925AB4100A911A9 /* CCGLProgramState.h in Headers */, + BAF92D7019C89D6D003BCFEF /* Manifest.h in Headers */, 50ABC0091926664800A911A9 /* CCCommon.h in Headers */, 15AE19BF19AAD3A700C27E9E /* Event.h in Headers */, 50ABBE531925AB6F00A911A9 /* CCEventDispatcher.h in Headers */, @@ -5397,6 +5442,7 @@ 1A570090180BC5A10088DEC7 /* CCActionTiledGrid.h in Headers */, 1A570094180BC5A10088DEC7 /* CCActionTween.h in Headers */, 1A57009B180BC5C10088DEC7 /* CCAtlasNode.h in Headers */, + BAF92D6119C89D6D003BCFEF /* AssetsManagerEx.h in Headers */, 15AE184919AAD2F700C27E9E /* cocos3d.h in Headers */, 15AE19F819AAD3A700C27E9E /* Animation.h in Headers */, 1A5700A1180BC5D20088DEC7 /* CCNode.h in Headers */, @@ -5614,6 +5660,7 @@ 15AE1A2019AAD3A700C27E9E /* spine-cocos2dx.h in Headers */, 15AE185D19AAD31200C27E9E /* CocosDenshion.h in Headers */, 15AE194319AAD35100C27E9E /* CCColliderDetector.h in Headers */, + BAF92D6D19C89D6D003BCFEF /* Downloader.h in Headers */, 15AE1BC419AADFFB00C27E9E /* ExtensionMacros.h in Headers */, 15AE185A19AAD31200C27E9E /* CDConfig.h in Headers */, 1A57034E180BD09B0088DEC7 /* tinyxml2.h in Headers */, @@ -5639,6 +5686,7 @@ 50ABBE301925AB6F00A911A9 /* ccConfig.h in Headers */, 15AE195819AAD35100C27E9E /* CCInputDelegate.h in Headers */, 50ABBDAC1925AB4100A911A9 /* CCRenderCommandPool.h in Headers */, + BAF92D6519C89D6D003BCFEF /* CCEventAssetsManagerEx.h in Headers */, 5034CA3C191D591100CE6051 /* ccShader_PositionColor.vert in Headers */, 50ABC0181926664800A911A9 /* CCImage.h in Headers */, 15AE1A4E19AAD3D500C27E9E /* b2PolygonShape.h in Headers */, @@ -5648,6 +5696,7 @@ 46C02E0A18E91123004B7456 /* xxhash.h in Headers */, 5034CA4C191D591100CE6051 /* ccShader_Label_df_glow.frag in Headers */, 503DD8EB1926736A00CD74DD /* CCGL-ios.h in Headers */, + BAF92D6919C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.h in Headers */, 50ABBE3C1925AB6F00A911A9 /* CCData.h in Headers */, 503DD8FA1926B0DB00CD74DD /* CCIMEDispatcher.h in Headers */, 50ABBEC81925AB6F00A911A9 /* etc1.h in Headers */, @@ -5749,6 +5798,7 @@ 15AE18D219AAD33D00C27E9E /* CCNodeLoaderListener.h in Headers */, 15AE184D19AAD30800C27E9E /* SimpleAudioEngine.h in Headers */, 1A01C68D18F57BE800EFE3A6 /* CCDeprecated.h in Headers */, + BAF92D7119C89D6D003BCFEF /* Manifest.h in Headers */, 503DD8EA1926736A00CD74DD /* CCESRenderer-ios.h in Headers */, 50ABBE581925AB6F00A911A9 /* CCEventFocus.h in Headers */, 15AE196419AAD35100C27E9E /* CCTransformHelp.h in Headers */, @@ -5944,6 +5994,7 @@ 15AE188419AAD33D00C27E9E /* CCBSequence.cpp in Sources */, 50ABBEBF1925AB6F00A911A9 /* CCValue.cpp in Sources */, 1A570098180BC5C10088DEC7 /* CCAtlasNode.cpp in Sources */, + BAF92D6E19C89D6D003BCFEF /* Manifest.cpp in Sources */, 1A57009E180BC5D20088DEC7 /* CCNode.cpp in Sources */, 50ED2BD919BE5D5D00A0AB90 /* CCEventListenerController.cpp in Sources */, B257B460198A353E00D9A687 /* CCPrimitiveCommand.cpp in Sources */, @@ -5981,6 +6032,7 @@ 15AE1A7A19AAD40300C27E9E /* b2PolygonContact.cpp in Sources */, 15AE191119AAD35000C27E9E /* CCProcessBase.cpp in Sources */, 15AE18EE19AAD35000C27E9E /* CCArmature.cpp in Sources */, + BAF92D6219C89D6D003BCFEF /* CCEventAssetsManagerEx.cpp in Sources */, 15AE1BCD19AAE01E00C27E9E /* CCControlColourPicker.cpp in Sources */, 1A5701B1180BCB590088DEC7 /* CCFontFNT.cpp in Sources */, 15AE181619AAD2F700C27E9E /* CCAttachNode.cpp in Sources */, @@ -6080,10 +6132,12 @@ 15AE19C619AAD3A700C27E9E /* AnimationState.cpp in Sources */, 15AE1B5519AADA9900C27E9E /* UIScrollView.cpp in Sources */, 15AE191919AAD35000C27E9E /* CCSSceneReader.cpp in Sources */, + BAF92D6619C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.cpp in Sources */, 15AE19EC19AAD3A700C27E9E /* spine-cocos2dx.cpp in Sources */, 50ABBE7D1925AB6F00A911A9 /* CCEventTouch.cpp in Sources */, 1A5702EA180BCE750088DEC7 /* CCTileMapAtlas.cpp in Sources */, 50ABBD971925AB4100A911A9 /* CCGLProgramStateCache.cpp in Sources */, + BAF92D5E19C89D6D003BCFEF /* AssetsManagerEx.cpp in Sources */, 15AE182019AAD2F700C27E9E /* CCBundleReader.cpp in Sources */, 15AE1AD819AAD41000C27E9E /* b2Rope.cpp in Sources */, 15AE19C419AAD3A700C27E9E /* Animation.cpp in Sources */, @@ -6208,6 +6262,7 @@ 50ABBE611925AB6F00A911A9 /* CCEventListenerAcceleration.cpp in Sources */, 50ABBD9F1925AB4100A911A9 /* CCGroupCommand.cpp in Sources */, 15AE1A8E19AAD40300C27E9E /* b2RopeJoint.cpp in Sources */, + BAF92D6A19C89D6D003BCFEF /* Downloader.cpp in Sources */, 15AE19BC19AAD3A700C27E9E /* SkeletonBounds.cpp in Sources */, 50ABBD871925AB4100A911A9 /* CCCustomCommand.cpp in Sources */, 50ABBDBD1925AB4100A911A9 /* CCTextureCache.cpp in Sources */, @@ -6299,6 +6354,7 @@ 503DD8EE1926736A00CD74DD /* CCImage-ios.mm in Sources */, B37510811823ACA100B3BA6A /* CCPhysicsJointInfo_chipmunk.cpp in Sources */, 46A170FC1807CECB005B8026 /* CCPhysicsBody.cpp in Sources */, + BAF92D6319C89D6D003BCFEF /* CCEventAssetsManagerEx.cpp in Sources */, 15AE1BEA19AAE01E00C27E9E /* CCControlButton.cpp in Sources */, 50ABBD941925AB4100A911A9 /* CCGLProgramState.cpp in Sources */, B257B44F1989D5E800D9A687 /* CCPrimitive.cpp in Sources */, @@ -6333,6 +6389,7 @@ 15AE19EF19AAD3A700C27E9E /* SkeletonBounds.cpp in Sources */, 15AE18B219AAD33D00C27E9E /* CCBReader.cpp in Sources */, 15AE193C19AAD35100C27E9E /* CCArmatureDefine.cpp in Sources */, + BAF92D5F19C89D6D003BCFEF /* AssetsManagerEx.cpp in Sources */, B29594B51926D5EC003EEF37 /* CCMeshCommand.cpp in Sources */, 15AE194B19AAD35100C27E9E /* CCComRender.cpp in Sources */, 15AE1ACA19AAD40300C27E9E /* b2MouseJoint.cpp in Sources */, @@ -6419,6 +6476,7 @@ 15AE195F19AAD35100C27E9E /* CCSpriteFrameCacheHelper.cpp in Sources */, 15AE193019AAD35100C27E9E /* CCActionManagerEx.cpp in Sources */, 503DD8E21926736A00CD74DD /* CCCommon-ios.mm in Sources */, + BAF92D6F19C89D6D003BCFEF /* Manifest.cpp in Sources */, 292DB14A19B4574100A80320 /* UIEditBoxImpl-ios.mm in Sources */, 15AE1A9419AAD40300C27E9E /* b2BlockAllocator.cpp in Sources */, 15AE1A4D19AAD3D500C27E9E /* b2PolygonShape.cpp in Sources */, @@ -6555,6 +6613,7 @@ 15AE1B7819AADA9A00C27E9E /* UIRichText.cpp in Sources */, 15AE195D19AAD35100C27E9E /* CCSkin.cpp in Sources */, 1A5702F7180BCE750088DEC7 /* CCTMXTiledMap.cpp in Sources */, + BAF92D6719C89D6D003BCFEF /* CCEventListenerAssetsManagerEx.cpp in Sources */, 50ABBEC61925AB6F00A911A9 /* etc1.cpp in Sources */, 50ABBE8C1925AB6F00A911A9 /* CCNS.cpp in Sources */, 15AE1BA919AADFDF00C27E9E /* UIVBox.cpp in Sources */, @@ -6569,6 +6628,7 @@ 464AD6E6197EBB1400E502D8 /* pvr.cpp in Sources */, 15AE1B7619AADA9A00C27E9E /* UIPageView.cpp in Sources */, 1A570311180BCF190088DEC7 /* CCComponentContainer.cpp in Sources */, + BAF92D6B19C89D6D003BCFEF /* Downloader.cpp in Sources */, 50ABBE2C1925AB6F00A911A9 /* ccCArray.cpp in Sources */, 15AE193219AAD35100C27E9E /* CCActionNode.cpp in Sources */, 15AE195319AAD35100C27E9E /* CCDisplayFactory.cpp in Sources */, diff --git a/build/cocos2d_tests.xcodeproj/project.pbxproj b/build/cocos2d_tests.xcodeproj/project.pbxproj index 9c7f793e97..38c4bf7206 100644 --- a/build/cocos2d_tests.xcodeproj/project.pbxproj +++ b/build/cocos2d_tests.xcodeproj/project.pbxproj @@ -690,8 +690,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 */; }; @@ -947,6 +947,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 */; }; @@ -2770,8 +2776,8 @@ 1AC35D7818CEE59900F37B72 /* cocosbuilderRes */ = {isa = PBXFileReference; lastKnownFileType = folder; name = cocosbuilderRes; path = "../tests/lua-tests/res/cocosbuilderRes"; sourceTree = ""; }; 1AC35D7D18CEE5B100F37B72 /* AppDelegate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppDelegate.cpp; sourceTree = ""; }; 1AC35D7E18CEE5B100F37B72 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 1AC35D7F18CEE5B100F37B72 /* lua_assetsmanager_test_sample.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_assetsmanager_test_sample.cpp; sourceTree = ""; }; - 1AC35D8018CEE5B100F37B72 /* lua_assetsmanager_test_sample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lua_assetsmanager_test_sample.h; sourceTree = ""; }; + 1AC35D7F18CEE5B100F37B72 /* lua_assetsmanagerex_test_sample.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_assetsmanagerex_test_sample.cpp; sourceTree = ""; }; + 1AC35D8018CEE5B100F37B72 /* lua_assetsmanagerex_test_sample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lua_assetsmanagerex_test_sample.h; sourceTree = ""; }; 1AC35D8618CEE5D100F37B72 /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = ""; }; 1AC35D8718CEE5D100F37B72 /* AppController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AppController.mm; sourceTree = ""; }; 1AC35D8818CEE5D100F37B72 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; @@ -2974,6 +2980,9 @@ B609E67219C18DAD003D0074 /* BillBoardTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BillBoardTest.h; path = BillBoardTest/BillBoardTest.h; sourceTree = ""; }; B6C039D719C95D83007207DC /* LightTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LightTest.cpp; path = LightTest/LightTest.cpp; sourceTree = ""; }; B6C039D819C95D83007207DC /* LightTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LightTest.h; path = LightTest/LightTest.h; sourceTree = ""; }; + BA4B67D019E6699200BAF8F9 /* AssetsManagerExTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AssetsManagerExTest.cpp; sourceTree = ""; }; + BA4B67D119E6699200BAF8F9 /* AssetsManagerExTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AssetsManagerExTest.h; sourceTree = ""; }; + BAF402E119E675F30060A895 /* Manifests */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Manifests; path = "../tests/cpp-tests/Resources/Manifests"; sourceTree = ""; }; C04F93581941B05400E9FEAB /* TileMapTest2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TileMapTest2.cpp; sourceTree = ""; }; C04F93591941B05400E9FEAB /* TileMapTest2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TileMapTest2.h; sourceTree = ""; }; C08689C018D370C90093E810 /* background.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = background.caf; path = "../tests/cpp-tests/Resources/background.caf"; sourceTree = ""; }; @@ -5793,6 +5802,7 @@ 1AC359B418CECF0B00F37B72 /* ExtensionsTest */ = { isa = PBXGroup; children = ( + BA4B67CF19E6699200BAF8F9 /* AssetsManagerExTest */, 38FA2E70194AEBE100FF2BE4 /* CocoStudioActionTimelineTest */, 1AC359B518CECF0B00F37B72 /* CocosBuilderTest */, 1AC359DC18CECF0B00F37B72 /* CocoStudioArmatureTest */, @@ -6490,6 +6500,7 @@ 1AC35CBA18CED84500F37B72 /* fonts */, 1AC35CBC18CED84500F37B72 /* hd */, 1AC35CBE18CED84500F37B72 /* Images */, + BAF402E119E675F30060A895 /* Manifests */, 1AC35CC118CED84500F37B72 /* Misc */, 1AC35CC318CED84500F37B72 /* Particles */, 1AC35CC618CED84500F37B72 /* Shaders */, @@ -6617,8 +6628,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"; @@ -7193,6 +7204,15 @@ name = LightTest; sourceTree = ""; }; + BA4B67CF19E6699200BAF8F9 /* AssetsManagerExTest */ = { + isa = PBXGroup; + children = ( + BA4B67D019E6699200BAF8F9 /* AssetsManagerExTest.cpp */, + BA4B67D119E6699200BAF8F9 /* AssetsManagerExTest.h */, + ); + path = AssetsManagerExTest; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -7631,6 +7651,7 @@ 15D1FD47199863E800302043 /* DeprecatedCocoStudioClass.lua in Resources */, 3E2F27BC19D00D7200E7C490 /* audio in Resources */, 1AC35DC318CEE65100F37B72 /* Misc in Resources */, + BAF402E419E676370060A895 /* Manifests in Resources */, 1AC35DC618CEE65100F37B72 /* Shaders in Resources */, 15D1FD141998637C00302043 /* extern.lua in Resources */, 1AC35DBB18CEE65100F37B72 /* components in Resources */, @@ -7719,6 +7740,7 @@ 15C90B4C18E66C3100D69802 /* url.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 */, @@ -7813,6 +7835,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 */, @@ -7892,6 +7915,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 */, @@ -8007,7 +8031,7 @@ 1AC35D8118CEE5B100F37B72 /* AppDelegate.cpp in Sources */, 1AC35DB518CEE5DA00F37B72 /* LuaObjectCBridgeTest.mm 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; }; @@ -8020,7 +8044,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; }; @@ -8185,6 +8209,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 */, @@ -8329,6 +8354,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 */, diff --git a/cocos/2d/libcocos2d.vcxproj b/cocos/2d/libcocos2d.vcxproj index d0453f314c..190c41bf33 100644 --- a/cocos/2d/libcocos2d.vcxproj +++ b/cocos/2d/libcocos2d.vcxproj @@ -184,6 +184,11 @@ xcopy /Y /Q "$(ProjectDir)..\..\external\chipmunk\prebuilt\win32\release-lib\*.* + + + + + @@ -511,6 +516,11 @@ xcopy /Y /Q "$(ProjectDir)..\..\external\chipmunk\prebuilt\win32\release-lib\*.* + + + + + diff --git a/cocos/2d/libcocos2d.vcxproj.filters b/cocos/2d/libcocos2d.vcxproj.filters index 1e55d334ca..80f74251cc 100644 --- a/cocos/2d/libcocos2d.vcxproj.filters +++ b/cocos/2d/libcocos2d.vcxproj.filters @@ -1168,6 +1168,21 @@ ui\UIWidgets\EditBox + + extension\AssetsManager + + + extension\AssetsManager + + + extension\AssetsManager + + + extension\AssetsManager + + + extension\AssetsManager + ui\UIWidgets @@ -2314,6 +2329,21 @@ ui\UIWidgets\EditBox + + extension\AssetsManager + + + extension\AssetsManager + + + extension\AssetsManager + + + extension\AssetsManager + + + extension\AssetsManager + ui\UIWidgets diff --git a/cocos/Android.mk b/cocos/Android.mk index ac8b308458..d817bc7a3e 100644 --- a/cocos/Android.mk +++ b/cocos/Android.mk @@ -194,7 +194,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)/. \ diff --git a/cocos/platform/CCFileUtils.cpp b/cocos/platform/CCFileUtils.cpp index ddc162c22c..f4ee16e7ee 100644 --- a/cocos/platform/CCFileUtils.cpp +++ b/cocos/platform/CCFileUtils.cpp @@ -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. + ****************************************************************************/ #include "CCFileUtils.h" @@ -43,11 +43,15 @@ THE SOFTWARE. #include #endif +#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) +#include +#endif + #if (CC_TARGET_PLATFORM != CC_PLATFORM_IOS) && (CC_TARGET_PLATFORM != CC_PLATFORM_MAC) NS_CC_BEGIN -typedef enum +typedef enum { SAX_NONE = 0, SAX_KEY, @@ -71,36 +75,36 @@ public: SAXResult _resultType; ValueMap _rootDict; ValueVector _rootArray; - + std::string _curKey; ///< parsed key std::string _curValue; // parsed value SAXState _state; - + ValueMap* _curDict; ValueVector* _curArray; - + std::stack _dictStack; std::stack _arrayStack; std::stack _stateStack; - + public: - DictMaker() - : _resultType(SAX_RESULT_NONE) + DictMaker() + : _resultType(SAX_RESULT_NONE) { } - + ~DictMaker() { } - + ValueMap dictionaryWithContentsOfFile(const std::string& fileName) { _resultType = SAX_RESULT_DICT; SAXParser parser; - + CCASSERT(parser.init("UTF-8"), "The file format isn't UTF-8"); parser.setDelegator(this); - + parser.parse(fileName); return _rootDict; } @@ -121,14 +125,14 @@ public: { _resultType = SAX_RESULT_ARRAY; SAXParser parser; - + CCASSERT(parser.init("UTF-8"), "The file format isn't UTF-8"); parser.setDelegator(this); - + parser.parse(fileName); return _rootArray; } - + void startElement(void *ctx, const char *name, const char **atts) { CC_UNUSED_PARAM(ctx); @@ -140,15 +144,15 @@ public: { _curDict = &_rootDict; } - + _state = SAX_DICT; - + SAXState preState = SAX_NONE; if (! _stateStack.empty()) { preState = _stateStack.top(); } - + if (SAX_ARRAY == preState) { // add a new dictionary into the array @@ -163,7 +167,7 @@ public: (*preDict)[_curKey] = Value(ValueMap()); _curDict = &(*preDict)[_curKey].asValueMap(); } - + // record the dict state _stateStack.push(_state); _dictStack.push(_curDict); @@ -187,7 +191,7 @@ public: else if (sName == "array") { _state = SAX_ARRAY; - + if (_resultType == SAX_RESULT_ARRAY && _rootArray.empty()) { _curArray = &_rootArray; @@ -197,7 +201,7 @@ public: { preState = _stateStack.top(); } - + if (preState == SAX_DICT) { (*_curDict)[_curKey] = Value(ValueVector()); @@ -219,7 +223,7 @@ public: _state = SAX_NONE; } } - + void endElement(void *ctx, const char *name) { CC_UNUSED_PARAM(ctx); @@ -285,13 +289,13 @@ public: else (*_curDict)[_curKey] = Value(utils::atof(_curValue.c_str())); } - + _curValue.clear(); } _state = SAX_NONE; } - + void textHandler(void *ctx, const char *ch, int len) { CC_UNUSED_PARAM(ctx); @@ -299,18 +303,18 @@ public: { return; } - + SAXState curState = _stateStack.empty() ? SAX_DICT : _stateStack.top(); const std::string text = std::string((char*)ch,0,len); - + switch(_state) { - case SAX_KEY: - _curKey = text; - break; - case SAX_INT: - case SAX_REAL: - case SAX_STRING: + case SAX_KEY: + _curKey = text; + break; + case SAX_INT: + case SAX_REAL: + case SAX_STRING: { if (curState == SAX_DICT) { @@ -319,9 +323,9 @@ public: _curValue.append(text); } - break; - default: - break; + break; + default: + break; } } }; @@ -419,7 +423,7 @@ static tinyxml2::XMLElement* generateElementForObject(const Value& value, tinyxm node->LinkEndChild(content); return node; } - + // object is real if (value.getType() == Value::Type::FLOAT || value.getType() == Value::Type::DOUBLE) { @@ -434,8 +438,8 @@ static tinyxml2::XMLElement* generateElementForObject(const Value& value, tinyxm tinyxml2::XMLElement* node = doc->NewElement(value.asString().c_str()); return node; } - - + + // object is Array if (value.getType() == Value::Type::VECTOR) return generateElementForArray(value.asValueVector(), doc); @@ -475,7 +479,7 @@ static tinyxml2::XMLElement* generateElementForDict(const ValueMap& dict, tinyxm static tinyxml2::XMLElement* generateElementForArray(const ValueVector& array, tinyxml2::XMLDocument *pDoc) { tinyxml2::XMLElement* rootNode = pDoc->NewElement("array"); - + for(const auto &value : array) { tinyxml2::XMLElement *element = generateElementForObject(value, pDoc); if (element) @@ -636,38 +640,38 @@ unsigned char* FileUtils::getFileDataFromZip(const std::string& zipFilePath, con unsigned char * buffer = nullptr; unzFile file = nullptr; *size = 0; - - do + + do { CC_BREAK_IF(zipFilePath.empty()); - + file = unzOpen(zipFilePath.c_str()); CC_BREAK_IF(!file); - + int ret = unzLocateFile(file, filename.c_str(), 1); CC_BREAK_IF(UNZ_OK != ret); - + char filePathA[260]; unz_file_info fileInfo; ret = unzGetCurrentFileInfo(file, &fileInfo, filePathA, sizeof(filePathA), nullptr, 0, nullptr, 0); CC_BREAK_IF(UNZ_OK != ret); - + ret = unzOpenCurrentFile(file); CC_BREAK_IF(UNZ_OK != ret); - + buffer = (unsigned char*)malloc(fileInfo.uncompressed_size); int CC_UNUSED readedSize = unzReadCurrentFile(file, buffer, static_cast(fileInfo.uncompressed_size)); CCASSERT(readedSize == 0 || readedSize == (int)fileInfo.uncompressed_size, "the file size is wrong"); - + *size = fileInfo.uncompressed_size; unzCloseCurrentFile(file); } while (0); - + if (file) { unzClose(file); } - + return buffer; } @@ -677,7 +681,7 @@ std::string FileUtils::getNewFilename(const std::string &filename) const // in Lookup Filename dictionary ? auto iter = _filenameLookupDict.find(filename); - + if (iter == _filenameLookupDict.end()) { newFileName = filename; @@ -723,7 +727,7 @@ std::string FileUtils::fullPathForFilename(const std::string &filename) { return filename; } - + // Already Cached ? auto cacheIter = _fullPathCache.find(filename); if( cacheIter != _fullPathCache.end() ) @@ -796,6 +800,7 @@ void FileUtils::addSearchResolutionsOrder(const std::string &order,const bool fr std::string resOrder = order; if (!resOrder.empty() && resOrder[resOrder.length()-1] != '/') resOrder.append("/"); + if (front) { _searchResolutionsOrderArray.insert(_searchResolutionsOrderArray.begin(), resOrder); } else { @@ -852,7 +857,7 @@ void FileUtils::addSearchPath(const std::string &searchpath,const bool front) std::string prefix; if (!isAbsolutePath(searchpath)) prefix = _defaultResRootPath; - + std::string path = prefix + searchpath; if (path.length() > 0 && path[path.length()-1] != '/') { @@ -867,7 +872,7 @@ void FileUtils::addSearchPath(const std::string &searchpath,const bool front) void FileUtils::setFilenameLookupDictionary(const ValueMap& filenameLookupDict) { - _fullPathCache.clear(); + _fullPathCache.clear(); _filenameLookupDict = filenameLookupDict; } @@ -893,7 +898,7 @@ void FileUtils::loadFilenameLookupDictionaryFromFile(const std::string &filename std::string FileUtils::getFullPathForDirectoryAndFilename(const std::string& directory, const std::string& filename) { - // get directory+filename, safely adding '/' as necessary + // get directory+filename, safely adding '/' as necessary std::string ret = directory; if (directory.size() && directory[directory.size()-1] != '/'){ ret += '/'; diff --git a/cocos/platform/CCFileUtils.h b/cocos/platform/CCFileUtils.h index ee097a3c53..275db8b947 100644 --- a/cocos/platform/CCFileUtils.h +++ b/cocos/platform/CCFileUtils.h @@ -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 * * @@ -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& 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& 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& 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& 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& 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 _fullPathCache; diff --git a/cocos/scripting/lua-bindings/manual/CCLuaEngine.cpp b/cocos/scripting/lua-bindings/manual/CCLuaEngine.cpp index 0cc0d2ba61..19fb31cd39 100644 --- a/cocos/scripting/lua-bindings/manual/CCLuaEngine.cpp +++ b/cocos/scripting/lua-bindings/manual/CCLuaEngine.cpp @@ -773,11 +773,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: @@ -950,7 +950,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; @@ -959,35 +959,35 @@ int LuaEngine::handleAssetsManagerEvent(ScriptHandlerMgr::HandlerType type,void* if (nullptr == eventData->nativeObject || nullptr == eventData->value) return 0; - LuaAssetsManagerEventData* assetsManagerData = static_cast(eventData->value); +// LuaAssetsManagerEventData* assetsManagerData = static_cast(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) diff --git a/cocos/scripting/lua-bindings/manual/CCLuaEngine.h b/cocos/scripting/lua-bindings/manual/CCLuaEngine.h index 10e4277960..f56f7704b6 100644 --- a/cocos/scripting/lua-bindings/manual/CCLuaEngine.h +++ b/cocos/scripting/lua-bindings/manual/CCLuaEngine.h @@ -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& func); int handleArmatureWrapper(ScriptHandlerMgr::HandlerType type,void* data); diff --git a/cocos/scripting/lua-bindings/manual/cocos2d/LuaScriptHandlerMgr.h b/cocos/scripting/lua-bindings/manual/cocos2d/LuaScriptHandlerMgr.h index 27c1473adb..7f334efa9b 100644 --- a/cocos/scripting/lua-bindings/manual/cocos2d/LuaScriptHandlerMgr.h +++ b/cocos/scripting/lua-bindings/manual/cocos2d/LuaScriptHandlerMgr.h @@ -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, diff --git a/cocos/scripting/lua-bindings/manual/extension/lua_cocos2dx_extension_manual.cpp b/cocos/scripting/lua-bindings/manual/extension/lua_cocos2dx_extension_manual.cpp index 48a3eda657..f4b6548a7c 100644 --- a/cocos/scripting/lua-bindings/manual/extension/lua_cocos2dx_extension_manual.cpp +++ b/cocos/scripting/lua-bindings/manual/extension/lua_cocos2dx_extension_manual.cpp @@ -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(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; } diff --git a/cocos/scripting/lua-bindings/manual/extension/lua_cocos2dx_extension_manual.h b/cocos/scripting/lua-bindings/manual/extension/lua_cocos2dx_extension_manual.h index 44a9a86cd2..9144cdb868 100644 --- a/cocos/scripting/lua-bindings/manual/extension/lua_cocos2dx_extension_manual.h +++ b/cocos/scripting/lua-bindings/manual/extension/lua_cocos2dx_extension_manual.h @@ -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; diff --git a/cocos/scripting/lua-bindings/script/cocos2d/Cocos2dConstants.lua b/cocos/scripting/lua-bindings/script/cocos2d/Cocos2dConstants.lua index 41dc89d60d..9164bf30eb 100644 --- a/cocos/scripting/lua-bindings/script/cocos2d/Cocos2dConstants.lua +++ b/cocos/scripting/lua-bindings/script/cocos2d/Cocos2dConstants.lua @@ -207,6 +207,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 @@ -476,7 +509,6 @@ cc.KeyCodeKey = cc.KeyCode = { - } for k,v in ipairs(cc.KeyCodeKey) do @@ -485,6 +517,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, diff --git a/extensions/Android.mk b/extensions/Android.mk index 2603f2f3d2..d7d4f2777e 100644 --- a/extensions/Android.mk +++ b/extensions/Android.mk @@ -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 \ diff --git a/extensions/CMakeLists.txt b/extensions/CMakeLists.txt index b5b057e8c2..fd212cba4e 100644 --- a/extensions/CMakeLists.txt +++ b/extensions/CMakeLists.txt @@ -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 diff --git a/extensions/assets-manager/AssetsManagerEx.cpp b/extensions/assets-manager/AssetsManagerEx.cpp new file mode 100644 index 0000000000..66cb676c13 --- /dev/null +++ b/extensions/assets-manager/AssetsManagerEx.cpp @@ -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 +#include +#include + +#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->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 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 diff --git a/extensions/assets-manager/AssetsManagerEx.h b/extensions/assets-manager/AssetsManagerEx.h new file mode 100644 index 0000000000..8e2afcc769 --- /dev/null +++ b/extensions/assets-manager/AssetsManagerEx.h @@ -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 +#include +#include + +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; + + //! The reference to the local assets + const std::unordered_map *_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 _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 _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__) */ diff --git a/extensions/assets-manager/CCEventAssetsManagerEx.cpp b/extensions/assets-manager/CCEventAssetsManagerEx.cpp new file mode 100644 index 0000000000..ba2c0f8d2f --- /dev/null +++ b/extensions/assets-manager/CCEventAssetsManagerEx.cpp @@ -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 +#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 diff --git a/extensions/assets-manager/CCEventAssetsManagerEx.h b/extensions/assets-manager/CCEventAssetsManagerEx.h new file mode 100644 index 0000000000..a94b39b1e6 --- /dev/null +++ b/extensions/assets-manager/CCEventAssetsManagerEx.h @@ -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__) */ diff --git a/extensions/assets-manager/CCEventListenerAssetsManagerEx.cpp b/extensions/assets-manager/CCEventListenerAssetsManagerEx.cpp new file mode 100644 index 0000000000..99045c2e06 --- /dev/null +++ b/extensions/assets-manager/CCEventListenerAssetsManagerEx.cpp @@ -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& 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& callback) +{ + bool ret = false; + + _AssetsManagerEx = AssetsManagerEx; + _onAssetsManagerExEvent = callback; + + auto func = [this](EventCustom *event) -> void + { + EventAssetsManagerEx *eventAssetsManagerEx = dynamic_cast(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 \ No newline at end of file diff --git a/extensions/assets-manager/CCEventListenerAssetsManagerEx.h b/extensions/assets-manager/CCEventListenerAssetsManagerEx.h new file mode 100644 index 0000000000..03693d49ee --- /dev/null +++ b/extensions/assets-manager/CCEventListenerAssetsManagerEx.h @@ -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& 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& callback); + +protected: + static const std::string LISTENER_ID; + + std::function _onAssetsManagerExEvent; + + const AssetsManagerEx *_AssetsManagerEx; + + //friend class luaEventListenerAssetsManagerEx; +}; + +NS_CC_EXT_END + +#endif /* defined(__cocos2d_libs__CCEventListenerAssetsManagerEx__) */ diff --git a/extensions/assets-manager/Downloader.cpp b/extensions/assets-manager/Downloader.cpp new file mode 100644 index 0000000000..2b5bb638f2 --- /dev/null +++ b/extensions/assets-manager/Downloader.cpp @@ -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 +#include +#include +#include + +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 = 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 = 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 = 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 ptr = shared_from_this(); + Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{ + if (!ptr.expired()) + { + std::shared_ptr 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 = 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 = 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 = 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 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 = 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 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 = 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 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 = 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 diff --git a/extensions/assets-manager/Downloader.h b/extensions/assets-manager/Downloader.h new file mode 100644 index 0000000000..55fb405c3e --- /dev/null +++ b/extensions/assets-manager/Downloader.h @@ -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 +#include +#include +#include + +NS_CC_EXT_BEGIN + +class CC_EX_DLL Downloader : public std::enable_shared_from_this +{ +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; + 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 DownloadUnits; + + typedef std::function ErrorCallback; + typedef std::function ProgressCallback; + typedef std::function 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 _files; + + std::vector _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__) */ diff --git a/extensions/assets-manager/Manifest.cpp b/extensions/assets-manager/Manifest.cpp new file mode 100644 index 0000000000..370c14c581 --- /dev/null +++ b/extensions/assets-manager/Manifest.cpp @@ -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 + +#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 bGroups = b->getGroups(); + std::unordered_map 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 Manifest::genDiff(const Manifest *b) const +{ + std::unordered_map diff_map; + std::unordered_map bAssets = b->getAssets(); + + std::string key; + Asset valueA; + Asset valueB; + std::unordered_map::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 searchPaths = FileUtils::getInstance()->getSearchPaths(); + std::vector::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& Manifest::getGroups() const +{ + return _groups; +} + +const std::unordered_map& Manifest::getGroupVerions() const +{ + return _groupVer; +} + +const std::string& Manifest::getGroupVersion(const std::string &group) const +{ + return _groupVer.at(group); +} + +const std::unordered_map& 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(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 writer(buffer); + _json.Accept(writer); + + std::ofstream output(filepath, std::ofstream::out); + if(!output.bad()) + output << buffer.GetString() << std::endl; +} + +NS_CC_EXT_END \ No newline at end of file diff --git a/extensions/assets-manager/Manifest.h b/extensions/assets-manager/Manifest.h new file mode 100644 index 0000000000..adebf3e404 --- /dev/null +++ b/extensions/assets-manager/Manifest.h @@ -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 +#include +#include + +#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 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& getGroups() const; + + /** @brief Gets all groups version. + */ + const std::unordered_map& 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& 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 _groups; + + //! The versions of all local group [Optional] + std::unordered_map _groupVer; + + //! The version of local engine + std::string _engineVer; + + //! Full assets list + std::unordered_map _assets; + + //! All search paths + std::vector _searchPaths; + + rapidjson::Document _json; +}; + +NS_CC_EXT_END +#endif /* defined(__Manifest__) */ diff --git a/extensions/cocos-ext.h b/extensions/cocos-ext.h index 6f742b7046..9ff891ed60 100644 --- a/extensions/cocos-ext.h +++ b/extensions/cocos-ext.h @@ -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__ */ diff --git a/templates/cocos2dx_files.json b/templates/cocos2dx_files.json index 3352af24e8..cc022fdac9 100644 --- a/templates/cocos2dx_files.json +++ b/templates/cocos2dx_files.json @@ -1165,6 +1165,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", diff --git a/tests/cpp-tests/CMakeLists.txt b/tests/cpp-tests/CMakeLists.txt index 2f9ee37b04..f8a92032d0 100644 --- a/tests/cpp-tests/CMakeLists.txt +++ b/tests/cpp-tests/CMakeLists.txt @@ -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 diff --git a/tests/cpp-tests/Classes/AppDelegate.cpp b/tests/cpp-tests/Classes/AppDelegate.cpp index 707872191c..5b29f2290c 100644 --- a/tests/cpp-tests/Classes/AppDelegate.cpp +++ b/tests/cpp-tests/Classes/AppDelegate.cpp @@ -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 diff --git a/tests/cpp-tests/Classes/ExtensionsTest/AssetsManagerExTest/AssetsManagerExTest.cpp b/tests/cpp-tests/Classes/ExtensionsTest/AssetsManagerExTest/AssetsManagerExTest.cpp new file mode 100644 index 0000000000..b1044ccb7c --- /dev/null +++ b/tests/cpp-tests/Classes/ExtensionsTest/AssetsManagerExTest/AssetsManagerExTest.cpp @@ -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(); +} diff --git a/tests/cpp-tests/Classes/ExtensionsTest/AssetsManagerExTest/AssetsManagerExTest.h b/tests/cpp-tests/Classes/ExtensionsTest/AssetsManagerExTest/AssetsManagerExTest.h new file mode 100644 index 0000000000..a9c78b3162 --- /dev/null +++ b/tests/cpp-tests/Classes/ExtensionsTest/AssetsManagerExTest/AssetsManagerExTest.h @@ -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__) */ diff --git a/tests/cpp-tests/Classes/ExtensionsTest/ExtensionsTest.cpp b/tests/cpp-tests/Classes/ExtensionsTest/ExtensionsTest.cpp index 10d31a2900..196fea607d 100644 --- a/tests/cpp-tests/Classes/ExtensionsTest/ExtensionsTest.cpp +++ b/tests/cpp-tests/Classes/ExtensionsTest/ExtensionsTest.cpp @@ -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 callback; } g_extensionsTests[] = { + { "AssetsManagerExTest", [](Ref* sender) { + AssetsManagerExLoaderScene *scene = new AssetsManagerExLoaderScene(); + scene->runThisTest(); + } }, { "NotificationCenterTest", [](Ref* sender) { runNotificationCenterTest(); } }, { "CCControlButtonTest", [](Ref *sender){ diff --git a/tests/cpp-tests/Resources/Manifests/AMTestScene1/project.manifest b/tests/cpp-tests/Resources/Manifests/AMTestScene1/project.manifest new file mode 100644 index 0000000000..43780bcece --- /dev/null +++ b/tests/cpp-tests/Resources/Manifests/AMTestScene1/project.manifest @@ -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" : [ + ] +} \ No newline at end of file diff --git a/tests/cpp-tests/Resources/Manifests/AMTestScene2/project.manifest b/tests/cpp-tests/Resources/Manifests/AMTestScene2/project.manifest new file mode 100644 index 0000000000..5d6bbfeedd --- /dev/null +++ b/tests/cpp-tests/Resources/Manifests/AMTestScene2/project.manifest @@ -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" : [ + ] +} \ No newline at end of file diff --git a/tests/cpp-tests/Resources/Manifests/AMTestScene3/project.manifest b/tests/cpp-tests/Resources/Manifests/AMTestScene3/project.manifest new file mode 100644 index 0000000000..b074d0e46f --- /dev/null +++ b/tests/cpp-tests/Resources/Manifests/AMTestScene3/project.manifest @@ -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" : [ + ] +} \ No newline at end of file diff --git a/tests/cpp-tests/proj.android/jni/Android.mk b/tests/cpp-tests/proj.android/jni/Android.mk index 566aec556f..0c5593c36a 100644 --- a/tests/cpp-tests/proj.android/jni/Android.mk +++ b/tests/cpp-tests/proj.android/jni/Android.mk @@ -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 \ diff --git a/tests/cpp-tests/proj.win32/cpp-tests.vcxproj b/tests/cpp-tests/proj.win32/cpp-tests.vcxproj index 37a51472fc..b5eef9c801 100644 --- a/tests/cpp-tests/proj.win32/cpp-tests.vcxproj +++ b/tests/cpp-tests/proj.win32/cpp-tests.vcxproj @@ -145,6 +145,7 @@ + @@ -334,6 +335,7 @@ + diff --git a/tests/cpp-tests/proj.win32/cpp-tests.vcxproj.filters b/tests/cpp-tests/proj.win32/cpp-tests.vcxproj.filters index 158b6fab9c..c663bfcba7 100644 --- a/tests/cpp-tests/proj.win32/cpp-tests.vcxproj.filters +++ b/tests/cpp-tests/proj.win32/cpp-tests.vcxproj.filters @@ -331,6 +331,9 @@ {54a30b92-ddfb-420e-908b-886c23c21cf1} + + {f6c2eb6d-ad25-4287-a2a4-1c0d7382a49f} + {a0b90b93-5575-4729-9afc-8a3839b378ac} @@ -876,6 +879,9 @@ Classes\BillBoardTest + + Classes\ExtensionsTest\AssetsManagerExTest + Classes\LightTest @@ -1622,6 +1628,9 @@ Classes\BillBoardTest + + Classes\ExtensionsTest\AssetsManagerExTest + Classes\LightTest diff --git a/tests/lua-tests/project/CMakeLists.txt b/tests/lua-tests/project/CMakeLists.txt index 89a1a1f15b..46acb178b1 100644 --- a/tests/lua-tests/project/CMakeLists.txt +++ b/tests/lua-tests/project/CMakeLists.txt @@ -2,7 +2,7 @@ set(APP_NAME lua-tests) set(SAMPLE_SRC Classes/AppDelegate.cpp - Classes/lua_assetsmanager_test_sample.cpp + Classes/lua_assetsmanagerex_test_sample.cpp ) if(LINUX) diff --git a/tests/lua-tests/project/Classes/AppDelegate.cpp b/tests/lua-tests/project/Classes/AppDelegate.cpp index a9185b6afe..f5955dfff7 100644 --- a/tests/lua-tests/project/Classes/AppDelegate.cpp +++ b/tests/lua-tests/project/Classes/AppDelegate.cpp @@ -2,7 +2,7 @@ #include "AppDelegate.h" #include "CCLuaEngine.h" #include "audio/include/SimpleAudioEngine.h" -#include "lua_assetsmanager_test_sample.h" +#include "lua_assetsmanagerex_test_sample.h" #include "lua_module_register.h" using namespace CocosDenshion; @@ -30,22 +30,20 @@ bool AppDelegate::applicationDidFinishLaunching() // register lua engine LuaEngine* pEngine = LuaEngine::getInstance(); ScriptEngineManager::getInstance()->setScriptEngine(pEngine); - +#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID ||CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC) LuaStack* stack = pEngine->getLuaStack(); - stack->setXXTEAKeyAndSign("2dxLua", strlen("2dxLua"), "XXTEA", strlen("XXTEA")); lua_State* L = stack->getLuaState(); - lua_module_register(L); - #if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID ||CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC) + lua_getglobal(L, "_G"); if (lua_istable(L,-1))//stack:...,_G, { - register_assetsmanager_test_sample(L); + register_assetsmanagerex_test_sample(stack->getLuaState()); } lua_pop(L, 1); - #endif +#endif pEngine->executeScriptFile("src/controller.lua"); diff --git a/tests/lua-tests/project/Classes/lua_assetsmanager_test_sample.h b/tests/lua-tests/project/Classes/lua_assetsmanager_test_sample.h deleted file mode 100644 index 967593de71..0000000000 --- a/tests/lua-tests/project/Classes/lua_assetsmanager_test_sample.h +++ /dev/null @@ -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 diff --git a/tests/lua-tests/project/Classes/lua_assetsmanager_test_sample.cpp b/tests/lua-tests/project/Classes/lua_assetsmanagerex_test_sample.cpp similarity index 97% rename from tests/lua-tests/project/Classes/lua_assetsmanager_test_sample.cpp rename to tests/lua-tests/project/Classes/lua_assetsmanagerex_test_sample.cpp index f76157f0d4..057597d494 100644 --- a/tests/lua-tests/project/Classes/lua_assetsmanager_test_sample.cpp +++ b/tests/lua-tests/project/Classes/lua_assetsmanagerex_test_sample.cpp @@ -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); diff --git a/tests/lua-tests/project/Classes/lua_assetsmanagerex_test_sample.h b/tests/lua-tests/project/Classes/lua_assetsmanagerex_test_sample.h new file mode 100644 index 0000000000..26b17f7c01 --- /dev/null +++ b/tests/lua-tests/project/Classes/lua_assetsmanagerex_test_sample.h @@ -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 diff --git a/tests/lua-tests/project/proj.android/jni/Android.mk b/tests/lua-tests/project/proj.android/jni/Android.mk index 877693bf1b..d15b34c04a 100644 --- a/tests/lua-tests/project/proj.android/jni/Android.mk +++ b/tests/lua-tests/project/proj.android/jni/Android.mk @@ -8,7 +8,7 @@ LOCAL_MODULE_FILENAME := liblua_tests LOCAL_SRC_FILES += main.cpp \ ../../Classes/AppDelegate.cpp \ - ../../Classes/lua_assetsmanager_test_sample.cpp + ../../Classes/lua_assetsmanagerex_test_sample.cpp LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../Classes diff --git a/tests/lua-tests/project/proj.win32/lua-tests.win32.vcxproj b/tests/lua-tests/project/proj.win32/lua-tests.win32.vcxproj index 897aaa6864..5d1c482f76 100644 --- a/tests/lua-tests/project/proj.win32/lua-tests.win32.vcxproj +++ b/tests/lua-tests/project/proj.win32/lua-tests.win32.vcxproj @@ -181,13 +181,13 @@ xcopy "$(ProjectDir)..\..\..\cpp-tests\Resources" "$(ProjectDir)..\..\res" /e /Y - + - + diff --git a/tests/lua-tests/project/proj.win32/lua-tests.win32.vcxproj.filters b/tests/lua-tests/project/proj.win32/lua-tests.win32.vcxproj.filters index e6cf7a3008..75e078a166 100644 --- a/tests/lua-tests/project/proj.win32/lua-tests.win32.vcxproj.filters +++ b/tests/lua-tests/project/proj.win32/lua-tests.win32.vcxproj.filters @@ -15,7 +15,7 @@ win32 - + Classes @@ -29,7 +29,7 @@ win32 - + Classes diff --git a/tests/lua-tests/src/AssetsManagerTest/AssetsManagerModule.lua b/tests/lua-tests/src/AssetsManagerExTest/AssetsManagerExModule.lua similarity index 100% rename from tests/lua-tests/src/AssetsManagerTest/AssetsManagerModule.lua rename to tests/lua-tests/src/AssetsManagerExTest/AssetsManagerExModule.lua diff --git a/tests/lua-tests/src/AssetsManagerExTest/AssetsManagerExTest.lua b/tests/lua-tests/src/AssetsManagerExTest/AssetsManagerExTest.lua new file mode 100644 index 0000000000..8e61ed38da --- /dev/null +++ b/tests/lua-tests/src/AssetsManagerExTest/AssetsManagerExTest.lua @@ -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 diff --git a/tests/lua-tests/src/AssetsManagerTest/AssetsManagerTest.lua b/tests/lua-tests/src/AssetsManagerTest/AssetsManagerTest.lua deleted file mode 100644 index 4d6000557a..0000000000 --- a/tests/lua-tests/src/AssetsManagerTest/AssetsManagerTest.lua +++ /dev/null @@ -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 diff --git a/tests/lua-tests/src/mainMenu.lua b/tests/lua-tests/src/mainMenu.lua index 63a4a55dba..7c4268ad96 100644 --- a/tests/lua-tests/src/mainMenu.lua +++ b/tests/lua-tests/src/mainMenu.lua @@ -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 }, diff --git a/tools/tolua/cocos2dx_extension.ini b/tools/tolua/cocos2dx_extension.ini index 162ebddd02..adee569872 100644 --- a/tools/tolua/cocos2dx_extension.ini +++ b/tools/tolua/cocos2dx_extension.ini @@ -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 From 4e9e40363f7d8a38b01376ec1348e87e6de1dbea Mon Sep 17 00:00:00 2001 From: pandamicro Date: Thu, 9 Oct 2014 19:55:11 +0800 Subject: [PATCH 2/2] Feature #4977: Fix an issue about checkUpdate function --- extensions/assets-manager/AssetsManagerEx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/assets-manager/AssetsManagerEx.cpp b/extensions/assets-manager/AssetsManagerEx.cpp index 66cb676c13..3011e81bda 100644 --- a/extensions/assets-manager/AssetsManagerEx.cpp +++ b/extensions/assets-manager/AssetsManagerEx.cpp @@ -375,7 +375,7 @@ AssetsManagerEx::State AssetsManagerEx::getState() const void AssetsManagerEx::downloadVersion() { - if (_updateState != State::PREDOWNLOAD_VERSION) + if (_updateState > State::PREDOWNLOAD_VERSION) return; std::string versionUrl = _localManifest->getVersionFileUrl();