@colyseus/schema 3.0.42 → 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.
Files changed (52) hide show
  1. package/build/cjs/index.js +365 -219
  2. package/build/cjs/index.js.map +1 -1
  3. package/build/esm/index.mjs +365 -219
  4. package/build/esm/index.mjs.map +1 -1
  5. package/build/umd/index.js +365 -219
  6. package/lib/Schema.d.ts +4 -3
  7. package/lib/Schema.js +22 -4
  8. package/lib/Schema.js.map +1 -1
  9. package/lib/bench_encode.d.ts +1 -0
  10. package/lib/bench_encode.js +130 -0
  11. package/lib/bench_encode.js.map +1 -0
  12. package/lib/debug.d.ts +1 -0
  13. package/lib/debug.js +51 -0
  14. package/lib/debug.js.map +1 -0
  15. package/lib/decoder/Decoder.js +8 -9
  16. package/lib/decoder/Decoder.js.map +1 -1
  17. package/lib/encoder/ChangeTree.d.ts +57 -7
  18. package/lib/encoder/ChangeTree.js +172 -106
  19. package/lib/encoder/ChangeTree.js.map +1 -1
  20. package/lib/encoder/Encoder.js +19 -20
  21. package/lib/encoder/Encoder.js.map +1 -1
  22. package/lib/encoder/Root.d.ts +9 -8
  23. package/lib/encoder/Root.js +84 -27
  24. package/lib/encoder/Root.js.map +1 -1
  25. package/lib/encoder/StateView.d.ts +1 -1
  26. package/lib/encoder/StateView.js +28 -23
  27. package/lib/encoder/StateView.js.map +1 -1
  28. package/lib/types/custom/ArraySchema.js +7 -5
  29. package/lib/types/custom/ArraySchema.js.map +1 -1
  30. package/lib/types/custom/CollectionSchema.js +1 -1
  31. package/lib/types/custom/CollectionSchema.js.map +1 -1
  32. package/lib/types/custom/MapSchema.js +9 -4
  33. package/lib/types/custom/MapSchema.js.map +1 -1
  34. package/lib/types/symbols.d.ts +14 -14
  35. package/lib/types/symbols.js +14 -14
  36. package/lib/types/symbols.js.map +1 -1
  37. package/lib/utils.js +7 -3
  38. package/lib/utils.js.map +1 -1
  39. package/package.json +2 -1
  40. package/src/Schema.ts +23 -7
  41. package/src/bench_encode.ts +108 -0
  42. package/src/debug.ts +55 -0
  43. package/src/decoder/Decoder.ts +9 -13
  44. package/src/encoder/ChangeTree.ts +203 -116
  45. package/src/encoder/Encoder.ts +21 -19
  46. package/src/encoder/Root.ts +90 -29
  47. package/src/encoder/StateView.ts +34 -26
  48. package/src/types/custom/ArraySchema.ts +8 -6
  49. package/src/types/custom/CollectionSchema.ts +1 -1
  50. package/src/types/custom/MapSchema.ts +10 -4
  51. package/src/types/symbols.ts +15 -15
  52. package/src/utils.ts +9 -3
package/lib/utils.js CHANGED
@@ -15,10 +15,13 @@ function dumpChanges(schema) {
15
15
  refs: []
16
16
  };
17
17
  // for (const refId in $root.changes) {
18
- $root.changes.forEach(changeTree => {
18
+ let current = $root.changes.next;
19
+ while (current) {
20
+ const changeTree = current.changeTree;
19
21
  // skip if ChangeTree is undefined
20
22
  if (changeTree === undefined) {
21
- return;
23
+ current = current.next;
24
+ continue;
22
25
  }
23
26
  const changes = changeTree.indexedOperations;
24
27
  dump.refs.push(`refId#${changeTree.refId}`);
@@ -30,7 +33,8 @@ function dumpChanges(schema) {
30
33
  }
31
34
  dump.ops[spec_1.OPERATION[op]]++;
32
35
  }
33
- });
36
+ current = current.next;
37
+ }
34
38
  return dump;
35
39
  }
36
40
  function getNextPowerOf2(number) {
package/lib/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;AAeA,8BAIC;AAED,kCAyBC;AAED,0CAeC;AA9DD,0CAA4C;AAC5C,6CAA2C;AAa3C,SAAgB,SAAS,CAAC,KAAa;IACnC,OAAO,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAC3C,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CACpC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACf,CAAC;AAED,SAAgB,WAAW,CAAC,MAAc;IACtC,MAAM,KAAK,GAAG,MAAM,CAAC,kBAAQ,CAAC,CAAC,IAAI,CAAC;IAEpC,MAAM,IAAI,GAAe;QACrB,GAAG,EAAE,EAAE;QACP,IAAI,EAAE,EAAE;KACX,CAAC;IAEF,uCAAuC;IACvC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;QAC/B,kCAAkC;QAClC,IAAI,UAAU,KAAK,SAAS,EAAG,CAAC;YAAC,OAAO;QAAC,CAAC;QAE1C,MAAM,OAAO,GAAG,UAAU,CAAC,iBAAiB,CAAC;QAE7C,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;QAC5C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC1B,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;YAC1B,MAAM,MAAM,GAAG,gBAAS,CAAC,EAAE,CAAC,CAAC;YAC7B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAAC,CAAC;YAChD,IAAI,CAAC,GAAG,CAAC,gBAAS,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAC9B,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,SAAgB,eAAe,CAAC,MAAc;IAC1C,+CAA+C;IAC/C,IAAI,CAAC,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,gDAAgD;IAChD,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,OAAO,MAAM,GAAG,CAAC,EAAE,CAAC;QAChB,MAAM,KAAK,CAAC,CAAC;QACb,WAAW,EAAE,CAAC;IAClB,CAAC;IAED,6BAA6B;IAC7B,OAAO,CAAC,IAAI,WAAW,CAAC;AAC5B,CAAC","sourcesContent":["import type { Schema } from \"./Schema\";\nimport { OPERATION } from \"./encoding/spec\";\nimport { $changes } from \"./types/symbols\";\n\ntype ChangeItem = [string, number | string, any?];\n\ninterface ChangeDump {\n ops: {\n ADD?: number;\n REMOVE?: number;\n REPLACE?: number;\n },\n refs: string[],\n}\n\nexport function getIndent(level: number) {\n return (new Array(level).fill(0)).map((_, i) =>\n (i === level - 1) ? `└─ ` : ` `\n ).join(\"\");\n}\n\nexport function dumpChanges(schema: Schema) {\n const $root = schema[$changes].root;\n\n const dump: ChangeDump = {\n ops: {},\n refs: []\n };\n\n // for (const refId in $root.changes) {\n $root.changes.forEach(changeTree => {\n // skip if ChangeTree is undefined\n if (changeTree === undefined) { return; }\n\n const changes = changeTree.indexedOperations;\n\n dump.refs.push(`refId#${changeTree.refId}`);\n for (const index in changes) {\n const op = changes[index];\n const opName = OPERATION[op];\n if (!dump.ops[opName]) { dump.ops[opName] = 0; }\n dump.ops[OPERATION[op]]++;\n }\n });\n\n return dump;\n}\n\nexport function getNextPowerOf2(number: number) {\n // If number is already a power of 2, return it\n if ((number & (number - 1)) === 0) {\n return number;\n }\n\n // Find the position of the most significant bit\n let msbPosition = 0;\n while (number > 0) {\n number >>= 1;\n msbPosition++;\n }\n\n // Return the next power of 2\n return 1 << msbPosition;\n}"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;AAeA,8BAIC;AAED,kCA+BC;AAED,0CAeC;AApED,0CAA4C;AAC5C,6CAA2C;AAa3C,SAAgB,SAAS,CAAC,KAAa;IACnC,OAAO,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAC3C,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CACpC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACf,CAAC;AAED,SAAgB,WAAW,CAAC,MAAc;IACtC,MAAM,KAAK,GAAG,MAAM,CAAC,kBAAQ,CAAC,CAAC,IAAI,CAAC;IAEpC,MAAM,IAAI,GAAe;QACrB,GAAG,EAAE,EAAE;QACP,IAAI,EAAE,EAAE;KACX,CAAC;IAEF,uCAAuC;IACvC,IAAI,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;IACjC,OAAO,OAAO,EAAE,CAAC;QACb,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACtC,kCAAkC;QAClC,IAAI,UAAU,KAAK,SAAS,EAAG,CAAC;YAC5B,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;YACvB,SAAS;QACb,CAAC;QAED,MAAM,OAAO,GAAG,UAAU,CAAC,iBAAiB,CAAC;QAE7C,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;QAC5C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC1B,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;YAC1B,MAAM,MAAM,GAAG,gBAAS,CAAC,EAAE,CAAC,CAAC;YAC7B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAAC,CAAC;YAChD,IAAI,CAAC,GAAG,CAAC,gBAAS,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAC9B,CAAC;QACD,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,SAAgB,eAAe,CAAC,MAAc;IAC1C,+CAA+C;IAC/C,IAAI,CAAC,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,gDAAgD;IAChD,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,OAAO,MAAM,GAAG,CAAC,EAAE,CAAC;QAChB,MAAM,KAAK,CAAC,CAAC;QACb,WAAW,EAAE,CAAC;IAClB,CAAC;IAED,6BAA6B;IAC7B,OAAO,CAAC,IAAI,WAAW,CAAC;AAC5B,CAAC","sourcesContent":["import type { Schema } from \"./Schema\";\nimport { OPERATION } from \"./encoding/spec\";\nimport { $changes } from \"./types/symbols\";\n\ntype ChangeItem = [string, number | string, any?];\n\ninterface ChangeDump {\n ops: {\n ADD?: number;\n REMOVE?: number;\n REPLACE?: number;\n },\n refs: string[],\n}\n\nexport function getIndent(level: number) {\n return (new Array(level).fill(0)).map((_, i) =>\n (i === level - 1) ? `└─ ` : ` `\n ).join(\"\");\n}\n\nexport function dumpChanges(schema: Schema) {\n const $root = schema[$changes].root;\n\n const dump: ChangeDump = {\n ops: {},\n refs: []\n };\n\n // for (const refId in $root.changes) {\n let current = $root.changes.next;\n while (current) {\n const changeTree = current.changeTree;\n // skip if ChangeTree is undefined\n if (changeTree === undefined) {\n current = current.next;\n continue;\n }\n\n const changes = changeTree.indexedOperations;\n\n dump.refs.push(`refId#${changeTree.refId}`);\n for (const index in changes) {\n const op = changes[index];\n const opName = OPERATION[op];\n if (!dump.ops[opName]) { dump.ops[opName] = 0; }\n dump.ops[OPERATION[op]]++;\n }\n current = current.next;\n }\n\n return dump;\n}\n\nexport function getNextPowerOf2(number: number) {\n // If number is already a power of 2, return it\n if ((number & (number - 1)) === 0) {\n return number;\n }\n\n // Find the position of the most significant bit\n let msbPosition = 0;\n while (number > 0) {\n number >>= 1;\n msbPosition++;\n }\n\n // Return the next power of 2\n return 1 << msbPosition;\n}"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colyseus/schema",
3
- "version": "3.0.42",
3
+ "version": "3.0.44",
4
4
  "description": "Binary state serializer with delta encoding for games",
5
5
  "bin": {
6
6
  "schema-codegen": "bin/schema-codegen",
@@ -66,6 +66,7 @@
66
66
  "@types/rimraf": "^2.0.3",
67
67
  "@types/sinon": "^7.0.3",
68
68
  "benchmark": "^2.1.4",
69
+ "core-js": "^3.44.0",
69
70
  "flatbuffers": "^1.10.2",
70
71
  "fossil-delta": "^1.0.2",
71
72
  "glob": "^7.1.5",
package/src/Schema.ts CHANGED
@@ -3,7 +3,7 @@ import { DEFAULT_VIEW_TAG, type DefinitionType } from "./annotations";
3
3
 
4
4
  import { NonFunctionPropNames, ToJSON } from './types/HelperTypes';
5
5
 
6
- import { ChangeSet, ChangeTree, Ref } from './encoder/ChangeTree';
6
+ import { ChangeSet, ChangeSetName, ChangeTree, Ref } from './encoder/ChangeTree';
7
7
  import { $changes, $decoder, $deleteByIndex, $descriptors, $encoder, $filter, $getByIndex, $track } from './types/symbols';
8
8
  import { StateView } from './encoder/StateView';
9
9
 
@@ -185,7 +185,7 @@ export class Schema {
185
185
  * @param showContents display JSON contents of the instance
186
186
  * @returns
187
187
  */
188
- static debugRefIds(ref: Ref, showContents: boolean = false, level: number = 0, decoder?: Decoder) {
188
+ static debugRefIds(ref: Ref, showContents: boolean = false, level: number = 0, decoder?: Decoder, keyPrefix: string = "") {
189
189
  const contents = (showContents) ? ` - ${JSON.stringify(ref.toJSON())}` : "";
190
190
  const changeTree: ChangeTree = ref[$changes];
191
191
 
@@ -197,15 +197,29 @@ export class Schema {
197
197
  ? ` [×${root.refCount[refId]}]`
198
198
  : '';
199
199
 
200
- let output = `${getIndent(level)}${ref.constructor.name} (refId: ${refId})${refCount}${contents}\n`;
200
+ let output = `${getIndent(level)}${keyPrefix}${ref.constructor.name} (refId: ${refId})${refCount}${contents}\n`;
201
201
 
202
- changeTree.forEachChild((childChangeTree) =>
203
- output += this.debugRefIds(childChangeTree.ref, showContents, level + 1, decoder));
202
+ changeTree.forEachChild((childChangeTree, key) => {
203
+ const keyPrefix = (ref['forEach'] !== undefined && key !== undefined) ? `["${key}"]: ` : "";
204
+ output += this.debugRefIds(childChangeTree.ref, showContents, level + 1, decoder, keyPrefix);
205
+ });
204
206
 
205
207
  return output;
206
208
  }
207
209
 
208
- static debugRefIdsDecoder(decoder: Decoder) {
210
+ static debugRefIdEncodingOrder(ref: Ref, changeSet: ChangeSetName = 'allChanges') {
211
+ let encodeOrder: number[] = [];
212
+ let current = ref[$changes].root[changeSet].next;
213
+ while (current) {
214
+ if (current.changeTree) {
215
+ encodeOrder.push(current.changeTree.refId);
216
+ }
217
+ current = current.next;
218
+ }
219
+ return encodeOrder;
220
+ }
221
+
222
+ static debugRefIdsFromDecoder(decoder: Decoder) {
209
223
  return this.debugRefIds(decoder.state, false, 0, decoder);
210
224
  }
211
225
 
@@ -263,15 +277,17 @@ export class Schema {
263
277
  static debugChangesDeep(ref: Ref, changeSetName: "changes" | "allChanges" | "allFilteredChanges" | "filteredChanges" = "changes") {
264
278
  let output = "";
265
279
 
266
- const rootChangeTree = ref[$changes];
280
+ const rootChangeTree: ChangeTree = ref[$changes];
267
281
  const root = rootChangeTree.root;
268
282
  const changeTrees: Map<ChangeTree, ChangeTree[]> = new Map();
269
283
 
270
284
  const instanceRefIds = [];
271
285
  let totalOperations = 0;
272
286
 
287
+ // TODO: FIXME: this method is not working as expected
273
288
  for (const [refId, changes] of Object.entries(root[changeSetName])) {
274
289
  const changeTree = root.changeTrees[refId];
290
+ if (!changeTree) { continue; }
275
291
 
276
292
  let includeChangeTree = false;
277
293
  let parentChangeTrees: ChangeTree[] = [];
@@ -0,0 +1,108 @@
1
+ import { nanoid } from "nanoid";
2
+ import { Schema, type, MapSchema, ArraySchema, Encoder } from ".";
3
+
4
+ class Attribute extends Schema {
5
+ @type("string") name: string;
6
+ @type("number") value: number;
7
+ }
8
+
9
+ class Item extends Schema {
10
+ @type("number") price: number;
11
+ @type([ Attribute ]) attributes = new ArraySchema<Attribute>();
12
+ }
13
+
14
+ class Position extends Schema {
15
+ @type("number") x: number;
16
+ @type("number") y: number;
17
+ }
18
+
19
+ class Player extends Schema {
20
+ @type(Position) position = new Position();
21
+ @type({ map: Item }) items = new MapSchema<Item>();
22
+ }
23
+
24
+ class State extends Schema {
25
+ @type({ map: Player }) players = new MapSchema<Player>();
26
+ @type("string") currentTurn;
27
+ }
28
+
29
+ const state = new State();
30
+
31
+ Encoder.BUFFER_SIZE = 4096 * 4096;
32
+ const encoder = new Encoder(state);
33
+
34
+
35
+ let now = Date.now();
36
+
37
+ // for (let i = 0; i < 10000; i++) {
38
+ // const player = new Player();
39
+ // state.players.set(`p-${nanoid()}`, player);
40
+ //
41
+ // player.position.x = (i + 1) * 100;
42
+ // player.position.y = (i + 1) * 100;
43
+ // for (let j = 0; j < 10; j++) {
44
+ // const item = new Item();
45
+ // player.items.set(`item-${j}`, item);
46
+ // item.price = (i + 1) * 50;
47
+ // for (let k = 0; k < 5; k++) {
48
+ // const attr = new Attribute();
49
+ // attr.name = `Attribute ${k}`;
50
+ // attr.value = k;
51
+ // item.attributes.push(attr);
52
+ // }
53
+ // }
54
+ // }
55
+ // console.log("time to make changes:", Date.now() - now);
56
+
57
+
58
+ // measure time to .encodeAll()
59
+
60
+ now = Date.now();
61
+ // for (let i = 0; i < 1000; i++) {
62
+ // encoder.encodeAll();
63
+ // }
64
+ // console.log(Date.now() - now);
65
+
66
+ const total = 100;
67
+ const allEncodes = Date.now();
68
+
69
+ let avgTimeToEncode = 0;
70
+ let avgTimeToMakeChanges = 0;
71
+
72
+ for (let i = 0; i < total; i++) {
73
+ now = Date.now();
74
+ for (let j = 0; j < 50; j++) {
75
+ const player = new Player();
76
+ state.players.set(`p-${nanoid()}`, player);
77
+
78
+ player.position.x = (j + 1) * 100;
79
+ player.position.y = (j + 1) * 100;
80
+ for (let k = 0; k < 10; k++) {
81
+ const item = new Item();
82
+ item.price = (j + 1) * 50;
83
+ for (let l = 0; l < 5; l++) {
84
+ const attr = new Attribute();
85
+ attr.name = `Attribute ${l}`;
86
+ attr.value = l;
87
+ item.attributes.push(attr);
88
+ }
89
+ player.items.set(`item-${k}`, item);
90
+ }
91
+ }
92
+ const timeToMakeChanges = Date.now() - now;
93
+ console.log("time to make changes:", timeToMakeChanges);
94
+ avgTimeToMakeChanges += timeToMakeChanges;
95
+
96
+ now = Date.now();
97
+ encoder.encode();
98
+ encoder.discardChanges();
99
+
100
+ const timeToEncode = Date.now() - now;
101
+ console.log("time to encode:", timeToEncode);
102
+ avgTimeToEncode += timeToEncode;
103
+ }
104
+ console.log("avg time to encode:", (avgTimeToEncode) / total);
105
+ console.log("avg time to make changes:", (avgTimeToMakeChanges) / total);
106
+ console.log("time for all encodes:", Date.now() - allEncodes);
107
+
108
+ console.log(Array.from(encoder.encodeAll()).length, "bytes");
package/src/debug.ts ADDED
@@ -0,0 +1,55 @@
1
+ import * as fs from "fs";
2
+ import { Reflection, Decoder } from "./index";
3
+
4
+ const contents = fs.readFileSync("/Users/endel/Projects/colyseus/clients/bubbits/project/@bubbits/backend/schema-debug.txt", { encoding: "utf8" }).toString();
5
+
6
+ let isCommentBlock = false;
7
+ let lastComment = "";
8
+
9
+ let decoder: Decoder;
10
+
11
+ function getBuffer(line: string) {
12
+ const start = line.lastIndexOf(":");
13
+ const buffer = Buffer.from(new Uint8Array(line.substring(start + 1).split(",").map(n => Number(n))));
14
+ console.log(`(${buffer.byteLength}) ${Array.from(buffer).join(",")}`)
15
+ // console.log("");
16
+ // console.log("");
17
+ // console.log("> ", line);
18
+ // console.log("> substring:", line.substring(start + 1))
19
+ return buffer;
20
+ }
21
+
22
+ function decode(buffer: Buffer) {
23
+ try {
24
+ decoder.decode(buffer);
25
+ } catch (e) {
26
+ console.error(e);
27
+ console.log("Last log:\n\n")
28
+ console.log(lastComment);
29
+ }
30
+ }
31
+
32
+ contents.split("\n").forEach((line) => {
33
+ if (line.startsWith("#")) {
34
+ // reset last comment.
35
+ if (isCommentBlock === false) { lastComment = ""; }
36
+
37
+ isCommentBlock = true;
38
+ lastComment += line.substring(line.indexOf(":") + 1) + "\n";
39
+ return;
40
+ }
41
+
42
+ isCommentBlock = false;
43
+
44
+ if (line.startsWith("handshake:") && !decoder) {
45
+ decoder = Reflection.decode(getBuffer(line));
46
+
47
+ } else if (line.startsWith("state:")) {
48
+ decode(getBuffer(line));
49
+
50
+ } else if (line.startsWith("patch:")) {
51
+ decode(getBuffer(line));
52
+ }
53
+ });
54
+
55
+ console.log(decoder.state.toJSON());
@@ -58,6 +58,8 @@ export class Decoder<T extends Schema = any> {
58
58
  if (bytes[it.offset] == SWITCH_TO_STRUCTURE) {
59
59
  it.offset++;
60
60
 
61
+ ref[$onDecodeEnd]?.()
62
+
61
63
  const nextRefId = decode.number(bytes, it);
62
64
  const nextRef = $root.refs.get(nextRefId);
63
65
 
@@ -65,17 +67,17 @@ export class Decoder<T extends Schema = any> {
65
67
  // Trying to access a reference that haven't been decoded yet.
66
68
  //
67
69
  if (!nextRef) {
70
+ throw new Error(`"refId" not found: ${nextRefId}`);
68
71
  console.error(`"refId" not found: ${nextRefId}`, { previousRef: ref, previousRefId: this.currentRefId });
69
72
  console.warn("Please report this to the developers. All refIds =>");
70
- console.warn(Schema.debugRefIdsDecoder(this));
73
+ console.warn(Schema.debugRefIdsFromDecoder(this));
71
74
  this.skipCurrentStructure(bytes, it, totalBytes);
72
- }
73
- ref[$onDecodeEnd]?.()
74
75
 
75
- this.currentRefId = nextRefId;
76
-
77
- ref = nextRef;
78
- decoder = ref.constructor[$decoder];
76
+ } else {
77
+ ref = nextRef;
78
+ decoder = ref.constructor[$decoder];
79
+ this.currentRefId = nextRefId;
80
+ }
79
81
 
80
82
  continue;
81
83
  }
@@ -131,12 +133,6 @@ export class Decoder<T extends Schema = any> {
131
133
  }
132
134
 
133
135
  createInstanceOfType (type: typeof Schema): Schema {
134
- // let instance: Schema = new (type as any)();
135
-
136
- // // assign root on $changes
137
- // instance[$changes].root = this.root[$changes].root;
138
-
139
- // return instance;
140
136
  return new (type as any)();
141
137
  }
142
138