murow 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -0
- package/dist/core/binary-codec/binary-codec.d.ts +159 -0
- package/dist/core/binary-codec/binary-codec.js +336 -0
- package/dist/core/binary-codec/index.d.ts +1 -0
- package/dist/core/binary-codec/index.js +1 -0
- package/dist/core/events/event-system.d.ts +71 -0
- package/dist/core/events/event-system.js +88 -0
- package/dist/core/events/index.d.ts +1 -0
- package/dist/core/events/index.js +1 -0
- package/dist/core/fixed-ticker/fixed-ticker.d.ts +105 -0
- package/dist/core/fixed-ticker/fixed-ticker.js +91 -0
- package/dist/core/fixed-ticker/index.d.ts +1 -0
- package/dist/core/fixed-ticker/index.js +1 -0
- package/dist/core/generate-id/generate-id.d.ts +21 -0
- package/dist/core/generate-id/generate-id.js +25 -0
- package/dist/core/generate-id/index.d.ts +1 -0
- package/dist/core/generate-id/index.js +1 -0
- package/dist/core/index.d.ts +8 -0
- package/dist/core/index.js +8 -0
- package/dist/core/lerp/index.d.ts +1 -0
- package/dist/core/lerp/index.js +1 -0
- package/dist/core/lerp/lerp.d.ts +40 -0
- package/dist/core/lerp/lerp.js +42 -0
- package/dist/core/navmesh/index.d.ts +1 -0
- package/dist/core/navmesh/index.js +1 -0
- package/dist/core/navmesh/navmesh.d.ts +116 -0
- package/dist/core/navmesh/navmesh.js +666 -0
- package/dist/core/pooled-codec/index.d.ts +1 -0
- package/dist/core/pooled-codec/index.js +1 -0
- package/dist/core/pooled-codec/pooled-codec.d.ts +140 -0
- package/dist/core/pooled-codec/pooled-codec.js +213 -0
- package/dist/core/prediction/index.d.ts +1 -0
- package/dist/core/prediction/index.js +1 -0
- package/dist/core/prediction/prediction.d.ts +64 -0
- package/dist/core/prediction/prediction.js +90 -0
- package/dist/core.esm.js +1 -0
- package/dist/core.js +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +18 -0
- package/dist/protocol/index.d.ts +43 -0
- package/dist/protocol/index.js +43 -0
- package/dist/protocol/intent/index.d.ts +39 -0
- package/dist/protocol/intent/index.js +38 -0
- package/dist/protocol/intent/intent-registry.d.ts +54 -0
- package/dist/protocol/intent/intent-registry.js +73 -0
- package/dist/protocol/intent/intent.d.ts +12 -0
- package/dist/protocol/intent/intent.js +1 -0
- package/dist/protocol/snapshot/index.d.ts +44 -0
- package/dist/protocol/snapshot/index.js +43 -0
- package/dist/protocol/snapshot/snapshot-codec.d.ts +48 -0
- package/dist/protocol/snapshot/snapshot-codec.js +56 -0
- package/dist/protocol/snapshot/snapshot-registry.d.ts +100 -0
- package/dist/protocol/snapshot/snapshot-registry.js +136 -0
- package/dist/protocol/snapshot/snapshot.d.ts +19 -0
- package/dist/protocol/snapshot/snapshot.js +30 -0
- package/package.json +54 -0
- package/src/core/binary-codec/README.md +60 -0
- package/src/core/binary-codec/binary-codec.test.ts +300 -0
- package/src/core/binary-codec/binary-codec.ts +430 -0
- package/src/core/binary-codec/index.ts +1 -0
- package/src/core/events/README.md +47 -0
- package/src/core/events/event-system.test.ts +243 -0
- package/src/core/events/event-system.ts +140 -0
- package/src/core/events/index.ts +1 -0
- package/src/core/fixed-ticker/README.md +77 -0
- package/src/core/fixed-ticker/fixed-ticker.test.ts +151 -0
- package/src/core/fixed-ticker/fixed-ticker.ts +158 -0
- package/src/core/fixed-ticker/index.ts +1 -0
- package/src/core/generate-id/README.md +18 -0
- package/src/core/generate-id/generate-id.test.ts +79 -0
- package/src/core/generate-id/generate-id.ts +37 -0
- package/src/core/generate-id/index.ts +1 -0
- package/src/core/index.ts +8 -0
- package/src/core/lerp/README.md +79 -0
- package/src/core/lerp/index.ts +1 -0
- package/src/core/lerp/lerp.test.ts +90 -0
- package/src/core/lerp/lerp.ts +42 -0
- package/src/core/navmesh/README.md +124 -0
- package/src/core/navmesh/index.ts +1 -0
- package/src/core/navmesh/navmesh.test.ts +344 -0
- package/src/core/navmesh/navmesh.ts +850 -0
- package/src/core/pooled-codec/README.md +70 -0
- package/src/core/pooled-codec/index.ts +1 -0
- package/src/core/pooled-codec/pooled-codec.test.ts +349 -0
- package/src/core/pooled-codec/pooled-codec.ts +239 -0
- package/src/core/prediction/README.md +64 -0
- package/src/core/prediction/index.ts +1 -0
- package/src/core/prediction/prediction.test.ts +422 -0
- package/src/core/prediction/prediction.ts +101 -0
- package/src/index.ts +20 -0
- package/src/protocol/README.md +310 -0
- package/src/protocol/index.ts +44 -0
- package/src/protocol/intent/index.ts +40 -0
- package/src/protocol/intent/intent-registry.test.ts +237 -0
- package/src/protocol/intent/intent-registry.ts +88 -0
- package/src/protocol/intent/intent.ts +12 -0
- package/src/protocol/snapshot/index.ts +45 -0
- package/src/protocol/snapshot/snapshot-codec.test.ts +138 -0
- package/src/protocol/snapshot/snapshot-codec.ts +71 -0
- package/src/protocol/snapshot/snapshot-registry.test.ts +302 -0
- package/src/protocol/snapshot/snapshot-registry.ts +162 -0
- package/src/protocol/snapshot/snapshot.test.ts +76 -0
- package/src/protocol/snapshot/snapshot.ts +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Murow
|
|
2
|
+
|
|
3
|
+
A lightweight TypeScript game engine for server-authoritative multiplayer games.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install murow
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import {
|
|
15
|
+
FixedTicker,
|
|
16
|
+
EventSystem,
|
|
17
|
+
BinaryCodec,
|
|
18
|
+
generateId,
|
|
19
|
+
lerp,
|
|
20
|
+
NavMesh,
|
|
21
|
+
PooledCodec,
|
|
22
|
+
IntentTracker,
|
|
23
|
+
Reconciliator
|
|
24
|
+
} from 'murow';
|
|
25
|
+
// or
|
|
26
|
+
import { FixedTicker } from 'murow/core';
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Modules
|
|
30
|
+
|
|
31
|
+
### Core Utilities
|
|
32
|
+
- `FixedTicker`: Deterministic fixed-rate update loop
|
|
33
|
+
- `EventSystem`: High-performance event handling
|
|
34
|
+
- `BinaryCodec`: Schema-driven binary serialization
|
|
35
|
+
- `generateId`: Cryptographically secure ID generation
|
|
36
|
+
- `lerp`: Linear interpolation utility
|
|
37
|
+
- `NavMesh`: Pathfinding with dynamic obstacles
|
|
38
|
+
- `PooledCodec`: Object-pooled binary codec
|
|
39
|
+
- `IntentTracker` & `Reconciliator`: Client-side prediction
|
|
40
|
+
|
|
41
|
+
### Protocol Layer
|
|
42
|
+
Minimalist networking primitives:
|
|
43
|
+
- `IntentRegistry`: Type-safe intent codec registry
|
|
44
|
+
- `SnapshotCodec`: Binary encoding for state deltas
|
|
45
|
+
- `Snapshot<T>`: Delta-based state updates
|
|
46
|
+
- `applySnapshot()`: Deep merge snapshots into state
|
|
47
|
+
|
|
48
|
+
Works harmoniously with core utilities (`FixedTicker`, `IntentTracker`, `Reconciliator`).
|
|
49
|
+
|
|
50
|
+
See [Protocol Layer Documentation](./src/protocol/README.md) for usage.
|
|
51
|
+
|
|
52
|
+
## Building
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm install
|
|
56
|
+
npm run build
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## License
|
|
60
|
+
|
|
61
|
+
MIT
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A binary field descriptor.
|
|
3
|
+
* Defines how a single value is serialized/deserialized
|
|
4
|
+
* at a fixed byte size.
|
|
5
|
+
*/
|
|
6
|
+
export type Field<T> = {
|
|
7
|
+
/** Size of the field in bytes */
|
|
8
|
+
size: number;
|
|
9
|
+
/**
|
|
10
|
+
* Writes a value into a DataView at the given offset.
|
|
11
|
+
* @param dv DataView to write into
|
|
12
|
+
* @param o Byte offset
|
|
13
|
+
* @param v Value to write
|
|
14
|
+
*/
|
|
15
|
+
write(dv: DataView, o: number, v: T): void;
|
|
16
|
+
/**
|
|
17
|
+
* Reads a value from a DataView at the given offset.
|
|
18
|
+
* @param dv DataView to read from
|
|
19
|
+
* @param o Byte offset
|
|
20
|
+
*/
|
|
21
|
+
read(dv: DataView, o: number): T;
|
|
22
|
+
/**
|
|
23
|
+
* Returns the nil value
|
|
24
|
+
*/
|
|
25
|
+
toNil(): T;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* A schema mapping object keys to binary fields.
|
|
29
|
+
* The order of iteration defines the binary layout.
|
|
30
|
+
*
|
|
31
|
+
* IMPORTANT:
|
|
32
|
+
* Property order is respected as insertion order.
|
|
33
|
+
* Do not rely on computed or dynamic keys.
|
|
34
|
+
*/
|
|
35
|
+
export type Schema<T> = {
|
|
36
|
+
[K in keyof T]: Field<T[K]>;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Base codec implementation.
|
|
40
|
+
* Handles schema-driven encoding/decoding.
|
|
41
|
+
*/
|
|
42
|
+
export declare class BaseBinaryCodec {
|
|
43
|
+
/**
|
|
44
|
+
* Encodes an object into a binary buffer using the given schema.
|
|
45
|
+
*
|
|
46
|
+
* Allocates a right-sized buffer per call.
|
|
47
|
+
* Safe for concurrent and re-entrant usage.
|
|
48
|
+
*
|
|
49
|
+
* @param schema Binary schema definition
|
|
50
|
+
* @param data Object to encode
|
|
51
|
+
* @returns A Uint8Array containing the encoded bytes
|
|
52
|
+
*/
|
|
53
|
+
protected static encodeInto<T extends object>(schema: Schema<T>, data: T): Uint8Array;
|
|
54
|
+
/**
|
|
55
|
+
* Decodes a binary buffer into a target object using the given schema.
|
|
56
|
+
*
|
|
57
|
+
* Validates buffer size before reading.
|
|
58
|
+
* Does not mutate shared state.
|
|
59
|
+
*
|
|
60
|
+
* @param schema Binary schema definition
|
|
61
|
+
* @param buf Buffer containing encoded data
|
|
62
|
+
* @param target Target object to mutate
|
|
63
|
+
* @returns The mutated target object
|
|
64
|
+
*/
|
|
65
|
+
static decodeInto<T extends object>(schema: Schema<T>, buf: Uint8Array, target: T): T;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Built-in binary primitive field definitions for multiplayer games.
|
|
69
|
+
*/
|
|
70
|
+
export declare class BinaryPrimitives {
|
|
71
|
+
/** Unsigned 8-bit integer */
|
|
72
|
+
static readonly u8: Field<number>;
|
|
73
|
+
/** Unsigned 16-bit integer (big-endian) */
|
|
74
|
+
static readonly u16: Field<number>;
|
|
75
|
+
/** Unsigned 32-bit integer (big-endian) */
|
|
76
|
+
static readonly u32: Field<number>;
|
|
77
|
+
/** Signed 8-bit integer */
|
|
78
|
+
static readonly i8: Field<number>;
|
|
79
|
+
/** Signed 16-bit integer (big-endian) */
|
|
80
|
+
static readonly i16: Field<number>;
|
|
81
|
+
/** Signed 32-bit integer (big-endian) */
|
|
82
|
+
static readonly i32: Field<number>;
|
|
83
|
+
/** 32-bit floating point number (IEEE 754, big-endian) */
|
|
84
|
+
static readonly f32: Field<number>;
|
|
85
|
+
/** 64-bit floating point number (double, big-endian) */
|
|
86
|
+
static readonly f64: Field<number>;
|
|
87
|
+
/** Boolean stored as 1 byte (0 = false, 1 = true) */
|
|
88
|
+
static readonly bool: Field<boolean>;
|
|
89
|
+
/**
|
|
90
|
+
* String field with UTF-8 encoding and 2-byte length prefix.
|
|
91
|
+
* @param maxLength Maximum number of bytes allowed
|
|
92
|
+
*/
|
|
93
|
+
static string(maxLength: number): Field<string>;
|
|
94
|
+
/** 2D vector of f32 (x, y) */
|
|
95
|
+
static readonly vec2: Field<{
|
|
96
|
+
x: number;
|
|
97
|
+
y: number;
|
|
98
|
+
}>;
|
|
99
|
+
/** 3D vector of f32 (x, y, z) */
|
|
100
|
+
static readonly vec3: Field<{
|
|
101
|
+
x: number;
|
|
102
|
+
y: number;
|
|
103
|
+
z: number;
|
|
104
|
+
}>;
|
|
105
|
+
/** RGBA color packed as 4 u8 bytes */
|
|
106
|
+
static readonly color: Field<{
|
|
107
|
+
r: number;
|
|
108
|
+
g: number;
|
|
109
|
+
b: number;
|
|
110
|
+
a: number;
|
|
111
|
+
}>;
|
|
112
|
+
/** 32-bit floating point number (IEEE 754, little-endian) */
|
|
113
|
+
static readonly f32_le: Field<number>;
|
|
114
|
+
/** 64-bit floating point number (double, little-endian) */
|
|
115
|
+
static readonly f64_le: Field<number>;
|
|
116
|
+
/** Unsigned 16-bit integer (little-endian) */
|
|
117
|
+
static readonly u16_le: Field<number>;
|
|
118
|
+
/** Unsigned 32-bit integer (little-endian) */
|
|
119
|
+
static readonly u32_le: Field<number>;
|
|
120
|
+
/** Signed 16-bit integer (little-endian) */
|
|
121
|
+
static readonly i16_le: Field<number>;
|
|
122
|
+
/** Signed 32-bit integer (little-endian) */
|
|
123
|
+
static readonly i32_le: Field<number>;
|
|
124
|
+
/**
|
|
125
|
+
* 2D vector of f32 stored as a tuple [x, y] (little-endian).
|
|
126
|
+
* Useful for compact math data or shader-friendly layouts.
|
|
127
|
+
*/
|
|
128
|
+
static readonly vec2_le: Field<[number, number]>;
|
|
129
|
+
/**
|
|
130
|
+
* 3D vector of f32 stored as a tuple [x, y, z] (little-endian).
|
|
131
|
+
* Commonly used for positions, velocities, or directions.
|
|
132
|
+
*/
|
|
133
|
+
static readonly vec3_le: Field<[number, number, number]>;
|
|
134
|
+
/**
|
|
135
|
+
* 4D vector of f32 stored as a tuple [x, y, z, w] (little-endian).
|
|
136
|
+
* Useful for quaternions, colors in shaders, or homogeneous coordinates.
|
|
137
|
+
*/
|
|
138
|
+
static readonly vec4_le: Field<[number, number, number, number]>;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Public codec API.
|
|
142
|
+
* Re-exports primitives and exposes encode/decode helpers.
|
|
143
|
+
*/
|
|
144
|
+
export declare class BinaryCodec extends BaseBinaryCodec {
|
|
145
|
+
/** Unsigned 8-bit integer field */
|
|
146
|
+
static readonly u8: Field<number>;
|
|
147
|
+
/** Unsigned 16-bit integer field */
|
|
148
|
+
static readonly u16: Field<number>;
|
|
149
|
+
/** 32-bit floating point field */
|
|
150
|
+
static readonly f32: Field<number>;
|
|
151
|
+
/**
|
|
152
|
+
* Encodes an object into a binary buffer.
|
|
153
|
+
*/
|
|
154
|
+
static encode<T extends object>(schema: Schema<T>, data: T): Uint8Array;
|
|
155
|
+
/**
|
|
156
|
+
* Decodes a binary buffer into an existing object.
|
|
157
|
+
*/
|
|
158
|
+
static decode<T extends object>(schema: Schema<T>, buf: Uint8Array, target: T): T;
|
|
159
|
+
}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal symbol used to cache computed schema byte size.
|
|
3
|
+
*/
|
|
4
|
+
const SCHEMA_SIZE = Symbol("schemaSize");
|
|
5
|
+
/**
|
|
6
|
+
* Computes and caches the total byte size of a schema.
|
|
7
|
+
* @param schema Binary schema definition
|
|
8
|
+
*/
|
|
9
|
+
function getSchemaSize(schema) {
|
|
10
|
+
const cached = schema[SCHEMA_SIZE];
|
|
11
|
+
if (cached !== undefined)
|
|
12
|
+
return cached;
|
|
13
|
+
let size = 0;
|
|
14
|
+
for (const k of Object.keys(schema)) {
|
|
15
|
+
size += schema[k].size;
|
|
16
|
+
}
|
|
17
|
+
schema[SCHEMA_SIZE] = size;
|
|
18
|
+
return size;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Base codec implementation.
|
|
22
|
+
* Handles schema-driven encoding/decoding.
|
|
23
|
+
*/
|
|
24
|
+
export class BaseBinaryCodec {
|
|
25
|
+
/**
|
|
26
|
+
* Encodes an object into a binary buffer using the given schema.
|
|
27
|
+
*
|
|
28
|
+
* Allocates a right-sized buffer per call.
|
|
29
|
+
* Safe for concurrent and re-entrant usage.
|
|
30
|
+
*
|
|
31
|
+
* @param schema Binary schema definition
|
|
32
|
+
* @param data Object to encode
|
|
33
|
+
* @returns A Uint8Array containing the encoded bytes
|
|
34
|
+
*/
|
|
35
|
+
static encodeInto(schema, data) {
|
|
36
|
+
const size = getSchemaSize(schema);
|
|
37
|
+
const buffer = new ArrayBuffer(size);
|
|
38
|
+
const view = new DataView(buffer);
|
|
39
|
+
let o = 0;
|
|
40
|
+
for (const k of Object.keys(schema)) {
|
|
41
|
+
const f = schema[k];
|
|
42
|
+
f.write(view, o, data[k]);
|
|
43
|
+
o += f.size;
|
|
44
|
+
}
|
|
45
|
+
return new Uint8Array(buffer);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Decodes a binary buffer into a target object using the given schema.
|
|
49
|
+
*
|
|
50
|
+
* Validates buffer size before reading.
|
|
51
|
+
* Does not mutate shared state.
|
|
52
|
+
*
|
|
53
|
+
* @param schema Binary schema definition
|
|
54
|
+
* @param buf Buffer containing encoded data
|
|
55
|
+
* @param target Target object to mutate
|
|
56
|
+
* @returns The mutated target object
|
|
57
|
+
*/
|
|
58
|
+
static decodeInto(schema, buf, target) {
|
|
59
|
+
const expectedSize = getSchemaSize(schema);
|
|
60
|
+
if (buf.byteLength < expectedSize) {
|
|
61
|
+
throw new RangeError(`Buffer too small: expected ${expectedSize} bytes, got ${buf.byteLength}`);
|
|
62
|
+
}
|
|
63
|
+
const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
64
|
+
let o = 0;
|
|
65
|
+
for (const k of Object.keys(schema)) {
|
|
66
|
+
const f = schema[k];
|
|
67
|
+
target[k] = f.read(view, o);
|
|
68
|
+
o += f.size;
|
|
69
|
+
}
|
|
70
|
+
return target;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Built-in binary primitive field definitions for multiplayer games.
|
|
75
|
+
*/
|
|
76
|
+
export class BinaryPrimitives {
|
|
77
|
+
/**
|
|
78
|
+
* String field with UTF-8 encoding and 2-byte length prefix.
|
|
79
|
+
* @param maxLength Maximum number of bytes allowed
|
|
80
|
+
*/
|
|
81
|
+
static string(maxLength) {
|
|
82
|
+
return {
|
|
83
|
+
size: maxLength + 2,
|
|
84
|
+
write(dv, o, v) {
|
|
85
|
+
const encoder = new TextEncoder();
|
|
86
|
+
const bytes = encoder.encode(v);
|
|
87
|
+
if (bytes.length > maxLength)
|
|
88
|
+
throw new RangeError(`String too long, max ${maxLength} bytes`);
|
|
89
|
+
dv.setUint16(o, bytes.length, false);
|
|
90
|
+
for (let i = 0; i < bytes.length; i++)
|
|
91
|
+
dv.setUint8(o + 2 + i, bytes[i]);
|
|
92
|
+
for (let i = bytes.length; i < maxLength; i++)
|
|
93
|
+
dv.setUint8(o + 2 + i, 0);
|
|
94
|
+
},
|
|
95
|
+
read(dv, o) {
|
|
96
|
+
const length = dv.getUint16(o, false);
|
|
97
|
+
const bytes = new Uint8Array(length);
|
|
98
|
+
for (let i = 0; i < length; i++)
|
|
99
|
+
bytes[i] = dv.getUint8(o + 2 + i);
|
|
100
|
+
return new TextDecoder().decode(bytes);
|
|
101
|
+
},
|
|
102
|
+
toNil: () => "",
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** Unsigned 8-bit integer */
|
|
107
|
+
BinaryPrimitives.u8 = {
|
|
108
|
+
size: 1,
|
|
109
|
+
write: (dv, o, v) => dv.setUint8(o, v),
|
|
110
|
+
read: (dv, o) => dv.getUint8(o),
|
|
111
|
+
toNil: () => 0,
|
|
112
|
+
};
|
|
113
|
+
/** Unsigned 16-bit integer (big-endian) */
|
|
114
|
+
BinaryPrimitives.u16 = {
|
|
115
|
+
size: 2,
|
|
116
|
+
write: (dv, o, v) => dv.setUint16(o, v, false),
|
|
117
|
+
read: (dv, o) => dv.getUint16(o, false),
|
|
118
|
+
toNil: () => 0,
|
|
119
|
+
};
|
|
120
|
+
/** Unsigned 32-bit integer (big-endian) */
|
|
121
|
+
BinaryPrimitives.u32 = {
|
|
122
|
+
size: 4,
|
|
123
|
+
write: (dv, o, v) => dv.setUint32(o, v, false),
|
|
124
|
+
read: (dv, o) => dv.getUint32(o, false),
|
|
125
|
+
toNil: () => 0,
|
|
126
|
+
};
|
|
127
|
+
/** Signed 8-bit integer */
|
|
128
|
+
BinaryPrimitives.i8 = {
|
|
129
|
+
size: 1,
|
|
130
|
+
write: (dv, o, v) => dv.setInt8(o, v),
|
|
131
|
+
read: (dv, o) => dv.getInt8(o),
|
|
132
|
+
toNil: () => 0,
|
|
133
|
+
};
|
|
134
|
+
/** Signed 16-bit integer (big-endian) */
|
|
135
|
+
BinaryPrimitives.i16 = {
|
|
136
|
+
size: 2,
|
|
137
|
+
write: (dv, o, v) => dv.setInt16(o, v, false),
|
|
138
|
+
read: (dv, o) => dv.getInt16(o, false),
|
|
139
|
+
toNil: () => 0,
|
|
140
|
+
};
|
|
141
|
+
/** Signed 32-bit integer (big-endian) */
|
|
142
|
+
BinaryPrimitives.i32 = {
|
|
143
|
+
size: 4,
|
|
144
|
+
write: (dv, o, v) => dv.setInt32(o, v, false),
|
|
145
|
+
read: (dv, o) => dv.getInt32(o, false),
|
|
146
|
+
toNil: () => 0,
|
|
147
|
+
};
|
|
148
|
+
/** 32-bit floating point number (IEEE 754, big-endian) */
|
|
149
|
+
BinaryPrimitives.f32 = {
|
|
150
|
+
size: 4,
|
|
151
|
+
write: (dv, o, v) => dv.setFloat32(o, v, false),
|
|
152
|
+
read: (dv, o) => dv.getFloat32(o, false),
|
|
153
|
+
toNil: () => 0,
|
|
154
|
+
};
|
|
155
|
+
/** 64-bit floating point number (double, big-endian) */
|
|
156
|
+
BinaryPrimitives.f64 = {
|
|
157
|
+
size: 8,
|
|
158
|
+
write: (dv, o, v) => dv.setFloat64(o, v, false),
|
|
159
|
+
read: (dv, o) => dv.getFloat64(o, false),
|
|
160
|
+
toNil: () => 0,
|
|
161
|
+
};
|
|
162
|
+
/** Boolean stored as 1 byte (0 = false, 1 = true) */
|
|
163
|
+
BinaryPrimitives.bool = {
|
|
164
|
+
size: 1,
|
|
165
|
+
write: (dv, o, v) => dv.setUint8(o, v ? 1 : 0),
|
|
166
|
+
read: (dv, o) => dv.getUint8(o) !== 0,
|
|
167
|
+
toNil: () => false,
|
|
168
|
+
};
|
|
169
|
+
/** 2D vector of f32 (x, y) */
|
|
170
|
+
BinaryPrimitives.vec2 = {
|
|
171
|
+
size: 8,
|
|
172
|
+
write(dv, o, v) {
|
|
173
|
+
dv.setFloat32(o, v.x, false);
|
|
174
|
+
dv.setFloat32(o + 4, v.y, false);
|
|
175
|
+
},
|
|
176
|
+
read(dv, o) {
|
|
177
|
+
return { x: dv.getFloat32(o, false), y: dv.getFloat32(o + 4, false) };
|
|
178
|
+
},
|
|
179
|
+
toNil: () => ({ x: 0, y: 0 }),
|
|
180
|
+
};
|
|
181
|
+
/** 3D vector of f32 (x, y, z) */
|
|
182
|
+
BinaryPrimitives.vec3 = {
|
|
183
|
+
size: 12,
|
|
184
|
+
write(dv, o, v) {
|
|
185
|
+
dv.setFloat32(o, v.x, false);
|
|
186
|
+
dv.setFloat32(o + 4, v.y, false);
|
|
187
|
+
dv.setFloat32(o + 8, v.z, false);
|
|
188
|
+
},
|
|
189
|
+
read(dv, o) {
|
|
190
|
+
return {
|
|
191
|
+
x: dv.getFloat32(o, false),
|
|
192
|
+
y: dv.getFloat32(o + 4, false),
|
|
193
|
+
z: dv.getFloat32(o + 8, false),
|
|
194
|
+
};
|
|
195
|
+
},
|
|
196
|
+
toNil: () => ({ x: 0, y: 0, z: 0 }),
|
|
197
|
+
};
|
|
198
|
+
/** RGBA color packed as 4 u8 bytes */
|
|
199
|
+
BinaryPrimitives.color = {
|
|
200
|
+
size: 4,
|
|
201
|
+
write(dv, o, v) {
|
|
202
|
+
dv.setUint8(o, v.r);
|
|
203
|
+
dv.setUint8(o + 1, v.g);
|
|
204
|
+
dv.setUint8(o + 2, v.b);
|
|
205
|
+
dv.setUint8(o + 3, v.a);
|
|
206
|
+
},
|
|
207
|
+
read(dv, o) {
|
|
208
|
+
return {
|
|
209
|
+
r: dv.getUint8(o),
|
|
210
|
+
g: dv.getUint8(o + 1),
|
|
211
|
+
b: dv.getUint8(o + 2),
|
|
212
|
+
a: dv.getUint8(o + 3),
|
|
213
|
+
};
|
|
214
|
+
},
|
|
215
|
+
toNil: () => ({ r: 0, g: 0, b: 0, a: 0 }),
|
|
216
|
+
};
|
|
217
|
+
/** 32-bit floating point number (IEEE 754, little-endian) */
|
|
218
|
+
BinaryPrimitives.f32_le = {
|
|
219
|
+
size: 4,
|
|
220
|
+
write: (dv, o, v) => dv.setFloat32(o, v, true),
|
|
221
|
+
read: (dv, o) => dv.getFloat32(o, true),
|
|
222
|
+
toNil: () => 0,
|
|
223
|
+
};
|
|
224
|
+
/** 64-bit floating point number (double, little-endian) */
|
|
225
|
+
BinaryPrimitives.f64_le = {
|
|
226
|
+
size: 8,
|
|
227
|
+
write: (dv, o, v) => dv.setFloat64(o, v, true),
|
|
228
|
+
read: (dv, o) => dv.getFloat64(o, true),
|
|
229
|
+
toNil: () => 0,
|
|
230
|
+
};
|
|
231
|
+
/** Unsigned 16-bit integer (little-endian) */
|
|
232
|
+
BinaryPrimitives.u16_le = {
|
|
233
|
+
size: 2,
|
|
234
|
+
write: (dv, o, v) => dv.setUint16(o, v, true),
|
|
235
|
+
read: (dv, o) => dv.getUint16(o, true),
|
|
236
|
+
toNil: () => 0,
|
|
237
|
+
};
|
|
238
|
+
/** Unsigned 32-bit integer (little-endian) */
|
|
239
|
+
BinaryPrimitives.u32_le = {
|
|
240
|
+
size: 4,
|
|
241
|
+
write: (dv, o, v) => dv.setUint32(o, v, true),
|
|
242
|
+
read: (dv, o) => dv.getUint32(o, true),
|
|
243
|
+
toNil: () => 0,
|
|
244
|
+
};
|
|
245
|
+
/** Signed 16-bit integer (little-endian) */
|
|
246
|
+
BinaryPrimitives.i16_le = {
|
|
247
|
+
size: 2,
|
|
248
|
+
write: (dv, o, v) => dv.setInt16(o, v, true),
|
|
249
|
+
read: (dv, o) => dv.getInt16(o, true),
|
|
250
|
+
toNil: () => 0,
|
|
251
|
+
};
|
|
252
|
+
/** Signed 32-bit integer (little-endian) */
|
|
253
|
+
BinaryPrimitives.i32_le = {
|
|
254
|
+
size: 4,
|
|
255
|
+
write: (dv, o, v) => dv.setInt32(o, v, true),
|
|
256
|
+
read: (dv, o) => dv.getInt32(o, true),
|
|
257
|
+
toNil: () => 0,
|
|
258
|
+
};
|
|
259
|
+
/**
|
|
260
|
+
* 2D vector of f32 stored as a tuple [x, y] (little-endian).
|
|
261
|
+
* Useful for compact math data or shader-friendly layouts.
|
|
262
|
+
*/
|
|
263
|
+
BinaryPrimitives.vec2_le = {
|
|
264
|
+
size: 8,
|
|
265
|
+
write: (dv, o, v) => {
|
|
266
|
+
dv.setFloat32(o, v[0], true);
|
|
267
|
+
dv.setFloat32(o + 4, v[1], true);
|
|
268
|
+
},
|
|
269
|
+
read: (dv, o) => [
|
|
270
|
+
dv.getFloat32(o, true),
|
|
271
|
+
dv.getFloat32(o + 4, true),
|
|
272
|
+
],
|
|
273
|
+
toNil: () => [0, 0],
|
|
274
|
+
};
|
|
275
|
+
/**
|
|
276
|
+
* 3D vector of f32 stored as a tuple [x, y, z] (little-endian).
|
|
277
|
+
* Commonly used for positions, velocities, or directions.
|
|
278
|
+
*/
|
|
279
|
+
BinaryPrimitives.vec3_le = {
|
|
280
|
+
size: 12,
|
|
281
|
+
write: (dv, o, v) => {
|
|
282
|
+
dv.setFloat32(o, v[0], true);
|
|
283
|
+
dv.setFloat32(o + 4, v[1], true);
|
|
284
|
+
dv.setFloat32(o + 8, v[2], true);
|
|
285
|
+
},
|
|
286
|
+
read: (dv, o) => [
|
|
287
|
+
dv.getFloat32(o, true),
|
|
288
|
+
dv.getFloat32(o + 4, true),
|
|
289
|
+
dv.getFloat32(o + 8, true),
|
|
290
|
+
],
|
|
291
|
+
toNil: () => [0, 0, 0],
|
|
292
|
+
};
|
|
293
|
+
/**
|
|
294
|
+
* 4D vector of f32 stored as a tuple [x, y, z, w] (little-endian).
|
|
295
|
+
* Useful for quaternions, colors in shaders, or homogeneous coordinates.
|
|
296
|
+
*/
|
|
297
|
+
BinaryPrimitives.vec4_le = {
|
|
298
|
+
size: 16,
|
|
299
|
+
write: (dv, o, v) => {
|
|
300
|
+
dv.setFloat32(o, v[0], true);
|
|
301
|
+
dv.setFloat32(o + 4, v[1], true);
|
|
302
|
+
dv.setFloat32(o + 8, v[2], true);
|
|
303
|
+
dv.setFloat32(o + 12, v[3], true);
|
|
304
|
+
},
|
|
305
|
+
read: (dv, o) => [
|
|
306
|
+
dv.getFloat32(o, true),
|
|
307
|
+
dv.getFloat32(o + 4, true),
|
|
308
|
+
dv.getFloat32(o + 8, true),
|
|
309
|
+
dv.getFloat32(o + 12, true),
|
|
310
|
+
],
|
|
311
|
+
toNil: () => [0, 0, 0, 0],
|
|
312
|
+
};
|
|
313
|
+
/**
|
|
314
|
+
* Public codec API.
|
|
315
|
+
* Re-exports primitives and exposes encode/decode helpers.
|
|
316
|
+
*/
|
|
317
|
+
export class BinaryCodec extends BaseBinaryCodec {
|
|
318
|
+
/**
|
|
319
|
+
* Encodes an object into a binary buffer.
|
|
320
|
+
*/
|
|
321
|
+
static encode(schema, data) {
|
|
322
|
+
return this.encodeInto(schema, data);
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Decodes a binary buffer into an existing object.
|
|
326
|
+
*/
|
|
327
|
+
static decode(schema, buf, target) {
|
|
328
|
+
return this.decodeInto(schema, buf, target);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/** Unsigned 8-bit integer field */
|
|
332
|
+
BinaryCodec.u8 = BinaryPrimitives.u8;
|
|
333
|
+
/** Unsigned 16-bit integer field */
|
|
334
|
+
BinaryCodec.u16 = BinaryPrimitives.u16;
|
|
335
|
+
/** 32-bit floating point field */
|
|
336
|
+
BinaryCodec.f32 = BinaryPrimitives.f32;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './binary-codec';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './binary-codec';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
type Callback<Props> = (props: Props) => void;
|
|
2
|
+
type EventMapFromTuple<T extends [string, unknown][]> = {
|
|
3
|
+
[K in T[number] as K[0]]: K[1];
|
|
4
|
+
};
|
|
5
|
+
interface EventSystemProps<EventNames extends string> {
|
|
6
|
+
/**
|
|
7
|
+
* @description
|
|
8
|
+
* The list of events to ever be registered.
|
|
9
|
+
*/
|
|
10
|
+
events: EventNames[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* @description
|
|
14
|
+
* A callback-based event handling system designed to simplify
|
|
15
|
+
* event-driven programming.
|
|
16
|
+
*/
|
|
17
|
+
export declare class EventSystem<EventTuple extends [string, unknown][]> {
|
|
18
|
+
/**
|
|
19
|
+
* @private
|
|
20
|
+
* @description
|
|
21
|
+
* The map of registered events and their callbacks.
|
|
22
|
+
*/
|
|
23
|
+
private callbacks;
|
|
24
|
+
/**
|
|
25
|
+
* @private
|
|
26
|
+
* @description
|
|
27
|
+
* The list of events that were registered.
|
|
28
|
+
*/
|
|
29
|
+
private events;
|
|
30
|
+
constructor({ events }: EventSystemProps<string>);
|
|
31
|
+
/**
|
|
32
|
+
* @description
|
|
33
|
+
* Registers a callback for an event.
|
|
34
|
+
*
|
|
35
|
+
* @param name Event name
|
|
36
|
+
* @param callback Callback to run when the event is emitted
|
|
37
|
+
*/
|
|
38
|
+
on<EventName extends keyof EventMapFromTuple<EventTuple> & string>(name: EventName, callback: Callback<EventMapFromTuple<EventTuple>[EventName]>): void;
|
|
39
|
+
/**
|
|
40
|
+
* @description
|
|
41
|
+
* Registers a callback for an event that runs only once.
|
|
42
|
+
*
|
|
43
|
+
* @param name Event name
|
|
44
|
+
* @param callback Callback to run when the event is emitted
|
|
45
|
+
*/
|
|
46
|
+
once<EventName extends keyof EventMapFromTuple<EventTuple> & string>(name: EventName, callback: Callback<EventMapFromTuple<EventTuple>[EventName]>): void;
|
|
47
|
+
/**
|
|
48
|
+
* @description
|
|
49
|
+
* Emits an event, running all registered callbacks.
|
|
50
|
+
*
|
|
51
|
+
* @param name Event name
|
|
52
|
+
* @param data Event data
|
|
53
|
+
*/
|
|
54
|
+
emit<EventName extends keyof EventMapFromTuple<EventTuple> & string>(name: EventName, data: EventMapFromTuple<EventTuple>[EventName]): void;
|
|
55
|
+
/**
|
|
56
|
+
* @description
|
|
57
|
+
* Removes a callback from an event.
|
|
58
|
+
*
|
|
59
|
+
* @param name Event name
|
|
60
|
+
* @param callback Callback to remove
|
|
61
|
+
*/
|
|
62
|
+
off<EventName extends keyof EventMapFromTuple<EventTuple> & string>(name: EventName, callback: Callback<EventMapFromTuple<EventTuple>[EventName]>): void;
|
|
63
|
+
/**
|
|
64
|
+
* @description
|
|
65
|
+
* Removes all callbacks.
|
|
66
|
+
*
|
|
67
|
+
* @param name Optional event name
|
|
68
|
+
*/
|
|
69
|
+
clear<EventName extends keyof EventMapFromTuple<EventTuple> & string>(name?: EventName): void;
|
|
70
|
+
}
|
|
71
|
+
export {};
|