@colyseus/schema 3.0.36 → 3.0.38

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.
@@ -1032,19 +1032,35 @@ class ChangeTree {
1032
1032
  setRoot(root) {
1033
1033
  this.root = root;
1034
1034
  this.checkIsFiltered(this.parent, this.parentIndex);
1035
+ //
1036
+ // TODO: refactor and possibly unify .setRoot() and .setParent()
1037
+ //
1035
1038
  // Recursively set root on child structures
1036
1039
  const metadata = this.ref.constructor[Symbol.metadata];
1037
1040
  if (metadata) {
1038
1041
  metadata[$refTypeFieldIndexes]?.forEach((index) => {
1039
1042
  const field = metadata[index];
1040
- const value = this.ref[field.name];
1041
- value?.[$changes].setRoot(root);
1043
+ const changeTree = this.ref[field.name]?.[$changes];
1044
+ if (changeTree) {
1045
+ if (changeTree.root !== root) {
1046
+ changeTree.setRoot(root);
1047
+ }
1048
+ else {
1049
+ root.add(changeTree); // increment refCount
1050
+ }
1051
+ }
1042
1052
  });
1043
1053
  }
1044
1054
  else if (this.ref[$childType] && typeof (this.ref[$childType]) !== "string") {
1045
1055
  // MapSchema / ArraySchema, etc.
1046
1056
  this.ref.forEach((value, key) => {
1047
- value[$changes].setRoot(root);
1057
+ const changeTree = value[$changes];
1058
+ if (changeTree.root !== root) {
1059
+ changeTree.setRoot(root);
1060
+ }
1061
+ else {
1062
+ root.add(changeTree); // increment refCount
1063
+ }
1048
1064
  });
1049
1065
  }
1050
1066
  }
@@ -1068,14 +1084,19 @@ class ChangeTree {
1068
1084
  if (metadata) {
1069
1085
  metadata[$refTypeFieldIndexes]?.forEach((index) => {
1070
1086
  const field = metadata[index];
1071
- const value = this.ref[field.name];
1072
- value?.[$changes].setParent(this.ref, root, index);
1087
+ const changeTree = this.ref[field.name]?.[$changes];
1088
+ if (changeTree && changeTree.root !== root) {
1089
+ changeTree.setParent(this.ref, root, index);
1090
+ }
1073
1091
  });
1074
1092
  }
1075
1093
  else if (this.ref[$childType] && typeof (this.ref[$childType]) !== "string") {
1076
1094
  // MapSchema / ArraySchema, etc.
1077
1095
  this.ref.forEach((value, key) => {
1078
- value[$changes].setParent(this.ref, root, this.indexes[key] ?? key);
1096
+ const changeTree = value[$changes];
1097
+ if (changeTree.root !== root) {
1098
+ changeTree.setParent(this.ref, root, this.indexes[key] ?? key);
1099
+ }
1079
1100
  });
1080
1101
  }
1081
1102
  }
@@ -1307,12 +1328,11 @@ class ChangeTree {
1307
1328
  this.allFilteredChanges.indexes = {};
1308
1329
  this.allFilteredChanges.operations.length = 0;
1309
1330
  }
1310
- // remove children references
1311
- this.forEachChild((changeTree, _) => this.root?.remove(changeTree));
1312
1331
  }
1313
1332
  }
1314
1333
  /**
1315
1334
  * Recursively discard all changes from this, and child structures.
1335
+ * (Used in tests only)
1316
1336
  */
1317
1337
  discardAll() {
1318
1338
  const keys = Object.keys(this.indexedOperations);
@@ -1983,8 +2003,7 @@ class ArraySchema {
1983
2003
  push(...values) {
1984
2004
  let length = this.tmpItems.length;
1985
2005
  const changeTree = this[$changes];
1986
- // values.forEach((value, i) => {
1987
- for (let i = 0, l = values.length; i < values.length; i++, length++) {
2006
+ for (let i = 0, l = values.length; i < l; i++, length++) {
1988
2007
  const value = values[i];
1989
2008
  if (value === undefined || value === null) {
1990
2009
  // skip null values
@@ -2003,8 +2022,6 @@ class ArraySchema {
2003
2022
  //
2004
2023
  value[$changes]?.setParent(this, changeTree.root, length);
2005
2024
  }
2006
- // length++;
2007
- // });
2008
2025
  return length;
2009
2026
  }
2010
2027
  /**
@@ -2083,21 +2100,9 @@ class ArraySchema {
2083
2100
  }
2084
2101
  // discard previous operations.
2085
2102
  const changeTree = this[$changes];
2086
- // discard children
2087
- changeTree.forEachChild((changeTree, _) => {
2088
- changeTree.discard(true);
2089
- //
2090
- // TODO: add tests with instance sharing + .clear()
2091
- // FIXME: this.root? is required because it is being called at decoding time.
2092
- //
2093
- // TODO: do not use [$changes] at decoding time.
2094
- //
2095
- const root = changeTree.root;
2096
- if (root !== undefined) {
2097
- root.removeChangeFromChangeSet("changes", changeTree);
2098
- root.removeChangeFromChangeSet("allChanges", changeTree);
2099
- root.removeChangeFromChangeSet("allFilteredChanges", changeTree);
2100
- }
2103
+ // remove children references
2104
+ changeTree.forEachChild((childChangeTree, _) => {
2105
+ changeTree.root?.remove(childChangeTree);
2101
2106
  });
2102
2107
  changeTree.discard(true);
2103
2108
  changeTree.operation(exports.OPERATION.CLEAR);
@@ -2682,6 +2687,10 @@ class MapSchema {
2682
2687
  // discard previous operations.
2683
2688
  changeTree.discard(true);
2684
2689
  changeTree.indexes = {};
2690
+ // remove children references
2691
+ changeTree.forEachChild((childChangeTree, _) => {
2692
+ changeTree.root?.remove(childChangeTree);
2693
+ });
2685
2694
  // clear previous indexes
2686
2695
  this.$indexes.clear();
2687
2696
  // clear items
@@ -3279,6 +3288,10 @@ class Schema {
3279
3288
  }
3280
3289
  return obj;
3281
3290
  }
3291
+ /**
3292
+ * Used in tests only
3293
+ * @internal
3294
+ */
3282
3295
  discardAllChanges() {
3283
3296
  this[$changes].discardAll();
3284
3297
  }
@@ -3301,8 +3314,11 @@ class Schema {
3301
3314
  const contents = (showContents) ? ` - ${JSON.stringify(ref.toJSON())}` : "";
3302
3315
  const changeTree = ref[$changes];
3303
3316
  const refId = changeTree.refId;
3304
- let output = "";
3305
- output += `${getIndent(level)}${ref.constructor.name} (refId: ${refId})${contents}\n`;
3317
+ // log reference count if > 1
3318
+ const refCount = (changeTree.root?.refCount?.[refId] > 1)
3319
+ ? ` [×${changeTree.root.refCount[refId]}]`
3320
+ : '';
3321
+ let output = `${getIndent(level)}${ref.constructor.name} (refId: ${refId})${refCount}${contents}\n`;
3306
3322
  changeTree.forEachChild((childChangeTree) => output += this.debugRefIds(childChangeTree.ref, showContents, level + 1));
3307
3323
  return output;
3308
3324
  }
@@ -3487,6 +3503,10 @@ class CollectionSchema {
3487
3503
  // discard previous operations.
3488
3504
  changeTree.discard(true);
3489
3505
  changeTree.indexes = {};
3506
+ // remove children references
3507
+ changeTree.forEachChild((childChangeTree, _) => {
3508
+ changeTree.root?.remove(childChangeTree);
3509
+ });
3490
3510
  // clear previous indexes
3491
3511
  this.$indexes.clear();
3492
3512
  // clear items
@@ -3819,6 +3839,7 @@ class Root {
3819
3839
  this.removeChangeFromChangeSet("filteredChanges", changeTree);
3820
3840
  }
3821
3841
  this.refCount[changeTree.refId] = 0;
3842
+ changeTree.forEachChild((child, _) => this.remove(child));
3822
3843
  }
3823
3844
  else {
3824
3845
  this.refCount[changeTree.refId] = refCount;
@@ -3840,7 +3861,6 @@ class Root {
3840
3861
  enqueueChangeTree(this, changeTree, "changes");
3841
3862
  }
3842
3863
  }
3843
- changeTree.forEachChild((child, _) => this.remove(child));
3844
3864
  return refCount;
3845
3865
  }
3846
3866
  removeChangeFromChangeSet(changeSetName, changeTree) {
@@ -4989,6 +5009,10 @@ class StateView {
4989
5009
  }
4990
5010
  // DELETE / DELETE BY REF ID
4991
5011
  changes[changeTree.parentIndex] = exports.OPERATION.DELETE;
5012
+ // Remove child schema from visible set
5013
+ changeTree.forEachChild((childChangeTree) => {
5014
+ this.visible.delete(childChangeTree);
5015
+ });
4992
5016
  }
4993
5017
  else {
4994
5018
  // delete all "tagged" properties.