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