protocol

Updated for v0.3.3

A protocol describes a list of properties and their binary types.

All Entities, LocalMessages, Messages, and Commands must have a protocol defined before nengi can send them over the network.

Example protocol

{
    name: nengi.String,
    foo: nengi.Boolean,
    bar: nengi.Float32,
    baz: nengi.UInt8
}

Nengi uses protocols to:

Syntax for interpolation

{
    x: { type: nengi.Float32, interp: true },
    y: { type: nengi.Float32, interp: true },
    hp: { type: nengi.UInt8, interp: true },
    armorType: nengi.UInt4 // same as armorType: { type: nengi.UInt4, interp: false },
}

The above syntax enables interpolation for x, y, hp, but not for armorType.

Note: almost every game with continuous movement should enable interpolation for x and y (disable it for discrete movement).

Note2: setting x, y to be types of Integers and interpolating usually makes for better network performance than leaving x,y as Float64.

Syntax for Arrays

{
    arrayOfUInt16s: { type: nengi.UInt16, indexType: nengi.UInt8 },
    arrayOfStrings: { type: nengi.String, indexType: nengi.UInt8 }
}

The syntax above shows how to make typed arrays of any nengi type. The indexType is the maximum array length, so UInt8 means the array can a length of up to 255. There is no support for mixed types in arrays.

Syntax for subprotocols

{
    subObject: Foo.protocol,
    arrayOfSubObjects: { type: Foo.protocol, indexType: nengi.UInt32 }
}

It is possible to create a protocol that itself refers to a protocol or an array of protocols. While this sounds like an awesome feature, it is not my intent that this be used very much. I pretty much put this feature in just for the sake of sending tile maps.

Map data example:

var tileProtocol = {
    tileType: nengi.UInt4,
    waterAmount: nengi.UInt8,
    lavaAmount: nengi.UInt8,
    isBlocked: nengi.Boolean
}
var mapProtocol = {
    tiles: { type: tileProtocol, indexType: nengi.UInt32 }
}

// example object that could be sent/received using the above protocols:
var map = [
    { tileType: 0, waterAmount: 23, lavaAmount: 0, isBlocked: false },
    { tileType: 0, waterAmount: 26, lavaAmount: 0, isBlocked: false },
    { tileType: 1, waterAmount: 0, lavaAmount: 0, isBlocked: true },
]

Special rules for Entities

Entities, due to the complexity of being scanned for changes, may not have the following within their protocols:

This doesn't mean that an entity can't have contain an array, it just means that an entity can't have an array that it contains be automatically networked.

Attaching protocols to Entities, LocalMessages, Messages, and Commands

In the current version of nengi the protocol is added as a static object on the constructor of the type that it describes:

class PlayerCharacter {
    constructor() {
        this.x = 0
        this.y = 0
        this.hitpoints = 100
        this.name = 'Alex'
        this.foo = true
        this.bar = 23.424923
    }
}
PlayerCharacter.protocol = {
    x: nengi.Number,
    y: nengi.Number,
    hitpoints: nengi.Number,
    name: nengi.String,
    foo: nengi.Boolean,
    bar: nengi.Float32,
}

Syntax for nested properties

{
    'velocity.x': nengi.Number,
    'velocity.y': nengi.Number,
    'foo.bar.baz': nengi.String,
}

// the above would work for an object such as:
var obj = {
    velocity: { 
        x: 5, 
        y: 6
    },
    foo: {
        bar: {
            baz: 'hello'
        }
    }
}

Nested properties are limited to a depth of 3.