nengiConfig

Updated for v1.0.0

The nengiConfig contains the common language that allow the client and server to communicate. The nengiConfig contains a list of all the protocols that will be used in a game. It also contains varying tickrate-related information and misc config options.

For most games, the only thing to change is the UPDATE_RATE, and then add protocols as the game is developed.

Example nengiConfig

var config = {
    UPDATE_RATE: 20,
    USE_HISTORIAN: true,
    ID_BINARY_TYPE: nengi.UInt16,
    TYPE_BINARY_TYPE: nengi.UInt8,
    ID_PROPERTY_NAME: 'nid',
    TYPE_PROPERTY_NAME: 'ntype',
    protocols: {    
        entities: [],
        localMessages: [],
        messages: [],
        commands: [],
        basics: []
    }
}

UPDATE_RATE

The serverside tickrate for your game in ticks per second. UPDATE_RATE must be correct for clientside interpolation. Note: no part of nengi verifies that your game code invokes instance.update() at UPDATE_RATE times per second, that's up to you! (see demos)

USE_HISTORIAN

The historian is a serverside feature that stores copies of entity state for several ticks thus allowing instances to rewind state for lag compensationed collision checks. If you do not need this you may as well turn it off, and disabling the historian is currently the only way to support tens of thousands of entities. A future version of nengi will offer more granular control over the historian so that some entities may have a history while others do not.

About id, type, and their binary types

When entities, localMessages, mesasges, and commands are added to clients or instances they are automatically stamped with some extra data. Example:

class Dragon {
    constructor() {
        this.x = 50
        this.y = 50
    }
}
Dragon.protocol = ...

var dragon = new Dragon()
/* dragon looks like this: { x: 50, y: 50 } */

instance.addEntity(dragon)
/* now dragon may look like this: { nid: 64353, ntype: 33, x: 50, y: 50, protocol: ... } */

Because nengi mutates objects, the nengiConfig is an attempt to give you control over these changes by choosing the property names (nid, ntype).

ID_BINARY_TYPE

The binary type of the 'id' property associated with Entity. This affects the maximum number of entities that can be added to a nengi instance at one time. The default of UInt16 allows for up to 65536 entities. Exceeding this will throw 'IdPool overflow' error from the within the instance. Reducing this number (if applicable for your game) will help optimized bandwidth usage.

TYPE_BINARY_TYPE

The binary type of the 'type' property associated with Entity, Message, LocalMessage, and Command. This affects the maximum number different types of Entities, Messages, etc. The default of UInt8 allows for up to 256 TYPES of Entity, Message, etc. This is a total per category, not combined. If your game needs more than 256 types for any single category (wow!), increase this binary type.

ID_PROPERTY_NAME

The property nengi uses for id; nengi demos default to using 'nid' meaning "nengi id" or "network id." Using the entity.nid is very common in code, as it is the main way to perform actions on a specific entity from the client.

TYPE_PROPERTY_NAME

The property nengi uses for type; nengi demos default to use 'ntype' meaning "nengi type" or "network type." Using the entity.ntype directly is relatively uncommon, as all entities have a friendly name attached to their protocol : entity.protocol.name // e.g. PlayerCharacter.

protocols

A list of all protocols used for your game by category. Here is a real example from a small demo game:

var protocols = {
    
    entities: [
        ['ExampleEntity', ExampleEntity], // where ExampleEntity is a class
        ['Bullet', Bullet]
    ],

    localMessages: [], 

    messages: [
        ['Identity', Identity]
    ],

    commands: [
        ['WASDCommand', WASDCommand]
    ],

    basics: [] // see Basics section

}

// Here's what one of those required classes above looks like:
//server/entity/ExampleEntity.js
class ExampleEntity {
    constructor() {
        this.x = 0
        this.y = 0
    }
}
ExampleEntity.protocol = { // protocol is a static object on the class
    x: { type: nengi.Float32, interp: true },
    y: { type: nengi.Float32, interp: true }
}

Gotchas

Classes may only appear in the protocols section once -- for example a message that sometimes needs to be sent globally, and other times needs to be sent locally, cannot be added to both sections. This may change in the future, but for now the only solution is create two classes.

The syntax for adding protocol is ['protocolName', class]. Currently there is no support for anything other than the OOP pattern of using a Class with a protocol.

"basics" protocol section

The basics section is used to contain subProtocols, which are protocols that are used within other protocols. Remember these cannot be protocols that are already defined (this will likely be improved in a future release).