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