Introducing the Humble API

The Humble API is currently a small collection of C-based functions that allow your game to be played via asm.js on the Humble Widget. The current API covers file syncing, player sizing, asset streaming, and demo handling. This API is provided in the form of an emscripten js library. Currently this library is only available for asm.js games.

What is an emscripten js Library?

Emscripten’s library system uses a method of registering available functions (implemented in pure javascript) that can be used by the emscripten linker when no implementation is found. For an example, let’s start with something simple. Your game uses the chdir function, which in emscripten is implemented in the src/library.js as a javascript function. So the emscripten linker pulls in that one function because you used it, and then it looks for a chdir__deps definition to see what else is needed because of your use of chdir, in this case the filesystem and error system. In order to add extra libraries, we need to add the following link option when building our game:

--js-library path/to/my_library.jslib



For the Humble API, this is actually two libraries: the Humble API and the CLOUDFS system. For cmake builds, this is done easily by adding a JS_LIBS to the CreateProgram call. (see the https://github.com/HumbleDeveloper/ASMJSDemo/ application):



JS_LIBS

lib/humble/library_humble.jslib

lib/humble/library_cloudfs.jslib



This will automatically pull in the required Humble API core when you use any Humble API method.

Initializing the Humble API

Early on in your application startup (ideally the first line) you should call the humble_init() function. Currently the only thing this function does is ensure that the required bits of the API and CLOUDFS are pulled in.

#ifdef USE_HUMBLE_API

#include "humble_api.h"

#endif

int main(int argc, char* argv[]) {

#ifdef USE_HUMBLE_API

humble_init();

#endif

return 0;

}



Using the Humble Cloud Filesystem

For the Humble Mozilla Bundle, we built out a cloud filesystem infrastructure. This was built as two pieces: the emscripten filesystem driver and a backend driver. The library_cloudfs.js file contains the emscripten driver that will interface with the backend driver that is injected into the web shell. This allows us at Humble to easily upgrade and replace the actual implementation without needing to rebuild all asm.js games. The Cloud filesystem also has a local cache of files in the user’s local browser storage. This allows for faster play on the same machine over multiple sessions, as the files do not need to be resynchronized if they are current.

To use the Humble Cloud Filesystem, you need to make sure you are calling humble_init() in your game code, saving user files to the correct location, and calling humble_syncfs() whenever you need to make the changes persistent.

Save Locations

When running your asm.js on Humble’s site, we create a /user_data/ directory that is CLOUDFS-enabled before your game runs. Any content that you want persistent should be saved to this directory. Any temporary data should be saved to an alternate location such as /user_temp/. Be sure to create the directory first. The CLOUDFS library uses modification timestamps to determine what has changed.

Persisting Files

Files are not automatically synced — your game code must tell the Humble API when to synchronize the files by calling humble_syncfs(). Try to call this once when saving a group of files instead of calling it after each file is written. Also, it is a very good idea to close your files before calling humble_syncfs(), as the entire syncing process is performed in the background.

Demo Games

For demo versions of games, or when running in the widget, the CLOUDFS library is disabled and all files are treated as temporary and never persisted.

Respecting the Humble Widget Size

Running your game in a browser has some additional restraints on sizes. You don’t really want to default to a 1440 by 900 sized resolution, as that would use huge amounts of space on the web page that the player or widget has been embedded in. The Humble API allows for a configurable windowed mode size via the humble_get_player_size() method. The usage of this method should be like this:



int width = 0, height = 0;

if (humble_get_player_size(&width, &height) == 0) {

// the player is not enforcing a certain size, use a sane default.

width = 640;

height = 480;

}



Now you can safely create your game window to the width and height specified. And this will work perfectly outside of the Humble Widget and simply return 0.

Streaming Music and Other Assets

When your asm.js game is hosted on our site, it is delivered via a CDN. As such, any async requests to the server for other assets need to be handled specially so that the correct file and parameters are fetched. To help this, the Humble API includes humble_fetch_asset_data(..) function. This function triggers off an asynchronous background fetch of the requested relative path and will execute a callback method when it finishes.

class AudioManager {

static void musicPlayCB(void *arg, void* buff, int buff_size) {

AudioManager *self = reinterpret_cast<AudioManager*>(arg);

// now play the audio that is in buff. You must copy the contents of buff as it will be released once this callback returns.

}

static void musicErrorCB(void *arg) {

AudioManager *self = reinterpret_cast<AudioManager*>(arg);

// do something to handle the error

}

void playMusic(const char* track) {

humble_fetch_asset_data(track, (void*)this, &musicPlayCB, &musicErrorCB);

}



One nice feature of the humble_fetch_asset_data method is that it will work on the Humble CDN as well as on any regular hosted service, so there is no reason to not use this method to fetch relative assets.

Handling Demo Builds of Games

The Humble API provides a single, simple method to denote the end of the demo. This should only be used in your demo builds of the game, and you should ensure that your game stops meaningfully after you call this method (for example post an up-sell screen).

bool done = false;

void loop_iteration(Game* g) {

if (done) return;}void mark_demo_end() {

done = true;

humble_demo_ended();

}



When running outside of the Humble Widget, your game will hit the “done being true” check and not allow the game to be played anymore. However, while execution is within the Humble Widget, the call to humble_demo_ended() will stop your game’s main loop entirely, exit fullscreen mode, and present an overlay with an appropriate call to action.

Wrapping Things Up

The Humble API right now is very simple but covers the fundamentals! Over the course of this year, we will be adding in more functionality so developers can do more with Humble API and their games.