Skip to content

Instantly share code, notes, and snippets.

@darkdukey
Last active August 29, 2015 14:10
Show Gist options
  • Save darkdukey/fbb1c4f6aaae3764740b to your computer and use it in GitHub Desktop.
Save darkdukey/fbb1c4f6aaae3764740b to your computer and use it in GitHub Desktop.
Cocos PackageManager

Package Manager

Package Manager provides a way for developers to easily extend cocos2d-x with plugins

Core Features:

  • Modularize coocs2d-x enable developers to customize the engine for their own game
  • Developers can search, manage and install plugins
  • Update project for the developers when install, remove or update the plugin
  • Developers can share their plugin with others

enter image description here

~

Use Cases

Search Plugin

$ cd myapp

$ cocos search leaderboard
searching "leaderboard" in repository ... ok
> leaderboard 1.2 (Zhan Huang)
> leaderboard-gamecenter 1.0 (Zhan Huang)
done.

search will list all the plugins contains the search keyword, each search result contains three parts

  • Plugin Name
  • Version
  • Maintainer

~

Check Plugin detail

$ cd myapp

$ cocos info leaderboard
get description for plugin "leaderboard" ... ok

name: leaderboard
version: 1.2
updated: 2014/11/11
author: Zhan Huang

This plugin allows people to be ranked based on their scores.

info followed by the fullname of the plugin

~

Install Plugin

$ cd myapp

$ cocos install leaderboard
downloading plugin "leaderboard 1.2 (Zhan Huang)" ... ok
installing ...
> add file src/packages/leaderboard/init.lua
> add file src/packages/leaderboard/Leaderboard.lua
done.

For script plugin, we just need to copy the scripts to related folder

For C/C++ plugin, we have to update project file

$ cd myapp

$ cocos install gamecenter
downloading plugin "gamecenter 1.0 (Peng Li)" ... ok
installing ...
> add file native/packages/gamecenter/GameCenter.mm
> add file native/packages/gamecenter/GameCenter.h
> add file native/packages/gamecenter/GameCenterIOS.mm
> add file native/packages/gamecenter/GameCenterIOS.h
> add file native/packages/gamecenter/GameCenterMac.mm
> add file native/packages/gamecenter/GameCenterMac.h
> add file native/packages/gamecenter/GameCenterLuabinding.cpp
> add file native/packages/gamecenter/GameCenterLuabinding.h
> updating project file native/proj.ios_mac/packages.xcodeproj
done.

~

Delete Plugin

$ cd myapp

$ cocos uninstall gamecenter
uninstalling ...
> remove file native/packages/gamecenter/GameCenter.mm
> remove file native/packages/gamecenter/GameCenter.h
> remove file native/packages/gamecenter/GameCenterIOS.mm
> remove file native/packages/gamecenter/GameCenterIOS.h
> remove file native/packages/gamecenter/GameCenterMac.mm
> remove file native/packages/gamecenter/GameCenterMac.h
> remove file native/packages/gamecenter/GameCenterLuabinding.cpp
> remove file native/packages/gamecenter/GameCenterLuabinding.h
> updating project file native/proj.ios_mac/packages.xcodeproj
done.

~

List installed plugin

$ cd myapp

$ cocos list
list all installed plugins ...
> leaderboard 1.2 (Zhan Huang)
> gamecenter 1.0 (Peng Li)
done.

~

Update plugin

$ cd myapp

$ cocos upgrade leaderboard
searching latest version for plugin "leaderboard" ... ok
downloading "leaderboard 1.3 (Zhan Huang)" ... ok
installing ...
> update file src/packages/leaderboard/init.lua
> update file src/packages/leaderboard/leaderboard.lua
> add file src/packages/leaderboard/leaderboardExt.lua
done.

~

Update to specific version

If developer needs a certain version of the plugin, they can use this command to download this certain version

For example, we have the latest 1.3 version of leaderboard, and now we need to revert back to 1.2 version

$ cd myapp

$ cocos install leaderboard 1.2
downloading plugin "leaderboard 1.2 (Zhan Huang)" ... ok
installing ...
> replace file src/packages/leaderboard/init.lua
> replace file src/packages/leaderboard/leaderboard.lua
> remove file src/packages/leaderboard/leaderboardExt.lua
done.

~

Create Plugin project

Developer can use this command to create a new plugin project

$ cocos create-plugin myplugin
> create directory "myplugin"
> create file "README.md"
> create file "config.json"
> create file "install.json"
> create file "src/init.lua"
> create file "src/myplugin.lua"
done.

For C/C++ plugin, you need -native

$ cocos create-plugin -native myplugin
$ cocos create-plugin myplugin
> create directory "myplugin"
> create file "README.md"
> create file "config.json"
> create file "install.json"
> create file "native/myplugin.cpp"
> create file "native/myplugin.h"
done.

Developer can add whatever code thats required for their plugin based on the plugin project

~

Plugin Structure

Each plugin contains following parts

  • config.json Plugin metadata file:

    {
        "name": "PluginName",
        "version": "1.1",
        "engine": "supported cocos2d-x version",
        "author": "auther",
        "url": "website or repo",
        "description": "Whether article spirits new her covered hastily
        sitting her.\n\nMoney witty books nor son add. Chicken age had evening
        believe but pretend mrs. At missed advice my it no sister. Miss told
        ham dull knew see she spot near can. Spirit her entire her called.",
        "depends": [
            {"name": "Name of the dependency", "version": "version number of dependency"},
            {"name": "Name of the dependency", "version": "version number of dependency"}
        ]
    }
  • install.json Installation file:

    [
        {"command": "command", param ... },
        {"command": "command", param ... }
    ]
  • src/, native/ source code directories

~

config.json

config.json defines the metadata file for a plugin:

  • name: Plugin name must start with letters, "-","_" and numbers are allowed, case insensitive. Must be unique from all the plugins

  • version: Version number is two numbers, new version number must be bigger than the old version

  • engine: supported engine version, it can support multiple version like 3.1-3.2

    supported engine version can only be final or release version, in another word, it has to have a version number.

    • major.minor: specific version
    • major.minor+:higher version
    • major.minor-major.minor:between two version

    Here are some examples:

    • 3.3+: cocos2d-x 3.3 or higher
    • 2.2.1-2.2.5: between cocos2d-x 2.2.1 to 2.2.5
  • author: the author of the plugin。

  • url: website of the plugin, can be a url to the github repo

  • description: Description for the plugin。

  • depends: dependencies。

    Some plugin will require other plugins in order to work, that when depends come in:

    "depends": [
        {"name": "plugin name", "version": "version"},
        {"name": "plugin name", "version": "version"}
    ]

    For example leaderboard-gamecenter requires leaderboard version 1.0 or higher,then the depends setting will be:

    "depends": [
        {"name": "leaderboard", "version": "1.0+"}
    ]

    Version number rule is the same with engine

~

install.json

install.json Tells package manager how to install plugin

install.json contains serials of commands to install a plugin

[
    {"command": "command", param ... },
    {"command": "command", param ... }
]

Following are the supported commands

  • copy_files: copy files to the specified path

    {
        "command": "copy_files",
        "from": "src/*",
        "to": "src/packages/leaderboard/",
    }

    cory all the files from <Plugin>/src/ to <Project>/src/packages/leaderboard, it will copy all the subfolder within it.

    copy_files also supports wild card

    {
        "command": "copy_files",
        "from": "native/LeaderboardGameCenter.*",
        "to": "native/packages/leaderboard-gamecenter/"
    }

    this will copy all the files match LeaderboardGameCenter.* to project folder

  • update_project: update the project file

    plugin that contains C/C++ or Objective-C/Java code, requires update_project to update the project files:

    {
        "command": "update_project",
        "add_files": [
            "native/packages/leaderboard-gamecenter/*.mm",
        ],
        "platform": ["ios", "mac"]
    }

    The code above will add the specific files to the project file.

    • All the source file of a plugin will be added into a group with the same name as the plugin.

      For example the above command will create a group named leaderboard-gamecenter(because they belongs to plugin leaderboard-gamecenter) and then add all the source files under it.

    • When adding the new files, it will also update header search paths

    • use platform field for platform specific commands, if platform is not specified, the command will perform on all platforms.

    • For android, if you want to import a Java package, you need to use add_packages param, and specify the path that contains the source code. Note, Because in Java, package name needs to be the same as the folder of the source code. So you don't need to specify the full path here. such as com/cocos2d/org are not required

    • If you want to add libraries to the project use add_libs param

~

Here is an example of how to create install.json for flurry SDK

[
    {
        "command": "copy_files",
        "from": "native/*",
        "to": "native/packages/flurry/"
    },
    {
        "command": "copy_files",
        "from": "src/*",
        "to": "src/packages/flurry/"
    },
    {
        "command": "update_project",
        "add_files": [
            "native/packages/flurry/*.cpp",
            "native/packages/flurry/*.h"
        ]
    },
    {
        "command": "update_project",
        "add_files": [
            "native/packages/flurry/*.mm"
        ],
        "add_libs": [
            "native/package/flurry/ios/libflurry.a"
        ],
        "platform": "ios"
    },
    {
        "command": "update_project",
        "add_packages": [
            "native/packages/flurry/java/",
        ],
        "add_libs": [
            "native/package/flurry/android/libflurry.so"
        ],
        "platform": "android"
    }
]

Here is what the script performs:

  • Copy Flurry code and libs to <Project>/native/packages/flurry/
  • Copy script code into <Project>/src/packages/flurry/
  • Update ios/android project, add required code and libraries.

~

Resolve dependency and conflict

Here is what happens when install a plugin with dependencies:

  1. Iterate through all the plugins
  2. Check if a plugin is already installed 2.1 not installed: add to the list to install 2.2 installed: check the version, if not match the requirement, add to the list to install
  3. Download the config.json of all the dependencies, and repeat setp 2 and add plugins to install list
  4. Make sure plugins install list don't have duplicate entries
  5. Stop the installation and notify user if a conflict has been detected

After installation list is prepared, we can start install all the plugins

~

Use Plugin (Scripting)

All the scripting for the plugin goes to src folder

To use leaderboard simply call

local leaderboard = cc.load("leaderboard")

cc.load() implementation:

cc.load = function(pluginName)
    -- all ways load packages.pluginname.init to initialze the plugin
    local packageName = string.format("packages.%s.init", pluginName)
    return require(packageName)
end

since cc.load() will always call init function, plugins always need to implement this function for initialization.

~

Use Plugin (Native)

Compare to scripting native plugins will be a bit more complicated

Based on the commands in install.json, it will copy the source files and update the project, make sure the updated project still compiles

We'll need to change cocos2d-x's project structure a little bit. We'll need to add a packages folder for the plugins

enter image description here

this plugins project will use CMake to generate projects, so developers don't need to manually modify the project.

~

Publishing

After creating the plugin, developers needs to publish their plugin

Because developers could update their plugin constantly, a centralized server to download everything maybe is not a good idea.

So if a developer wants to submit their plugin, there are two ways to do it.

  • Submit a git hub repo, with proper tagging

    For example, a github repo url coule be https://github.com/dualface/leaderboard/ with tag 1.2, the url should be

    https://github.com/dualface/leaderboard/tree/1.2

  • Submit a url, with config.json as well as the zip contains all the files plugin requires

    For example http://mysite.com/downloads/

    we'll download http://mysite.com/downloads/config.json first, and based on name and version we can decide which zip to download

    if name is leaderboard, version is 1.2, then the final zip url should be http://mysite.com/downloads/leaderboard-1.2.zip

Developer must submit their plugin to the repo server. and then user will be able to search and use them.

Before publish your plugin, you can use following command to validate the plugin.

$ cd myplugin
$ cocos validate-plugin

It will check if config.json and install.json are valid.

~

After submit plugin to the Package Manager, package manager server will valid if the url of the plugin is valid.

~

Maintain Plugins

Everytime a plguin updates, developer just need to prepare the latest version and submit to the Package Manager server.

~

PackageManager server API

To support cocos command, Package Manager server will require the following API:

  • ?search=keyword

    If we want to search leaderboard, then the query will be:

    http://repo.cocos.org/?search=leaderboard

    Return value of json will be:

    {
        "ok": true,
        "result": [
            {
                "name": "leaderboard",
                "version": "1.2",
                "author": "Zhan Huang"
            },
            {
                "name": "leaderboard-gamecenter",
                "version": "1.0",
                "author": "Zhan Huang"
            }
        ]
    }
  • ?info=plugin name

    If we want to get the details of leaderboard,the query should be:

    http://repo.cocos.org/?info=leaderboard

    Return value of json will be:

    {
        "name": "leaderboard",
        "version": "1.2",
        "author": "Zhan Huang",
        "description": "XXXXX",
        "url": "https://github.com/dualface/leaderboard/tree/1.2"
    }

    Package Manager didn't have download command, because cocos install will use the detail info to findout the download url. ~

Implementation

The biggest challenge will be the client side

cocos command will need the following function

  • download plugin
  • Analyze install.json file to install plugin
  • Update project file for C/C++/Java project file
  • Maintain what plugin and which version user already installed.
  • Handle upgrading plugin.
  • Handle delete plugin and clean up

Some idea:

  • each project will have a plugins.json file to record the name and version of installed plugin
  • copy scripting file directly to src/pacakges/pluginname folder
  • For C/C++ file, copy to native/packages/pluginname folder
  • Use CMake to update project file.
  • Delete the old plugin when upgrading.

~

The Package Manager System

Package Manager System contains the following parts

  • A website for plugin submission
  • A server side app for query plugin info.
  • New commands for cocos command line.

-EOF-

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment