@genex-ai/multiplayer 0.8.2 → 0.8.4

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.
Files changed (2) hide show
  1. package/dist/index.js +20 -8
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ var INTERP_RATIO = 1.5;
7
7
  var INTERP_MIN_MS = 90;
8
8
  var INTERP_MAX_MS = 300;
9
9
  var JITTER_SAFETY = 1.2;
10
+ var POISON_GUARD_MS = 2e3;
10
11
  var INTERP_EASE = 0.1;
11
12
  var MAX_EXTRAP_MS = 250;
12
13
  var ROT_EXTRAP_MS = 150;
@@ -189,8 +190,10 @@ function attachSession(client, initialRoom) {
189
190
  const objRaw = /* @__PURE__ */ new Map();
190
191
  const localObjState = /* @__PURE__ */ new Map();
191
192
  let hostId;
193
+ const testSkew = typeof globalThis !== "undefined" && globalThis.__GENEX_MP_TEST_SKEW__ || 0;
194
+ const now = testSkew ? () => nowMs() + testSkew : nowMs;
192
195
  const pushSnap = (id, state, sendTime) => {
193
- const arrival = nowMs();
196
+ const arrival = now();
194
197
  const t = sendTime ?? arrival;
195
198
  if (sendTime != null) {
196
199
  let win = offsetWin.get(id);
@@ -223,13 +226,14 @@ function attachSession(client, initialRoom) {
223
226
  buf.push({ t, state });
224
227
  const cutoff = t - 1500;
225
228
  while (buf.length > 2 && buf[0].t < cutoff) buf.shift();
229
+ while (buf.length > 1 && buf[0].t > buf[buf.length - 1].t + POISON_GUARD_MS) buf.shift();
226
230
  };
227
231
  const sampleSmoothed = (streamKey, localNow) => {
228
232
  const buf = buffers.get(streamKey);
229
233
  const autoDelay = autoDelayById.get(streamKey) ?? 100;
230
234
  const renderTime = localNow - (clockOffsets.get(streamKey) ?? 0) - autoDelay;
231
235
  const sampled = buf && sampleBuffer(buf, renderTime);
232
- if (!sampled) return void 0;
236
+ if (!sampled) return smoothed.get(streamKey);
233
237
  const prev = smoothed.get(streamKey);
234
238
  let out;
235
239
  if (prev) {
@@ -252,6 +256,14 @@ function attachSession(client, initialRoom) {
252
256
  intervalsById.delete(streamKey);
253
257
  autoDelayById.delete(streamKey);
254
258
  };
259
+ const clearStreamClock = (streamKey) => {
260
+ buffers.delete(streamKey);
261
+ lastStamp.delete(streamKey);
262
+ clockOffsets.delete(streamKey);
263
+ offsetWin.delete(streamKey);
264
+ intervalsById.delete(streamKey);
265
+ autoDelayById.delete(streamKey);
266
+ };
255
267
  const emitters = /* @__PURE__ */ new Map();
256
268
  const bridged = /* @__PURE__ */ new Set();
257
269
  const reserved = /* @__PURE__ */ new Set([
@@ -294,7 +306,7 @@ function attachSession(client, initialRoom) {
294
306
  else objOwners.delete(id);
295
307
  if (owner !== room.sessionId) {
296
308
  localObjState.delete(id);
297
- clearStream(key);
309
+ clearStreamClock(key);
298
310
  }
299
311
  }
300
312
  if (blob.d && typeof blob.d === "object" && Object.keys(blob.d).length > 0) {
@@ -333,7 +345,7 @@ function attachSession(client, initialRoom) {
333
345
  $(r.state).players.onAdd((player, id) => {
334
346
  const { state, sendTime } = parseData(player.data);
335
347
  emit("join", id, state);
336
- if (id !== room.sessionId) pushSnap(id, state, sendTime);
348
+ if (id !== room.sessionId && sendTime != null) pushSnap(id, state, sendTime);
337
349
  $(player).onChange(() => {
338
350
  const { state: st, sendTime: ts } = parseData(player.data);
339
351
  emit("change", id, st);
@@ -431,7 +443,7 @@ function attachSession(client, initialRoom) {
431
443
  id: room.sessionId,
432
444
  get players() {
433
445
  const out = /* @__PURE__ */ new Map();
434
- const localNow = nowMs();
446
+ const localNow = now();
435
447
  room.state?.players?.forEach((p, id) => {
436
448
  const latest = cachedParse(id, p.data);
437
449
  let state = latest;
@@ -455,7 +467,7 @@ function attachSession(client, initialRoom) {
455
467
  }
456
468
  const clean = sanitizeFinite(state);
457
469
  localState = clean;
458
- send0("state", JSON.stringify({ ...clean, [SEND_TIME_KEY]: nowMs() }));
470
+ send0("state", JSON.stringify({ ...clean, [SEND_TIME_KEY]: now() }));
459
471
  }
460
472
  },
461
473
  shared: {
@@ -497,7 +509,7 @@ function attachSession(client, initialRoom) {
497
509
  const key = String(id);
498
510
  const clean = sanitizeFinite(state);
499
511
  if (objOwners.get(key) === room.sessionId) localObjState.set(key, clean);
500
- send0("obj", { id: key, d: clean, t: nowMs() });
512
+ send0("obj", { id: key, d: clean, t: now() });
501
513
  },
502
514
  get(id) {
503
515
  const key = String(id);
@@ -512,7 +524,7 @@ function attachSession(client, initialRoom) {
512
524
  raw = mine;
513
525
  } else {
514
526
  raw = objRaw.get(key) ?? {};
515
- state = sampleSmoothed(OBJ_PREFIX + key, nowMs()) ?? raw;
527
+ state = sampleSmoothed(OBJ_PREFIX + key, now()) ?? raw;
516
528
  }
517
529
  return { id: key, owner, isMine, state, stateRaw: raw };
518
530
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genex-ai/multiplayer",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "description": "The multiplayer client wrapper + shared room schema for genex.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",