Developer Guide - nodeGame/nodegame GitHub Wiki

nodeGame Developer Guide

Installation and Overview

Install the latest version of nodeGame using the command:

node nodegame-installer.js @dev (for more info see Getting Started).

Inside the node_modules folder you will find several dependencies. Specifically, nodeGame is composed by following submodules:

  • JSUS: Functional programming helper library shared across all submodules
  • NDDB: Javascript database shared by client, window, widgets and server
  • nodegame-server: Handles all connections and game rooms
  • nodegame-client: Core library for all connecting clients (remotely), but also bots and logics
  • nodegame-window: Handles the manipulation of the page
  • nodegame-widgets: Collection of reusable components
  • nodegame-requirements: Contains collection of functions for handling testing of requirements.
  • nodegame-game-template: Collection of default files used if a game does not implement them.
  • nodegame-monitor: Handles the monitor interface
  • nodegame-generator: Generates new games from a boiler plate.

The following modules are experimental or outdated:

  • shelf.js: handles settings of cookies and access to local storage
  • nodegame-db: generic interface to a database
  • nodegame-mongodb: interface to MongoDb
  • descil-mturk: interface to the ETH Zurich Decision Science Laboratory API.

Preparation

Git-hooks enable some automatic code-style enforcement and automatic doc-building on committing.

Copy the file git-hooks/pre-commit in every submodule git folder, for example for nodegame-server it would be:

cp git-hooks/pre-commit node_modules/nodegame-server/.git/hooks/

Making Changes and Building nodeGame

NodeGame server caches a copy of the file that is sent to the clients upon connection under nodegame-server/public/javascripts/nodegame-full.js. So, if you make changes to any of the following modules:

  • JSUS
  • NDDB
  • nodegame-server
  • nodegame-client
  • nodegame-window
  • nodegame-widgets

you will need to rebuild the copy sent to the clients. To do so, start the server with the -b (build) option, followed by the name of the modules you have changed. Examples:

If you made a change to a widget you need to run:

node launcher -b widgets

If you made a change to a widget and the window:

node launcher -b widgets,window

If you just made a change to the client, you do not need to pass extra params:

node launcher -b

Debugging

JavaScript / Node.JS have a built-in debugger. Follow the links below for further information.

Furthermore, nodeGame can be executed in debug-mode if the flag node.debug is set to TRUE. In debug-mode all errors will be thrown. Otherwise, nodeGame will try to catch them.

NodeGame Events

See the list of all nodeGame events.

Writing Code

The source code of nodeGame follows the following conventions.

Whitespace

  • Indenting uses four spaces, tabs are never used.
  • Lines do not have any trailing whitespace.
  • Source files have one newline at the end.
  • In control flow statements, the opening parenthesis follows a space (see examples in Braces).
  • There is no space between a function name and the opening parenthesis of its parameters.

Braces

  • Opening braces are on the same line as their corresponding control flow statements.
  • Closing braces are on their own line.
  • When a control flow statement is broken into multiple lines, it is followed by an empty line.
  • Braces may only be left out if the single statement it would contain is on the same line as the leading control flow statement (see bottom of example).

Examples:

function control(a, b) {  // No space after 'control'.
    if (a >= b) {
        console.log('Greater or equal');
    }
    else if (a < b) {  // Note brace arrangement around 'else'.
        console.log('Less');
    }
    else {
        console.log('NaN');
    }

    while (veryLongCondition1 &&
           veryLongCondition2) {  // Empty line following.

        doThing(function(e) {   // No space after 'function'.
            console.log(e);
        });
    }
}

if (x < 0) x = 0;  // OK

if (x === 5) {
  x = 8;  // OK
}

if (x > 9)
    x = 9;  // NOT OK!

Logic

  • Strict in-/equality !==/=== is used instead of !=/== wherever possible.
  • All "for-in" loops check hasOwnProperty on each iteration.
  • Variable shadowing should be avoided.

Examples:

function printProps(obj) {
    var i;

    for (i in obj) {
        if (obj.hasOwnProperty(i)) {  // Important.
            console.log(i, obj[i] === null ? 'N/A' : obj[i]);
        }
    }

    function() {
        var obj;  // Shadowing NOT OK!
    }();
}

Naming

  • Variable names use camelCase.
  • Constant names use UNDERSCORED_UPPER_CASE.
  • Class names use PascalCase.
  • Names should be descriptive.

Miscellaneous

  • Lines are at most 80 characters long.
  • Strings use single quotes by default, double quotes if more convenient.
  • All variables are declared at the top of their scope and are assigned to separately.
  • Messages in new exceptions start with the class name suffixed with a dot (if inside a class), followed by the function name and a colon. The description starts with a lower-case letter and ends with a period.
  • Comments are generally on lines of their own, before the code they concern, starting with a capital letter and ending with a punctuation symbol, usually a period.

Examples:

function sumArray(array) {
    var i, sum;  // All declarations on top, no assignments.

    // Check input.
    if (!array || 'number' !== typeof array.length) {
        throw new TypeError('sumArray: array.length must be number.');
    }

    // Sum up elements.
    sum = 0;
    for (i = 0; i < array.length; ++i) {
        sum += array[i];
    }

    console.log("Sum of 'array': " + sum + '.');
    return sum;
}

MyClass.prototype.fail = function() {
    throw new Error('MyClass.fail: always throws.');
}

Writing Documentation

nodeGame uses docker to generate its documentation. In addition to the above practices used in the code, the following rules apply for doc comments.

For an example of these rules used in practice, see the documentation of nodegame-server.

Sections

Docker pages use a hierarchy of sections, with different levels denoted by #, ##, ### etc. A nodeGame source file has the following structure:

# ClassName [filename without extension]
## ClassName constructor
### ClassName.field
### ...
## ClassName methods
### ClassName.method
### ...

For example:

# Circle
## Circle constructor
### Circle.posX
### Circle.posY
### Circle.radius
## Circle methods
### Circle.setPosition
### Circle.getArea
### Circle.draw

In special cases, more sections can be added.

Documentation comments

After the section definition, the rest of the doc comment describes the documented field or method.

  • The first line is a short summary, beginning with a capital letter and ending without a period, surrounded by empty lines. For methods, this should start with a verb in third person.
  • Next, an optional longer description follows. The sentences in the descriptions end in a punctuation symbol.

Field example:

/**
 * ### Circle.radius
 *
 * Radius of the circle
 *
 * The radius is half the diameter.
 */
this.radius = radius;

For methods:

  • Parameter descriptions start with a capital letter, the last sentence has no period.
  • Descriptions of optional parameters begin with "Optional.".
  • @param, @return sections that span multiple lines have the extra lines indented by two spaces.
  • There is a blank line before @return sections.

Method example:

/**
 * ### Circle.setPosition
 *
 * Sets the circle's position
 *
 * @param {number} x The new x position
 * @param {number} y The new y position
 * @param {boolean} rel Optional. Whether to add to the old position
 *   instead of using absolute coordinates. Default: FALSE
 *
 * @return {boolean} TRUE on success, FALSE on failure
 */
Circle.prototype.setPosition = function(x, y, rel) { ... }
  • Horizontal lines (---) are never used.

Bulleted lists

  • All bulleted lists in documentation comments are surrounded by empty lines.
  • Lists in @param and @return are indented by two spaces.

Example:

/**
 * ### Circle.draw
 *
 * Draws the circle
 *
 * Can draw to either:
 *
 * - The console
 * - An HTML canvas
 *
 * @param {object} options Drawing options with the following fields:
 *
 *   - target (string): Where to draw
 *   - color (string): Optional. Color with which to draw
 *
 * @return {object} An object containing the results with the
 *   following fields:
 *
 *   - success (boolean): Whether the drawing was successful
 */
Circle.prototype.draw = function(options) { ... }

Building documentation

After changing code and especially documentation comments for a module, it is recommended to re-build the HTML documentation with node bin/make.js doc.

This is done automatically with every git commit if the developer's the pre-commit Git-hook was copied over from nodegame/git-hooks/.

To get the updated documentation onto a module's GitHub page (e.g. http://nodegame.github.io/nodegame-server/docs/index.js.html), execute the following command in the master branch:

git checkout gh-pages && git merge master && git pull && git push && git checkout master

For convenience, create an alias in your Git configuration file (~/.gitconfig on Linux):

...
[alias]
    pushpages = !git checkout gh-pages && git merge master && \
      git pull && git push && git checkout master
...