@irtio/client 0.5.2 → 0.7.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/dist/{physics-H2VDQLAU.js → chunk-DABQDR3S.js} +417 -269
- package/dist/{chunk-7UTJ7RSF.js → chunk-XWVXZRBS.js} +73 -8
- package/dist/index.d.ts +1496 -179
- package/dist/index.js +1417 -47
- package/dist/physics-RT5T36P5.js +219 -0
- package/dist/physics2d-HOFMWPZV.js +255 -0
- package/package.json +15 -6
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/contract.ts
|
|
2
2
|
var E_CONNECT_FAILED = "E_CONNECT_FAILED";
|
|
3
3
|
var MAX_PREDICTED_BODIES = 64;
|
|
4
|
+
var MAX_PROXY_BODIES = 256;
|
|
4
5
|
var PREDICTION_EPSILON = 0.05;
|
|
5
6
|
var SMOOTHING_HALF_LIFE_MS = 70;
|
|
6
7
|
var SMOOTHING_SNAP_UNITS = 4;
|
|
@@ -12,9 +13,14 @@ function emptyPredictionStats() {
|
|
|
12
13
|
snaps: 0,
|
|
13
14
|
suppressed: 0,
|
|
14
15
|
overCap: 0,
|
|
16
|
+
proxies: 0,
|
|
17
|
+
absent: 0,
|
|
15
18
|
lastResimMicros: 0,
|
|
16
19
|
smoothing: 0,
|
|
17
|
-
stampGap: 0
|
|
20
|
+
stampGap: 0,
|
|
21
|
+
stampGapRaw: 0,
|
|
22
|
+
lastStampTick: 0,
|
|
23
|
+
lastAppliedTick: 0
|
|
18
24
|
};
|
|
19
25
|
}
|
|
20
26
|
|
|
@@ -58,6 +64,10 @@ var ClientCollectionImpl = class {
|
|
|
58
64
|
}
|
|
59
65
|
store;
|
|
60
66
|
desc;
|
|
67
|
+
/** D50: point this facade at the same collection in a rebuilt schema. */
|
|
68
|
+
retarget(desc) {
|
|
69
|
+
this.desc = desc;
|
|
70
|
+
}
|
|
61
71
|
get plain() {
|
|
62
72
|
return entityOf(this.store.plain, this.desc.name);
|
|
63
73
|
}
|
|
@@ -101,7 +111,8 @@ var ClientStore = class {
|
|
|
101
111
|
for (const c of ext.collections) this.descs.set(c.name, c);
|
|
102
112
|
this.plain = createState(ext);
|
|
103
113
|
this.tracked = track(ext, this.plain);
|
|
104
|
-
this.view =
|
|
114
|
+
this.view = {};
|
|
115
|
+
this.buildViewInto(this.view);
|
|
105
116
|
}
|
|
106
117
|
ext;
|
|
107
118
|
meOf;
|
|
@@ -109,6 +120,8 @@ var ClientStore = class {
|
|
|
109
120
|
tracked;
|
|
110
121
|
descs = /* @__PURE__ */ new Map();
|
|
111
122
|
frozen = /* @__PURE__ */ new WeakMap();
|
|
123
|
+
/** Live collection facades by name, so a D50 swap can retarget rather than replace them. */
|
|
124
|
+
facades = /* @__PURE__ */ new Map();
|
|
112
125
|
/** The object handed out as `room.state`; identity survives a resync. */
|
|
113
126
|
view;
|
|
114
127
|
/** Flushed-but-unjudged writes, oldest first, at most `RESIM_DEPTH` entries (D19). */
|
|
@@ -122,6 +135,29 @@ var ClientStore = class {
|
|
|
122
135
|
* walks the window tick by tick starts from here, not from the newest local value.
|
|
123
136
|
*/
|
|
124
137
|
baselineIntents = /* @__PURE__ */ new Map();
|
|
138
|
+
/**
|
|
139
|
+
* D50: rebuild every schema-derived handle in this store against `newExt`, keeping the objects
|
|
140
|
+
* user code holds. `view` keeps its identity (contractual, and pinned by test), and so does each
|
|
141
|
+
* collection facade behind it, because a game may well have hoisted `room.state.players` into a
|
|
142
|
+
* local.
|
|
143
|
+
*
|
|
144
|
+
* State itself is *not* carried across: `plain` is re-created empty under the new schema. That
|
|
145
|
+
* is not a loss, because a swap only ever happens immediately before the resync WELCOME that
|
|
146
|
+
* `rejoinAll` sends, and `loadSnapshot` re-seeds everything from it. Carrying the old records
|
|
147
|
+
* forward would be actively wrong — `normalizeRecord` rejects field names the old schema did
|
|
148
|
+
* not have, and a record built under the old descriptor is missing the new fields entirely.
|
|
149
|
+
*/
|
|
150
|
+
swapSchema(newExt) {
|
|
151
|
+
this.ext = newExt;
|
|
152
|
+
this.descs.clear();
|
|
153
|
+
for (const c of newExt.collections) this.descs.set(c.name, c);
|
|
154
|
+
this.plain = createState(newExt);
|
|
155
|
+
this.tracked = track(newExt, this.plain);
|
|
156
|
+
this.pendingWrites.length = 0;
|
|
157
|
+
this.evictedThroughTick = 0;
|
|
158
|
+
this.baselineIntents.clear();
|
|
159
|
+
this.buildViewInto(this.view);
|
|
160
|
+
}
|
|
125
161
|
// -- snapshot / resync -----------------------------------------------------
|
|
126
162
|
loadSnapshot(bytes) {
|
|
127
163
|
this.plain = decodeSnapshot(this.ext, bytes).state;
|
|
@@ -182,20 +218,48 @@ var ClientStore = class {
|
|
|
182
218
|
}
|
|
183
219
|
this.remarkOwned();
|
|
184
220
|
}
|
|
185
|
-
|
|
186
|
-
|
|
221
|
+
/**
|
|
222
|
+
* Defines one accessor per collection on `view`. Called once at construction and again on every
|
|
223
|
+
* schema swap, always against the SAME object, so `room.state`'s identity never changes.
|
|
224
|
+
*
|
|
225
|
+
* A collection that survives the swap keeps its facade and is retargeted at the new descriptor;
|
|
226
|
+
* a collection the new schema adds gets a fresh one; a collection that disappears has its
|
|
227
|
+
* accessor deleted. Only the first two can happen on an additive swap, but a `delete` is one
|
|
228
|
+
* line and a stale accessor reading a collection that no longer exists would throw from inside
|
|
229
|
+
* a getter, which is a miserable thing to debug.
|
|
230
|
+
*/
|
|
231
|
+
buildViewInto(view) {
|
|
232
|
+
const names = /* @__PURE__ */ new Set();
|
|
187
233
|
for (const c of this.ext.collections) {
|
|
234
|
+
names.add(c.name);
|
|
188
235
|
if (c.kind === "entity") {
|
|
189
|
-
const
|
|
190
|
-
|
|
236
|
+
const existing = this.facades.get(c.name);
|
|
237
|
+
if (existing) {
|
|
238
|
+
existing.retarget(c);
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const impl = new ClientCollectionImpl(this, c);
|
|
242
|
+
this.facades.set(c.name, impl);
|
|
243
|
+
const facade = withIndexSugar(impl);
|
|
244
|
+
Object.defineProperty(view, c.name, {
|
|
245
|
+
get: () => facade,
|
|
246
|
+
enumerable: true,
|
|
247
|
+
configurable: true
|
|
248
|
+
});
|
|
191
249
|
} else {
|
|
192
250
|
Object.defineProperty(view, c.name, {
|
|
193
251
|
get: () => this.freeze(this.plain[c.name], this.singletonHint(c)),
|
|
194
|
-
enumerable: true
|
|
252
|
+
enumerable: true,
|
|
253
|
+
configurable: true
|
|
195
254
|
});
|
|
196
255
|
}
|
|
197
256
|
}
|
|
198
|
-
|
|
257
|
+
for (const name of Object.keys(view)) {
|
|
258
|
+
if (!names.has(name)) {
|
|
259
|
+
delete view[name];
|
|
260
|
+
this.facades.delete(name);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
199
263
|
}
|
|
200
264
|
// -- instances ------------------------------------------------------------
|
|
201
265
|
/** The writable tracked proxy when this client owns `id`, otherwise a frozen one. */
|
|
@@ -559,6 +623,7 @@ var ClientStore = class {
|
|
|
559
623
|
export {
|
|
560
624
|
E_CONNECT_FAILED,
|
|
561
625
|
MAX_PREDICTED_BODIES,
|
|
626
|
+
MAX_PROXY_BODIES,
|
|
562
627
|
PREDICTION_EPSILON,
|
|
563
628
|
SMOOTHING_HALF_LIFE_MS,
|
|
564
629
|
SMOOTHING_SNAP_UNITS,
|