@colyseus/schema 3.0.22 → 3.0.24

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.
@@ -1829,7 +1829,7 @@ class ArraySchema {
1829
1829
  return (!view ||
1830
1830
  typeof (ref[$childType]) === "string" ||
1831
1831
  // view.items.has(ref[$getByIndex](index)[$changes])
1832
- view.items.has(ref['tmpItems'][index]?.[$changes]));
1832
+ view.visible.has(ref['tmpItems'][index]?.[$changes]));
1833
1833
  }
1834
1834
  static is(type) {
1835
1835
  return (
@@ -2485,7 +2485,7 @@ class MapSchema {
2485
2485
  static [(_a$3 = $encoder, _b$3 = $decoder, $filter)](ref, index, view) {
2486
2486
  return (!view ||
2487
2487
  typeof (ref[$childType]) === "string" ||
2488
- view.items.has((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
2488
+ view.visible.has((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
2489
2489
  }
2490
2490
  static is(type) {
2491
2491
  return type['map'] !== undefined;
@@ -3102,7 +3102,7 @@ class Schema {
3102
3102
  }
3103
3103
  else if (tag === DEFAULT_VIEW_TAG) {
3104
3104
  // view pass: default tag
3105
- return view.items.has(ref[$changes]);
3105
+ return view.visible.has(ref[$changes]);
3106
3106
  }
3107
3107
  else {
3108
3108
  // view pass: custom tag
@@ -3315,7 +3315,7 @@ class CollectionSchema {
3315
3315
  static [(_a$1 = $encoder, _b$1 = $decoder, $filter)](ref, index, view) {
3316
3316
  return (!view ||
3317
3317
  typeof (ref[$childType]) === "string" ||
3318
- view.items.has((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
3318
+ view.visible.has((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
3319
3319
  }
3320
3320
  static is(type) {
3321
3321
  return type['collection'] !== undefined;
@@ -3475,7 +3475,7 @@ class SetSchema {
3475
3475
  static [(_a = $encoder, _b = $decoder, $filter)](ref, index, view) {
3476
3476
  return (!view ||
3477
3477
  typeof (ref[$childType]) === "string" ||
3478
- view.items.has((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
3478
+ view.visible.has((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
3479
3479
  }
3480
3480
  static is(type) {
3481
3481
  return type['set'] !== undefined;
@@ -3795,7 +3795,7 @@ class Encoder {
3795
3795
  for (let i = 0, numChangeTrees = changeTrees.length; i < numChangeTrees; i++) {
3796
3796
  const changeTree = changeTrees[i];
3797
3797
  if (hasView) {
3798
- if (!view.items.has(changeTree)) {
3798
+ if (!view.visible.has(changeTree)) {
3799
3799
  view.invisible.add(changeTree);
3800
3800
  continue; // skip this change tree
3801
3801
  }
@@ -4711,11 +4711,12 @@ function getRawChangesCallback(decoder, callback) {
4711
4711
  }
4712
4712
 
4713
4713
  class StateView {
4714
- constructor() {
4714
+ constructor(iterable = false) {
4715
+ this.iterable = iterable;
4715
4716
  /**
4716
4717
  * List of ChangeTree's that are visible to this view
4717
4718
  */
4718
- this.items = new WeakSet();
4719
+ this.visible = new WeakSet();
4719
4720
  /**
4720
4721
  * List of ChangeTree's that are invisible to this view
4721
4722
  */
@@ -4725,17 +4726,36 @@ class StateView {
4725
4726
  * (This is used to force encoding a property, even if it was not changed)
4726
4727
  */
4727
4728
  this.changes = new Map();
4729
+ if (iterable) {
4730
+ this.items = [];
4731
+ }
4728
4732
  }
4729
4733
  // TODO: allow to set multiple tags at once
4730
4734
  add(obj, tag = DEFAULT_VIEW_TAG, checkIncludeParent = true) {
4731
- if (!obj?.[$changes]) {
4735
+ const changeTree = obj?.[$changes];
4736
+ if (!changeTree) {
4732
4737
  console.warn("StateView#add(), invalid object:", obj);
4733
4738
  return this;
4734
4739
  }
4740
+ else if (!changeTree.parent &&
4741
+ changeTree.refId !== 0 // allow root object
4742
+ ) {
4743
+ /**
4744
+ * TODO: can we avoid this?
4745
+ *
4746
+ * When the "parent" structure has the @view() tag, it is currently
4747
+ * not possible to identify it has to be added to the view as well
4748
+ * (this.addParentOf() is not called).
4749
+ */
4750
+ throw new Error(`Cannot add a detached instance to the StateView. Make sure to assign the "${changeTree.ref.constructor.name}" instance to the state before calling view.add()`);
4751
+ }
4735
4752
  // FIXME: ArraySchema/MapSchema do not have metadata
4736
4753
  const metadata = obj.constructor[Symbol.metadata];
4737
- const changeTree = obj[$changes];
4738
- this.items.add(changeTree);
4754
+ this.visible.add(changeTree);
4755
+ // add to iterable list (only the explicitly added items)
4756
+ if (this.iterable && checkIncludeParent) {
4757
+ this.items.push(obj);
4758
+ }
4739
4759
  // add parent ChangeTree's
4740
4760
  // - if it was invisible to this view
4741
4761
  // - if it were previously filtered out
@@ -4809,9 +4829,9 @@ class StateView {
4809
4829
  addParentOf(childChangeTree, tag) {
4810
4830
  const changeTree = childChangeTree.parent[$changes];
4811
4831
  const parentIndex = childChangeTree.parentIndex;
4812
- if (!this.items.has(changeTree)) {
4832
+ if (!this.visible.has(changeTree)) {
4813
4833
  // view must have all "changeTree" parent tree
4814
- this.items.add(changeTree);
4834
+ this.visible.add(changeTree);
4815
4835
  // add parent's parent
4816
4836
  const parentChangeTree = changeTree.parent?.[$changes];
4817
4837
  if (parentChangeTree && (parentChangeTree.filteredChanges !== undefined)) {
@@ -4842,13 +4862,19 @@ class StateView {
4842
4862
  changes[parentIndex] = OPERATION.ADD;
4843
4863
  }
4844
4864
  }
4845
- remove(obj, tag = DEFAULT_VIEW_TAG) {
4865
+ remove(obj, tag = DEFAULT_VIEW_TAG, _isClear = false) {
4846
4866
  const changeTree = obj[$changes];
4847
4867
  if (!changeTree) {
4848
4868
  console.warn("StateView#remove(), invalid object:", obj);
4849
4869
  return this;
4850
4870
  }
4851
- this.items.delete(changeTree);
4871
+ this.visible.delete(changeTree);
4872
+ // remove from iterable list
4873
+ if (this.iterable &&
4874
+ !_isClear // no need to remove during clear(), as it will be cleared entirely
4875
+ ) {
4876
+ spliceOne(this.items, this.items.indexOf(obj));
4877
+ }
4852
4878
  const ref = changeTree.ref;
4853
4879
  const metadata = ref.constructor[Symbol.metadata]; // ArraySchema/MapSchema do not have metadata
4854
4880
  let changes = this.changes.get(changeTree.refId);
@@ -4897,12 +4923,22 @@ class StateView {
4897
4923
  return this;
4898
4924
  }
4899
4925
  has(obj) {
4900
- return this.items.has(obj[$changes]);
4926
+ return this.visible.has(obj[$changes]);
4901
4927
  }
4902
4928
  hasTag(ob, tag = DEFAULT_VIEW_TAG) {
4903
4929
  const tags = this.tags?.get(ob[$changes]);
4904
4930
  return tags?.has(tag) ?? false;
4905
4931
  }
4932
+ clear() {
4933
+ if (!this.iterable) {
4934
+ throw new Error("StateView#clear() is only available for iterable StateView's. Use StateView(iterable: true) constructor.");
4935
+ }
4936
+ for (let i = 0, l = this.items.length; i < l; i++) {
4937
+ this.remove(this.items[i], DEFAULT_VIEW_TAG, true);
4938
+ }
4939
+ // clear items array
4940
+ this.items.length = 0;
4941
+ }
4906
4942
  }
4907
4943
 
4908
4944
  registerType("map", { constructor: MapSchema });