@colyseus/schema 3.0.43 → 3.0.44

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.
@@ -1086,6 +1086,7 @@ class ChangeTree {
1086
1086
  // re-assigning a child of the same root, move it to the end
1087
1087
  // of the changes queue so encoding order is preserved
1088
1088
  //
1089
+ root.add(child);
1089
1090
  root.moveToEndOfChanges(child);
1090
1091
  return;
1091
1092
  }
@@ -1423,7 +1424,7 @@ class ChangeTree {
1423
1424
  */
1424
1425
  addParent(parent, index) {
1425
1426
  // Check if this parent already exists in the chain
1426
- if (this.hasParent((p, i) => p === parent && i === index)) {
1427
+ if (this.hasParent((p, i) => p[$changes] === parent[$changes] && i === index)) {
1427
1428
  return;
1428
1429
  }
1429
1430
  this.parentChain = {
@@ -1437,7 +1438,7 @@ class ChangeTree {
1437
1438
  * @param parent - The parent to remove
1438
1439
  * @returns true if parent was removed
1439
1440
  */
1440
- removeParent(parent) {
1441
+ removeParent(parent = this.parent) {
1441
1442
  let current = this.parentChain;
1442
1443
  let previous = null;
1443
1444
  while (current) {
@@ -2007,7 +2008,7 @@ class ArraySchema {
2007
2008
  }
2008
2009
  if (previousValue !== undefined) {
2009
2010
  // remove root reference from previous value
2010
- previousValue[$changes].root?.remove(previousValue[$changes]);
2011
+ previousValue[$changes].root?.remove(previousValue[$changes], obj);
2011
2012
  }
2012
2013
  }
2013
2014
  else {
@@ -2164,7 +2165,7 @@ class ArraySchema {
2164
2165
  const changeTree = this[$changes];
2165
2166
  // remove children references
2166
2167
  changeTree.forEachChild((childChangeTree, _) => {
2167
- changeTree.root?.remove(childChangeTree);
2168
+ changeTree.root?.remove(childChangeTree, this);
2168
2169
  });
2169
2170
  changeTree.discard(true);
2170
2171
  changeTree.operation(OPERATION.CLEAR);
@@ -2718,7 +2719,7 @@ class MapSchema {
2718
2719
  operation = OPERATION.DELETE_AND_ADD;
2719
2720
  // remove reference from previous value
2720
2721
  if (previousValue !== undefined) {
2721
- previousValue[$changes].root?.remove(previousValue[$changes]);
2722
+ previousValue[$changes].root?.remove(previousValue[$changes], this);
2722
2723
  }
2723
2724
  }
2724
2725
  }
@@ -2755,7 +2756,7 @@ class MapSchema {
2755
2756
  changeTree.indexes = {};
2756
2757
  // remove children references
2757
2758
  changeTree.forEachChild((childChangeTree, _) => {
2758
- changeTree.root?.remove(childChangeTree);
2759
+ changeTree.root?.remove(childChangeTree, this);
2759
2760
  });
2760
2761
  // clear previous indexes
2761
2762
  this.$indexes.clear();
@@ -3396,9 +3397,9 @@ class Schema {
3396
3397
  });
3397
3398
  return output;
3398
3399
  }
3399
- static debugRefIdEncodeOrder(ref) {
3400
+ static debugRefIdEncodingOrder(ref, changeSet = 'allChanges') {
3400
3401
  let encodeOrder = [];
3401
- let current = ref[$changes].root.allChanges.next;
3402
+ let current = ref[$changes].root[changeSet].next;
3402
3403
  while (current) {
3403
3404
  if (current.changeTree) {
3404
3405
  encodeOrder.push(current.changeTree.refId);
@@ -3407,7 +3408,7 @@ class Schema {
3407
3408
  }
3408
3409
  return encodeOrder;
3409
3410
  }
3410
- static debugRefIdsDecoder(decoder) {
3411
+ static debugRefIdsFromDecoder(decoder) {
3411
3412
  return this.debugRefIds(decoder.state, false, 0, decoder);
3412
3413
  }
3413
3414
  /**
@@ -3597,7 +3598,7 @@ class CollectionSchema {
3597
3598
  changeTree.indexes = {};
3598
3599
  // remove children references
3599
3600
  changeTree.forEachChild((childChangeTree, _) => {
3600
- changeTree.root?.remove(childChangeTree);
3601
+ changeTree.root?.remove(childChangeTree, this);
3601
3602
  });
3602
3603
  // clear previous indexes
3603
3604
  this.$indexes.clear();
@@ -3916,10 +3917,12 @@ class Root {
3916
3917
  }
3917
3918
  }
3918
3919
  this.refCount[changeTree.refId] = (previousRefCount || 0) + 1;
3920
+ // console.log("ADD", { refId: changeTree.refId, refCount: this.refCount[changeTree.refId] });
3919
3921
  return isNewChangeTree;
3920
3922
  }
3921
- remove(changeTree) {
3923
+ remove(changeTree, parent) {
3922
3924
  const refCount = (this.refCount[changeTree.refId]) - 1;
3925
+ // console.log("REMOVE", { refId: changeTree.refId, refCount });
3923
3926
  if (refCount <= 0) {
3924
3927
  //
3925
3928
  // Only remove "root" reference if it's the last reference
@@ -3938,7 +3941,7 @@ class Root {
3938
3941
  if ((child.parentChain === undefined || // no parent, remove it
3939
3942
  (child.parentChain && this.refCount[child.refId] > 1) // parent is still in use, but has more than one reference, remove it
3940
3943
  )) {
3941
- this.remove(child);
3944
+ this.remove(child, changeTree.ref);
3942
3945
  }
3943
3946
  else if (child.parentChain) {
3944
3947
  // re-assigning a child of the same root, move it to the end
@@ -4419,11 +4422,7 @@ class Decoder {
4419
4422
  // Trying to access a reference that haven't been decoded yet.
4420
4423
  //
4421
4424
  if (!nextRef) {
4422
- // throw new Error(`"refId" not found: ${nextRefId}`);
4423
- console.error(`"refId" not found: ${nextRefId}`, { previousRef: ref, previousRefId: this.currentRefId });
4424
- console.warn("Please report this to the developers. All refIds =>");
4425
- console.warn(Schema.debugRefIdsDecoder(this));
4426
- this.skipCurrentStructure(bytes, it, totalBytes);
4425
+ throw new Error(`"refId" not found: ${nextRefId}`);
4427
4426
  }
4428
4427
  else {
4429
4428
  ref = nextRef;
@@ -4999,11 +4998,12 @@ class StateView {
4999
4998
  // TODO: allow to set multiple tags at once
5000
4999
  add(obj, tag = DEFAULT_VIEW_TAG, checkIncludeParent = true) {
5001
5000
  const changeTree = obj?.[$changes];
5001
+ const parentChangeTree = changeTree.parent;
5002
5002
  if (!changeTree) {
5003
5003
  console.warn("StateView#add(), invalid object:", obj);
5004
- return this;
5004
+ return false;
5005
5005
  }
5006
- else if (!changeTree.parent &&
5006
+ else if (!parentChangeTree &&
5007
5007
  changeTree.refId !== 0 // allow root object
5008
5008
  ) {
5009
5009
  /**
@@ -5025,18 +5025,31 @@ class StateView {
5025
5025
  // add parent ChangeTree's
5026
5026
  // - if it was invisible to this view
5027
5027
  // - if it were previously filtered out
5028
- if (checkIncludeParent && changeTree.parent) {
5028
+ if (checkIncludeParent && parentChangeTree) {
5029
5029
  this.addParentOf(changeTree, tag);
5030
5030
  }
5031
- //
5032
- // TODO: when adding an item of a MapSchema, the changes may not
5033
- // be set (only the parent's changes are set)
5034
- //
5035
5031
  let changes = this.changes.get(changeTree.refId);
5036
5032
  if (changes === undefined) {
5037
5033
  changes = {};
5034
+ // FIXME / OPTIMIZE: do not add if no changes are needed
5038
5035
  this.changes.set(changeTree.refId, changes);
5039
5036
  }
5037
+ let isChildAdded = false;
5038
+ //
5039
+ // Add children of this ChangeTree first.
5040
+ // If successful, we must link the current ChangeTree to the child.
5041
+ //
5042
+ changeTree.forEachChild((change, index) => {
5043
+ // Do not ADD children that don't have the same tag
5044
+ if (metadata &&
5045
+ metadata[index].tag !== undefined &&
5046
+ metadata[index].tag !== tag) {
5047
+ return;
5048
+ }
5049
+ if (this.add(change.ref, tag, false)) {
5050
+ isChildAdded = true;
5051
+ }
5052
+ });
5040
5053
  // set tag
5041
5054
  if (tag !== DEFAULT_VIEW_TAG) {
5042
5055
  if (!this.tags) {
@@ -5058,11 +5071,12 @@ class StateView {
5058
5071
  }
5059
5072
  });
5060
5073
  }
5061
- else {
5062
- const isInvisible = this.invisible.has(changeTree);
5074
+ else if (!changeTree.isNew || isChildAdded) {
5075
+ // new structures will be added as part of .encode() call, no need to force it to .encodeView()
5063
5076
  const changeSet = (changeTree.filteredChanges !== undefined)
5064
5077
  ? changeTree.allFilteredChanges
5065
5078
  : changeTree.allChanges;
5079
+ const isInvisible = this.invisible.has(changeTree);
5066
5080
  for (let i = 0, len = changeSet.operations.length; i < len; i++) {
5067
5081
  const index = changeSet.operations[i];
5068
5082
  if (index === undefined) {
@@ -5070,27 +5084,17 @@ class StateView {
5070
5084
  } // skip "undefined" indexes
5071
5085
  const op = changeTree.indexedOperations[index] ?? OPERATION.ADD;
5072
5086
  const tagAtIndex = metadata?.[index].tag;
5073
- if (!changeTree.isNew && // new structures will be added as part of .encode() call, no need to force it to .encodeView()
5087
+ if (op !== OPERATION.DELETE &&
5074
5088
  (isInvisible || // if "invisible", include all
5075
5089
  tagAtIndex === undefined || // "all change" with no tag
5076
5090
  tagAtIndex === tag // tagged property
5077
- ) &&
5078
- op !== OPERATION.DELETE) {
5091
+ )) {
5079
5092
  changes[index] = op;
5093
+ isChildAdded = true; // FIXME: assign only once
5080
5094
  }
5081
5095
  }
5082
5096
  }
5083
- // Add children of this ChangeTree to this view
5084
- changeTree.forEachChild((change, index) => {
5085
- // Do not ADD children that don't have the same tag
5086
- if (metadata &&
5087
- metadata[index].tag !== undefined &&
5088
- metadata[index].tag !== tag) {
5089
- return;
5090
- }
5091
- this.add(change.ref, tag, false);
5092
- });
5093
- return this;
5097
+ return isChildAdded;
5094
5098
  }
5095
5099
  addParentOf(childChangeTree, tag) {
5096
5100
  const changeTree = childChangeTree.parent[$changes];