@genex-ai/multiplayer 0.8.3 → 0.8.5

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 CHANGED
@@ -111,7 +111,7 @@ room.on('join', (id, state) => {}); // a player appeared (also fires for YOU
111
111
  room.on('change', (id, state) => {}); // a player updated their me-state
112
112
  room.on('leave', (id) => {}); // a player left
113
113
  room.on('shared', (key, value) => {}); // a shared key changed
114
- room.on('object', (id) => {}); // an object's owner changed (handoff)
114
+ room.on('object', (id) => {}); // an object's owner changed — the render glides across it (soft handoff)
115
115
  room.on('host', (id) => {}); // the room host changed
116
116
  room.on('hit', (payload) => {}); // a custom event someone sent (see `send`)
117
117
 
@@ -141,9 +141,12 @@ drops keep the full reconnection grace.
141
141
 
142
142
  ## `inputs` + `onHostTick` — host-authoritative physics (contested objects)
143
143
 
144
- Claim-on-touch is right for one-touch objects (kick a ball). For **sustained contact**
145
- (two players pushing one crate) let ONE simulation own the contest: everyone sends inputs —
146
- the relay routes them to the **current host only** — and the host applies them on a fixed
144
+ Claim-on-touch fits any **ownable** body (a ball, a box, a prop) — even when players take turns
145
+ bumping it, because the ownership **handoff glides** (a soft handoff, since 0.8.4) instead of
146
+ teleporting; give the object a Rapier proxy that's `dynamic` while you own it and a `kinematicPosition`
147
+ follower of `state` when you don't. Reserve host-authoritative for a genuine **simultaneous** contest
148
+ (two players pushing one crate *against each other*, sumo): let ONE neutral simulation own it — everyone
149
+ sends inputs, the relay routes them to the **current host only**, and the host applies them on a fixed
147
150
  tick and publishes results via `objects` (auto-smoothed for everyone):
148
151
 
149
152
  ```ts
package/dist/index.js CHANGED
@@ -233,7 +233,7 @@ function attachSession(client, initialRoom) {
233
233
  const autoDelay = autoDelayById.get(streamKey) ?? 100;
234
234
  const renderTime = localNow - (clockOffsets.get(streamKey) ?? 0) - autoDelay;
235
235
  const sampled = buf && sampleBuffer(buf, renderTime);
236
- if (!sampled) return void 0;
236
+ if (!sampled) return smoothed.get(streamKey);
237
237
  const prev = smoothed.get(streamKey);
238
238
  let out;
239
239
  if (prev) {
@@ -256,6 +256,14 @@ function attachSession(client, initialRoom) {
256
256
  intervalsById.delete(streamKey);
257
257
  autoDelayById.delete(streamKey);
258
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
+ };
259
267
  const emitters = /* @__PURE__ */ new Map();
260
268
  const bridged = /* @__PURE__ */ new Set();
261
269
  const reserved = /* @__PURE__ */ new Set([
@@ -298,7 +306,7 @@ function attachSession(client, initialRoom) {
298
306
  else objOwners.delete(id);
299
307
  if (owner !== room.sessionId) {
300
308
  localObjState.delete(id);
301
- clearStream(key);
309
+ clearStreamClock(key);
302
310
  }
303
311
  }
304
312
  if (blob.d && typeof blob.d === "object" && Object.keys(blob.d).length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genex-ai/multiplayer",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "description": "The multiplayer client wrapper + shared room schema for genex.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",