@colyseus/schema 3.0.36 → 3.0.37

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.
@@ -1030,19 +1030,35 @@ class ChangeTree {
1030
1030
  setRoot(root) {
1031
1031
  this.root = root;
1032
1032
  this.checkIsFiltered(this.parent, this.parentIndex);
1033
+ //
1034
+ // TODO: refactor and possibly unify .setRoot() and .setParent()
1035
+ //
1033
1036
  // Recursively set root on child structures
1034
1037
  const metadata = this.ref.constructor[Symbol.metadata];
1035
1038
  if (metadata) {
1036
1039
  metadata[$refTypeFieldIndexes]?.forEach((index) => {
1037
1040
  const field = metadata[index];
1038
- const value = this.ref[field.name];
1039
- value?.[$changes].setRoot(root);
1041
+ const changeTree = this.ref[field.name]?.[$changes];
1042
+ if (changeTree) {
1043
+ if (changeTree.root !== root) {
1044
+ changeTree.setRoot(root);
1045
+ }
1046
+ else {
1047
+ root.add(changeTree); // increment refCount
1048
+ }
1049
+ }
1040
1050
  });
1041
1051
  }
1042
1052
  else if (this.ref[$childType] && typeof (this.ref[$childType]) !== "string") {
1043
1053
  // MapSchema / ArraySchema, etc.
1044
1054
  this.ref.forEach((value, key) => {
1045
- value[$changes].setRoot(root);
1055
+ const changeTree = value[$changes];
1056
+ if (changeTree.root !== root) {
1057
+ changeTree.setRoot(root);
1058
+ }
1059
+ else {
1060
+ root.add(changeTree); // increment refCount
1061
+ }
1046
1062
  });
1047
1063
  }
1048
1064
  }
@@ -1066,14 +1082,19 @@ class ChangeTree {
1066
1082
  if (metadata) {
1067
1083
  metadata[$refTypeFieldIndexes]?.forEach((index) => {
1068
1084
  const field = metadata[index];
1069
- const value = this.ref[field.name];
1070
- value?.[$changes].setParent(this.ref, root, index);
1085
+ const changeTree = this.ref[field.name]?.[$changes];
1086
+ if (changeTree && changeTree.root !== root) {
1087
+ changeTree.setParent(this.ref, root, index);
1088
+ }
1071
1089
  });
1072
1090
  }
1073
1091
  else if (this.ref[$childType] && typeof (this.ref[$childType]) !== "string") {
1074
1092
  // MapSchema / ArraySchema, etc.
1075
1093
  this.ref.forEach((value, key) => {
1076
- value[$changes].setParent(this.ref, root, this.indexes[key] ?? key);
1094
+ const changeTree = value[$changes];
1095
+ if (changeTree.root !== root) {
1096
+ changeTree.setParent(this.ref, root, this.indexes[key] ?? key);
1097
+ }
1077
1098
  });
1078
1099
  }
1079
1100
  }
@@ -1305,12 +1326,11 @@ class ChangeTree {
1305
1326
  this.allFilteredChanges.indexes = {};
1306
1327
  this.allFilteredChanges.operations.length = 0;
1307
1328
  }
1308
- // remove children references
1309
- this.forEachChild((changeTree, _) => this.root?.remove(changeTree));
1310
1329
  }
1311
1330
  }
1312
1331
  /**
1313
1332
  * Recursively discard all changes from this, and child structures.
1333
+ * (Used in tests only)
1314
1334
  */
1315
1335
  discardAll() {
1316
1336
  const keys = Object.keys(this.indexedOperations);
@@ -1981,8 +2001,7 @@ class ArraySchema {
1981
2001
  push(...values) {
1982
2002
  let length = this.tmpItems.length;
1983
2003
  const changeTree = this[$changes];
1984
- // values.forEach((value, i) => {
1985
- for (let i = 0, l = values.length; i < values.length; i++, length++) {
2004
+ for (let i = 0, l = values.length; i < l; i++, length++) {
1986
2005
  const value = values[i];
1987
2006
  if (value === undefined || value === null) {
1988
2007
  // skip null values
@@ -2001,8 +2020,6 @@ class ArraySchema {
2001
2020
  //
2002
2021
  value[$changes]?.setParent(this, changeTree.root, length);
2003
2022
  }
2004
- // length++;
2005
- // });
2006
2023
  return length;
2007
2024
  }
2008
2025
  /**
@@ -2081,21 +2098,9 @@ class ArraySchema {
2081
2098
  }
2082
2099
  // discard previous operations.
2083
2100
  const changeTree = this[$changes];
2084
- // discard children
2085
- changeTree.forEachChild((changeTree, _) => {
2086
- changeTree.discard(true);
2087
- //
2088
- // TODO: add tests with instance sharing + .clear()
2089
- // FIXME: this.root? is required because it is being called at decoding time.
2090
- //
2091
- // TODO: do not use [$changes] at decoding time.
2092
- //
2093
- const root = changeTree.root;
2094
- if (root !== undefined) {
2095
- root.removeChangeFromChangeSet("changes", changeTree);
2096
- root.removeChangeFromChangeSet("allChanges", changeTree);
2097
- root.removeChangeFromChangeSet("allFilteredChanges", changeTree);
2098
- }
2101
+ // remove children references
2102
+ changeTree.forEachChild((childChangeTree, _) => {
2103
+ changeTree.root?.remove(childChangeTree);
2099
2104
  });
2100
2105
  changeTree.discard(true);
2101
2106
  changeTree.operation(OPERATION.CLEAR);
@@ -2680,6 +2685,10 @@ class MapSchema {
2680
2685
  // discard previous operations.
2681
2686
  changeTree.discard(true);
2682
2687
  changeTree.indexes = {};
2688
+ // remove children references
2689
+ changeTree.forEachChild((childChangeTree, _) => {
2690
+ changeTree.root?.remove(childChangeTree);
2691
+ });
2683
2692
  // clear previous indexes
2684
2693
  this.$indexes.clear();
2685
2694
  // clear items
@@ -3277,6 +3286,10 @@ class Schema {
3277
3286
  }
3278
3287
  return obj;
3279
3288
  }
3289
+ /**
3290
+ * Used in tests only
3291
+ * @internal
3292
+ */
3280
3293
  discardAllChanges() {
3281
3294
  this[$changes].discardAll();
3282
3295
  }
@@ -3299,8 +3312,11 @@ class Schema {
3299
3312
  const contents = (showContents) ? ` - ${JSON.stringify(ref.toJSON())}` : "";
3300
3313
  const changeTree = ref[$changes];
3301
3314
  const refId = changeTree.refId;
3302
- let output = "";
3303
- output += `${getIndent(level)}${ref.constructor.name} (refId: ${refId})${contents}\n`;
3315
+ // log reference count if > 1
3316
+ const refCount = (changeTree.root?.refCount?.[refId] > 1)
3317
+ ? ` [×${changeTree.root.refCount[refId]}]`
3318
+ : '';
3319
+ let output = `${getIndent(level)}${ref.constructor.name} (refId: ${refId})${refCount}${contents}\n`;
3304
3320
  changeTree.forEachChild((childChangeTree) => output += this.debugRefIds(childChangeTree.ref, showContents, level + 1));
3305
3321
  return output;
3306
3322
  }
@@ -3485,6 +3501,10 @@ class CollectionSchema {
3485
3501
  // discard previous operations.
3486
3502
  changeTree.discard(true);
3487
3503
  changeTree.indexes = {};
3504
+ // remove children references
3505
+ changeTree.forEachChild((childChangeTree, _) => {
3506
+ changeTree.root?.remove(childChangeTree);
3507
+ });
3488
3508
  // clear previous indexes
3489
3509
  this.$indexes.clear();
3490
3510
  // clear items
@@ -3817,6 +3837,7 @@ class Root {
3817
3837
  this.removeChangeFromChangeSet("filteredChanges", changeTree);
3818
3838
  }
3819
3839
  this.refCount[changeTree.refId] = 0;
3840
+ changeTree.forEachChild((child, _) => this.remove(child));
3820
3841
  }
3821
3842
  else {
3822
3843
  this.refCount[changeTree.refId] = refCount;
@@ -3838,7 +3859,6 @@ class Root {
3838
3859
  enqueueChangeTree(this, changeTree, "changes");
3839
3860
  }
3840
3861
  }
3841
- changeTree.forEachChild((child, _) => this.remove(child));
3842
3862
  return refCount;
3843
3863
  }
3844
3864
  removeChangeFromChangeSet(changeSetName, changeTree) {