@genex-ai/multiplayer 0.16.1 → 0.17.0
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/PROTOCOL.md +624 -0
- package/README.md +191 -27
- package/dist/bridge.d.ts +89 -0
- package/dist/bridge.global.js +14 -0
- package/dist/bridge.js +558 -0
- package/dist/chunk-C52XFIB6.js +312 -0
- package/dist/chunk-CTDU4IJ5.js +2191 -0
- package/dist/index.d.ts +110 -18
- package/dist/index.js +7 -1778
- package/dist/protocol.d.ts +419 -0
- package/dist/protocol.js +58 -0
- package/dist/schema.d.ts +122 -68
- package/dist/schema.js +95 -16
- package/package.json +27 -10
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { ObjectControlOperation as ObjectControlOperation$1, ObjectControlReason as ObjectControlReason$1 } from './protocol.js';
|
|
2
|
+
export { ObjectState, PlayerState, RoomState } from './schema.js';
|
|
2
3
|
import '@colyseus/schema';
|
|
3
4
|
|
|
4
5
|
/** One remote participant in the voice mesh. */
|
|
@@ -70,6 +71,16 @@ type ConnectOptions = {
|
|
|
70
71
|
auth?: AuthSource;
|
|
71
72
|
/** Extra join options passed to the room. */
|
|
72
73
|
options?: Record<string, unknown>;
|
|
74
|
+
} & SessionOptions;
|
|
75
|
+
/** How remote posed players are smoothed (EXPERIMENTAL, see {@link SessionOptions.smoothing}). */
|
|
76
|
+
type PredictSmoothing = {
|
|
77
|
+
engine: 'predict';
|
|
78
|
+
/** Colyseus `Predict` mode. Default `'lerp'`. */
|
|
79
|
+
mode?: 'lerp' | 'damped';
|
|
80
|
+
/** `lerp` render delay in ms (Predict's default 100). */
|
|
81
|
+
delay?: number;
|
|
82
|
+
/** Predict's output spring / damped chase rate in ms (Predict's defaults when omitted). */
|
|
83
|
+
smoothMs?: number;
|
|
73
84
|
};
|
|
74
85
|
type PlayerView<TState> = {
|
|
75
86
|
id: string;
|
|
@@ -81,6 +92,14 @@ type PlayerView<TState> = {
|
|
|
81
92
|
avatarUrl: string;
|
|
82
93
|
/** Transport is live now. False while this reserved seat is inside reconnect grace. */
|
|
83
94
|
connected: boolean;
|
|
95
|
+
/** This player's stable id IN THIS GAME: the same across reloads, devices and rooms of the
|
|
96
|
+
* game, different in every other game, never the account id. Key anything that outlives a
|
|
97
|
+
* session (scores, colours, saves, "is this me") by it — `id` is a session id and changes on
|
|
98
|
+
* every reload. Opaque, ≤64 chars: never parse it. Relay-stamped from the verified token. */
|
|
99
|
+
uid: string;
|
|
100
|
+
/** Team index the relay assigned, or `-1` for no team: the `open` preset's `teams: N` (kept by
|
|
101
|
+
* `uid` for the room's life, never reshuffled) or the `teams` preset's current round. */
|
|
102
|
+
team: number;
|
|
84
103
|
/** RENDER ONLY — for remote players this is **auto-smoothed** (interpolated) and delayed;
|
|
85
104
|
* for yourself it's live. Numeric fields are lerped; everything else snaps. Use `stateRaw`
|
|
86
105
|
* for every gameplay read (hits, reach, pickups, flags, physics adoption). */
|
|
@@ -103,8 +122,12 @@ type ObjectView<TState> = {
|
|
|
103
122
|
/** The latest raw snapshot (never smoothed/delayed) — for hit-tests / logic. */
|
|
104
123
|
stateRaw: TState;
|
|
105
124
|
};
|
|
106
|
-
type ObjectControlOperation =
|
|
107
|
-
|
|
125
|
+
type ObjectControlOperation = ObjectControlOperation$1;
|
|
126
|
+
/** The relay's reasons (PROTOCOL.md §7.2), plus the ones this client settles a request with
|
|
127
|
+
* itself: `timeout`, `aborted` (your signal, or `leave()`), `disconnected` (the session ended). */
|
|
128
|
+
type ObjectControlReason = ObjectControlReason$1
|
|
129
|
+
/** @deprecated Never produced since protocol 3 — every relay answers control requests. */
|
|
130
|
+
| 'unsupported' | 'timeout' | 'aborted' | 'disconnected';
|
|
108
131
|
type ObjectControlResult = {
|
|
109
132
|
requestId: string;
|
|
110
133
|
operation: ObjectControlOperation;
|
|
@@ -185,7 +208,8 @@ type Session<TState extends Record<string, unknown>> = {
|
|
|
185
208
|
/** True if you are the elected room host — the earliest signed-in player still present
|
|
186
209
|
* (guests host only while no account is in the room); can migrate on join as well as leave.
|
|
187
210
|
* Settles within the first state patch after connect — read it in your loop or react to
|
|
188
|
-
* `on('host')`, not once.
|
|
211
|
+
* `on('host')`, not once. False while the session is reconnecting (until the fresh snapshot
|
|
212
|
+
* says who the host is now) and after it ends, so a write behind `isHost` is never stale. */
|
|
189
213
|
readonly isHost: boolean;
|
|
190
214
|
/** Session id of the current room host, or `undefined` until the first host patch lands. */
|
|
191
215
|
readonly host: string | undefined;
|
|
@@ -228,27 +252,35 @@ type Session<TState extends Record<string, unknown>> = {
|
|
|
228
252
|
limit?: number;
|
|
229
253
|
}) => void): () => void;
|
|
230
254
|
/**
|
|
231
|
-
* The connection dropped unexpectedly and auto-reconnect is underway (
|
|
232
|
-
* ~0.
|
|
233
|
-
* keep your loop running — the world resumes seamlessly on
|
|
255
|
+
* The connection dropped unexpectedly and auto-reconnect is underway (one event per
|
|
256
|
+
* attempt; the attempts back off ~0.25s→4s and all land inside the relay's 30s seat grace).
|
|
257
|
+
* Show a "reconnecting…" overlay; keep your loop running — the world resumes seamlessly on
|
|
258
|
+
* `reconnected`. Host ticks pause until then.
|
|
234
259
|
*/
|
|
235
260
|
on(event: 'reconnecting', cb: (info: {
|
|
236
261
|
attempt: number;
|
|
237
262
|
code: number;
|
|
238
263
|
}) => void): () => void;
|
|
239
|
-
/** Auto-reconnect succeeded: same session id, same seat — nothing was torn down.
|
|
264
|
+
/** Auto-reconnect succeeded: same session id, same seat — nothing was torn down. Fires once
|
|
265
|
+
* the room's state is current again (host, owners, players), so it is safe to read here. */
|
|
240
266
|
on(event: 'reconnected', cb: () => void): () => void;
|
|
241
267
|
/**
|
|
242
268
|
* The connection is gone for good: the server closed it on purpose (restart, revoked
|
|
243
|
-
* session, match eviction) or every reconnect attempt
|
|
244
|
-
* to play again, read a FRESH `getColyseusAuth()` and
|
|
269
|
+
* session 4401, a newer tab took the seat 4409, match eviction) or every reconnect attempt
|
|
270
|
+
* failed (4003). The session is dead — to play again, read a FRESH `getColyseusAuth()` and
|
|
271
|
+
* `connect()` anew (but not automatically after 4409: the player is playing elsewhere).
|
|
245
272
|
*/
|
|
246
273
|
on(event: 'disconnect', cb: (code: number) => void): () => void;
|
|
274
|
+
/** The host opened or closed this room to new matchmaking placements (`setRoomOpen`). */
|
|
275
|
+
on(event: 'room:open', cb: (info: {
|
|
276
|
+
open: boolean;
|
|
277
|
+
}) => void): () => void;
|
|
247
278
|
/** A custom event another client sent via `send(type, ...)`. */
|
|
248
279
|
on(event: string & {}, cb: (payload: unknown) => void): () => void;
|
|
249
280
|
/** Fire-and-forget event to all OTHER clients (not stored in state). Event names used
|
|
250
|
-
* by the relay itself (`state`, `shared`, `claim`, `
|
|
251
|
-
* `match:`/`
|
|
281
|
+
* by the relay itself (`state`, `shared`, `claim`, `release`, `destroy`, `obj`, `queue`,
|
|
282
|
+
* `seat`, and the `__`/`match:`/`server:`/`rate:` prefixes) and names over 128 characters
|
|
283
|
+
* are refused with a console warning — pick another name. */
|
|
252
284
|
send(type: string, payload?: unknown): void;
|
|
253
285
|
/** Text chat for this room. See {@link ChatApi}. */
|
|
254
286
|
chat: ChatApi;
|
|
@@ -263,12 +295,56 @@ type Session<TState extends Record<string, unknown>> = {
|
|
|
263
295
|
* keeps playing, and a reconnecting player still gets back in (reconnection uses a
|
|
264
296
|
* reserved seat, not matchmaking).
|
|
265
297
|
*
|
|
266
|
-
* Ignored (with no error) when called by a non-host — read `isHost` first.
|
|
267
|
-
*
|
|
298
|
+
* Ignored (with no error) when called by a non-host — read `isHost` first. When the host
|
|
299
|
+
* calls it every client is told, so you can render "closed" from the `room:open` event.
|
|
268
300
|
*/
|
|
269
301
|
setRoomOpen(open: boolean): void;
|
|
270
302
|
/** Leave the room (deliberate — no auto-reconnect, no `disconnect` event). */
|
|
271
303
|
leave(): void;
|
|
304
|
+
/**
|
|
305
|
+
* EXPERIMENTAL — the relay's server clock (PROTOCOL.md §16): milliseconds since the room was
|
|
306
|
+
* created, estimated from this client's heartbeat acks. `undefined` against a relay that does not
|
|
307
|
+
* publish its clock. For server-stamped deadlines prefer {@link timeUntil}; never use this to drive
|
|
308
|
+
* rendering (remote players stay on their senders' clocks).
|
|
309
|
+
*/
|
|
310
|
+
serverNow(): number | undefined;
|
|
311
|
+
/** EXPERIMENTAL — smoothed round-trip time to the relay in ms, from heartbeat acks. `undefined`
|
|
312
|
+
* until the first ack, and always against a relay that does not publish its clock. It includes
|
|
313
|
+
* the relay's hold until its next patch (0 to ~33 ms), so read it as an upper bound. */
|
|
314
|
+
readonly rtt: number | undefined;
|
|
315
|
+
/** EXPERIMENTAL — true once enough heartbeats were acked (~3 s) that `serverNow()` is within a few ms of the room clock. */
|
|
316
|
+
readonly clockSynced: boolean;
|
|
317
|
+
/**
|
|
318
|
+
* Milliseconds from now until a relay deadline stamped in epoch ms (a match's `startsAt` /
|
|
319
|
+
* `endsBy`; negative once it passed). Uses the server clock once it is synced — immune to a wrong
|
|
320
|
+
* clock on the player's device — and falls back to `deadline − Date.now()` otherwise.
|
|
321
|
+
*/
|
|
322
|
+
timeUntil(epochMs: number): number;
|
|
323
|
+
};
|
|
324
|
+
/** Session behaviour options shared by `connect()`, `matchmake()`, `createPrivate()` and
|
|
325
|
+
* `joinPrivate()`. Every one is EXPERIMENTAL and off by default: each is an A/B arm of the
|
|
326
|
+
* netcode bench (PROTOCOL.md §15) and stays opt-in until it wins its gate. */
|
|
327
|
+
type SessionOptions = {
|
|
328
|
+
/**
|
|
329
|
+
* EXPERIMENTAL — typed pose (PROTOCOL.md §6.6). Default `false`. When `true`, the reserved keys
|
|
330
|
+
* `x y z yaw vx vy vz anim` of `me.set()` / `me.snap()` are published as typed relay fields
|
|
331
|
+
* (float32 deltas instead of a re-sent JSON blob) and everything else as `data`, which is then sent
|
|
332
|
+
* only when it changes. If you omit `vx/vy/vz` they are derived from successive positions.
|
|
333
|
+
*
|
|
334
|
+
* Opt in for EVERY client of the game at once. Receivers then interpolate only the pose — `yaw`
|
|
335
|
+
* along the shortest arc (radians), `anim` switches when the rendered pose reaches it — and SNAP
|
|
336
|
+
* everything else in your state: a rotation you sync as a quaternion is no longer smoothed, so put
|
|
337
|
+
* the heading in `yaw`. A remote posed player's `state` always carries all eight pose keys.
|
|
338
|
+
*/
|
|
339
|
+
pose?: boolean;
|
|
340
|
+
/**
|
|
341
|
+
* EXPERIMENTAL — remote smoothing engine for POSED players. Default `'genex'`: the SDK's own
|
|
342
|
+
* sender-clock interpolation (PROTOCOL.md §10.1), which every other stream keeps whatever this says.
|
|
343
|
+
* `'predict'` (or a {@link PredictSmoothing}) hands posed players' `x y z vx vy vz` and `yaw` to
|
|
344
|
+
* Colyseus `Predict` instead — receive-time stamps, a fixed delay, no dead reckoning past the newest
|
|
345
|
+
* sample, and `anim`/`data` applied on arrival. It exists so the bench can A/B the two engines.
|
|
346
|
+
*/
|
|
347
|
+
smoothing?: 'genex' | 'predict' | PredictSmoothing;
|
|
272
348
|
};
|
|
273
349
|
/** One chat line, as the relay stamped it. Only `text` came from the sender's client —
|
|
274
350
|
* `from` and `name` are filled in server-side from the verified session, so a player
|
|
@@ -397,6 +473,16 @@ type MatchmakingView = {
|
|
|
397
473
|
/** Winner of the round shown while `status === 'ended'` (competitor id; null on a draw). */
|
|
398
474
|
winnerId: string | null;
|
|
399
475
|
message: string;
|
|
476
|
+
/** The relay's epoch-ms `startsAt` — when the countdown (or the result screen before the next
|
|
477
|
+
* round) ends — else null. */
|
|
478
|
+
startsAt: number | null;
|
|
479
|
+
/** Round time limit: the relay's epoch-ms `endsBy` (presets with a round limit), else null. */
|
|
480
|
+
endsBy: number | null;
|
|
481
|
+
/** Milliseconds until `startsAt` as of this read (≥ 0), or null. Measured on the relay's server
|
|
482
|
+
* clock once it is synced, so a wrong clock on the player's device cannot skew a countdown. */
|
|
483
|
+
startsInMs: number | null;
|
|
484
|
+
/** Milliseconds until `endsBy` as of this read (≥ 0), or null. Same clock as `startsInMs`. */
|
|
485
|
+
endsInMs: number | null;
|
|
400
486
|
};
|
|
401
487
|
type Matchmaking<TState extends Record<string, unknown>> = {
|
|
402
488
|
/** The live game session, or null while searching for a match. */
|
|
@@ -406,11 +492,17 @@ type Matchmaking<TState extends Record<string, unknown>> = {
|
|
|
406
492
|
/**
|
|
407
493
|
* searching: (re)entered the queue. queue: your position changed ({position,size}).
|
|
408
494
|
* matched: `session` is now live. matchStart: a round began ({roundId}).
|
|
409
|
-
* matchEnded: {winnerId,
|
|
495
|
+
* matchEnded: {winnerId,losers,draw,scores}. spectate: you're watching, not playing.
|
|
410
496
|
* error: joining the queue failed even after the SDK's automatic retries (persistent —
|
|
411
497
|
* e.g. auth is broken or the server is unreachable); fix the cause, then call `retry()`.
|
|
498
|
+
* A relay that refuses this SDK's protocol (code 426) fails at once, without retries: the
|
|
499
|
+
* game needs an SDK update.
|
|
500
|
+
* disconnect: the match seat ended with 4409 (this player opened the game in another tab or
|
|
501
|
+
* device) or 4401 (signed out). The handle stops and does NOT requeue; `session` is null. Tell
|
|
502
|
+
* the player, and call `retry()` only if they choose to play here again. Every other terminal
|
|
503
|
+
* drop requeues automatically.
|
|
412
504
|
*/
|
|
413
|
-
on(event: 'searching' | 'queue' | 'matched' | 'matchStart' | 'matchEnded' | 'spectate' | 'error', cb: (payload?: unknown) => void): () => void;
|
|
505
|
+
on(event: 'searching' | 'queue' | 'matched' | 'matchStart' | 'matchEnded' | 'spectate' | 'error' | 'disconnect', cb: (payload?: unknown) => void): () => void;
|
|
414
506
|
/** Report your OWN elimination (the `lastStanding` win condition). */
|
|
415
507
|
eliminated(): void;
|
|
416
508
|
/** Report a score delta for yourself (the `firstToScore` / `highScoreInTime` conditions). */
|
|
@@ -439,7 +531,7 @@ type MatchmakeOptions = {
|
|
|
439
531
|
* token; a static object is read only once and will be rejected once it expires.
|
|
440
532
|
*/
|
|
441
533
|
auth?: AuthSource;
|
|
442
|
-
};
|
|
534
|
+
} & SessionOptions;
|
|
443
535
|
/**
|
|
444
536
|
* Join a game's matchmaking. Returns immediately in the SEARCHING state (`session` is null); the
|
|
445
537
|
* matchmaker seats you into a match room, at which point `session` becomes a live Session and a
|
|
@@ -469,4 +561,4 @@ declare function createPrivate<TState extends Record<string, unknown> = never>(o
|
|
|
469
561
|
*/
|
|
470
562
|
declare function joinPrivate<TState extends Record<string, unknown> = never>(code: string, opts: MatchmakeOptions): Promise<Matchmaking<TState>>;
|
|
471
563
|
|
|
472
|
-
export { type AuthSource, type ChatApi, type ChatMessage, type ColyseusAuth, type ConnectOptions, type MatchStatus, type MatchmakeOptions, type Matchmaking, type MatchmakingView, type ObjectControlOperation, type ObjectControlOptions, type ObjectControlReason, type ObjectControlResult, type ObjectView, type PlayerView, type PrivateMatch, type Session, type VoiceApi, type VoiceJoinOptions, type VoiceParticipant, connect, createPrivate, joinPrivate, matchmake };
|
|
564
|
+
export { type AuthSource, type ChatApi, type ChatMessage, type ColyseusAuth, type ConnectOptions, type MatchStatus, type MatchmakeOptions, type Matchmaking, type MatchmakingView, type ObjectControlOperation, type ObjectControlOptions, type ObjectControlReason, type ObjectControlResult, type ObjectView, type PlayerView, type PredictSmoothing, type PrivateMatch, type Session, type SessionOptions, type VoiceApi, type VoiceJoinOptions, type VoiceParticipant, connect, createPrivate, joinPrivate, matchmake };
|