@genex-ai/multiplayer 0.17.0 → 0.17.6

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.
@@ -1,10 +1,20 @@
1
+ import {
2
+ explainJoinRefusal,
3
+ isProtocolRefusal,
4
+ joinOptions,
5
+ relayClient,
6
+ seedsInterpolation,
7
+ useSdkReconnection,
8
+ waitForFirstState,
9
+ warnProtocolRefusal,
10
+ withoutReconnection
11
+ } from "./chunk-UX3F6YTV.js";
1
12
  import {
2
13
  ClientMessage,
3
14
  ClientReconnection,
4
15
  ClockSync,
5
16
  CloseCode,
6
17
  Interpolation,
7
- JoinError,
8
18
  Limits,
9
19
  POSE_KEYS,
10
20
  PROTOCOL_VERSION,
@@ -13,10 +23,10 @@ import {
13
23
  SEND_TIME_KEY,
14
24
  ServerMessage,
15
25
  isReservedEventType
16
- } from "./chunk-C52XFIB6.js";
26
+ } from "./chunk-ZSWF4VCN.js";
17
27
 
18
28
  // src/index.ts
19
- import { Client, getStateCallbacks } from "@colyseus/sdk";
29
+ import { getStateCallbacks } from "@colyseus/sdk";
20
30
 
21
31
  // src/ice-request.ts
22
32
  function createIceRequester(send, timeoutMs) {
@@ -241,40 +251,6 @@ function msUntil(epochMs, clock) {
241
251
  return epochMs - clock.wallNow;
242
252
  }
243
253
 
244
- // src/room-lifecycle.ts
245
- function useSdkReconnection(room) {
246
- const r = room.reconnection;
247
- r.enabled = ClientReconnection.enabled;
248
- r.minUptime = ClientReconnection.minUptime;
249
- r.delay = ClientReconnection.delay;
250
- r.minDelay = ClientReconnection.minDelay;
251
- r.maxDelay = ClientReconnection.maxDelay;
252
- r.maxRetries = ClientReconnection.maxRetries;
253
- r.maxEnqueuedMessages = ClientReconnection.maxEnqueuedMessages;
254
- r.enqueuedMessages.length = 0;
255
- return room;
256
- }
257
- function withoutReconnection(room) {
258
- room.reconnection.enabled = false;
259
- return room;
260
- }
261
- function waitForFirstState(room, timeoutMs) {
262
- return new Promise((resolve) => {
263
- const onState = () => {
264
- clearTimeout(timer);
265
- resolve(true);
266
- };
267
- const timer = setTimeout(() => {
268
- room.onStateChange.remove(onState);
269
- resolve(false);
270
- }, timeoutMs);
271
- room.onStateChange.once(onState);
272
- });
273
- }
274
- function seedsInterpolation(id, selfId, sendTime) {
275
- return id !== selfId && sendTime != null;
276
- }
277
-
278
254
  // src/voice.ts
279
255
  var NOT_DELEGATED = "The microphone was refused by the page that frames this game, not by the player: the frame was not given it, so the browser never asked. On its Genex page a build is given the microphone only when it declares it. An up-to-date genex CLI declares it at `genex preview` and `genex publish` when the game's own source calls voice.join(); to declare it by hand, add \"microphone\" to genex.capabilities in the game's package.json. Then preview or publish again.";
280
256
  var VoiceNotDelegatedError = class extends Error {
@@ -680,14 +656,6 @@ var ICE_REQUEST_TIMEOUT_MS = 3e3;
680
656
  var CONTROL_TIMEOUT_MS = 5e3;
681
657
  var CONTROL_TIMEOUT_MAX_MS = 6e4;
682
658
  var POSE_DATA_KEEPALIVE_MS = 2e3;
683
- async function relayClient(opts) {
684
- if (opts.url) return new Client(opts.url);
685
- if (opts.urls.length > 1) return Client.selectByLatency(opts.urls);
686
- const url = opts.urls[0];
687
- if (!url) throw new Error("genex multiplayer: `urls` must contain at least one relay URL");
688
- return new Client(url);
689
- }
690
- var resolveAuth = (auth) => typeof auth === "function" ? auth() : auth;
691
659
  function predictSmoothing(opt) {
692
660
  if (opt === "predict") return { mode: "lerp" };
693
661
  if (opt && typeof opt === "object" && opt.engine === "predict") {
@@ -832,22 +800,6 @@ async function connect(opts) {
832
800
  );
833
801
  return attachSession(room, { pose: opts.pose, smoothing: opts.smoothing, predict });
834
802
  }
835
- function joinOptions(gameId, name, auth) {
836
- return {
837
- gameId,
838
- name,
839
- embedToken: resolveAuth(auth)?.embedToken,
840
- protocol: PROTOCOL_VERSION
841
- };
842
- }
843
- var isProtocolRefusal = (err) => !!err && typeof err === "object" && err.code === JoinError.PROTOCOL_UNSUPPORTED;
844
- var warnProtocolRefusal = () => console.error(
845
- `[multiplayer] the relay refused protocol ${PROTOCOL_VERSION} (code 426) \u2014 this game was built with a @genex-ai/multiplayer that this relay no longer serves. Update the package and republish.`
846
- );
847
- var explainJoinRefusal = (err) => {
848
- if (isProtocolRefusal(err)) warnProtocolRefusal();
849
- throw err;
850
- };
851
803
  var isSendableEventType = (type) => typeof type === "string" && type.length > 0 && type.length <= Limits.MAX_EVENT_TYPE_CHARS && !isReservedEventType(type);
852
804
  var LOCAL_EVENTS = /* @__PURE__ */ new Set([
853
805
  "join",
@@ -0,0 +1,27 @@
1
+ // src/authority/module.ts
2
+ var MODULE_CONTRACT = 1;
3
+ var LeaveReason = {
4
+ /** The client left on purpose. */
5
+ LEFT: "left",
6
+ /** The connection dropped and the reconnection grace ran out. */
7
+ DROPPED: "dropped",
8
+ /** A newer session of the same player took the seat. */
9
+ SUPERSEDED: "superseded",
10
+ /** The player's session was revoked. */
11
+ REVOKED: "revoked",
12
+ /** The room is closing (drain, halt or fault). */
13
+ CLOSING: "closing"
14
+ };
15
+ var RemotePredict = {
16
+ EXTRAPOLATE: "extrapolate",
17
+ HOLD: "hold",
18
+ INPUT_DECAY: "inputDecay"
19
+ };
20
+ var defineRoom = (module) => module;
21
+
22
+ export {
23
+ MODULE_CONTRACT,
24
+ LeaveReason,
25
+ RemotePredict,
26
+ defineRoom
27
+ };
@@ -0,0 +1,143 @@
1
+ import {
2
+ ClientReconnection,
3
+ JoinError,
4
+ PROTOCOL_VERSION
5
+ } from "./chunk-ZSWF4VCN.js";
6
+
7
+ // src/join.ts
8
+ import { Client as Client2 } from "@colyseus/sdk";
9
+
10
+ // src/relay-select.ts
11
+ import { Client } from "@colyseus/sdk";
12
+ var RELAY_SELECT_DEFAULTS = {
13
+ SAMPLES: 3,
14
+ // Well past Colyseus's 1.5 s, which a loading web export's main thread was measured exceeding.
15
+ TIMEOUT_MS: 4e3,
16
+ // A far relay's sample lands within a few hundred ms of a near one's; a dead relay must not hold
17
+ // a working join for the full timeout.
18
+ GRACE_MS: 1e3
19
+ };
20
+ async function selectRelayUrl(urls, options = {}) {
21
+ const first = urls[0];
22
+ if (first === void 0) throw new Error("genex multiplayer: `urls` must contain at least one relay URL");
23
+ if (urls.length === 1) return first;
24
+ const probe = options.probe ?? defaultProbe;
25
+ const samples = Math.max(1, options.samples ?? RELAY_SELECT_DEFAULTS.SAMPLES);
26
+ const timeoutMs = options.timeoutMs ?? RELAY_SELECT_DEFAULTS.TIMEOUT_MS;
27
+ const graceMs = options.graceMs ?? RELAY_SELECT_DEFAULTS.GRACE_MS;
28
+ const best = urls.map(() => void 0);
29
+ await new Promise((resolve) => {
30
+ let pending = urls.length * samples;
31
+ let grace;
32
+ const ceiling = setTimeout(done, timeoutMs);
33
+ function done() {
34
+ clearTimeout(ceiling);
35
+ clearTimeout(grace);
36
+ resolve();
37
+ }
38
+ const settle = () => {
39
+ if (--pending === 0) done();
40
+ };
41
+ urls.forEach((url, i) => {
42
+ for (let n = 0; n < samples; n++) {
43
+ let sample;
44
+ try {
45
+ sample = probe(url, timeoutMs);
46
+ } catch (err) {
47
+ sample = Promise.reject(err);
48
+ }
49
+ sample.then(
50
+ (ms) => {
51
+ if (Number.isFinite(ms) && ms >= 0) {
52
+ best[i] = Math.min(best[i] ?? Infinity, ms);
53
+ grace ??= setTimeout(done, graceMs);
54
+ }
55
+ settle();
56
+ },
57
+ settle
58
+ );
59
+ }
60
+ });
61
+ });
62
+ let pick = -1;
63
+ best.forEach((ms, i) => {
64
+ if (ms !== void 0 && (pick < 0 || ms < best[pick])) pick = i;
65
+ });
66
+ if (pick < 0) {
67
+ console.warn(`genex multiplayer: no relay answered the latency probe \u2014 connecting to ${first}`);
68
+ return first;
69
+ }
70
+ return urls[pick];
71
+ }
72
+ var defaultProbe = (url, timeoutMs) => new Client(url).getLatency({ pingCount: 1, timeout: timeoutMs });
73
+
74
+ // src/join.ts
75
+ var resolveAuth = (auth) => typeof auth === "function" ? auth() : auth;
76
+ async function relayClient(opts) {
77
+ if (opts.url) return new Client2(opts.url);
78
+ return new Client2(await selectRelayUrl(opts.urls));
79
+ }
80
+ function joinOptions(gameId, name, auth) {
81
+ return {
82
+ gameId,
83
+ name,
84
+ embedToken: resolveAuth(auth)?.embedToken,
85
+ protocol: PROTOCOL_VERSION
86
+ };
87
+ }
88
+ var isProtocolRefusal = (err) => !!err && typeof err === "object" && err.code === JoinError.PROTOCOL_UNSUPPORTED;
89
+ var warnProtocolRefusal = () => console.error(
90
+ `[multiplayer] the relay refused protocol ${PROTOCOL_VERSION} (code 426) \u2014 this game was built with a @genex-ai/multiplayer that this relay no longer serves. Update the package and republish.`
91
+ );
92
+ var explainJoinRefusal = (err) => {
93
+ if (isProtocolRefusal(err)) warnProtocolRefusal();
94
+ throw err;
95
+ };
96
+
97
+ // src/room-lifecycle.ts
98
+ function useSdkReconnection(room) {
99
+ const r = room.reconnection;
100
+ r.enabled = ClientReconnection.enabled;
101
+ r.minUptime = ClientReconnection.minUptime;
102
+ r.delay = ClientReconnection.delay;
103
+ r.minDelay = ClientReconnection.minDelay;
104
+ r.maxDelay = ClientReconnection.maxDelay;
105
+ r.maxRetries = ClientReconnection.maxRetries;
106
+ r.maxEnqueuedMessages = ClientReconnection.maxEnqueuedMessages;
107
+ r.enqueuedMessages.length = 0;
108
+ return room;
109
+ }
110
+ function withoutReconnection(room) {
111
+ room.reconnection.enabled = false;
112
+ return room;
113
+ }
114
+ function waitForFirstState(room, timeoutMs) {
115
+ return new Promise((resolve) => {
116
+ const onState = () => {
117
+ clearTimeout(timer);
118
+ resolve(true);
119
+ };
120
+ const timer = setTimeout(() => {
121
+ room.onStateChange.remove(onState);
122
+ resolve(false);
123
+ }, timeoutMs);
124
+ room.onStateChange.once(onState);
125
+ });
126
+ }
127
+ function seedsInterpolation(id, selfId, sendTime) {
128
+ return id !== selfId && sendTime != null;
129
+ }
130
+
131
+ export {
132
+ RELAY_SELECT_DEFAULTS,
133
+ defaultProbe,
134
+ relayClient,
135
+ joinOptions,
136
+ isProtocolRefusal,
137
+ warnProtocolRefusal,
138
+ explainJoinRefusal,
139
+ useSdkReconnection,
140
+ withoutReconnection,
141
+ waitForFirstState,
142
+ seedsInterpolation
143
+ };