@gameable/net
Classes
abstract BaseTransport
The base every transport extends: the listener lists and the closed latch.
A subclass feeds frames in with deliver, reports the far side going away with finish, and says how to tear down its own pipe in shutdown.
Example
ts
import { BaseTransport } from 'gameable/net';
class Echo extends BaseTransport {
readonly bufferedAmount = 0;
send(data: string | Uint8Array): void {
if (!this.isClosed) this.deliver(data);
}
protected shutdown(): void {}
}
const echo = new Echo();
echo.onMessage((data) => console.log(data));
echo.send('hello');Implements
Constructors
Constructor
ts
new BaseTransport(): BaseTransport;Returns
Properties
bufferedAmount
ts
abstract readonly bufferedAmount: number;Bytes queued to send and not yet written out; a sender can skip a binary frame while this is high.
Implementation of
Accessors
isClosed
Get Signature
ts
get protected isClosed(): boolean;Whether the transport has closed, from either end.
Returns
boolean
Methods
close()
ts
close(reason?): void;Closes the transport. Safe to call twice; the close listeners fire once.
Parameters
| Parameter | Type | Default value |
|---|---|---|
reason | string | 'closed' |
Returns
void
Implementation of
deliver()
ts
protected deliver(data): void;Hands one received frame to every message listener; nothing after close.
Parameters
| Parameter | Type |
|---|---|
data | TransportData |
Returns
void
finish()
ts
protected finish(reason): void;Latches closed and fires the close listeners, once however often it is called.
Parameters
| Parameter | Type |
|---|---|
reason | string |
Returns
void
onClose()
ts
onClose(cb): void;Registers a listener for the close, called once with the reason. Registering after close does nothing.
Parameters
| Parameter | Type |
|---|---|
cb | (reason) => void |
Returns
void
Implementation of
onMessage()
ts
onMessage(cb): void;Registers a listener for every frame received. Registering after close does nothing.
Parameters
| Parameter | Type |
|---|---|
cb | (data) => void |
Returns
void
Implementation of
send()
ts
abstract send(data): void;Sends one frame. After the transport is closed this does nothing.
Parameters
| Parameter | Type |
|---|---|
data | TransportData |
Returns
void
Implementation of
shutdown()
ts
abstract protected shutdown(reason): void;Tears down the underlying pipe; called once, by the first close.
Parameters
| Parameter | Type |
|---|---|
reason | string |
Returns
void
abstract FrameCodec
Little-endian reads over a byte array, and the frame-kind check every binary frame starts with.
Example
ts
class PingCodec extends FrameCodec {
decode(bytes: Uint8Array): number | null {
return this.isKind(bytes, 9, 5) ? this.u32(bytes, 1) : null;
}
}Extended by
Constructors
Constructor
ts
new FrameCodec(): FrameCodec;Returns
Methods
clampInt()
ts
protected clampInt(
value,
min,
max
): number;value rounded and clamped, for an integer wire field.
Parameters
| Parameter | Type | Description |
|---|---|---|
value | number | Any number. |
min | number | The least result. |
max | number | The greatest result. |
Returns
number
The rounded value in [min, max]; 0 for a non-finite value.
f32()
ts
protected f32(bytes, offset): number;The little-endian 32-bit float at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with four bytes in range. |
Returns
number
The float, which may be NaN or infinite on a hostile frame.
i16()
ts
protected i16(bytes, offset): number;The signed 16-bit integer at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with two bytes in range. |
Returns
number
A value in [-32768, 32767].
i32()
ts
protected i32(bytes, offset): number;The signed 32-bit integer at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with four bytes in range. |
Returns
number
A signed 32-bit value.
i8()
ts
protected i8(bytes, offset): number;The signed byte at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An in-range offset. |
Returns
number
A value in [-128, 127].
isKind()
ts
protected isKind(
bytes,
kind,
length,
exact?
): boolean;Whether bytes is a frame of kind and the right length.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
bytes | Uint8Array | undefined | The received frame. |
kind | number | undefined | The expected first byte. |
length | number | undefined | The frame's length, or its least length when exact is false. |
exact | boolean | true | Whether the length must match exactly. |
Returns
boolean
True when the length fits and the first byte is kind.
u16()
ts
protected u16(bytes, offset): number;The unsigned 16-bit integer at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with two bytes in range. |
Returns
number
A value in [0, 65535].
u32()
ts
protected u32(bytes, offset): number;The unsigned 32-bit integer at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with four bytes in range. |
Returns
number
An unsigned 32-bit value.
u8()
ts
protected u8(bytes, offset): number;The unsigned byte at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An in-range offset. |
Returns
number
A value in [0, 255].
InputCodec
Encodes and decodes input frames. Owns the one header object decode returns, so a decode allocates nothing.
Example
ts
const keys = () => new Uint32Array(KEY_WORDS);
const snapshot: MutableInputSnapshot = {
down: keys(), pressed: keys(), released: keys(),
mods: { shift: false, ctrl: false, alt: false, meta: false, capsLock: false, numLock: false },
mouse: { dx: -12, dy: 0, wheel: 0, buttons: 0, pressed: 0, released: 0 },
focused: true,
};
const codec = new InputCodec();
const out = new DataView(new ArrayBuffer(INPUT_FRAME_BYTES));
const bytes = codec.encode(out, 1, snapshot);
const header = codec.decode(new Uint8Array(out.buffer, 0, bytes), snapshot); // { seq: 1 }Extends
Constructors
Constructor
ts
new InputCodec(): InputCodec;Returns
Inherited from
Methods
clampInt()
ts
protected clampInt(
value,
min,
max
): number;value rounded and clamped, for an integer wire field.
Parameters
| Parameter | Type | Description |
|---|---|---|
value | number | Any number. |
min | number | The least result. |
max | number | The greatest result. |
Returns
number
The rounded value in [min, max]; 0 for a non-finite value.
Inherited from
decode()
ts
decode(bytes, into): InputHeader | null;Reads one input frame into into.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | Exactly one received frame. |
into | MutableInputSnapshot | The caller's record, written only when the frame is good. |
Returns
InputHeader | null
The frame's seq in an object reused by the next call, or null (with into untouched) when bytes is not exactly one input frame or a key array of into is shorter than KEY_WORDS.
encode()
ts
encode(
out,
seq,
snapshot
): number;Writes one input frame at the start of out.
Parameters
| Parameter | Type | Description |
|---|---|---|
out | DataView | The send buffer, owned by the caller. |
seq | number | The input sequence number; acks name it. |
snapshot | InputSnapshotLike | The step's input. |
Returns
number
Bytes written, or 0 (with nothing written) when out is too small.
f32()
ts
protected f32(bytes, offset): number;The little-endian 32-bit float at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with four bytes in range. |
Returns
number
The float, which may be NaN or infinite on a hostile frame.
Inherited from
i16()
ts
protected i16(bytes, offset): number;The signed 16-bit integer at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with two bytes in range. |
Returns
number
A value in [-32768, 32767].
Inherited from
i32()
ts
protected i32(bytes, offset): number;The signed 32-bit integer at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with four bytes in range. |
Returns
number
A signed 32-bit value.
Inherited from
i8()
ts
protected i8(bytes, offset): number;The signed byte at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An in-range offset. |
Returns
number
A value in [-128, 127].
Inherited from
isKind()
ts
protected isKind(
bytes,
kind,
length,
exact?
): boolean;Whether bytes is a frame of kind and the right length.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
bytes | Uint8Array | undefined | The received frame. |
kind | number | undefined | The expected first byte. |
length | number | undefined | The frame's length, or its least length when exact is false. |
exact | boolean | true | Whether the length must match exactly. |
Returns
boolean
True when the length fits and the first byte is kind.
Inherited from
u16()
ts
protected u16(bytes, offset): number;The unsigned 16-bit integer at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with two bytes in range. |
Returns
number
A value in [0, 65535].
Inherited from
u32()
ts
protected u32(bytes, offset): number;The unsigned 32-bit integer at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with four bytes in range. |
Returns
number
An unsigned 32-bit value.
Inherited from
u8()
ts
protected u8(bytes, offset): number;The unsigned byte at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An in-range offset. |
Returns
number
A value in [0, 255].
Inherited from
Quantizer
Position and rotation quantisation for the rows codec.
Example
ts
const quantizer = new Quantizer();
const mm = quantizer.position(1.2345); // 1235
const word = quantizer.packQuat(0, 0, 0, 1);
quantizer.unpackQuat(word, new Float32Array(4), 0);Constructors
Constructor
ts
new Quantizer(): Quantizer;Returns
Methods
packQuat()
ts
packQuat(
x,
y,
z,
w
): number;A rotation to its smallest-three word. The input is normalised first; a zero-length or non-finite quaternion encodes the identity.
Plain rounding of each lane can leave the rebuilt component nearly 2e-3 off, so the encoder tries the eight floor/ceil combinations of the three lanes and keeps the one whose worst component, rebuilt one included, is nearest: under 1e-3 for every rotation in a million-sample sweep.
Parameters
| Parameter | Type | Description |
|---|---|---|
x | number | Quaternion x. |
y | number | Quaternion y. |
z | number | Quaternion z. |
w | number | Quaternion w. |
Returns
number
The unsigned 32-bit word.
position()
ts
position(metres): number;Metres to whole millimetres.
Parameters
| Parameter | Type | Description |
|---|---|---|
metres | number | A position lane. |
Returns
number
Millimetres clamped to i32; 0 for a non-finite value.
unpackQuat()
ts
unpackQuat(
packed,
out,
offset
): void;A smallest-three word back to out[offset..offset+3] as xyzw. Any 32-bit word decodes to a unit quaternion, hostile ones included.
Parameters
| Parameter | Type | Description |
|---|---|---|
packed | number | The word off the wire. |
out | Float32Array | Receives x, y, z, w. |
offset | number | Where x goes in out. |
Returns
void
unposition()
ts
unposition(mm): number;Millimetres back to metres.
Parameters
| Parameter | Type | Description |
|---|---|---|
mm | number | A position lane off the wire. |
Returns
number
Metres.
RowsCodec
Encodes and decodes rows frames. Owns the one header object decode returns, so neither direction allocates.
Example
ts
const position = new Float32Array([1.5, 0, -2]);
const rotation = new Float32Array([0, 0, 0, 1]);
const scale = new Float32Array([1, 1, 1]);
const rows: RowSource = {
count: 1,
entity: () => 7,
flags: () => RowFlag.POSITION | RowFlag.ROTATION,
position: () => position,
rotation: () => rotation,
scale: () => scale,
};
const sink: RowSink = {
position: new Float32Array(3),
rotation: new Float32Array(4),
scale: new Float32Array(3),
row: (entity) => console.log(entity, sink.position),
};
const codec = new RowsCodec();
const out = new DataView(new ArrayBuffer(codec.frameBytes(rows)));
const bytes = codec.encode(out, 600, 12, rows);
codec.decode(new Uint8Array(out.buffer, 0, bytes), sink); // { frame: 600, ack: 12, count: 1, player: null }Extends
Constructors
Constructor
ts
new RowsCodec(): RowsCodec;Returns
Inherited from
Methods
clampInt()
ts
protected clampInt(
value,
min,
max
): number;value rounded and clamped, for an integer wire field.
Parameters
| Parameter | Type | Description |
|---|---|---|
value | number | Any number. |
min | number | The least result. |
max | number | The greatest result. |
Returns
number
The rounded value in [min, max]; 0 for a non-finite value.
Inherited from
decode()
ts
decode(bytes, sink): RowsHeader | null;Reads one rows frame, handing each row to sink.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | Exactly one received frame. |
sink | RowSink | Receives the rows, only once the whole frame has been checked. |
Returns
RowsHeader | null
The frame's header in an object reused by the next call (its player is the trailer, or null), or null (with the sink never called) when bytes is not exactly one well-formed rows frame: too short for its header or its rows, longer than its rows and not one whole trailer, another kind, a flag bit outside RowFlag or PlayerRowFlag, a non-finite scale or trailer lane, or sink arrays too short.
encode()
ts
encode(
out,
frame,
ack,
rows
): number;Writes one rows frame at the start of out; a non-finite scale lane is written as 1, one past the f32 range as its limit.
Parameters
| Parameter | Type | Description |
|---|---|---|
out | DataView | The send buffer, owned by the caller. |
frame | number | The authority's fixed-step counter. |
ack | number | The last input seq applied for the receiving player; also the trailer's seq. |
rows | RowSource | The rows to write, and rows.player's trailer after them when it is set. |
Returns
number
Bytes written, or 0 (with nothing written) when out is too small or rows.count is not an integer in [0, MAX_ROWS].
f32()
ts
protected f32(bytes, offset): number;The little-endian 32-bit float at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with four bytes in range. |
Returns
number
The float, which may be NaN or infinite on a hostile frame.
Inherited from
frameBytes()
ts
frameBytes(rows): number;The bytes encode would write; flag bits beyond RowFlag are ignored.
Parameters
| Parameter | Type | Description |
|---|---|---|
rows | RowSource | The rows to size. |
Returns
number
The frame's length.
i16()
ts
protected i16(bytes, offset): number;The signed 16-bit integer at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with two bytes in range. |
Returns
number
A value in [-32768, 32767].
Inherited from
i32()
ts
protected i32(bytes, offset): number;The signed 32-bit integer at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with four bytes in range. |
Returns
number
A signed 32-bit value.
Inherited from
i8()
ts
protected i8(bytes, offset): number;The signed byte at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An in-range offset. |
Returns
number
A value in [-128, 127].
Inherited from
isKind()
ts
protected isKind(
bytes,
kind,
length,
exact?
): boolean;Whether bytes is a frame of kind and the right length.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
bytes | Uint8Array | undefined | The received frame. |
kind | number | undefined | The expected first byte. |
length | number | undefined | The frame's length, or its least length when exact is false. |
exact | boolean | true | Whether the length must match exactly. |
Returns
boolean
True when the length fits and the first byte is kind.
Inherited from
u16()
ts
protected u16(bytes, offset): number;The unsigned 16-bit integer at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with two bytes in range. |
Returns
number
A value in [0, 65535].
Inherited from
u32()
ts
protected u32(bytes, offset): number;The unsigned 32-bit integer at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An offset with four bytes in range. |
Returns
number
An unsigned 32-bit value.
Inherited from
u8()
ts
protected u8(bytes, offset): number;The unsigned byte at offset.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | The frame, already length-checked. |
offset | number | An in-range offset. |
Returns
number
A value in [0, 255].
Inherited from
TextFrames
Text frame building and parsing for both directions.
Example
ts
const frames = new TextFrames();
const text = frames.buildClient({ t: 'ping', at: performance.now() });
const back = text === null ? null : frames.parseClient(text); // { t: 'ping', at: ... }Constructors
Constructor
ts
new TextFrames(): TextFrames;Returns
Methods
buildClient()
ts
buildClient(frame): string | null;A client frame as JSON text.
Parameters
| Parameter | Type | Description |
|---|---|---|
frame | ClientText | The frame to send. |
Returns
string | null
The text, or null when a msg payload is over the cap or not JSON, or the frame is over MAX_CLIENT_TEXT_BYTES.
buildServer()
ts
buildServer(frame): string | null;A server frame as JSON text.
Parameters
| Parameter | Type | Description |
|---|---|---|
frame | ServerText | The frame to send. |
Returns
string | null
The text, or null when a msg payload is over the cap or anything is not JSON.
byteLength()
ts
byteLength(text): number;UTF-8 bytes of text, counted without encoding it. A lone surrogate counts 3, as TextEncoder writes U+FFFD for it.
Parameters
| Parameter | Type | Description |
|---|---|---|
text | string | Any string. |
Returns
number
Its UTF-8 length.
parseClient()
ts
parseClient(text): ClientText | null;A client frame from its text. The frame is rebuilt from the fields it was checked on, so nothing else the client sent survives.
Parameters
| Parameter | Type | Description |
|---|---|---|
text | string | A received text message. |
Returns
ClientText | null
The checked frame, or null for anything malformed, mistyped or over the cap.
parseClientDetailed()
ts
parseClientDetailed(text): ClientText | ClientTextFailure;TextFrames.parseClient that says why it refused.
Parameters
| Parameter | Type | Description |
|---|---|---|
text | string | A received text message. |
Returns
ClientText | ClientTextFailure
The checked frame, or the reason: size (over the cap), depth (nested too deep), json (not JSON), type (no known t) or shape (not an object, or the fields of a known t are wrong).
parseServer()
ts
parseServer(text): ServerText | null;A server frame from its text.
Parameters
| Parameter | Type | Description |
|---|---|---|
text | string | A received text message. |
Returns
ServerText | null
The checked frame, or null for anything malformed or mistyped.
Interfaces
InputHeader
What decodeInput read besides the snapshot; reused across calls.
Properties
seq
ts
seq: number;InputSnapshotLike
One step of input as encodeInput reads it. The host's input snapshot fits this shape as it is; nothing has to be copied into it.
Properties
down
ts
readonly down: Uint32Array;Keys held, KEY_WORDS words.
focused
ts
readonly focused: boolean;mods
ts
readonly mods: Readonly<WireMods>;mouse
ts
readonly mouse: Readonly<WireMouse>;pressed
ts
readonly pressed: Uint32Array;Keys that went down this step, KEY_WORDS words.
released
ts
readonly released: Uint32Array;Keys that came up this step, KEY_WORDS words.
MutableInputSnapshot
The record decodeInput writes into. The caller owns it and its arrays, so one record can be reused for every frame from a player.
Properties
down
ts
readonly down: Uint32Array;focused
ts
focused: boolean;mods
ts
readonly mods: WireMods;mouse
ts
readonly mouse: WireMouse;pressed
ts
readonly pressed: Uint32Array;released
ts
readonly released: Uint32Array;PlayerRow
A decoded player trailer. The codec owns one and rewrites it every decode: read it, or copy it, before the next.
Properties
entity
ts
entity: number;The entity the player controls.
flags
ts
flags: number;PlayerRowFlag bits.
position
ts
readonly position: Float32Array;Body position xyz, metres, exact f32.
seq
ts
seq: number;The newest input seq the authority had applied for this player when it read the body.
velocity
ts
readonly velocity: Float32Array;Body linear velocity xyz, metres per second.
PlayerRowSource
One player's own body as the authority has it after a step, read in place when a rows frame is encoded.
Properties
entity
ts
readonly entity: number;The entity the player controls.
flags
ts
readonly flags: number;PlayerRowFlag bits: grounded, teleported.
position
ts
readonly position: ArrayLike<number>;Body position xyz, metres.
velocity
ts
readonly velocity: ArrayLike<number>;Body linear velocity xyz, metres per second.
PlayerSummary
One player as the room lists them.
Properties
connected
ts
connected: boolean;False while the seat is held for a reconnect.
id
ts
id: number;The player id, stable for the seat's life.
name
ts
name: string;The display name the player joined with.
RowsHeader
What decodeRows read besides the rows; reused across calls.
Properties
ack
ts
ack: number;count
ts
count: number;frame
ts
frame: number;player
ts
player: PlayerRow | null;The player trailer, or null when the frame has none.
RowSink
Where decoded rows go. Before each row call the decoder writes the lanes the flags name into the sink's own arrays; lanes the row does not carry are left as they were.
Properties
position
ts
readonly position: Float32Array;At least three lanes: position xyz, metres.
rotation
ts
readonly rotation: Float32Array;At least four lanes: rotation xyzw.
scale
ts
readonly scale: Float32Array;At least three lanes: scale xyz.
Methods
player()?
ts
optional player(row): void;The frame's player trailer, after its last row; never called for a frame without one. A sink that leaves it out ignores the trailer.
Parameters
| Parameter | Type |
|---|---|
row | PlayerRow |
Returns
void
row()
ts
row(entity, flags): void;One decoded row; read the arrays now, the next row overwrites them.
Parameters
| Parameter | Type |
|---|---|
entity | number |
flags | number |
Returns
void
RowSource
Rows to encode, addressed by index. Lanes are read only when the row's flags name them, and are read in place: a world record's own arrays can be handed back without a copy.
Properties
count
ts
readonly count: number;How many rows to write.
player?
ts
readonly optional player?: PlayerRowSource | null;The receiving player's own body, written as the frame's trailer after the rows; null or absent for a spectator (no entity, or no body). The trailer's seq is the frame's ack.
Methods
entity()
ts
entity(index): number;The entity id of row index.
Parameters
| Parameter | Type |
|---|---|
index | number |
Returns
number
flags()
ts
flags(index): number;The RowFlag bits of row index.
Parameters
| Parameter | Type |
|---|---|
index | number |
Returns
number
position()
ts
position(index): ArrayLike<number>;Position xyz of row index, metres.
Parameters
| Parameter | Type |
|---|---|
index | number |
Returns
ArrayLike<number>
rotation()
ts
rotation(index): ArrayLike<number>;Rotation quaternion xyzw of row index.
Parameters
| Parameter | Type |
|---|---|
index | number |
Returns
ArrayLike<number>
scale()
ts
scale(index): ArrayLike<number>;Scale xyz of row index.
Parameters
| Parameter | Type |
|---|---|
index | number |
Returns
ArrayLike<number>
Transport
A two-way pipe of frames. Text frames are the reliable channel; binary frames (inputs, rows) may be dropped on a lossy link.
Example
ts
import type { Transport } from 'gameable/net';
import { loopbackPair } from 'gameable/net/testing';
const [client, server]: [Transport, Transport] = loopbackPair();
server.onMessage((data) => console.log(data));
client.send('{"t":"ping","n":1}');Properties
bufferedAmount
ts
readonly bufferedAmount: number;Bytes queued to send and not yet written out; a sender can skip a binary frame while this is high.
Methods
close()
ts
close(reason?): void;Closes the transport. Safe to call twice; the close listeners fire once.
Parameters
| Parameter | Type |
|---|---|
reason? | string |
Returns
void
onClose()
ts
onClose(cb): void;Registers a listener for the close, called once with the reason. Registering after close does nothing.
Parameters
| Parameter | Type |
|---|---|
cb | (reason) => void |
Returns
void
onMessage()
ts
onMessage(cb): void;Registers a listener for every frame received. Registering after close does nothing.
Parameters
| Parameter | Type |
|---|---|
cb | (data) => void |
Returns
void
send()
ts
send(data): void;Sends one frame. After the transport is closed this does nothing.
Parameters
| Parameter | Type |
|---|---|
data | TransportData |
Returns
void
WireMods
Modifier keys, one bit each on the wire.
Properties
alt
ts
alt: boolean;capsLock
ts
capsLock: boolean;ctrl
ts
ctrl: boolean;meta
ts
meta: boolean;numLock
ts
numLock: boolean;shift
ts
shift: boolean;WireMouse
The mouse fields the wire carries. Deltas round to whole pixels and clamp to i16, the wheel to i8, the button masks to their low 8 bits.
Properties
buttons
ts
buttons: number;dx
ts
dx: number;dy
ts
dy: number;pressed
ts
pressed: number;released
ts
released: number;wheel
ts
wheel: number;Type Aliases
ClientText
ts
type ClientText =
| {
name: string;
room: string;
seat?: {
id: number;
secret: string;
};
t: "hello";
token?: string;
v: number;
}
| {
name: string;
payload: unknown;
t: "msg";
}
| {
at: number;
t: "ping";
};A JSON text frame a client sends, discriminated by t.
ServerErrorCode
ts
type ServerErrorCode = "room" | "full" | "seat" | "origin" | "budget" | "version" | "ended";Why the server refused or closed a connection.
ServerText
ts
type ServerText =
| {
entity: number;
frame: number;
player: number;
players: PlayerSummary[];
room?: string;
secret: string;
snapshot: unknown;
t: "welcome";
}
| {
ack: number;
commands: Command[];
entity: number;
frame: number;
t: "cmd";
}
| {
players: PlayerSummary[];
t: "players";
}
| {
from: number;
name: string;
payload: unknown;
t: "msg";
}
| {
at: number;
server: number;
t: "pong";
}
| {
code: ServerErrorCode;
detail?: string;
t: "error";
};A JSON text frame the server sends, discriminated by t.
Union Members
Type Literal
ts
{
entity: number;
frame: number;
player: number;
players: PlayerSummary[];
room?: string;
secret: string;
snapshot: unknown;
t: "welcome";
}entity
ts
entity: number;The entity this player controls, or 0 for none: "which entity is mine".
frame
ts
frame: number;player
ts
player: number;players
ts
players: PlayerSummary[];room?
ts
optional room?: string;The room's code, as the server knows it (the code to share); absent from a server that does not say.
secret
ts
secret: string;snapshot
ts
snapshot: unknown;t
ts
t: "welcome";Type Literal
ts
{
ack: number;
commands: Command[];
entity: number;
frame: number;
t: "cmd";
}entity: the entity this player controls now, or 0 (a possess or a despawn changes it).
Type Literal
ts
{
players: PlayerSummary[];
t: "players";
}Type Literal
ts
{
from: number;
name: string;
payload: unknown;
t: "msg";
}Type Literal
ts
{
at: number;
server: number;
t: "pong";
}Type Literal
ts
{
code: ServerErrorCode;
detail?: string;
t: "error";
}TransportData
ts
type TransportData = string | Uint8Array;One frame: JSON text, or the bytes of a binary frame.
Variables
AUTHORITY_SENDER
ts
const AUTHORITY_SENDER: 4294967295 = 0xffffffff;The sender id of a message from the authority itself. Room seats start at 0, so the authority is not 0: this is past every player id and still a u32 (the WIT's message-event.player). Keep ids unsigned: in an Int32Array this reads back as -1.
Example
ts
import { AUTHORITY_SENDER } from 'gameable';
const fromServer = (from: number): boolean => from === AUTHORITY_SENDER;FrameKind
ts
const FrameKind: object;The first byte of every binary frame.
Type Declaration
INPUT
ts
readonly INPUT: 1 = 1;Client to server: one step of one player's input.
ROWS
ts
readonly ROWS: 2 = 2;Server to client: the transform rows of one send.
INPUT_FRAME_BYTES
ts
const INPUT_FRAME_BYTES: number;Bytes of an input frame: kind, seq, three key sets, mods, mouse, focused.
MAX_CLIENT_TEXT_BYTES
ts
const MAX_CLIENT_TEXT_BYTES: number;The largest text frame a client may send, in UTF-8 bytes: a full payload plus room for the envelope (t, the message name, a hello's fields).
MAX_JSON_DEPTH
ts
const MAX_JSON_DEPTH: 32 = 32;The deepest nesting of arrays and objects a text frame may carry; a deeper frame is refused before JSON.parse sees it.
MAX_PAYLOAD_BYTES
ts
const MAX_PAYLOAD_BYTES: 2048 = 2048;The largest message payload, in UTF-8 bytes of its JSON, on ctx.net.send and on the wire.
MAX_ROWS
ts
const MAX_ROWS: 65535 = 0xffff;The most rows one frame can carry (count is a u16).
PLAYER_ROW_FLAG_MASK
ts
const PLAYER_ROW_FLAG_MASK: number;Every flag bit a player trailer may set; a frame with any other bit is refused.
PLAYER_TRAILER_BYTES
ts
const PLAYER_TRAILER_BYTES: number;Bytes of a rows frame's player trailer: tag u8, entity u32, seq u32, position 3 x f32, velocity 3 x f32, flags u8.
PLAYER_TRAILER_TAG
ts
const PLAYER_TRAILER_TAG: 1 = 1;The first byte of a rows frame's player trailer, after its last row.
PlayerRowFlag
ts
const PlayerRowFlag: object;What a player trailer's flags byte says about the body, OR-ed together.
Type Declaration
GROUNDED
ts
readonly GROUNDED: 1 = 1;The character body stood on walkable ground after the step.
TELEPORT
ts
readonly TELEPORT: 2 = 2;The authority teleported the body since the last rows this player was sent (a respawn, a set-body-transform with teleport): a predicting client snaps to it instead of counting a correction.
PROTOCOL_VERSION
ts
const PROTOCOL_VERSION: 1 = 1;The protocol version a client sends in hello; a mismatch is refused.
ROW_FLAG_MASK
ts
const ROW_FLAG_MASK: number;Every flag bit a row may set; a frame with any other bit is refused.
RowFlag
ts
const RowFlag: object;Which lanes a transform row carries, OR-ed together in its flags byte.
Type Declaration
POSITION
ts
readonly POSITION: 1 = 1;Position: three i32 millimetres.
ROTATION
ts
readonly ROTATION: 2 = 2;Rotation: one u32, smallest-three.
SCALE
ts
readonly SCALE: 4 = 4;Scale: three f32, exact and signed.
TELEPORT
ts
readonly TELEPORT: 16 = 16;No lanes: the entity teleported since the last rows this player was sent; snap to this pose instead of interpolating to it. The same bit as TRANSFORM_FLAGS.TELEPORT.
VISIBLE
ts
readonly VISIBLE: 8 = 8;No lanes: the entity was hidden at spawn and is now shown (the server's world record only ever turns visibility on). The same bit as the engine's TRANSFORM_FLAGS.VISIBLE, so a client can pass it through.
ROWS_HEADER_BYTES
ts
const ROWS_HEADER_BYTES: number;Bytes of a rows frame before its first row: kind, frame, ack, count.
Functions
buildClientText()
ts
function buildClientText(frame): string | null;A client frame as JSON text, or null when a msg payload is over MAX_PAYLOAD_BYTES.
Parameters
| Parameter | Type | Description |
|---|---|---|
frame | ClientText | The frame to send. |
Returns
string | null
The text, or null.
Example
ts
const text = buildClientText({ t: 'hello', v: 1, room: 'lobby', name: 'Ana' });
// '{"t":"hello","v":1,"room":"lobby","name":"Ana"}'buildServerText()
ts
function buildServerText(frame): string | null;A server frame as JSON text, or null when a msg payload is over MAX_PAYLOAD_BYTES.
Parameters
| Parameter | Type | Description |
|---|---|---|
frame | ServerText | The frame to send. |
Returns
string | null
The text, or null.
Example
ts
const text = buildServerText({ t: 'pong', at: 12.5, server: Date.now() });createInputCodec()
ts
function createInputCodec(): InputCodec;A new input codec with its own reusable header.
Returns
The codec.
Example
ts
const codec = createInputCodec();createRowsCodec()
ts
function createRowsCodec(): RowsCodec;A new rows codec with its own reusable header.
Returns
The codec.
Example
ts
const codec = createRowsCodec();createTextFrames()
ts
function createTextFrames(): TextFrames;A new text frame builder and parser.
Returns
The builder.
Example
ts
const frames = createTextFrames();
frames.parseServer('{"t":"pong","at":1,"server":2}'); // { t: 'pong', at: 1, server: 2 }decodeInput()
ts
function decodeInput(bytes, into): InputHeader | null;Reads one input frame into into; see InputCodec.decode. The returned object is shared by every call: read seq before the next decode.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | Exactly one received frame. |
into | MutableInputSnapshot | The caller's record. |
Returns
InputHeader | null
{ seq }, or null for a malformed frame.
Example
ts
const keys = () => new Uint32Array(KEY_WORDS);
const snapshot: MutableInputSnapshot = {
down: keys(), pressed: keys(), released: keys(),
mods: { shift: false, ctrl: false, alt: false, meta: false, capsLock: false, numLock: false },
mouse: { dx: -12, dy: 0, wheel: 0, buttons: 0, pressed: 0, released: 0 },
focused: true,
};
const out = new DataView(new ArrayBuffer(INPUT_FRAME_BYTES));
const message = new Uint8Array(out.buffer, 0, encodeInput(out, 42, snapshot));
const lastSeq = decodeInput(message, snapshot)?.seq; // 42decodeRows()
ts
function decodeRows(bytes, sink): RowsHeader | null;Reads one rows frame into sink; see RowsCodec.decode. The returned object is shared by every call: read it before the next decode.
Parameters
| Parameter | Type | Description |
|---|---|---|
bytes | Uint8Array | Exactly one received frame. |
sink | RowSink | Receives the rows. |
Returns
RowsHeader | null
{ frame, ack, count }, or null for a malformed frame.
Example
ts
const position = new Float32Array([1.5, 0, -2]);
const rotation = new Float32Array([0, 0, 0, 1]);
const scale = new Float32Array([1, 1, 1]);
const rows: RowSource = {
count: 1,
entity: () => 7,
flags: () => RowFlag.POSITION | RowFlag.ROTATION,
position: () => position,
rotation: () => rotation,
scale: () => scale,
};
const sink: RowSink = {
position: new Float32Array(3),
rotation: new Float32Array(4),
scale: new Float32Array(3),
row: (entity) => console.log(entity, sink.position),
};
const out = new DataView(new ArrayBuffer(rowsFrameBytes(rows)));
const message = new Uint8Array(out.buffer, 0, encodeRows(out, 600, 12, rows));
const newest = decodeRows(message, sink)?.frame; // 600encodeInput()
ts
function encodeInput(
out,
seq,
snapshot
): number;Writes one input frame at the start of out; see InputCodec.encode.
Parameters
| Parameter | Type | Description |
|---|---|---|
out | DataView | The send buffer, owned by the caller. |
seq | number | The input sequence number. |
snapshot | InputSnapshotLike | The step's input. |
Returns
number
Bytes written, or 0 when out is too small.
Example
ts
const keys = () => new Uint32Array(KEY_WORDS);
const snapshot: MutableInputSnapshot = {
down: keys(), pressed: keys(), released: keys(),
mods: { shift: false, ctrl: false, alt: false, meta: false, capsLock: false, numLock: false },
mouse: { dx: -12, dy: 0, wheel: 0, buttons: 0, pressed: 0, released: 0 },
focused: true,
};
const out = new DataView(new ArrayBuffer(INPUT_FRAME_BYTES));
const frame = new Uint8Array(out.buffer, 0, encodeInput(out, 1, snapshot)); // 111 bytes to sendencodeRows()
ts
function encodeRows(
out,
frame,
ack,
rows
): number;Writes one rows frame at the start of out; see RowsCodec.encode.
Parameters
| Parameter | Type | Description |
|---|---|---|
out | DataView | The send buffer, owned by the caller. |
frame | number | The authority's fixed-step counter. |
ack | number | The last input seq applied for the receiving player. |
rows | RowSource | The rows to write. |
Returns
number
Bytes written, or 0 when out is too small.
Example
ts
const position = new Float32Array([1.5, 0, -2]);
const rotation = new Float32Array([0, 0, 0, 1]);
const scale = new Float32Array([1, 1, 1]);
const rows: RowSource = {
count: 1,
entity: () => 7,
flags: () => RowFlag.POSITION | RowFlag.ROTATION,
position: () => position,
rotation: () => rotation,
scale: () => scale,
};
const out = new DataView(new ArrayBuffer(1024));
const bytes = encodeRows(out, 600, 12, rows);
const frame = new Uint8Array(out.buffer, out.byteOffset, bytes); // the bytes to sendpackQuat()
ts
function packQuat(
x,
y,
z,
w
): number;Packs a rotation into its smallest-three word; see Quantizer.packQuat.
Parameters
| Parameter | Type | Description |
|---|---|---|
x | number | Quaternion x. |
y | number | Quaternion y. |
z | number | Quaternion z. |
w | number | Quaternion w. |
Returns
number
The unsigned 32-bit word.
Example
ts
const word = packQuat(0, 0, Math.SQRT1_2, Math.SQRT1_2);parseClientText()
ts
function parseClientText(text): ClientText | null;A client frame from its text, or null for anything malformed or over the cap.
Parameters
| Parameter | Type | Description |
|---|---|---|
text | string | A received text message. |
Returns
ClientText | null
The checked frame, or null.
Example
ts
const frame = parseClientText('{"t":"ping","at":12.5}');
const at = frame?.t === 'ping' ? frame.at : null; // 12.5parseServerText()
ts
function parseServerText(text): ServerText | null;A server frame from its text, or null for anything malformed.
Parameters
| Parameter | Type | Description |
|---|---|---|
text | string | A received text message. |
Returns
ServerText | null
The checked frame, or null.
Example
ts
const frame = parseServerText('{"t":"error","code":"full"}');
const full = frame?.t === 'error' && frame.code === 'full'; // truerowsFrameBytes()
ts
function rowsFrameBytes(rows): number;The bytes encodeRows would write for rows; size the send buffer with it.
Parameters
| Parameter | Type | Description |
|---|---|---|
rows | RowSource | The rows to size. |
Returns
number
The frame's length.
Example
ts
const position = new Float32Array([1.5, 0, -2]);
const rotation = new Float32Array([0, 0, 0, 1]);
const scale = new Float32Array([1, 1, 1]);
const rows: RowSource = {
count: 1,
entity: () => 7,
flags: () => RowFlag.POSITION | RowFlag.ROTATION,
position: () => position,
rotation: () => rotation,
scale: () => scale,
};
const out = new DataView(new ArrayBuffer(rowsFrameBytes(rows))); // 11 + 21 bytesunpackQuat()
ts
function unpackQuat(
packed,
out,
offset
): void;Unpacks a smallest-three word into out at offset; see Quantizer.unpackQuat.
Parameters
| Parameter | Type | Description |
|---|---|---|
packed | number | The word off the wire. |
out | Float32Array | Receives x, y, z, w. |
offset | number | Where x goes in out. |
Returns
void
Example
ts
const q = new Float32Array(4);
unpackQuat(packQuat(0, 0, 0, 1), q, 0); // q = [0, 0, 0, 1]utf8ByteLength()
ts
function utf8ByteLength(text): number;UTF-8 bytes of text, counted without encoding it.
Parameters
| Parameter | Type | Description |
|---|---|---|
text | string | Any string. |
Returns
number
Its UTF-8 length.
Example
ts
utf8ByteLength('€'); // 3