@colyseus/schema 3.0.0-alpha.31 → 3.0.0-alpha.32

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.
@@ -473,7 +473,6 @@ class ChangeTree {
473
473
  changeSet.set(index, operation ?? exports.OPERATION.DELETE);
474
474
  // remove `root` reference
475
475
  if (previousValue && previousValue[$changes]) {
476
- previousValue[$changes].root = undefined;
477
476
  //
478
477
  // FIXME: this.root is "undefined"
479
478
  //
@@ -484,7 +483,13 @@ class ChangeTree {
484
483
  //
485
484
  // (the property descriptors should NOT be used at decoding time. only at encoding time.)
486
485
  //
487
- this.root?.remove(previousValue[$changes]);
486
+ const refCount = this.root?.remove(previousValue[$changes]);
487
+ //
488
+ // Only remove "root" reference if it's the last reference
489
+ //
490
+ if (refCount <= 0) {
491
+ previousValue[$changes].root = undefined;
492
+ }
488
493
  }
489
494
  //
490
495
  // FIXME: this is looking a bit ugly (and repeated from `.change()`)
@@ -863,21 +868,11 @@ var encode = /*#__PURE__*/Object.freeze({
863
868
  writeFloat64: writeFloat64
864
869
  });
865
870
 
866
- function encodeValue(encoder, bytes,
867
- // ref: Ref,
868
- type, value,
869
- // field: string | number,
870
- operation, it) {
871
+ function encodeValue(encoder, bytes, type, value, operation, it) {
871
872
  if (typeof (type) === "string") {
872
- //
873
- // Primitive values
874
- //
875
- // assertType(value, type as string, ref as Schema, field);
876
873
  encode[type]?.(bytes, value, it);
877
874
  }
878
875
  else if (type[Symbol.metadata] !== undefined) {
879
- // // TODO: move this to the `@type()` annotation
880
- // assertInstanceType(value, type as typeof Schema, ref as Schema, field);
881
876
  //
882
877
  // Encode refId for this instance.
883
878
  // The actual instance is going to be encoded on next `changeTree` iteration.
@@ -889,14 +884,6 @@ operation, it) {
889
884
  }
890
885
  }
891
886
  else {
892
- // //
893
- // // Custom type (MapSchema, ArraySchema, etc)
894
- // //
895
- // const definition = getType(Object.keys(type)[0]);
896
- // //
897
- // // ensure a ArraySchema has been provided
898
- // //
899
- // assertInstanceType(ref[field], definition.constructor, ref as Schema, field);
900
887
  //
901
888
  // Encode refId for this instance.
902
889
  // The actual instance is going to be encoded on next `changeTree` iteration.
@@ -916,14 +903,10 @@ const encodeSchemaOperation = function (encoder, bytes, changeTree, index, opera
916
903
  return;
917
904
  }
918
905
  const ref = changeTree.ref;
919
- const metadata = ref['constructor'][Symbol.metadata];
906
+ const metadata = ref.constructor[Symbol.metadata];
920
907
  const field = metadata[index];
921
908
  // TODO: inline this function call small performance gain
922
- encodeValue(encoder, bytes,
923
- // ref,
924
- metadata[index].type, ref[field.name],
925
- // index,
926
- operation, it);
909
+ encodeValue(encoder, bytes, metadata[index].type, ref[field.name], operation, it);
927
910
  };
928
911
  /**
929
912
  * Used for collections (MapSchema, CollectionSchema, SetSchema)
@@ -946,7 +929,7 @@ const encodeKeyValueOperation = function (encoder, bytes, changeTree, index, ope
946
929
  //
947
930
  // encode "alias" for dynamic fields (maps)
948
931
  //
949
- if ((operation & exports.OPERATION.ADD) == exports.OPERATION.ADD) { // ADD or DELETE_AND_ADD
932
+ if ((operation & exports.OPERATION.ADD) === exports.OPERATION.ADD) { // ADD or DELETE_AND_ADD
950
933
  if (typeof (ref['set']) === "function") {
951
934
  //
952
935
  // MapSchema dynamic key
@@ -955,8 +938,8 @@ const encodeKeyValueOperation = function (encoder, bytes, changeTree, index, ope
955
938
  string$1(bytes, dynamicIndex, it);
956
939
  }
957
940
  }
958
- const type = changeTree.getType(index);
959
- const value = changeTree.getValue(index);
941
+ const type = ref[$childType];
942
+ const value = ref[$getByIndex](index);
960
943
  // try { throw new Error(); } catch (e) {
961
944
  // // only print if not coming from Reflection.ts
962
945
  // if (!e.stack.includes("src/Reflection.ts")) {
@@ -970,11 +953,7 @@ const encodeKeyValueOperation = function (encoder, bytes, changeTree, index, ope
970
953
  // }
971
954
  // }
972
955
  // TODO: inline this function call small performance gain
973
- encodeValue(encoder, bytes,
974
- // ref,
975
- type, value,
976
- // index,
977
- operation, it);
956
+ encodeValue(encoder, bytes, type, value, operation, it);
978
957
  };
979
958
  /**
980
959
  * Used for collections (MapSchema, ArraySchema, etc.)
@@ -1018,11 +997,7 @@ const encodeArray = function (encoder, bytes, changeTree, field, operation, it,
1018
997
  // items: ref.toJSON(),
1019
998
  // });
1020
999
  // TODO: inline this function call small performance gain
1021
- encodeValue(encoder, bytes,
1022
- // ref,
1023
- type, value,
1024
- // field,
1025
- operation, it);
1000
+ encodeValue(encoder, bytes, type, value, operation, it);
1026
1001
  };
1027
1002
 
1028
1003
  /**
@@ -1328,7 +1303,9 @@ function decodeValue(decoder, operation, ref, index, type, bytes, it, allChanges
1328
1303
  if (!value) {
1329
1304
  value = decoder.createInstanceOfType(childType);
1330
1305
  }
1331
- $root.addRef(refId, value, (value !== previousValue));
1306
+ $root.addRef(refId, value, (value !== previousValue || // increment ref count if value has changed
1307
+ (operation === exports.OPERATION.DELETE_AND_ADD && value === previousValue) // increment ref count if the same instance is being added again
1308
+ ));
1332
1309
  }
1333
1310
  }
1334
1311
  else if (typeof (type) === "string") {
@@ -3475,24 +3452,36 @@ class Root {
3475
3452
  return this.nextUniqueId++;
3476
3453
  }
3477
3454
  add(changeTree) {
3478
- const refCount = this.refCount.get(changeTree) || 0;
3479
- this.refCount.set(changeTree, refCount + 1);
3455
+ const previousRefCount = this.refCount.get(changeTree);
3456
+ if (previousRefCount === 0) {
3457
+ //
3458
+ // When a ChangeTree is re-added, it means that it was previously removed.
3459
+ // We need to re-add all changes to the `changes` map.
3460
+ //
3461
+ changeTree.allChanges.forEach((operation, index) => {
3462
+ changeTree.changes.set(index, operation);
3463
+ });
3464
+ }
3465
+ const refCount = (previousRefCount || 0) + 1;
3466
+ this.refCount.set(changeTree, refCount);
3467
+ return refCount;
3480
3468
  }
3481
3469
  remove(changeTree) {
3482
- const refCount = this.refCount.get(changeTree);
3483
- if (refCount <= 1) {
3470
+ const refCount = (this.refCount.get(changeTree)) - 1;
3471
+ if (refCount <= 0) {
3484
3472
  this.allChanges.delete(changeTree);
3485
3473
  this.changes.delete(changeTree);
3486
3474
  if (changeTree.isFiltered || changeTree.isPartiallyFiltered) {
3487
3475
  this.allFilteredChanges.delete(changeTree);
3488
3476
  this.filteredChanges.delete(changeTree);
3489
3477
  }
3490
- this.refCount.delete(changeTree);
3478
+ this.refCount.set(changeTree, 0);
3491
3479
  }
3492
3480
  else {
3493
- this.refCount.set(changeTree, refCount - 1);
3481
+ this.refCount.set(changeTree, refCount);
3494
3482
  }
3495
3483
  changeTree.forEachChild((child, _) => this.remove(child));
3484
+ return refCount;
3496
3485
  }
3497
3486
  clear() {
3498
3487
  this.changes.clear();
@@ -3526,7 +3515,7 @@ class Encoder {
3526
3515
  const shouldClearChanges = !isEncodeAll && !hasView;
3527
3516
  for (const [changeTree, changes] of changeTrees.entries()) {
3528
3517
  const ref = changeTree.ref;
3529
- const ctor = ref['constructor'];
3518
+ const ctor = ref.constructor;
3530
3519
  const encoder = ctor[$encoder];
3531
3520
  const filter = ctor[$filter];
3532
3521
  // try { throw new Error(); } catch (e) {
@@ -3550,8 +3539,7 @@ class Encoder {
3550
3539
  buffer[it.offset++] = SWITCH_TO_STRUCTURE & 255;
3551
3540
  number$1(buffer, changeTree.refId, it);
3552
3541
  }
3553
- const changesIterator = changes.entries();
3554
- for (const [fieldIndex, operation] of changesIterator) {
3542
+ for (const [fieldIndex, operation] of changes.entries()) {
3555
3543
  //
3556
3544
  // first pass (encodeAll), identify "filtered" operations without encoding them
3557
3545
  // they will be encoded per client, based on their view.
@@ -3577,7 +3565,12 @@ class Encoder {
3577
3565
  encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);
3578
3566
  }
3579
3567
  // if (shouldClearChanges) {
3580
- // changeTree.endEncode();
3568
+ // // changeTree.endEncode();
3569
+ // changeTree.changes.clear();
3570
+ // // ArraySchema and MapSchema have a custom "encode end" method
3571
+ // changeTree.ref[$onEncodeEnd]?.();
3572
+ // // Not a new instance anymore
3573
+ // delete changeTree[$isNew];
3581
3574
  // }
3582
3575
  }
3583
3576
  if (it.offset > buffer.byteLength) {