@colyseus/schema 5.0.10 → 5.0.11
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/build/encoder/ChangeTree.d.ts +0 -1
- package/build/encoder/StateView.d.ts +0 -6
- package/build/index.cjs +19 -55
- package/build/index.cjs.map +1 -1
- package/build/index.js +19 -55
- package/build/index.mjs +19 -55
- package/build/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/encoder/ChangeTree.ts +0 -2
- package/src/encoder/Encoder.ts +3 -16
- package/src/encoder/StateView.ts +16 -35
package/package.json
CHANGED
|
@@ -232,7 +232,6 @@ export class ChangeTree<T extends Ref = any> implements ChangeRecorder {
|
|
|
232
232
|
// per-view WeakSet lookups with direct bitwise ops.
|
|
233
233
|
// Lazy: undefined until the tree participates in any view.
|
|
234
234
|
visibleViews?: number[];
|
|
235
|
-
invisibleViews?: number[];
|
|
236
235
|
|
|
237
236
|
// Per-(view, tag) bitmap, indexed by tag. Custom tags only —
|
|
238
237
|
// DEFAULT_VIEW_TAG visibility lives in `visibleViews`.
|
|
@@ -586,7 +585,6 @@ export class ChangeTree<T extends Ref = any> implements ChangeRecorder {
|
|
|
586
585
|
// per-view visibility lives on the tree (NOT keyed by refId), so a
|
|
587
586
|
// recycled tree must not inherit its previous life's view membership.
|
|
588
587
|
this.visibleViews = undefined;
|
|
589
|
-
this.invisibleViews = undefined;
|
|
590
588
|
this.tagViews = undefined;
|
|
591
589
|
this.subscribedViews = undefined;
|
|
592
590
|
}
|
package/src/encoder/Encoder.ts
CHANGED
|
@@ -119,16 +119,7 @@ function _fullSyncWalk(ctx: EncodeCtx, changeTree: ChangeTree): void {
|
|
|
119
119
|
// Visibility gate: when a view is active, a non-visible tree contributes
|
|
120
120
|
// nothing itself but we still recurse so descendants (possibly added to
|
|
121
121
|
// the view explicitly) are reachable.
|
|
122
|
-
|
|
123
|
-
if (ctx.hasView) {
|
|
124
|
-
const view = ctx.view!;
|
|
125
|
-
if (!view.isChangeTreeVisible(changeTree)) {
|
|
126
|
-
view.markInvisible(changeTree);
|
|
127
|
-
visibleHere = false;
|
|
128
|
-
} else {
|
|
129
|
-
view.unmarkInvisible(changeTree);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
122
|
+
const visibleHere = !ctx.hasView || ctx.view!.isChangeTreeVisible(changeTree);
|
|
132
123
|
|
|
133
124
|
if (visibleHere) {
|
|
134
125
|
const desc = changeTree.encDescriptor;
|
|
@@ -313,12 +304,8 @@ export class Encoder<T extends Schema = any> {
|
|
|
313
304
|
while (current = current.next) {
|
|
314
305
|
const changeTree = (current as ChangeTreeNode).changeTree;
|
|
315
306
|
|
|
316
|
-
if (hasView) {
|
|
317
|
-
|
|
318
|
-
view.markInvisible(changeTree);
|
|
319
|
-
continue;
|
|
320
|
-
}
|
|
321
|
-
view.unmarkInvisible(changeTree);
|
|
307
|
+
if (hasView && !view.isChangeTreeVisible(changeTree)) {
|
|
308
|
+
continue;
|
|
322
309
|
}
|
|
323
310
|
|
|
324
311
|
const recorder = unreliable ? changeTree.unreliableRecorder : changeTree;
|
package/src/encoder/StateView.ts
CHANGED
|
@@ -28,8 +28,6 @@ function _clearViewBitFromAllTrees(root: Root, slot: number, bit: number): void
|
|
|
28
28
|
const tree = trees[refId];
|
|
29
29
|
const v = tree.visibleViews;
|
|
30
30
|
if (v !== undefined && slot < v.length) v[slot] &= clearMask;
|
|
31
|
-
const i = tree.invisibleViews;
|
|
32
|
-
if (i !== undefined && slot < i.length) i[slot] &= clearMask;
|
|
33
31
|
const s = tree.subscribedViews;
|
|
34
32
|
if (s !== undefined && slot < s.length) s[slot] &= clearMask;
|
|
35
33
|
const t = tree.tagViews;
|
|
@@ -192,32 +190,6 @@ export class StateView {
|
|
|
192
190
|
if (slot < arr.length) arr[slot] &= ~this._bit;
|
|
193
191
|
}
|
|
194
192
|
|
|
195
|
-
/** True iff this view has previously marked `tree` as invisible. */
|
|
196
|
-
public isInvisible(tree: ChangeTree): boolean {
|
|
197
|
-
const arr = tree.invisibleViews;
|
|
198
|
-
const slot = this._slot;
|
|
199
|
-
return arr !== undefined && slot < arr.length && (arr[slot] & this._bit) !== 0;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/** Mark `tree` as invisible to this view (used by encode loop). */
|
|
203
|
-
public markInvisible(tree: ChangeTree): void {
|
|
204
|
-
const slot = this._slot;
|
|
205
|
-
let arr = tree.invisibleViews;
|
|
206
|
-
if (arr === undefined) {
|
|
207
|
-
arr = tree.invisibleViews = [];
|
|
208
|
-
}
|
|
209
|
-
while (arr.length <= slot) arr.push(0);
|
|
210
|
-
arr[slot] |= this._bit;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/** Clear invisible bit. */
|
|
214
|
-
public unmarkInvisible(tree: ChangeTree): void {
|
|
215
|
-
const arr = tree.invisibleViews;
|
|
216
|
-
if (arr === undefined) return;
|
|
217
|
-
const slot = this._slot;
|
|
218
|
-
if (slot < arr.length) arr[slot] &= ~this._bit;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
193
|
// ──────────────────────────────────────────────────────────────────
|
|
222
194
|
// Per-tag, per-view bitmap. Replaces the legacy
|
|
223
195
|
// `tags: WeakMap<ChangeTree, Set<number>>` storage. Hot read site is
|
|
@@ -371,13 +343,20 @@ export class StateView {
|
|
|
371
343
|
// subclasses yield a real Metadata object.
|
|
372
344
|
const metadata: Metadata = (obj.constructor as typeof Schema)[Symbol.metadata];
|
|
373
345
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
//
|
|
377
|
-
|
|
346
|
+
// Add to iterable list (only the explicitly added items), deduping
|
|
347
|
+
// re-adds of an already-visible instance. isVisible must be read
|
|
348
|
+
// BEFORE markVisible; indexOf runs only on the re-add path.
|
|
349
|
+
// NOTE: dedup applies to `items` only — a re-add still re-queues the
|
|
350
|
+
// full snapshot on purpose (shared-view bootstrap re-add: a
|
|
351
|
+
// late-attached client may not have consumed earlier drains).
|
|
352
|
+
// Callers wanting cheap idempotence can guard with `view.has(obj)`.
|
|
353
|
+
if (this.iterable && checkIncludeParent
|
|
354
|
+
&& (!this.isVisible(changeTree) || this.items.indexOf(obj) === -1)) {
|
|
378
355
|
this.items.push(obj);
|
|
379
356
|
}
|
|
380
357
|
|
|
358
|
+
this.markVisible(changeTree);
|
|
359
|
+
|
|
381
360
|
// add parent ChangeTree's
|
|
382
361
|
// - if it was invisible to this view
|
|
383
362
|
// - if it were previously filtered out
|
|
@@ -468,7 +447,6 @@ export class StateView {
|
|
|
468
447
|
|
|
469
448
|
} else if (!changeTree.isNew || isChildAdded) {
|
|
470
449
|
// new structures will be added as part of .encode() call, no need to force it to .encodeView()
|
|
471
|
-
const isInvisible = this.isInvisible(changeTree);
|
|
472
450
|
|
|
473
451
|
// Full-sync snapshot: walk the live ref structurally instead of
|
|
474
452
|
// iterating a cumulative recorder bucket. Every populated index
|
|
@@ -476,11 +454,14 @@ export class StateView {
|
|
|
476
454
|
// at encode time). Per-field tags come from the descriptor's
|
|
477
455
|
// precomputed `tags[]` array — direct index vs a metadata[i].tag
|
|
478
456
|
// object hop.
|
|
457
|
+
//
|
|
458
|
+
// Non-matching custom-tagged fields are NEVER included here —
|
|
459
|
+
// `view.changes` is drained without a per-field tag re-check,
|
|
460
|
+
// so anything added leaks straight to the wire.
|
|
479
461
|
const tags = changeTree.encDescriptor.tags;
|
|
480
462
|
changeTree.forEachLive((index) => {
|
|
481
463
|
const tagAtIndex = tags[index];
|
|
482
464
|
if (
|
|
483
|
-
isInvisible || // if "invisible", include all
|
|
484
465
|
tagAtIndex === undefined || // "all change" with no tag
|
|
485
466
|
tagAtIndex === DEFAULT_VIEW_TAG || // visible to all clients
|
|
486
467
|
(tag !== DEFAULT_VIEW_TAG && (tagAtIndex & tag) !== 0) // tag bits overlap
|
|
@@ -652,7 +633,7 @@ export class StateView {
|
|
|
652
633
|
|
|
653
634
|
// ── Streamable-collection unsubscribe (the stream itself) ─────
|
|
654
635
|
// Flush DELETE for every sent position and drop pending. After
|
|
655
|
-
// this, the stream is
|
|
636
|
+
// this, the stream is no longer visible to this view — any future
|
|
656
637
|
// `stream.add()` would still seed broadcast pending (if no views)
|
|
657
638
|
// but would NOT re-seed per-view pending (user must re-subscribe).
|
|
658
639
|
if (changeTree.isStreamCollection) {
|