@colyseus/schema 4.0.25 → 4.0.26
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/StateView.d.ts +1 -1
- package/build/index.cjs +64 -40
- package/build/index.cjs.map +1 -1
- package/build/index.js +64 -40
- package/build/index.mjs +64 -40
- package/build/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/Metadata.ts +17 -4
- package/src/Schema.ts +3 -2
- package/src/decoder/DecodeOperation.ts +13 -4
- package/src/encoder/StateView.ts +32 -32
|
@@ -15,7 +15,7 @@ export declare class StateView {
|
|
|
15
15
|
* List of ChangeTree's that are invisible to this view
|
|
16
16
|
*/
|
|
17
17
|
invisible: WeakSet<ChangeTree>;
|
|
18
|
-
tags?: WeakMap<ChangeTree,
|
|
18
|
+
tags?: WeakMap<ChangeTree, number>;
|
|
19
19
|
/**
|
|
20
20
|
* Manual "ADD" operations for changes per ChangeTree, specific to this view.
|
|
21
21
|
* (This is used to force encoding a property, even if it was not changed)
|
package/build/index.cjs
CHANGED
|
@@ -817,10 +817,25 @@ const Metadata = {
|
|
|
817
817
|
});
|
|
818
818
|
}
|
|
819
819
|
metadata[$viewFieldIndexes].push(index);
|
|
820
|
-
|
|
821
|
-
|
|
820
|
+
// Populate $fieldIndexesByViewTag: for a bitmask tag, register the field
|
|
821
|
+
// index under each individual set bit so that view.add(obj, Tag.ONE) finds
|
|
822
|
+
// fields tagged @view(Tag.ONE|Tag.TWO).
|
|
823
|
+
// Negative tags (i.e. DEFAULT_VIEW_TAG = -1) are stored as-is.
|
|
824
|
+
if (tag < 0) {
|
|
825
|
+
if (!metadata[$fieldIndexesByViewTag][tag]) {
|
|
826
|
+
metadata[$fieldIndexesByViewTag][tag] = [];
|
|
827
|
+
}
|
|
828
|
+
metadata[$fieldIndexesByViewTag][tag].push(index);
|
|
829
|
+
}
|
|
830
|
+
else {
|
|
831
|
+
for (let bits = tag; bits > 0; bits &= bits - 1) {
|
|
832
|
+
const bit = bits & (-bits); // isolate lowest set bit
|
|
833
|
+
if (!metadata[$fieldIndexesByViewTag][bit]) {
|
|
834
|
+
metadata[$fieldIndexesByViewTag][bit] = [];
|
|
835
|
+
}
|
|
836
|
+
metadata[$fieldIndexesByViewTag][bit].push(index);
|
|
837
|
+
}
|
|
822
838
|
}
|
|
823
|
-
metadata[$fieldIndexesByViewTag][tag].push(index);
|
|
824
839
|
},
|
|
825
840
|
setFields(target, fields) {
|
|
826
841
|
// for inheritance support
|
|
@@ -1676,17 +1691,25 @@ function decodeValue(decoder, operation, ref, index, type, bytes, it, allChanges
|
|
|
1676
1691
|
if (previousValue) {
|
|
1677
1692
|
let previousRefId = previousValue[$refId];
|
|
1678
1693
|
if (previousRefId !== undefined && refId !== previousRefId) {
|
|
1694
|
+
// Collection field replaced by a different instance.
|
|
1679
1695
|
//
|
|
1680
|
-
//
|
|
1681
|
-
//
|
|
1696
|
+
// Don't decrement children here: GC (`garbageCollectDeletedRefs`)
|
|
1697
|
+
// removes them once the previous collection's refId hits zero.
|
|
1698
|
+
// Doing it here too would double-decrement a *shared* child and
|
|
1699
|
+
// drop it while still referenced ("refId not found").
|
|
1700
|
+
if ((operation & exports.OPERATION.DELETE) !== exports.OPERATION.DELETE) {
|
|
1701
|
+
// Replacement not tagged DELETE (e.g. pending ADD not upgraded
|
|
1702
|
+
// to DELETE_AND_ADD), so the previous refId wasn't decremented
|
|
1703
|
+
// above. Release it here, else it never gets GC'd (leak).
|
|
1704
|
+
$root.removeRef(previousRefId);
|
|
1705
|
+
}
|
|
1706
|
+
// enqueue onRemove callbacks for the previous collection's children.
|
|
1682
1707
|
const entries = previousValue.entries();
|
|
1683
1708
|
let iter;
|
|
1684
1709
|
while ((iter = entries.next()) && !iter.done) {
|
|
1685
1710
|
const [key, value] = iter.value;
|
|
1686
|
-
// if value is a schema, remove its reference
|
|
1687
1711
|
if (typeof (value) === "object") {
|
|
1688
1712
|
previousRefId = value[$refId];
|
|
1689
|
-
$root.removeRef(previousRefId);
|
|
1690
1713
|
}
|
|
1691
1714
|
allChanges.push({
|
|
1692
1715
|
ref: previousValue,
|
|
@@ -3764,9 +3787,10 @@ class Schema {
|
|
|
3764
3787
|
return view.isChangeTreeVisible(ref[$changes]);
|
|
3765
3788
|
}
|
|
3766
3789
|
else {
|
|
3767
|
-
// view pass: custom tag
|
|
3790
|
+
// view pass: custom tag (bitmask)
|
|
3791
|
+
// tag is the field's stored bitmask; view.tags stores the accumulated bitmask of tags used in view.add().
|
|
3768
3792
|
const tags = view.tags?.get(ref[$changes]);
|
|
3769
|
-
return tags &&
|
|
3793
|
+
return tags != null && (tag & tags) !== 0;
|
|
3770
3794
|
}
|
|
3771
3795
|
}
|
|
3772
3796
|
// allow inherited classes to have a constructor
|
|
@@ -5580,7 +5604,7 @@ class StateView {
|
|
|
5580
5604
|
* List of ChangeTree's that are invisible to this view
|
|
5581
5605
|
*/
|
|
5582
5606
|
invisible = new WeakSet();
|
|
5583
|
-
tags; //
|
|
5607
|
+
tags; // bitmask of tags used to add each ChangeTree
|
|
5584
5608
|
/**
|
|
5585
5609
|
* Manual "ADD" operations for changes per ChangeTree, specific to this view.
|
|
5586
5610
|
* (This is used to force encoding a property, even if it was not changed)
|
|
@@ -5668,9 +5692,16 @@ class StateView {
|
|
|
5668
5692
|
changeTree.forEachChild((change, index) => {
|
|
5669
5693
|
// Do not ADD children that don't have the same tag
|
|
5670
5694
|
if (metadata &&
|
|
5671
|
-
metadata[index].tag !== undefined
|
|
5672
|
-
metadata[index].tag
|
|
5673
|
-
|
|
5695
|
+
metadata[index].tag !== undefined) {
|
|
5696
|
+
const fieldTag = metadata[index].tag;
|
|
5697
|
+
// DEFAULT_VIEW_TAG fields are visible to all clients.
|
|
5698
|
+
// Custom-tagged fields are only visible when bits overlap,
|
|
5699
|
+
// and never to default-tag clients.
|
|
5700
|
+
const tagMatch = fieldTag === DEFAULT_VIEW_TAG ||
|
|
5701
|
+
(tag !== DEFAULT_VIEW_TAG && (fieldTag & tag) !== 0);
|
|
5702
|
+
if (!tagMatch) {
|
|
5703
|
+
return;
|
|
5704
|
+
}
|
|
5674
5705
|
}
|
|
5675
5706
|
if (this.add(change.ref, tag, false)) {
|
|
5676
5707
|
isChildAdded = true;
|
|
@@ -5681,15 +5712,9 @@ class StateView {
|
|
|
5681
5712
|
if (!this.tags) {
|
|
5682
5713
|
this.tags = new WeakMap();
|
|
5683
5714
|
}
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
this.tags.set(changeTree, tags);
|
|
5688
|
-
}
|
|
5689
|
-
else {
|
|
5690
|
-
tags = this.tags.get(changeTree);
|
|
5691
|
-
}
|
|
5692
|
-
tags.add(tag);
|
|
5715
|
+
// Add tag bits into the bitmask stored for this ChangeTree.
|
|
5716
|
+
const currentMask = this.tags.get(changeTree) ?? 0;
|
|
5717
|
+
this.tags.set(changeTree, currentMask | tag);
|
|
5693
5718
|
// Ref: add tagged properties
|
|
5694
5719
|
metadata?.[$fieldIndexesByViewTag]?.[tag]?.forEach((index) => {
|
|
5695
5720
|
if (changeTree.getChange(index) !== exports.OPERATION.DELETE) {
|
|
@@ -5713,7 +5738,7 @@ class StateView {
|
|
|
5713
5738
|
if (op !== exports.OPERATION.DELETE &&
|
|
5714
5739
|
(isInvisible || // if "invisible", include all
|
|
5715
5740
|
tagAtIndex === undefined || // "all change" with no tag
|
|
5716
|
-
tagAtIndex === tag // tagged property
|
|
5741
|
+
(tagAtIndex === DEFAULT_VIEW_TAG || (tag !== DEFAULT_VIEW_TAG && (tagAtIndex & tag) !== 0)) // tagged property
|
|
5717
5742
|
)) {
|
|
5718
5743
|
changes[index] = op;
|
|
5719
5744
|
isChildAdded = true; // FIXME: assign only once
|
|
@@ -5739,18 +5764,16 @@ class StateView {
|
|
|
5739
5764
|
// add parent's tag properties
|
|
5740
5765
|
if (changeTree.getChange(parentIndex) !== exports.OPERATION.DELETE) {
|
|
5741
5766
|
const changes = this.touchChanges(changeTree.ref[$refId]);
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
tags = this.tags.get(changeTree);
|
|
5767
|
+
// Only accumulate positive (custom) tags in the bitmask.
|
|
5768
|
+
// DEFAULT_VIEW_TAG = -1 has all bits set and must not be OR'd in,
|
|
5769
|
+
// as it would make every custom-tagged field appear visible.
|
|
5770
|
+
if (tag !== DEFAULT_VIEW_TAG) {
|
|
5771
|
+
if (!this.tags) {
|
|
5772
|
+
this.tags = new WeakMap();
|
|
5773
|
+
}
|
|
5774
|
+
const currentMask = this.tags.has(changeTree) ? this.tags.get(changeTree) : 0;
|
|
5775
|
+
this.tags.set(changeTree, currentMask | tag);
|
|
5752
5776
|
}
|
|
5753
|
-
tags.add(tag);
|
|
5754
5777
|
changes[parentIndex] = exports.OPERATION.ADD;
|
|
5755
5778
|
}
|
|
5756
5779
|
}
|
|
@@ -5820,18 +5843,19 @@ class StateView {
|
|
|
5820
5843
|
}
|
|
5821
5844
|
// remove tag
|
|
5822
5845
|
if (this.tags && this.tags.has(changeTree)) {
|
|
5823
|
-
const tags = this.tags.get(changeTree);
|
|
5824
5846
|
if (tag === undefined) {
|
|
5825
5847
|
// delete all tags
|
|
5826
5848
|
this.tags.delete(changeTree);
|
|
5827
5849
|
}
|
|
5828
5850
|
else {
|
|
5829
|
-
//
|
|
5830
|
-
tags.
|
|
5831
|
-
|
|
5832
|
-
if (tags.size === 0) {
|
|
5851
|
+
// clear the tag's bits from the bitmask
|
|
5852
|
+
const newMask = this.tags.get(changeTree) & ~tag;
|
|
5853
|
+
if (newMask === 0) {
|
|
5833
5854
|
this.tags.delete(changeTree);
|
|
5834
5855
|
}
|
|
5856
|
+
else {
|
|
5857
|
+
this.tags.set(changeTree, newMask);
|
|
5858
|
+
}
|
|
5835
5859
|
}
|
|
5836
5860
|
}
|
|
5837
5861
|
return this;
|
|
@@ -5841,7 +5865,7 @@ class StateView {
|
|
|
5841
5865
|
}
|
|
5842
5866
|
hasTag(ob, tag = DEFAULT_VIEW_TAG) {
|
|
5843
5867
|
const tags = this.tags?.get(ob[$changes]);
|
|
5844
|
-
return tags
|
|
5868
|
+
return tags != null && (tags & tag) !== 0;
|
|
5845
5869
|
}
|
|
5846
5870
|
clear() {
|
|
5847
5871
|
if (!this.iterable) {
|