@colyseus/schema 3.0.27 → 3.0.29

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 (39) hide show
  1. package/build/cjs/index.js +51 -29
  2. package/build/cjs/index.js.map +1 -1
  3. package/build/esm/index.mjs +51 -29
  4. package/build/esm/index.mjs.map +1 -1
  5. package/build/umd/index.js +51 -29
  6. package/lib/Metadata.d.ts +1 -0
  7. package/lib/Metadata.js +3 -0
  8. package/lib/Metadata.js.map +1 -1
  9. package/lib/Schema.js +1 -1
  10. package/lib/Schema.js.map +1 -1
  11. package/lib/decoder/DecodeOperation.js +8 -4
  12. package/lib/decoder/DecodeOperation.js.map +1 -1
  13. package/lib/encoder/ChangeTree.d.ts +1 -0
  14. package/lib/encoder/ChangeTree.js +13 -15
  15. package/lib/encoder/ChangeTree.js.map +1 -1
  16. package/lib/encoder/EncodeOperation.js +1 -1
  17. package/lib/encoder/EncodeOperation.js.map +1 -1
  18. package/lib/encoder/Encoder.js +3 -4
  19. package/lib/encoder/Encoder.js.map +1 -1
  20. package/lib/encoder/StateView.d.ts +1 -0
  21. package/lib/encoder/StateView.js +19 -0
  22. package/lib/encoder/StateView.js.map +1 -1
  23. package/lib/types/custom/ArraySchema.js +1 -2
  24. package/lib/types/custom/ArraySchema.js.map +1 -1
  25. package/lib/types/custom/CollectionSchema.js +1 -1
  26. package/lib/types/custom/CollectionSchema.js.map +1 -1
  27. package/lib/types/custom/MapSchema.js +1 -1
  28. package/lib/types/custom/MapSchema.js.map +1 -1
  29. package/package.json +1 -1
  30. package/src/Metadata.ts +4 -0
  31. package/src/Schema.ts +1 -1
  32. package/src/decoder/DecodeOperation.ts +9 -4
  33. package/src/encoder/ChangeTree.ts +20 -17
  34. package/src/encoder/EncodeOperation.ts +1 -1
  35. package/src/encoder/Encoder.ts +3 -4
  36. package/src/encoder/StateView.ts +24 -0
  37. package/src/types/custom/ArraySchema.ts +1 -2
  38. package/src/types/custom/CollectionSchema.ts +1 -1
  39. package/src/types/custom/MapSchema.ts +1 -1
@@ -957,6 +957,9 @@ const Metadata = {
957
957
  fields[metadata[i].name] = metadata[i].type;
958
958
  }
959
959
  return fields;
960
+ },
961
+ hasViewTagAtIndex(metadata, index) {
962
+ return metadata?.[$viewFieldIndexes]?.includes(index);
960
963
  }
961
964
  };
962
965
 
@@ -1173,18 +1176,6 @@ class ChangeTree {
1173
1176
  for (const key in changeSet.indexes) {
1174
1177
  newIndexes[newKey++] = changeSet.indexes[key];
1175
1178
  }
1176
- // const newIndexes = {};
1177
- // let newKey = 0;
1178
- // for (const key in changeSet.indexes) {
1179
- // const index = changeSet.indexes[key];
1180
- // newIndexes[newKey++] = changeSet.indexes[key];
1181
- // console.log("...shiftAllChangeIndexes", { index: key, targetIndex: index, startIndex, shiftIndex });
1182
- // if (index > startIndex) {
1183
- // newIndexes[Number(key) + shiftIndex] = index;
1184
- // } else {
1185
- // newIndexes[Number(key)] = index;
1186
- // }
1187
- // }
1188
1179
  changeSet.indexes = newIndexes;
1189
1180
  for (let i = 0; i < changeSet.operations.length; i++) {
1190
1181
  const index = changeSet.operations[i];
@@ -1373,25 +1364,35 @@ class ChangeTree {
1373
1364
  const refType = Metadata.isValidInstance(this.ref)
1374
1365
  ? this.ref.constructor
1375
1366
  : this.ref[$childType];
1376
- if (!Metadata.isValidInstance(parent)) {
1377
- const parentChangeTree = parent[$changes];
1367
+ let parentChangeTree;
1368
+ let parentIsCollection = !Metadata.isValidInstance(parent);
1369
+ if (parentIsCollection) {
1370
+ parentChangeTree = parent[$changes];
1378
1371
  parent = parentChangeTree.parent;
1379
1372
  parentIndex = parentChangeTree.parentIndex;
1380
1373
  }
1374
+ else {
1375
+ parentChangeTree = parent[$changes];
1376
+ }
1381
1377
  const parentConstructor = parent.constructor;
1382
1378
  let key = `${this.root.types.getTypeId(refType)}`;
1383
1379
  if (parentConstructor) {
1384
1380
  key += `-${this.root.types.schemas.get(parentConstructor)}`;
1385
1381
  }
1386
1382
  key += `-${parentIndex}`;
1383
+ const fieldHasViewTag = Metadata.hasViewTagAtIndex(parentConstructor?.[Symbol.metadata], parentIndex);
1387
1384
  this.isFiltered = parent[$changes].isFiltered // in case parent is already filtered
1388
1385
  || this.root.types.parentFiltered[key]
1389
- || parentConstructor?.[Symbol.metadata]?.[$viewFieldIndexes]?.includes(parentIndex);
1386
+ || fieldHasViewTag;
1390
1387
  //
1391
1388
  // "isFiltered" may not be imedialely available during `change()` due to the instance not being attached to the root yet.
1392
1389
  // when it's available, we need to enqueue the "changes" changeset into the "filteredChanges" changeset.
1393
1390
  //
1394
1391
  if (this.isFiltered) {
1392
+ this.isVisibilitySharedWithParent = (parentChangeTree.isFiltered &&
1393
+ typeof (refType) !== "string" &&
1394
+ !fieldHasViewTag &&
1395
+ parentIsCollection);
1395
1396
  if (!this.filteredChanges) {
1396
1397
  this.filteredChanges = createChangeSet();
1397
1398
  this.allFilteredChanges = createChangeSet();
@@ -1522,7 +1523,7 @@ const encodeArray = function (encoder, bytes, changeTree, field, operation, it,
1522
1523
  // encode index
1523
1524
  encode.number(bytes, refOrIndex, it);
1524
1525
  // Do not encode value for DELETE operations
1525
- if (operation === OPERATION.DELETE) {
1526
+ if (operation === OPERATION.DELETE || operation === OPERATION.DELETE_BY_REFID) {
1526
1527
  return;
1527
1528
  }
1528
1529
  const type = changeTree.getType(field);
@@ -1743,10 +1744,14 @@ const decodeArray = function (decoder, bytes, it, ref, allChanges) {
1743
1744
  else if (operation === OPERATION.ADD_BY_REFID) {
1744
1745
  const refId = decode.number(bytes, it);
1745
1746
  const itemByRefId = decoder.root.refs.get(refId);
1746
- // use existing index, or push new value
1747
- index = (itemByRefId)
1748
- ? ref.findIndex((value) => value === itemByRefId)
1749
- : ref.length;
1747
+ // if item already exists, use existing index
1748
+ if (itemByRefId) {
1749
+ index = ref.findIndex((value) => value === itemByRefId);
1750
+ }
1751
+ // fallback to use last index
1752
+ if (index === -1 || index === undefined) {
1753
+ index = ref.length;
1754
+ }
1750
1755
  }
1751
1756
  else {
1752
1757
  index = decode.number(bytes, it);
@@ -1849,8 +1854,7 @@ class ArraySchema {
1849
1854
  static [(_a$4 = $encoder, _b$4 = $decoder, $filter)](ref, index, view) {
1850
1855
  return (!view ||
1851
1856
  typeof (ref[$childType]) === "string" ||
1852
- // view.items.has(ref[$getByIndex](index)[$changes])
1853
- view.visible.has(ref['tmpItems'][index]?.[$changes]));
1857
+ view.isChangeTreeVisible(ref['tmpItems'][index]?.[$changes]));
1854
1858
  }
1855
1859
  static is(type) {
1856
1860
  return (
@@ -2531,7 +2535,7 @@ class MapSchema {
2531
2535
  static [(_a$3 = $encoder, _b$3 = $decoder, $filter)](ref, index, view) {
2532
2536
  return (!view ||
2533
2537
  typeof (ref[$childType]) === "string" ||
2534
- view.visible.has((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
2538
+ view.isChangeTreeVisible((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
2535
2539
  }
2536
2540
  static is(type) {
2537
2541
  return type['map'] !== undefined;
@@ -3148,7 +3152,7 @@ class Schema {
3148
3152
  }
3149
3153
  else if (tag === DEFAULT_VIEW_TAG) {
3150
3154
  // view pass: default tag
3151
- return view.visible.has(ref[$changes]);
3155
+ return view.isChangeTreeVisible(ref[$changes]);
3152
3156
  }
3153
3157
  else {
3154
3158
  // view pass: custom tag
@@ -3361,7 +3365,7 @@ class CollectionSchema {
3361
3365
  static [(_a$1 = $encoder, _b$1 = $decoder, $filter)](ref, index, view) {
3362
3366
  return (!view ||
3363
3367
  typeof (ref[$childType]) === "string" ||
3364
- view.visible.has((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
3368
+ view.isChangeTreeVisible((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
3365
3369
  }
3366
3370
  static is(type) {
3367
3371
  return type['collection'] !== undefined;
@@ -3835,13 +3839,12 @@ class Encoder {
3835
3839
  continue;
3836
3840
  }
3837
3841
  if (hasView) {
3838
- if (!view.visible.has(changeTree)) {
3842
+ if (!view.isChangeTreeVisible(changeTree)) {
3843
+ // console.log("MARK AS INVISIBLE:", { ref: changeTree.ref.constructor.name, refId: changeTree.refId, raw: changeTree.ref.toJSON() });
3839
3844
  view.invisible.add(changeTree);
3840
3845
  continue; // skip this change tree
3841
3846
  }
3842
- else {
3843
- view.invisible.delete(changeTree); // remove from invisible list
3844
- }
3847
+ view.invisible.delete(changeTree); // remove from invisible list
3845
3848
  }
3846
3849
  const changeSet = changeTree[changeSetName];
3847
3850
  const ref = changeTree.ref;
@@ -4975,6 +4978,25 @@ class StateView {
4975
4978
  // clear items array
4976
4979
  this.items.length = 0;
4977
4980
  }
4981
+ isChangeTreeVisible(changeTree) {
4982
+ let isVisible = this.visible.has(changeTree);
4983
+ //
4984
+ // TODO: avoid checking for parent visibility, most of the time it's not needed
4985
+ // See test case: 'should not be required to manually call view.add() items to child arrays without @view() tag'
4986
+ //
4987
+ if (!isVisible && changeTree.isVisibilitySharedWithParent) {
4988
+ // console.log("CHECK AGAINST PARENT...", {
4989
+ // ref: changeTree.ref.constructor.name,
4990
+ // refId: changeTree.refId,
4991
+ // parent: changeTree.parent.constructor.name,
4992
+ // });
4993
+ if (this.visible.has(changeTree.parent[$changes])) {
4994
+ this.visible.add(changeTree);
4995
+ isVisible = true;
4996
+ }
4997
+ }
4998
+ return isVisible;
4999
+ }
4978
5000
  }
4979
5001
 
4980
5002
  registerType("map", { constructor: MapSchema });