-
Notifications
You must be signed in to change notification settings - Fork 291
Packages
Packages are work in progress. Please report Sprite Builder bugs and feature requests to [Sprite Builder's github page](https://github.com/Sprite Builder/Sprite Builder/). Cocos2d bugs and feature requests to Cocos2d's github home. If you need help using packages the [Sprite Builder forum](http://forum.Sprite Builder.com/) or Cocos2d forum are good places to start. We are looking forward to getting your feedback.
There will be an example app and updated Sprite Builder project templates soon.
A package is a zipped folder created with Sprite Builder. The general idea is to add content to an app during runtime which is located on a remote host. A package can be used to add any kind of file to an app. A feature is to patch existing assets.
Within an app a package is unique by it's name and resolution. OS is implicitly determined.
Central organ of the packages module is the CCPackageManager
. It's supposed to be used and accessed as a singleton. Use the class method sharedManager
to get hold of it.
- I. Download a package from a remote host using http
- II. Unzipping after download
- III. Install: Copy contents of unzipped archive to the installation folder, usually
/Library/Caches/Packages/<package-identifier>
(See naming convention) - IV. Enable in Cocos2d: Include new packages in search path, reload all sprite sheets and filename lookups
(Click to enlarge)
First of all you will need a package to be downloadable on a host. Note down the URL. Let's assume a package archive name: DLC-iOS-phonehd.zip
(See below for naming conventions). The full URL is http://foobar.com/packages/DLC-iOS-phonehd.zip
. OS is iOS.
To make the package available in your app the only the following lines are needed:
// 1.
[CCPackageManager sharedManager].baseURL = [NSURL URLWithString:@"http://foobar.com/packages"];
// 2.
[[CCPackageManager sharedManager] downloadPackageWithName:@"DLC"
resolution:@"phonehd"
// 3.
enableAfterDownload:YES]
- Is setting the baseURL to the host, note that the package file name is removed. This is a one time setup, especially helpful if you have several packages ready for download. This method also returns a freshly created
CCPackage
instance if needed. - This schedules a downlod as mentioned in the general flow of the Package Manager
- If
enableAfterDownload:
is set to NO the package is installed but not enabled in cocos2d
Note: The final URL is created as the OS is known.
If a package is already installed and enabled you will need to load and persist the package data.
A good place to load packages is after cocos2d has been configured, for example in application:didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
// 1.
[self setupCocos2dWithOptions:cocos2dSetup];
// 2.
[[CCPackageManager sharedManager] loadPackages];
...
}
- Always set up cocos2d first, this is just the example call of the template project.
- The package manager loads the packages from disk(NSUserDefaults), reinstate paused downloads, restarts unfinished unzipping tasks and finally enables packages if they were enabled last time the app ran
Note: Calling the loadPacakges method more than once won't do anything.
As of this writing the dev has to take care of calling the method to persist packages. This may change. A recommended way is to persist whenever the app closes or is being terminated. Using the following example should ensure a persisted packages state.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
// 1.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(savePackages)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(savePackages)
name:UIApplicationWillTerminateNotification
object:nil];
...
}
// 2.
- (void)savePackages
{
[[CCPackageManager sharedManager] savePackages];
}
- Default notification center used to trigger the savePackage method when the app closes or terminates
- Wrapper for the savePackages method for notification events
Processing packages is time consuming and therefore done in the background. The CCPackageManagerDelegate
protocol provides several methods to let you know when a certain step is finished(or failed). For fine grained feedback on downloads and unzipping there are optional delegate methods to give a regular update on progress.
There are more code exmamples at the end of this article for more use cases
The <package identifier>
should follow the naming convention
<name>-<os>-<resolution>
- name: freely chosen name, try to avoid white spaces
- os: iOS, Android, Mac
- resolution: usually phone, phonehd, tablet, tablethd
A zipped package is named <name>-<os>-<resolution>.zip
A zipped package should contain only one folder with the naming convention of the package identifier. That folder is the package folder. That folder can contain anything you'd like to integrate in your app. Usually the content will similarly structured like the Published folder created by Sprite Builder. That means there should be a spriteFrameFileList.plist
file located at the top level within the package folder if you want to include sprite sheets in your package.
A fileLookup.plist
should be present if files have been converted by Sprite Builder to a different format, like a wave file converted to ogg for Android. This file is usually generated by Sprite Builder during publishing.
The configCocos2d.plist
is not used at the moment.
An example for a package called DLC targeted for iOS, resolution is phonehd:
DLC-iOS-phonehd.zip
/DLC-iOS-phonehd
/sounds
mow.mp4
/resources-phonehd
spritesheet_spaceships.png
spritesheet_spaceships.plist
non_spritesheet_sprite.png
spriteFrameFileList.plist
fileLookup.plist
configCocos2d.plist
Packages created with Sprite Builder meet all these requirements.
Patching content is simply using the same asset name as in the main bundle. The ordering of Cocos2d search paths is important. Usually the package manager will make packages take precedence over the main published resources folder. See also notes below regarding taking effect of patched scenes/sprites.
-
It is not recommended to install more than one resolution of a package on a device. This can lead to unwanted search path ordering and wrong assets being loaded.
-
After installing and enabling a package patched assets won't take effect in present scenes residing in memory. You will have to reload those scenes/assets.
-
From Apple's documentation regarding the
/Library/Caches
folde default location for installed packages:- Use this directory to write any app-specific support files that your app can re-create easily. Your app is generally responsible for managing the contents of this directory and for adding and deleting files as needed.
- In iOS 2.2 and later, the contents of this directory are not backed up by iTunes. In addition, iTunes removes files in this directory during a full restoration of the device.
- On iOS 5.0 and later, the system may delete the Caches directory on rare occasions when the system is very low on disk space. This will never occur while an app is running. However, you should be aware that iTunes restore is not necessarily the only condition under which the Caches directory can be erased.
-
/Library/Application Support
might also be a good place to install packages to, the contents of this directory are backed up by iTunes.
If you're in need to get hold of a CCPackage
instance before starting any download, you can create that with the initializers found in CCPackage.h
. Add the package to the package manager by calling addPackage:
. The package is now registerd in the package manager and will be persisted. You can then start the download with CCPackageManager
's downloadPackage:enableAfterDownload:
method.
This can be handy if like to write a full fledged UI for package management.
If you just want to disable a package without deleting it permanently from disk use CCPackageManager
's disablePackage:
method. Scenes and sprites will have to reloaded to make changes visible. Same applies to enabling, use enablePackage:
If packages are in a CDN there may be no baseURL and even a filename might not be available in the URL of a package. There are two ways to get this done:
Use CCPackage
's initializer
- (instancetype)initWithName:(NSString *)name
resolution:(NSString *)resolution
remoteURL:(NSURL *)remoteURL;
and provide the full URL aby baseURL set will be ignored for this package. Then add and start downloading with the package manager.
A shortcut approach is to use CCPackageManager
's
- (CCPackage *)downloadPackageWithName:(NSString *)name
resolution:(NSString *)resolution
remoteURL:(NSURL *)remoteURL
enableAfterDownload:(BOOL)enableAfterDownload;
to start downloading immediately.
CCPackageManager
provides several methods to pause and resume single packages as well as all downloads.
Set CCPackageManager
's property unzippingQueue
. Default is the global low priority queue.
Implement the optional delegate method passwordForPackageZipFile:
to provide a password for a certain package.
A: A server has to provide the Content-Length
header to let the download know how big it actually will be. However this does not prevent the download from downloading more if more data is sent. If the response does provide a lenght, then total bytes is 0. Current downloaded bytes is not affected by this.
A: A server has to support range requests. If that is not the case a paused download can only be restarted since the server will always send the full package.
A: This is tricky: The SSZipArchive module and the underlying unzip.c do not test if the archive is password protected. The table of contents of a zip file can ALWAYS be read so SSZipArchive will actually create folders and files with 0 bytes or some meaninigless bytes. There is no workaround except putting alot of work into the unzip module. Test properly. You can always add a textfile to your package and read the contents. If the contents of that file compares to something you hardcore unzipping was successful.
A: CCFileUtils is the bottlenet. Although it caches filelookups it will still search recursively in all search paths(Packages and Main Resources) for a non cached asset. At the moment there is only advice: Is the package containing additional content, then enable it only when needed. CCFileUtils may get some love in the future to become more performant.
S