@colyseus/schema 3.0.0-alpha.1 → 3.0.0-alpha.11

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.
Files changed (43) hide show
  1. package/build/cjs/index.js +113 -69
  2. package/build/cjs/index.js.map +1 -1
  3. package/build/esm/index.mjs +113 -69
  4. package/build/esm/index.mjs.map +1 -1
  5. package/build/umd/index.js +113 -69
  6. package/lib/Reflection.d.ts +1 -1
  7. package/lib/Reflection.js +1 -2
  8. package/lib/Reflection.js.map +1 -1
  9. package/lib/decoder/DecodeOperation.js +2 -2
  10. package/lib/decoder/DecodeOperation.js.map +1 -1
  11. package/lib/decoder/Decoder.d.ts +1 -1
  12. package/lib/decoder/Decoder.js +4 -4
  13. package/lib/decoder/Decoder.js.map +1 -1
  14. package/lib/decoder/strategy/StateCallbacks.js +1 -1
  15. package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
  16. package/lib/encoder/ChangeTree.d.ts +0 -2
  17. package/lib/encoder/ChangeTree.js +2 -6
  18. package/lib/encoder/ChangeTree.js.map +1 -1
  19. package/lib/encoder/EncodeOperation.js +12 -0
  20. package/lib/encoder/EncodeOperation.js.map +1 -1
  21. package/lib/encoder/Encoder.d.ts +5 -4
  22. package/lib/encoder/Encoder.js +62 -48
  23. package/lib/encoder/Encoder.js.map +1 -1
  24. package/lib/encoder/StateView.d.ts +2 -0
  25. package/lib/encoder/StateView.js +4 -1
  26. package/lib/encoder/StateView.js.map +1 -1
  27. package/lib/encoding/decode.d.ts +21 -19
  28. package/lib/encoding/decode.js +6 -6
  29. package/lib/encoding/decode.js.map +1 -1
  30. package/lib/encoding/encode.d.ts +3 -2
  31. package/lib/encoding/encode.js +24 -22
  32. package/lib/encoding/encode.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/Reflection.ts +1 -2
  35. package/src/decoder/DecodeOperation.ts +3 -3
  36. package/src/decoder/Decoder.ts +5 -5
  37. package/src/decoder/strategy/StateCallbacks.ts +1 -1
  38. package/src/encoder/ChangeTree.ts +2 -6
  39. package/src/encoder/EncodeOperation.ts +13 -0
  40. package/src/encoder/Encoder.ts +69 -53
  41. package/src/encoder/StateView.ts +4 -0
  42. package/src/encoding/decode.ts +24 -25
  43. package/src/encoding/encode.ts +26 -23
@@ -168,7 +168,6 @@ class Root {
168
168
  // pending changes to be encoded
169
169
  this.changes = new Map();
170
170
  this.filteredChanges = new Map();
171
- this.views = [];
172
171
  }
173
172
  getNextUniqueId() {
174
173
  return this.nextUniqueId++;
@@ -263,14 +262,12 @@ class ChangeTree {
263
262
  this.checkIsFiltered(parent, parentIndex);
264
263
  if (!this.isFiltered) {
265
264
  this.root.changes.set(this, this.changes);
265
+ this.root.allChanges.set(this, this.allChanges);
266
266
  }
267
267
  if (this.isFiltered || this.isPartiallyFiltered) {
268
268
  this.root.filteredChanges.set(this, this.filteredChanges);
269
269
  this.root.allFilteredChanges.set(this, this.filteredChanges);
270
270
  }
271
- else {
272
- this.root.allChanges.set(this, this.allChanges);
273
- }
274
271
  this.ensureRefId();
275
272
  this.forEachChild((changeTree, atIndex) => {
276
273
  changeTree.setParent(this.ref, root, atIndex);
@@ -362,7 +359,6 @@ class ChangeTree {
362
359
  }
363
360
  _shiftAllChangeIndexes(shiftIndex, startIndex = 0, allChangeSet) {
364
361
  Array.from(allChangeSet.entries()).forEach(([index, op]) => {
365
- // console.log('shiftAllChangeIndexes', index >= startIndex, { index, op, shiftIndex, startIndex })
366
362
  if (index >= startIndex) {
367
363
  allChangeSet.delete(index);
368
364
  allChangeSet.set(index + shiftIndex, op);
@@ -503,7 +499,7 @@ class ChangeTree {
503
499
  }
504
500
  checkIsFiltered(parent, parentIndex) {
505
501
  // Detect if current structure has "filters" declared
506
- this.isPartiallyFiltered = this.ref['constructor']?.[Symbol.metadata]?.[-2];
502
+ this.isPartiallyFiltered = (this.ref['constructor']?.[Symbol.metadata]?.[-2] !== undefined);
507
503
  // TODO: support "partially filtered", where the instance is visible, but only a field is not.
508
504
  // Detect if parent has "filters" declared
509
505
  while (parent && !this.isFiltered) {
@@ -564,6 +560,29 @@ try {
564
560
  textEncoder = new TextEncoder();
565
561
  }
566
562
  catch (e) { }
563
+ const hasBufferByteLength = (typeof Buffer !== 'undefined' && Buffer.byteLength);
564
+ const utf8Length = (hasBufferByteLength)
565
+ ? Buffer.byteLength // node
566
+ : function (str, _) {
567
+ var c = 0, length = 0;
568
+ for (var i = 0, l = str.length; i < l; i++) {
569
+ c = str.charCodeAt(i);
570
+ if (c < 0x80) {
571
+ length += 1;
572
+ }
573
+ else if (c < 0x800) {
574
+ length += 2;
575
+ }
576
+ else if (c < 0xd800 || c >= 0xe000) {
577
+ length += 3;
578
+ }
579
+ else {
580
+ i++;
581
+ length += 4;
582
+ }
583
+ }
584
+ return length;
585
+ };
567
586
  function utf8Write(view, str, it) {
568
587
  var c = 0;
569
588
  for (var i = 0, l = str.length; i < l; i++) {
@@ -658,8 +677,7 @@ function string$1(bytes, value, it) {
658
677
  if (!value) {
659
678
  value = "";
660
679
  }
661
- // let length = utf8Length(value);
662
- let length = Buffer.byteLength(value, "utf8");
680
+ let length = utf8Length(value, "utf8");
663
681
  let size = 0;
664
682
  // fixstr
665
683
  if (length < 0x20) {
@@ -770,6 +788,7 @@ function number$1(bytes, value, it) {
770
788
 
771
789
  var encode = /*#__PURE__*/Object.freeze({
772
790
  __proto__: null,
791
+ utf8Length: utf8Length,
773
792
  utf8Write: utf8Write,
774
793
  int8: int8$1,
775
794
  uint8: uint8$1,
@@ -927,6 +946,18 @@ const encodeKeyValueOperation = function (encoder, bytes, changeTree, field, ope
927
946
  }
928
947
  const type = changeTree.getType(field);
929
948
  const value = changeTree.getValue(field);
949
+ // try { throw new Error(); } catch (e) {
950
+ // // only print if not coming from Reflection.ts
951
+ // if (!e.stack.includes("src/Reflection.ts")) {
952
+ // console.log("encodeKeyValueOperation -> ", {
953
+ // ref: changeTree.ref.constructor.name,
954
+ // field,
955
+ // operation: OPERATION[operation],
956
+ // value: value?.toJSON(),
957
+ // items: ref.toJSON(),
958
+ // });
959
+ // }
960
+ // }
930
961
  // TODO: inline this function call small performance gain
931
962
  encodeValue(encoder, bytes, ref, type, value, field, operation, it);
932
963
  };
@@ -993,9 +1024,9 @@ const encodeArray = function (encoder, bytes, changeTree, field, operation, it,
993
1024
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
994
1025
  * SOFTWARE
995
1026
  */
996
- function utf8Read(bytes, offset, length) {
1027
+ function utf8Read(bytes, it, length) {
997
1028
  var string = '', chr = 0;
998
- for (var i = offset, end = offset + length; i < end; i++) {
1029
+ for (var i = it.offset, end = it.offset + length; i < end; i++) {
999
1030
  var byte = bytes[i];
1000
1031
  if ((byte & 0x80) === 0x00) {
1001
1032
  string += String.fromCharCode(byte);
@@ -1030,6 +1061,7 @@ function utf8Read(bytes, offset, length) {
1030
1061
  // (do not throw error to avoid server/client from crashing due to hack attemps)
1031
1062
  // throw new Error('Invalid byte ' + byte.toString(16));
1032
1063
  }
1064
+ it.offset += length;
1033
1065
  return string;
1034
1066
  }
1035
1067
  function int8(bytes, it) {
@@ -1097,9 +1129,7 @@ function string(bytes, it) {
1097
1129
  else if (prefix === 0xdb) {
1098
1130
  length = uint32(bytes, it);
1099
1131
  }
1100
- const value = utf8Read(bytes, it.offset, length);
1101
- it.offset += length;
1102
- return value;
1132
+ return utf8Read(bytes, it, length);
1103
1133
  }
1104
1134
  function stringCheck(bytes, it) {
1105
1135
  const prefix = bytes[it.offset];
@@ -1203,6 +1233,7 @@ function switchStructureCheck(bytes, it) {
1203
1233
 
1204
1234
  var decode = /*#__PURE__*/Object.freeze({
1205
1235
  __proto__: null,
1236
+ utf8Read: utf8Read,
1206
1237
  int8: int8,
1207
1238
  uint8: uint8,
1208
1239
  int16: int16,
@@ -1226,7 +1257,7 @@ var decode = /*#__PURE__*/Object.freeze({
1226
1257
 
1227
1258
  const DEFINITION_MISMATCH = -1;
1228
1259
  function decodeValue(decoder, operation, ref, index, type, bytes, it, allChanges) {
1229
- const $root = decoder.$root;
1260
+ const $root = decoder.root;
1230
1261
  const previousValue = ref[$getByIndex](index);
1231
1262
  let value;
1232
1263
  if ((operation & exports.OPERATION.DELETE) === exports.OPERATION.DELETE) {
@@ -1426,7 +1457,7 @@ const decodeArray = function (decoder, bytes, it, ref, allChanges) {
1426
1457
  else if (operation === exports.OPERATION.DELETE_BY_REFID) {
1427
1458
  // TODO: refactor here, try to follow same flow as below
1428
1459
  const refId = number(bytes, it);
1429
- const previousValue = decoder.$root.refs.get(refId);
1460
+ const previousValue = decoder.root.refs.get(refId);
1430
1461
  const index = ref.findIndex((value) => value === previousValue);
1431
1462
  ref[$deleteByIndex](index);
1432
1463
  allChanges.push({
@@ -3362,13 +3393,13 @@ class Encoder {
3362
3393
  // });
3363
3394
  }
3364
3395
  setRoot(state) {
3365
- this.$root = new Root();
3396
+ this.root = new Root();
3366
3397
  this.state = state;
3367
- state[$changes].setRoot(this.$root);
3398
+ state[$changes].setRoot(this.root);
3368
3399
  }
3369
- encode(it = { offset: 0 }, view, bytes = this.sharedBuffer, changeTrees = this.$root.changes) {
3400
+ encode(it = { offset: 0 }, view, buffer = this.sharedBuffer, changeTrees = this.root.changes) {
3370
3401
  const initialOffset = it.offset; // cache current offset in case we need to resize the buffer
3371
- const isEncodeAll = this.$root.allChanges === changeTrees;
3402
+ const isEncodeAll = this.root.allChanges === changeTrees;
3372
3403
  const hasView = (view !== undefined);
3373
3404
  const rootChangeTree = this.state[$changes];
3374
3405
  const changeTreesIterator = changeTrees.entries();
@@ -3377,6 +3408,12 @@ class Encoder {
3377
3408
  const ctor = ref['constructor'];
3378
3409
  const encoder = ctor[$encoder];
3379
3410
  const filter = ctor[$filter];
3411
+ // try { throw new Error(); } catch (e) {
3412
+ // // only print if not coming from Reflection.ts
3413
+ // if (!e.stack.includes("src/Reflection.ts")) {
3414
+ // console.log("ChangeTree:", { ref: ref.constructor.name, });
3415
+ // }
3416
+ // }
3380
3417
  if (hasView) {
3381
3418
  if (!view.items.has(changeTree)) {
3382
3419
  view.invisible.add(changeTree);
@@ -3388,8 +3425,8 @@ class Encoder {
3388
3425
  }
3389
3426
  // skip root `refId` if it's the first change tree
3390
3427
  if (it.offset !== initialOffset || changeTree !== rootChangeTree) {
3391
- bytes[it.offset++] = SWITCH_TO_STRUCTURE & 255;
3392
- number$1(bytes, changeTree.refId, it);
3428
+ buffer[it.offset++] = SWITCH_TO_STRUCTURE & 255;
3429
+ number$1(buffer, changeTree.refId, it);
3393
3430
  }
3394
3431
  const changesIterator = changes.entries();
3395
3432
  for (const [fieldIndex, operation] of changesIterator) {
@@ -3406,22 +3443,31 @@ class Encoder {
3406
3443
  // view?.invisible.add(changeTree);
3407
3444
  continue;
3408
3445
  }
3409
- // console.log("WILL ENCODE", {
3410
- // ref: changeTree.ref.constructor.name,
3411
- // fieldIndex,
3412
- // operation: OPERATION[operation],
3413
- // });
3414
- encoder(this, bytes, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);
3446
+ // try { throw new Error(); } catch (e) {
3447
+ // // only print if not coming from Reflection.ts
3448
+ // if (!e.stack.includes("src/Reflection.ts")) {
3449
+ // // console.log("WILL ENCODE", {
3450
+ // // ref: changeTree.ref.constructor.name,
3451
+ // // fieldIndex,
3452
+ // // operation: OPERATION[operation],
3453
+ // // });
3454
+ // }
3455
+ // }
3456
+ encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);
3415
3457
  }
3416
3458
  }
3417
- if (it.offset > bytes.byteLength) {
3418
- const newSize = getNextPowerOf2(this.sharedBuffer.byteLength * 2);
3419
- console.warn("@colyseus/schema encode buffer overflow. Current buffer size: " + bytes.byteLength + ", encoding offset: " + it.offset + ", new size: " + newSize);
3459
+ if (it.offset > buffer.byteLength) {
3460
+ const newSize = getNextPowerOf2(buffer.byteLength * 2);
3461
+ console.warn("@colyseus/schema encode buffer overflow. Current buffer size: " + buffer.byteLength + ", encoding offset: " + it.offset + ", new size: " + newSize);
3420
3462
  //
3421
3463
  // resize buffer and re-encode (TODO: can we avoid re-encoding here?)
3422
3464
  //
3423
- this.sharedBuffer = Buffer.allocUnsafeSlow(newSize);
3424
- return this.encode({ offset: initialOffset }, view);
3465
+ buffer = Buffer.allocUnsafeSlow(newSize);
3466
+ // assign resized buffer to local sharedBuffer
3467
+ if (buffer === this.sharedBuffer) {
3468
+ this.sharedBuffer = buffer;
3469
+ }
3470
+ return this.encode({ offset: initialOffset }, view, buffer);
3425
3471
  }
3426
3472
  else {
3427
3473
  //
@@ -3433,42 +3479,41 @@ class Encoder {
3433
3479
  //
3434
3480
  this.onEndEncode(changeTrees);
3435
3481
  }
3436
- // return bytes;
3437
- return bytes.slice(0, it.offset);
3482
+ return buffer.subarray(0, it.offset);
3438
3483
  }
3439
3484
  }
3440
- encodeAll(it = { offset: 0 }) {
3441
- // console.log(`encodeAll(), this.$root.allChanges (${this.$root.allChanges.size})`);
3442
- // Array.from(this.$root.allChanges.entries()).map((item) => {
3443
- // console.log("->", item[0].refId, item[0].ref.toJSON());
3485
+ encodeAll(it = { offset: 0 }, buffer = this.sharedBuffer) {
3486
+ // console.log(`encodeAll(), this.root.allChanges (${this.root.allChanges.size})`);
3487
+ // Array.from(this.root.allChanges.entries()).map((item) => {
3488
+ // console.log("->", { ref: item[0].ref.constructor.name, refId: item[0].refId, changes: item[1].size });
3444
3489
  // });
3445
- return this.encode(it, undefined, this.sharedBuffer, this.$root.allChanges);
3490
+ return this.encode(it, undefined, buffer, this.root.allChanges);
3446
3491
  }
3447
3492
  encodeAllView(view, sharedOffset, it, bytes = this.sharedBuffer) {
3448
3493
  const viewOffset = it.offset;
3449
- // console.log(`encodeAllView(), this.$root.allFilteredChanges (${this.$root.allFilteredChanges.size})`);
3494
+ // console.log(`encodeAllView(), this.root.allFilteredChanges (${this.root.allFilteredChanges.size})`);
3450
3495
  // this.debugAllFilteredChanges();
3451
3496
  // try to encode "filtered" changes
3452
- this.encode(it, view, bytes, this.$root.allFilteredChanges);
3497
+ this.encode(it, view, bytes, this.root.allFilteredChanges);
3453
3498
  return Buffer.concat([
3454
- bytes.slice(0, sharedOffset),
3455
- bytes.slice(viewOffset, it.offset)
3499
+ bytes.subarray(0, sharedOffset),
3500
+ bytes.subarray(viewOffset, it.offset)
3456
3501
  ]);
3457
3502
  }
3458
- // debugAllFilteredChanges() {
3459
- // Array.from(this.$root.allFilteredChanges.entries()).map((item) => {
3460
- // console.log("->", { refId: item[0].refId }, item[0].ref.toJSON());
3461
- // if (Array.isArray(item[0].ref.toJSON())) {
3462
- // item[1].forEach((op, key) => {
3463
- // console.log(" ->", { key, op: OPERATION[op] });
3464
- // })
3465
- // }
3466
- // });
3467
- // }
3503
+ debugAllFilteredChanges() {
3504
+ Array.from(this.root.allFilteredChanges.entries()).map((item) => {
3505
+ console.log("->", { refId: item[0].refId, changes: item[1].size }, item[0].ref.toJSON());
3506
+ if (Array.isArray(item[0].ref.toJSON())) {
3507
+ item[1].forEach((op, key) => {
3508
+ console.log(" ->", { key, op: exports.OPERATION[op] });
3509
+ });
3510
+ }
3511
+ });
3512
+ }
3468
3513
  encodeView(view, sharedOffset, it, bytes = this.sharedBuffer) {
3469
3514
  const viewOffset = it.offset;
3470
3515
  // try to encode "filtered" changes
3471
- this.encode(it, view, bytes, this.$root.filteredChanges);
3516
+ this.encode(it, view, bytes, this.root.filteredChanges);
3472
3517
  // encode visibility changes (add/remove for this view)
3473
3518
  const viewChangesIterator = view.changes.entries();
3474
3519
  for (const [changeTree, changes] of viewChangesIterator) {
@@ -3496,11 +3541,11 @@ class Encoder {
3496
3541
  // clear "view" changes after encoding
3497
3542
  view.changes.clear();
3498
3543
  return Buffer.concat([
3499
- bytes.slice(0, sharedOffset),
3500
- bytes.slice(viewOffset, it.offset)
3544
+ bytes.subarray(0, sharedOffset),
3545
+ bytes.subarray(viewOffset, it.offset)
3501
3546
  ]);
3502
3547
  }
3503
- onEndEncode(changeTrees = this.$root.changes) {
3548
+ onEndEncode(changeTrees = this.root.changes) {
3504
3549
  const changeTreesIterator = changeTrees.entries();
3505
3550
  for (const [changeTree, _] of changeTreesIterator) {
3506
3551
  changeTree.endEncode();
@@ -3508,14 +3553,14 @@ class Encoder {
3508
3553
  }
3509
3554
  discardChanges() {
3510
3555
  // discard shared changes
3511
- if (this.$root.changes.size > 0) {
3512
- this.onEndEncode(this.$root.changes);
3513
- this.$root.changes.clear();
3556
+ if (this.root.changes.size > 0) {
3557
+ this.onEndEncode(this.root.changes);
3558
+ this.root.changes.clear();
3514
3559
  }
3515
3560
  // discard filtered changes
3516
- if (this.$root.filteredChanges.size > 0) {
3517
- this.onEndEncode(this.$root.filteredChanges);
3518
- this.$root.filteredChanges.clear();
3561
+ if (this.root.filteredChanges.size > 0) {
3562
+ this.onEndEncode(this.root.filteredChanges);
3563
+ this.root.filteredChanges.clear();
3519
3564
  }
3520
3565
  }
3521
3566
  tryEncodeTypeId(bytes, baseType, targetType, it) {
@@ -3676,12 +3721,12 @@ class Decoder {
3676
3721
  }
3677
3722
  setRoot(root) {
3678
3723
  this.state = root;
3679
- this.$root = new ReferenceTracker();
3680
- this.$root.addRef(0, root);
3724
+ this.root = new ReferenceTracker();
3725
+ this.root.addRef(0, root);
3681
3726
  }
3682
3727
  decode(bytes, it = { offset: 0 }, ref = this.state) {
3683
3728
  const allChanges = [];
3684
- const $root = this.$root;
3729
+ const $root = this.root;
3685
3730
  const totalBytes = bytes.byteLength;
3686
3731
  let decoder = ref['constructor'][$decoder];
3687
3732
  this.currentRefId = 0;
@@ -3762,7 +3807,7 @@ class Decoder {
3762
3807
  previousValue: value
3763
3808
  });
3764
3809
  if (needRemoveRef) {
3765
- this.$root.removeRef(this.$root.refIds.get(value));
3810
+ this.root.removeRef(this.root.refIds.get(value));
3766
3811
  }
3767
3812
  });
3768
3813
  }
@@ -3802,7 +3847,7 @@ class Reflection extends Schema {
3802
3847
  super(...arguments);
3803
3848
  this.types = new ArraySchema();
3804
3849
  }
3805
- static encode(instance, context) {
3850
+ static encode(instance, context, it = { offset: 0 }) {
3806
3851
  if (!context) {
3807
3852
  context = new TypeContext(instance.constructor);
3808
3853
  }
@@ -3859,7 +3904,6 @@ class Reflection extends Schema {
3859
3904
  }
3860
3905
  buildType(type, klass[Symbol.metadata]);
3861
3906
  }
3862
- const it = { offset: 0 };
3863
3907
  const buf = encoder.encodeAll(it);
3864
3908
  return Buffer.from(buf, 0, it.offset);
3865
3909
  }