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 }
}

Whenever indexType appears in the configuration for a property, it denotes that the property's value is an array. The 'type' will be the type for the values in the array, and the 'indexType' will be the type for the array length. So selecting an indexType of UInt8 means the array will have a length between 0 and 255. If you do not want to deal with this level of microoptimization, just pick UInt32 for the indexType, which should be plenty big. Mixed types (an array that has different types of numbers, booleans, strings, etc) are not supported.

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.