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

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 (134) hide show
  1. package/README.md +131 -61
  2. package/build/cjs/index.js +966 -563
  3. package/build/cjs/index.js.map +1 -1
  4. package/build/esm/index.mjs +965 -562
  5. package/build/esm/index.mjs.map +1 -1
  6. package/build/umd/index.js +966 -563
  7. package/lib/Metadata.d.ts +15 -4
  8. package/lib/Metadata.js +86 -18
  9. package/lib/Metadata.js.map +1 -1
  10. package/lib/Reflection.d.ts +2 -3
  11. package/lib/Reflection.js +24 -28
  12. package/lib/Reflection.js.map +1 -1
  13. package/lib/Schema.d.ts +2 -2
  14. package/lib/Schema.js +28 -41
  15. package/lib/Schema.js.map +1 -1
  16. package/lib/annotations.d.ts +1 -21
  17. package/lib/annotations.js +73 -153
  18. package/lib/annotations.js.map +1 -1
  19. package/lib/bench_encode.d.ts +1 -0
  20. package/lib/bench_encode.js +142 -0
  21. package/lib/bench_encode.js.map +1 -0
  22. package/lib/codegen/api.js +1 -2
  23. package/lib/codegen/api.js.map +1 -1
  24. package/lib/codegen/languages/cpp.js +1 -2
  25. package/lib/codegen/languages/cpp.js.map +1 -1
  26. package/lib/codegen/languages/csharp.js +1 -2
  27. package/lib/codegen/languages/csharp.js.map +1 -1
  28. package/lib/codegen/languages/haxe.js +1 -2
  29. package/lib/codegen/languages/haxe.js.map +1 -1
  30. package/lib/codegen/languages/java.js +1 -2
  31. package/lib/codegen/languages/java.js.map +1 -1
  32. package/lib/codegen/languages/js.js +1 -2
  33. package/lib/codegen/languages/js.js.map +1 -1
  34. package/lib/codegen/languages/lua.js +1 -2
  35. package/lib/codegen/languages/lua.js.map +1 -1
  36. package/lib/codegen/languages/ts.js +1 -2
  37. package/lib/codegen/languages/ts.js.map +1 -1
  38. package/lib/codegen/parser.js +2 -3
  39. package/lib/codegen/parser.js.map +1 -1
  40. package/lib/codegen/types.js +3 -3
  41. package/lib/codegen/types.js.map +1 -1
  42. package/lib/debug.d.ts +1 -0
  43. package/lib/debug.js +52 -0
  44. package/lib/debug.js.map +1 -0
  45. package/lib/decoder/DecodeOperation.d.ts +0 -1
  46. package/lib/decoder/DecodeOperation.js +23 -11
  47. package/lib/decoder/DecodeOperation.js.map +1 -1
  48. package/lib/decoder/Decoder.d.ts +6 -7
  49. package/lib/decoder/Decoder.js +8 -8
  50. package/lib/decoder/Decoder.js.map +1 -1
  51. package/lib/decoder/ReferenceTracker.js +3 -2
  52. package/lib/decoder/ReferenceTracker.js.map +1 -1
  53. package/lib/decoder/strategy/RawChanges.js +1 -2
  54. package/lib/decoder/strategy/RawChanges.js.map +1 -1
  55. package/lib/decoder/strategy/StateCallbacks.d.ts +44 -11
  56. package/lib/decoder/strategy/StateCallbacks.js +75 -65
  57. package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
  58. package/lib/encoder/ChangeTree.d.ts +9 -19
  59. package/lib/encoder/ChangeTree.js +129 -145
  60. package/lib/encoder/ChangeTree.js.map +1 -1
  61. package/lib/encoder/EncodeOperation.d.ts +1 -5
  62. package/lib/encoder/EncodeOperation.js +74 -58
  63. package/lib/encoder/EncodeOperation.js.map +1 -1
  64. package/lib/encoder/Encoder.d.ts +10 -8
  65. package/lib/encoder/Encoder.js +89 -56
  66. package/lib/encoder/Encoder.js.map +1 -1
  67. package/lib/encoder/Root.d.ts +17 -0
  68. package/lib/encoder/Root.js +44 -0
  69. package/lib/encoder/Root.js.map +1 -0
  70. package/lib/encoder/StateView.d.ts +2 -2
  71. package/lib/encoder/StateView.js +49 -59
  72. package/lib/encoder/StateView.js.map +1 -1
  73. package/lib/encoding/assert.d.ts +2 -1
  74. package/lib/encoding/assert.js +5 -5
  75. package/lib/encoding/assert.js.map +1 -1
  76. package/lib/encoding/decode.js +21 -22
  77. package/lib/encoding/decode.js.map +1 -1
  78. package/lib/encoding/encode.d.ts +2 -2
  79. package/lib/encoding/encode.js +40 -39
  80. package/lib/encoding/encode.js.map +1 -1
  81. package/lib/encoding/spec.d.ts +2 -1
  82. package/lib/encoding/spec.js +1 -0
  83. package/lib/encoding/spec.js.map +1 -1
  84. package/lib/index.d.ts +6 -3
  85. package/lib/index.js +18 -13
  86. package/lib/index.js.map +1 -1
  87. package/lib/types/TypeContext.d.ts +23 -0
  88. package/lib/types/TypeContext.js +102 -0
  89. package/lib/types/TypeContext.js.map +1 -0
  90. package/lib/types/custom/ArraySchema.d.ts +2 -2
  91. package/lib/types/custom/ArraySchema.js +6 -9
  92. package/lib/types/custom/ArraySchema.js.map +1 -1
  93. package/lib/types/custom/CollectionSchema.js +1 -0
  94. package/lib/types/custom/CollectionSchema.js.map +1 -1
  95. package/lib/types/custom/MapSchema.js +5 -0
  96. package/lib/types/custom/MapSchema.js.map +1 -1
  97. package/lib/types/custom/SetSchema.js +1 -0
  98. package/lib/types/custom/SetSchema.js.map +1 -1
  99. package/lib/types/registry.js +3 -4
  100. package/lib/types/registry.js.map +1 -1
  101. package/lib/types/symbols.d.ts +1 -0
  102. package/lib/types/symbols.js +2 -1
  103. package/lib/types/symbols.js.map +1 -1
  104. package/lib/types/utils.js +1 -2
  105. package/lib/types/utils.js.map +1 -1
  106. package/lib/utils.js +3 -4
  107. package/lib/utils.js.map +1 -1
  108. package/package.json +5 -5
  109. package/src/Metadata.ts +104 -26
  110. package/src/Reflection.ts +26 -28
  111. package/src/Schema.ts +35 -47
  112. package/src/annotations.ts +82 -176
  113. package/src/bench_encode.ts +121 -0
  114. package/src/debug.ts +56 -0
  115. package/src/decoder/DecodeOperation.ts +28 -11
  116. package/src/decoder/Decoder.ts +13 -11
  117. package/src/decoder/ReferenceTracker.ts +3 -2
  118. package/src/decoder/strategy/StateCallbacks.ts +152 -81
  119. package/src/encoder/ChangeTree.ts +147 -166
  120. package/src/encoder/EncodeOperation.ts +93 -70
  121. package/src/encoder/Encoder.ts +111 -65
  122. package/src/encoder/Root.ts +51 -0
  123. package/src/encoder/StateView.ts +53 -69
  124. package/src/encoding/assert.ts +4 -3
  125. package/src/encoding/decode.ts +1 -2
  126. package/src/encoding/encode.ts +25 -22
  127. package/src/encoding/spec.ts +1 -0
  128. package/src/index.ts +8 -14
  129. package/src/types/TypeContext.ts +122 -0
  130. package/src/types/custom/ArraySchema.ts +10 -2
  131. package/src/types/custom/CollectionSchema.ts +1 -0
  132. package/src/types/custom/MapSchema.ts +6 -0
  133. package/src/types/custom/SetSchema.ts +1 -0
  134. package/src/types/symbols.ts +2 -0
@@ -1,28 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.encodeArray = exports.encodeKeyValueOperation = exports.encodeSchemaOperation = exports.encodeValue = exports.encodePrimitiveType = void 0;
3
+ exports.encodeArray = exports.encodeKeyValueOperation = exports.encodeSchemaOperation = void 0;
4
+ exports.encodeValue = encodeValue;
4
5
  const spec_1 = require("../encoding/spec");
5
6
  const symbols_1 = require("../types/symbols");
6
- const registry_1 = require("../types/registry");
7
7
  const encode = require("../encoding/encode");
8
- const assert_1 = require("../encoding/assert");
9
- function encodePrimitiveType(type, bytes, value, klass, field, it) {
10
- (0, assert_1.assertType)(value, type, klass, field);
11
- const encodeFunc = encode[type];
12
- if (encodeFunc) {
13
- encodeFunc(bytes, value, it);
14
- // encodeFunc(bytes, value);
15
- }
16
- else {
17
- throw new assert_1.EncodeSchemaError(`a '${type}' was expected, but ${value} was provided in ${klass.constructor.name}#${field}`);
8
+ function encodeValue(encoder, bytes,
9
+ // ref: Ref,
10
+ type, value,
11
+ // field: string | number,
12
+ operation, it) {
13
+ if (typeof (type) === "string") {
14
+ //
15
+ // Primitive values
16
+ //
17
+ // assertType(value, type as string, ref as Schema, field);
18
+ encode[type]?.(bytes, value, it);
18
19
  }
19
- }
20
- exports.encodePrimitiveType = encodePrimitiveType;
21
- ;
22
- function encodeValue(encoder, bytes, ref, type, value, field, operation, it) {
23
- if (type[Symbol.metadata] !== undefined) {
24
- // TODO: move this to the `@type()` annotation
25
- (0, assert_1.assertInstanceType)(value, type, ref, field);
20
+ else if (type[Symbol.metadata] !== undefined) {
21
+ // // TODO: move this to the `@type()` annotation
22
+ // assertInstanceType(value, type as typeof Schema, ref as Schema, field);
26
23
  //
27
24
  // Encode refId for this instance.
28
25
  // The actual instance is going to be encoded on next `changeTree` iteration.
@@ -33,21 +30,15 @@ function encodeValue(encoder, bytes, ref, type, value, field, operation, it) {
33
30
  encoder.tryEncodeTypeId(bytes, type, value.constructor, it);
34
31
  }
35
32
  }
36
- else if (typeof (type) === "string") {
37
- //
38
- // Primitive values
39
- //
40
- encodePrimitiveType(type, bytes, value, ref, field, it);
41
- }
42
33
  else {
43
- //
44
- // Custom type (MapSchema, ArraySchema, etc)
45
- //
46
- const definition = (0, registry_1.getType)(Object.keys(type)[0]);
47
- //
48
- // ensure a ArraySchema has been provided
49
- //
50
- (0, assert_1.assertInstanceType)(ref[field], definition.constructor, ref, field);
34
+ // //
35
+ // // Custom type (MapSchema, ArraySchema, etc)
36
+ // //
37
+ // const definition = getType(Object.keys(type)[0]);
38
+ // //
39
+ // // ensure a ArraySchema has been provided
40
+ // //
41
+ // assertInstanceType(ref[field], definition.constructor, ref as Schema, field);
51
42
  //
52
43
  // Encode refId for this instance.
53
44
  // The actual instance is going to be encoded on next `changeTree` iteration.
@@ -55,33 +46,33 @@ function encodeValue(encoder, bytes, ref, type, value, field, operation, it) {
55
46
  encode.number(bytes, value[symbols_1.$changes].refId, it);
56
47
  }
57
48
  }
58
- exports.encodeValue = encodeValue;
59
49
  /**
60
50
  * Used for Schema instances.
61
51
  * @private
62
52
  */
63
53
  const encodeSchemaOperation = function (encoder, bytes, changeTree, index, operation, it) {
64
- const ref = changeTree.ref;
65
- const metadata = ref['constructor'][Symbol.metadata];
66
- const field = metadata[index];
67
- const type = metadata[field].type;
68
- const value = ref[field];
69
54
  // "compress" field index + operation
70
55
  bytes[it.offset++] = (index | operation) & 255;
71
56
  // Do not encode value for DELETE operations
72
57
  if (operation === spec_1.OPERATION.DELETE) {
73
58
  return;
74
59
  }
60
+ const ref = changeTree.ref;
61
+ const metadata = ref['constructor'][Symbol.metadata];
62
+ const field = metadata[index];
75
63
  // TODO: inline this function call small performance gain
76
- encodeValue(encoder, bytes, ref, type, value, field, operation, it);
64
+ encodeValue(encoder, bytes,
65
+ // ref,
66
+ metadata[index].type, ref[field.name],
67
+ // index,
68
+ operation, it);
77
69
  };
78
70
  exports.encodeSchemaOperation = encodeSchemaOperation;
79
71
  /**
80
72
  * Used for collections (MapSchema, CollectionSchema, SetSchema)
81
73
  * @private
82
74
  */
83
- const encodeKeyValueOperation = function (encoder, bytes, changeTree, field, operation, it) {
84
- const ref = changeTree.ref;
75
+ const encodeKeyValueOperation = function (encoder, bytes, changeTree, index, operation, it) {
85
76
  // encode operation
86
77
  bytes[it.offset++] = operation & 255;
87
78
  // custom operations
@@ -89,11 +80,12 @@ const encodeKeyValueOperation = function (encoder, bytes, changeTree, field, ope
89
80
  return;
90
81
  }
91
82
  // encode index
92
- encode.number(bytes, field, it);
83
+ encode.number(bytes, index, it);
93
84
  // Do not encode value for DELETE operations
94
85
  if (operation === spec_1.OPERATION.DELETE) {
95
86
  return;
96
87
  }
88
+ const ref = changeTree.ref;
97
89
  //
98
90
  // encode "alias" for dynamic fields (maps)
99
91
  //
@@ -102,14 +94,30 @@ const encodeKeyValueOperation = function (encoder, bytes, changeTree, field, ope
102
94
  //
103
95
  // MapSchema dynamic key
104
96
  //
105
- const dynamicIndex = changeTree.ref['$indexes'].get(field);
97
+ const dynamicIndex = changeTree.ref['$indexes'].get(index);
106
98
  encode.string(bytes, dynamicIndex, it);
107
99
  }
108
100
  }
109
- const type = changeTree.getType(field);
110
- const value = changeTree.getValue(field);
101
+ const type = changeTree.getType(index);
102
+ const value = changeTree.getValue(index);
103
+ // try { throw new Error(); } catch (e) {
104
+ // // only print if not coming from Reflection.ts
105
+ // if (!e.stack.includes("src/Reflection.ts")) {
106
+ // console.log("encodeKeyValueOperation -> ", {
107
+ // ref: changeTree.ref.constructor.name,
108
+ // field,
109
+ // operation: OPERATION[operation],
110
+ // value: value?.toJSON(),
111
+ // items: ref.toJSON(),
112
+ // });
113
+ // }
114
+ // }
111
115
  // TODO: inline this function call small performance gain
112
- encodeValue(encoder, bytes, ref, type, value, field, operation, it);
116
+ encodeValue(encoder, bytes,
117
+ // ref,
118
+ type, value,
119
+ // index,
120
+ operation, it);
113
121
  };
114
122
  exports.encodeKeyValueOperation = encodeKeyValueOperation;
115
123
  /**
@@ -118,15 +126,19 @@ exports.encodeKeyValueOperation = encodeKeyValueOperation;
118
126
  */
119
127
  const encodeArray = function (encoder, bytes, changeTree, field, operation, it, isEncodeAll, hasView) {
120
128
  const ref = changeTree.ref;
121
- if (hasView &&
122
- operation === spec_1.OPERATION.DELETE &&
123
- typeof (changeTree.getType(field)) !== "string") {
124
- // encode delete by refId (array of schemas)
125
- bytes[it.offset++] = spec_1.OPERATION.DELETE_BY_REFID;
126
- const value = ref['tmpItems'][field];
127
- const refId = value[symbols_1.$changes].refId;
128
- encode.number(bytes, refId, it);
129
- return;
129
+ const useOperationByRefId = hasView && changeTree.isFiltered && (typeof (changeTree.getType(field)) !== "string");
130
+ let refOrIndex;
131
+ if (useOperationByRefId) {
132
+ refOrIndex = ref['tmpItems'][field][symbols_1.$changes].refId;
133
+ if (operation === spec_1.OPERATION.DELETE) {
134
+ operation = spec_1.OPERATION.DELETE_BY_REFID;
135
+ }
136
+ else if (operation === spec_1.OPERATION.ADD) {
137
+ operation = spec_1.OPERATION.ADD_BY_REFID;
138
+ }
139
+ }
140
+ else {
141
+ refOrIndex = field;
130
142
  }
131
143
  // encode operation
132
144
  bytes[it.offset++] = operation & 255;
@@ -135,7 +147,7 @@ const encodeArray = function (encoder, bytes, changeTree, field, operation, it,
135
147
  return;
136
148
  }
137
149
  // encode index
138
- encode.number(bytes, field, it);
150
+ encode.number(bytes, refOrIndex, it);
139
151
  // Do not encode value for DELETE operations
140
152
  if (operation === spec_1.OPERATION.DELETE) {
141
153
  return;
@@ -150,7 +162,11 @@ const encodeArray = function (encoder, bytes, changeTree, field, operation, it,
150
162
  // items: ref.toJSON(),
151
163
  // });
152
164
  // TODO: inline this function call small performance gain
153
- encodeValue(encoder, bytes, ref, type, value, field, operation, it);
165
+ encodeValue(encoder, bytes,
166
+ // ref,
167
+ type, value,
168
+ // field,
169
+ operation, it);
154
170
  };
155
171
  exports.encodeArray = encodeArray;
156
172
  //# sourceMappingURL=EncodeOperation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"EncodeOperation.js","sourceRoot":"","sources":["../../src/encoder/EncodeOperation.ts"],"names":[],"mappings":"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","sourcesContent":["import { OPERATION } from \"../encoding/spec\";\nimport { $changes } from \"../types/symbols\";\nimport { getType } from \"../types/registry\";\n\nimport * as encode from \"../encoding/encode\";\nimport { EncodeSchemaError, assertInstanceType, assertType } from \"../encoding/assert\";\n\nimport type { ChangeTree, Ref } from \"./ChangeTree\";\nimport type { Encoder } from \"./Encoder\";\nimport type { Schema } from \"../Schema\";\nimport type { PrimitiveType } from \"../annotations\";\n\nimport type { Iterator } from \"../encoding/decode\";\nimport type { ArraySchema } from \"../types/custom/ArraySchema\";\n\nexport type EncodeOperation<T extends Ref = any> = (\n encoder: Encoder,\n bytes: Buffer,\n changeTree: ChangeTree<T>,\n index: number,\n operation: OPERATION,\n it: Iterator,\n isEncodeAll: boolean,\n hasView: boolean,\n) => void;\n\nexport function encodePrimitiveType(\n type: PrimitiveType,\n bytes: Buffer,\n value: any,\n klass: Schema,\n field: string | number,\n it: Iterator,\n) {\n assertType(value, type as string, klass, field);\n\n const encodeFunc = encode[type as string];\n\n if (encodeFunc) {\n encodeFunc(bytes, value, it);\n // encodeFunc(bytes, value);\n\n } else {\n throw new EncodeSchemaError(`a '${type}' was expected, but ${value} was provided in ${klass.constructor.name}#${field}`);\n }\n};\n\nexport function encodeValue(\n encoder: Encoder,\n bytes: Buffer,\n ref: Ref,\n type: any,\n value: any,\n field: string | number,\n operation: OPERATION,\n it: Iterator,\n) {\n if (type[Symbol.metadata] !== undefined) {\n // TODO: move this to the `@type()` annotation\n assertInstanceType(value, type as typeof Schema, ref as Schema, field);\n\n //\n // Encode refId for this instance.\n // The actual instance is going to be encoded on next `changeTree` iteration.\n //\n encode.number(bytes, value[$changes].refId, it);\n\n // Try to encode inherited TYPE_ID if it's an ADD operation.\n if ((operation & OPERATION.ADD) === OPERATION.ADD) {\n encoder.tryEncodeTypeId(bytes, type as typeof Schema, value.constructor as typeof Schema, it);\n }\n\n } else if (typeof (type) === \"string\") {\n //\n // Primitive values\n //\n encodePrimitiveType(type as PrimitiveType, bytes, value, ref as Schema, field, it);\n\n } else {\n //\n // Custom type (MapSchema, ArraySchema, etc)\n //\n const definition = getType(Object.keys(type)[0]);\n\n //\n // ensure a ArraySchema has been provided\n //\n assertInstanceType(ref[field], definition.constructor, ref as Schema, field);\n\n //\n // Encode refId for this instance.\n // The actual instance is going to be encoded on next `changeTree` iteration.\n //\n encode.number(bytes, value[$changes].refId, it);\n }\n}\n\n/**\n * Used for Schema instances.\n * @private\n */\nexport const encodeSchemaOperation: EncodeOperation = function (\n encoder: Encoder,\n bytes: Buffer,\n changeTree: ChangeTree<Schema>,\n index: number,\n operation: OPERATION,\n it: Iterator,\n) {\n const ref = changeTree.ref;\n const metadata = ref['constructor'][Symbol.metadata];\n\n const field = metadata[index];\n const type = metadata[field].type;\n const value = ref[field];\n\n // \"compress\" field index + operation\n bytes[it.offset++] = (index | operation) & 255;\n\n // Do not encode value for DELETE operations\n if (operation === OPERATION.DELETE) {\n return;\n }\n\n // TODO: inline this function call small performance gain\n encodeValue(encoder, bytes, ref, type, value, field, operation, it);\n}\n\n/**\n * Used for collections (MapSchema, CollectionSchema, SetSchema)\n * @private\n */\nexport const encodeKeyValueOperation: EncodeOperation = function (\n encoder: Encoder,\n bytes: Buffer,\n changeTree: ChangeTree,\n field: number,\n operation: OPERATION,\n it: Iterator,\n) {\n const ref = changeTree.ref;\n\n // encode operation\n bytes[it.offset++] = operation & 255;\n\n // custom operations\n if (operation === OPERATION.CLEAR) {\n return;\n }\n\n // encode index\n encode.number(bytes, field, it);\n\n // Do not encode value for DELETE operations\n if (operation === OPERATION.DELETE) {\n return;\n }\n\n //\n // encode \"alias\" for dynamic fields (maps)\n //\n if ((operation & OPERATION.ADD) == OPERATION.ADD) { // ADD or DELETE_AND_ADD\n if (typeof(ref['set']) === \"function\") {\n //\n // MapSchema dynamic key\n //\n const dynamicIndex = changeTree.ref['$indexes'].get(field);\n encode.string(bytes, dynamicIndex, it);\n }\n }\n\n const type = changeTree.getType(field);\n const value = changeTree.getValue(field);\n\n // TODO: inline this function call small performance gain\n encodeValue(encoder, bytes, ref, type, value, field, operation, it);\n}\n\n/**\n * Used for collections (MapSchema, ArraySchema, etc.)\n * @private\n */\nexport const encodeArray: EncodeOperation = function (\n encoder: Encoder,\n bytes: Buffer,\n changeTree: ChangeTree<ArraySchema>,\n field: number,\n operation: OPERATION,\n it: Iterator,\n isEncodeAll: boolean,\n hasView: boolean,\n) {\n const ref = changeTree.ref;\n\n if (\n hasView &&\n operation === OPERATION.DELETE &&\n typeof (changeTree.getType(field)) !== \"string\"\n ) {\n // encode delete by refId (array of schemas)\n bytes[it.offset++] = OPERATION.DELETE_BY_REFID;\n const value = ref['tmpItems'][field];\n const refId = value[$changes].refId;\n encode.number(bytes, refId, it);\n return;\n }\n\n // encode operation\n bytes[it.offset++] = operation & 255;\n\n // custom operations\n if (operation === OPERATION.CLEAR) {\n return;\n }\n\n // encode index\n encode.number(bytes, field, it);\n\n // Do not encode value for DELETE operations\n if (operation === OPERATION.DELETE) {\n return;\n }\n\n const type = changeTree.getType(field);\n const value = changeTree.getValue(field, isEncodeAll);\n\n // console.log(\"encodeArray -> \", {\n // ref: changeTree.ref.constructor.name,\n // field,\n // operation: OPERATION[operation],\n // value: value?.toJSON(),\n // items: ref.toJSON(),\n // });\n\n // TODO: inline this function call small performance gain\n encodeValue(encoder, bytes, ref, type, value, field, operation, it);\n}"]}
1
+ {"version":3,"file":"EncodeOperation.js","sourceRoot":"","sources":["../../src/encoder/EncodeOperation.ts"],"names":[],"mappings":"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","sourcesContent":["import { OPERATION } from \"../encoding/spec\";\nimport { $changes } from \"../types/symbols\";\nimport { getType } from \"../types/registry\";\n\nimport * as encode from \"../encoding/encode\";\n// import { EncodeSchemaError, assertInstanceType, assertType } from \"../encoding/assert\";\n\nimport type { ChangeTree, Ref } from \"./ChangeTree\";\nimport type { Encoder } from \"./Encoder\";\nimport type { Schema } from \"../Schema\";\nimport type { PrimitiveType } from \"../annotations\";\n\nimport type { Iterator } from \"../encoding/decode\";\nimport type { ArraySchema } from \"../types/custom/ArraySchema\";\nimport type { Metadata } from \"../Metadata\";\n\nexport type EncodeOperation<T extends Ref = any> = (\n encoder: Encoder,\n bytes: Buffer,\n changeTree: ChangeTree<T>,\n index: number,\n operation: OPERATION,\n it: Iterator,\n isEncodeAll: boolean,\n hasView: boolean,\n) => void;\n\nexport function encodeValue(\n encoder: Encoder,\n bytes: Buffer,\n // ref: Ref,\n type: any,\n value: any,\n // field: string | number,\n operation: OPERATION,\n it: Iterator,\n) {\n if (typeof (type) === \"string\") {\n //\n // Primitive values\n //\n // assertType(value, type as string, ref as Schema, field);\n\n encode[type]?.(bytes, value, it);\n\n } else if (type[Symbol.metadata] !== undefined) {\n // // TODO: move this to the `@type()` annotation\n // assertInstanceType(value, type as typeof Schema, ref as Schema, field);\n\n //\n // Encode refId for this instance.\n // The actual instance is going to be encoded on next `changeTree` iteration.\n //\n encode.number(bytes, value[$changes].refId, it);\n\n // Try to encode inherited TYPE_ID if it's an ADD operation.\n if ((operation & OPERATION.ADD) === OPERATION.ADD) {\n encoder.tryEncodeTypeId(bytes, type as typeof Schema, value.constructor as typeof Schema, it);\n }\n\n } else {\n // //\n // // Custom type (MapSchema, ArraySchema, etc)\n // //\n // const definition = getType(Object.keys(type)[0]);\n\n // //\n // // ensure a ArraySchema has been provided\n // //\n // assertInstanceType(ref[field], definition.constructor, ref as Schema, field);\n\n //\n // Encode refId for this instance.\n // The actual instance is going to be encoded on next `changeTree` iteration.\n //\n encode.number(bytes, value[$changes].refId, it);\n }\n}\n\n/**\n * Used for Schema instances.\n * @private\n */\nexport const encodeSchemaOperation: EncodeOperation = function (\n encoder: Encoder,\n bytes: Buffer,\n changeTree: ChangeTree<Schema>,\n index: number,\n operation: OPERATION,\n it: Iterator,\n) {\n // \"compress\" field index + operation\n bytes[it.offset++] = (index | operation) & 255;\n\n // Do not encode value for DELETE operations\n if (operation === OPERATION.DELETE) {\n return;\n }\n\n const ref = changeTree.ref;\n const metadata: Metadata = ref['constructor'][Symbol.metadata];\n const field = metadata[index];\n\n // TODO: inline this function call small performance gain\n encodeValue(\n encoder,\n bytes,\n // ref,\n metadata[index].type,\n ref[field.name],\n // index,\n operation,\n it\n );\n}\n\n/**\n * Used for collections (MapSchema, CollectionSchema, SetSchema)\n * @private\n */\nexport const encodeKeyValueOperation: EncodeOperation = function (\n encoder: Encoder,\n bytes: Buffer,\n changeTree: ChangeTree,\n index: number,\n operation: OPERATION,\n it: Iterator,\n) {\n // encode operation\n bytes[it.offset++] = operation & 255;\n\n // custom operations\n if (operation === OPERATION.CLEAR) {\n return;\n }\n\n // encode index\n encode.number(bytes, index, it);\n\n // Do not encode value for DELETE operations\n if (operation === OPERATION.DELETE) {\n return;\n }\n\n const ref = changeTree.ref;\n\n //\n // encode \"alias\" for dynamic fields (maps)\n //\n if ((operation & OPERATION.ADD) == OPERATION.ADD) { // ADD or DELETE_AND_ADD\n if (typeof(ref['set']) === \"function\") {\n //\n // MapSchema dynamic key\n //\n const dynamicIndex = changeTree.ref['$indexes'].get(index);\n encode.string(bytes, dynamicIndex, it);\n }\n }\n\n const type = changeTree.getType(index);\n const value = changeTree.getValue(index);\n\n // try { throw new Error(); } catch (e) {\n // // only print if not coming from Reflection.ts\n // if (!e.stack.includes(\"src/Reflection.ts\")) {\n // console.log(\"encodeKeyValueOperation -> \", {\n // ref: changeTree.ref.constructor.name,\n // field,\n // operation: OPERATION[operation],\n // value: value?.toJSON(),\n // items: ref.toJSON(),\n // });\n // }\n // }\n\n // TODO: inline this function call small performance gain\n encodeValue(\n encoder,\n bytes,\n // ref,\n type,\n value,\n // index,\n operation,\n it\n );\n}\n\n/**\n * Used for collections (MapSchema, ArraySchema, etc.)\n * @private\n */\nexport const encodeArray: EncodeOperation = function (\n encoder: Encoder,\n bytes: Buffer,\n changeTree: ChangeTree<ArraySchema>,\n field: number,\n operation: OPERATION,\n it: Iterator,\n isEncodeAll: boolean,\n hasView: boolean,\n) {\n const ref = changeTree.ref;\n const useOperationByRefId = hasView && changeTree.isFiltered && (typeof (changeTree.getType(field)) !== \"string\");\n\n let refOrIndex: number;\n\n if (useOperationByRefId) {\n refOrIndex = ref['tmpItems'][field][$changes].refId;\n\n if (operation === OPERATION.DELETE) {\n operation = OPERATION.DELETE_BY_REFID;\n\n } else if (operation === OPERATION.ADD) {\n operation = OPERATION.ADD_BY_REFID;\n }\n\n } else {\n refOrIndex = field;\n }\n\n // encode operation\n bytes[it.offset++] = operation & 255;\n\n // custom operations\n if (operation === OPERATION.CLEAR) {\n return;\n }\n\n // encode index\n encode.number(bytes, refOrIndex, it);\n\n // Do not encode value for DELETE operations\n if (operation === OPERATION.DELETE) {\n return;\n }\n\n const type = changeTree.getType(field);\n const value = changeTree.getValue(field, isEncodeAll);\n\n // console.log(\"encodeArray -> \", {\n // ref: changeTree.ref.constructor.name,\n // field,\n // operation: OPERATION[operation],\n // value: value?.toJSON(),\n // items: ref.toJSON(),\n // });\n\n // TODO: inline this function call small performance gain\n encodeValue(\n encoder,\n bytes,\n // ref,\n type,\n value,\n // field,\n operation,\n it\n );\n}"]}
@@ -1,22 +1,24 @@
1
- /// <reference types="node" />
2
1
  import type { Schema } from "../Schema";
3
- import { TypeContext } from "../annotations";
2
+ import { TypeContext } from "../types/TypeContext";
4
3
  import type { Iterator } from "../encoding/decode";
5
- import { Root } from "./ChangeTree";
4
+ import { OPERATION } from '../encoding/spec';
5
+ import { Root } from "./Root";
6
6
  import type { StateView } from "./StateView";
7
+ import type { ChangeTree } from "./ChangeTree";
7
8
  export declare class Encoder<T extends Schema = any> {
8
9
  static BUFFER_SIZE: number;
9
10
  sharedBuffer: Buffer;
10
11
  context: TypeContext;
11
12
  state: T;
12
13
  root: Root;
13
- constructor(root: T);
14
- protected setRoot(state: T): void;
15
- encode(it?: Iterator, view?: StateView, bytes?: Buffer, changeTrees?: Map<import("./ChangeTree").ChangeTree<any>, Map<number, import("../encoding/spec").OPERATION>>): Buffer;
16
- encodeAll(it?: Iterator): Buffer;
14
+ constructor(state: T);
15
+ protected setState(state: T): void;
16
+ encode(it?: Iterator, view?: StateView, buffer?: Buffer, changeTrees?: Map<ChangeTree<any>, Map<number, OPERATION>>, isEncodeAll?: boolean, initialOffset?: number): Buffer;
17
+ encodeAll(it?: Iterator, buffer?: Buffer): Buffer;
17
18
  encodeAllView(view: StateView, sharedOffset: number, it: Iterator, bytes?: Buffer): Buffer;
19
+ debugChanges(field: "changes" | "allFilteredChanges" | "allChanges" | "filteredChanges" | Map<ChangeTree, Map<number, OPERATION>>): void;
18
20
  encodeView(view: StateView, sharedOffset: number, it: Iterator, bytes?: Buffer): Buffer;
19
- onEndEncode(changeTrees?: Map<import("./ChangeTree").ChangeTree<any>, Map<number, import("../encoding/spec").OPERATION>>): void;
21
+ onEndEncode(changeTrees?: Map<ChangeTree<any>, Map<number, OPERATION>>): void;
20
22
  discardChanges(): void;
21
23
  tryEncodeTypeId(bytes: Buffer, baseType: typeof Schema, targetType: typeof Schema, it: Iterator): void;
22
24
  }
@@ -1,43 +1,48 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Encoder = void 0;
4
- const annotations_1 = require("../annotations");
4
+ const TypeContext_1 = require("../types/TypeContext");
5
5
  const symbols_1 = require("../types/symbols");
6
6
  const encode = require("../encoding/encode");
7
7
  const spec_1 = require("../encoding/spec");
8
- const ChangeTree_1 = require("./ChangeTree");
8
+ const Root_1 = require("./Root");
9
9
  const utils_1 = require("../utils");
10
10
  class Encoder {
11
11
  static { this.BUFFER_SIZE = 8 * 1024; } // 8KB
12
- constructor(root) {
12
+ constructor(state) {
13
13
  this.sharedBuffer = Buffer.allocUnsafeSlow(Encoder.BUFFER_SIZE);
14
- this.setRoot(root);
15
14
  //
16
15
  // TODO: cache and restore "Context" based on root schema
17
16
  // (to avoid creating a new context for every new room)
18
17
  //
19
- this.context = new annotations_1.TypeContext(root.constructor);
18
+ this.context = new TypeContext_1.TypeContext(state.constructor);
19
+ this.root = new Root_1.Root(this.context);
20
+ this.setState(state);
20
21
  // console.log(">>>>>>>>>>>>>>>> Encoder types");
21
22
  // this.context.schemas.forEach((id, schema) => {
22
23
  // console.log("type:", id, schema.name, Object.keys(schema[Symbol.metadata]));
23
24
  // });
24
25
  }
25
- setRoot(state) {
26
- this.root = new ChangeTree_1.Root();
26
+ setState(state) {
27
27
  this.state = state;
28
- state[symbols_1.$changes].setRoot(this.root);
28
+ this.state[symbols_1.$changes].setRoot(this.root);
29
29
  }
30
- encode(it = { offset: 0 }, view, bytes = this.sharedBuffer, changeTrees = this.root.changes) {
31
- const initialOffset = it.offset; // cache current offset in case we need to resize the buffer
32
- const isEncodeAll = this.root.allChanges === changeTrees;
30
+ encode(it = { offset: 0 }, view, buffer = this.sharedBuffer, changeTrees = this.root.changes, isEncodeAll = this.root.allChanges === changeTrees, initialOffset = it.offset // cache current offset in case we need to resize the buffer
31
+ ) {
33
32
  const hasView = (view !== undefined);
34
33
  const rootChangeTree = this.state[symbols_1.$changes];
35
- const changeTreesIterator = changeTrees.entries();
36
- for (const [changeTree, changes] of changeTreesIterator) {
34
+ const shouldClearChanges = !isEncodeAll && !hasView;
35
+ for (const [changeTree, changes] of changeTrees.entries()) {
37
36
  const ref = changeTree.ref;
38
37
  const ctor = ref['constructor'];
39
38
  const encoder = ctor[symbols_1.$encoder];
40
39
  const filter = ctor[symbols_1.$filter];
40
+ // try { throw new Error(); } catch (e) {
41
+ // // only print if not coming from Reflection.ts
42
+ // if (!e.stack.includes("src/Reflection.ts")) {
43
+ // console.log("ChangeTree:", { ref: ref.constructor.name, });
44
+ // }
45
+ // }
41
46
  if (hasView) {
42
47
  if (!view.items.has(changeTree)) {
43
48
  view.invisible.add(changeTree);
@@ -48,9 +53,10 @@ class Encoder {
48
53
  }
49
54
  }
50
55
  // skip root `refId` if it's the first change tree
51
- if (it.offset !== initialOffset || changeTree !== rootChangeTree) {
52
- bytes[it.offset++] = spec_1.SWITCH_TO_STRUCTURE & 255;
53
- encode.number(bytes, changeTree.refId, it);
56
+ // (unless it "hasView", which will need to revisit the root)
57
+ if (hasView || it.offset > initialOffset || changeTree !== rootChangeTree) {
58
+ buffer[it.offset++] = spec_1.SWITCH_TO_STRUCTURE & 255;
59
+ encode.number(buffer, changeTree.refId, it);
54
60
  }
55
61
  const changesIterator = changes.entries();
56
62
  for (const [fieldIndex, operation] of changesIterator) {
@@ -62,74 +68,94 @@ class Encoder {
62
68
  // TODO: avoid checking if no view tags were defined
63
69
  //
64
70
  if (filter && !filter(ref, fieldIndex, view)) {
65
- // console.log("SKIP FIELD:", { ref: changeTree.ref.constructor.name, fieldIndex, })
66
71
  // console.log("ADD AS INVISIBLE:", fieldIndex, changeTree.ref.constructor.name)
67
72
  // view?.invisible.add(changeTree);
68
73
  continue;
69
74
  }
70
- // console.log("WILL ENCODE", {
71
- // ref: changeTree.ref.constructor.name,
72
- // fieldIndex,
73
- // operation: OPERATION[operation],
74
- // });
75
- encoder(this, bytes, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);
75
+ // try { throw new Error(); } catch (e) {
76
+ // // only print if not coming from Reflection.ts
77
+ // if (!e.stack.includes("src/Reflection.ts")) {
78
+ // console.log("WILL ENCODE", {
79
+ // ref: changeTree.ref.constructor.name,
80
+ // fieldIndex,
81
+ // operation: OPERATION[operation],
82
+ // });
83
+ // }
84
+ // }
85
+ encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);
76
86
  }
87
+ // if (shouldClearChanges) {
88
+ // changeTree.endEncode();
89
+ // }
77
90
  }
78
- if (it.offset > bytes.byteLength) {
79
- const newSize = (0, utils_1.getNextPowerOf2)(this.sharedBuffer.byteLength * 2);
80
- console.warn("@colyseus/schema encode buffer overflow. Current buffer size: " + bytes.byteLength + ", encoding offset: " + it.offset + ", new size: " + newSize);
91
+ if (it.offset > buffer.byteLength) {
92
+ const newSize = (0, utils_1.getNextPowerOf2)(buffer.byteLength * 2);
93
+ console.warn(`@colyseus/schema buffer overflow. Encoded state is higher than default BUFFER_SIZE. Use the following to increase default BUFFER_SIZE:
94
+
95
+ import { Encoder } from "@colyseus/schema";
96
+ Encoder.BUFFER_SIZE = ${Math.round(newSize / 1024)} * 1024; // ${Math.round(newSize / 1024)} KB
97
+ `);
81
98
  //
82
99
  // resize buffer and re-encode (TODO: can we avoid re-encoding here?)
83
100
  //
84
- this.sharedBuffer = Buffer.allocUnsafeSlow(newSize);
85
- return this.encode({ offset: initialOffset }, view);
101
+ buffer = Buffer.allocUnsafeSlow(newSize);
102
+ // assign resized buffer to local sharedBuffer
103
+ if (buffer === this.sharedBuffer) {
104
+ this.sharedBuffer = buffer;
105
+ }
106
+ return this.encode({ offset: initialOffset }, view, buffer, changeTrees, isEncodeAll);
86
107
  }
87
108
  else {
88
109
  //
89
110
  // only clear changes after making sure buffer resize is not required.
90
111
  //
91
- if (!isEncodeAll && !hasView) {
112
+ if (shouldClearChanges) {
92
113
  //
93
114
  // FIXME: avoid iterating over change trees twice.
94
115
  //
95
116
  this.onEndEncode(changeTrees);
96
117
  }
97
- // return bytes;
98
- return bytes.slice(0, it.offset);
118
+ return buffer.subarray(0, it.offset);
99
119
  }
100
120
  }
101
- encodeAll(it = { offset: 0 }) {
102
- // console.log(`encodeAll(), this.$root.allChanges (${this.$root.allChanges.size})`);
103
- // Array.from(this.$root.allChanges.entries()).map((item) => {
104
- // console.log("->", item[0].refId, item[0].ref.toJSON());
105
- // });
106
- return this.encode(it, undefined, this.sharedBuffer, this.root.allChanges);
121
+ encodeAll(it = { offset: 0 }, buffer = this.sharedBuffer) {
122
+ // console.log(`\nencodeAll(), this.root.allChanges (${this.root.allChanges.size})`);
123
+ // this.debugChanges("allChanges");
124
+ return this.encode(it, undefined, buffer, this.root.allChanges, true);
107
125
  }
108
126
  encodeAllView(view, sharedOffset, it, bytes = this.sharedBuffer) {
109
127
  const viewOffset = it.offset;
110
- // console.log(`encodeAllView(), this.$root.allFilteredChanges (${this.$root.allFilteredChanges.size})`);
111
- // this.debugAllFilteredChanges();
128
+ // console.log(`\nencodeAllView(), this.root.allFilteredChanges (${this.root.allFilteredChanges.size})`);
129
+ // this.debugChanges("allFilteredChanges");
112
130
  // try to encode "filtered" changes
113
- this.encode(it, view, bytes, this.root.allFilteredChanges);
131
+ this.encode(it, view, bytes, this.root.allFilteredChanges, true, viewOffset);
114
132
  return Buffer.concat([
115
- bytes.slice(0, sharedOffset),
116
- bytes.slice(viewOffset, it.offset)
133
+ bytes.subarray(0, sharedOffset),
134
+ bytes.subarray(viewOffset, it.offset)
117
135
  ]);
118
136
  }
119
- // debugAllFilteredChanges() {
120
- // Array.from(this.$root.allFilteredChanges.entries()).map((item) => {
121
- // console.log("->", { refId: item[0].refId }, item[0].ref.toJSON());
122
- // if (Array.isArray(item[0].ref.toJSON())) {
123
- // item[1].forEach((op, key) => {
124
- // console.log(" ->", { key, op: OPERATION[op] });
125
- // })
126
- // }
127
- // });
128
- // }
137
+ debugChanges(field) {
138
+ const changeSet = (typeof (field) === "string")
139
+ ? this.root[field]
140
+ : field;
141
+ Array.from(changeSet.entries()).map((item) => {
142
+ const metadata = item[0].ref.constructor[Symbol.metadata];
143
+ console.log("->", { ref: item[0].ref.constructor.name, refId: item[0].refId, changes: item[1].size });
144
+ item[1].forEach((op, index) => {
145
+ console.log(" ->", {
146
+ index,
147
+ field: metadata?.[index],
148
+ op: spec_1.OPERATION[op],
149
+ });
150
+ });
151
+ });
152
+ }
129
153
  encodeView(view, sharedOffset, it, bytes = this.sharedBuffer) {
130
154
  const viewOffset = it.offset;
131
- // try to encode "filtered" changes
132
- this.encode(it, view, bytes, this.root.filteredChanges);
155
+ // console.log(`\nencodeView(), view.changes (${view.changes.size})`);
156
+ // this.debugChanges(view.changes);
157
+ // console.log(`\nencodeView(), this.root.filteredChanges (${this.root.filteredChanges.size})`);
158
+ // this.debugChanges("filteredChanges");
133
159
  // encode visibility changes (add/remove for this view)
134
160
  const viewChangesIterator = view.changes.entries();
135
161
  for (const [changeTree, changes] of viewChangesIterator) {
@@ -156,15 +182,22 @@ class Encoder {
156
182
  //
157
183
  // clear "view" changes after encoding
158
184
  view.changes.clear();
185
+ // try to encode "filtered" changes
186
+ this.encode(it, view, bytes, this.root.filteredChanges, false, viewOffset);
159
187
  return Buffer.concat([
160
- bytes.slice(0, sharedOffset),
161
- bytes.slice(viewOffset, it.offset)
188
+ bytes.subarray(0, sharedOffset),
189
+ bytes.subarray(viewOffset, it.offset)
162
190
  ]);
163
191
  }
164
192
  onEndEncode(changeTrees = this.root.changes) {
165
193
  const changeTreesIterator = changeTrees.entries();
166
194
  for (const [changeTree, _] of changeTreesIterator) {
167
195
  changeTree.endEncode();
196
+ // changeTree.changes.clear();
197
+ // // ArraySchema and MapSchema have a custom "encode end" method
198
+ // changeTree.ref[$onEncodeEnd]?.();
199
+ // // Not a new instance anymore
200
+ // delete changeTree[$isNew];
168
201
  }
169
202
  }
170
203
  discardChanges() {
@@ -1 +1 @@
1
- {"version":3,"file":"Encoder.js","sourceRoot":"","sources":["../../src/encoder/Encoder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Schema } from \"../Schema\";\nimport { TypeContext } from \"../annotations\";\nimport { $changes, $encoder, $filter } from \"../types/symbols\";\n\nimport * as encode from \"../encoding/encode\";\nimport type { Iterator } from \"../encoding/decode\";\n\nimport { SWITCH_TO_STRUCTURE, TYPE_ID } from '../encoding/spec';\nimport { Root } from \"./ChangeTree\";\nimport { getNextPowerOf2 } from \"../utils\";\nimport type { StateView } from \"./StateView\";\n\nexport class Encoder<T extends Schema = any> {\n static BUFFER_SIZE = 8 * 1024;// 8KB\n sharedBuffer = Buffer.allocUnsafeSlow(Encoder.BUFFER_SIZE);\n\n context: TypeContext;\n state: T;\n\n root: Root;\n\n constructor(root: T) {\n this.setRoot(root);\n\n //\n // TODO: cache and restore \"Context\" based on root schema\n // (to avoid creating a new context for every new room)\n //\n this.context = new TypeContext(root.constructor as typeof Schema);\n\n // console.log(\">>>>>>>>>>>>>>>> Encoder types\");\n // this.context.schemas.forEach((id, schema) => {\n // console.log(\"type:\", id, schema.name, Object.keys(schema[Symbol.metadata]));\n // });\n }\n\n protected setRoot(state: T) {\n this.root = new Root();\n this.state = state;\n state[$changes].setRoot(this.root);\n }\n\n encode(\n it: Iterator = { offset: 0 },\n view?: StateView,\n bytes = this.sharedBuffer,\n changeTrees = this.root.changes\n ): Buffer {\n const initialOffset = it.offset; // cache current offset in case we need to resize the buffer\n\n const isEncodeAll = this.root.allChanges === changeTrees;\n const hasView = (view !== undefined);\n const rootChangeTree = this.state[$changes];\n\n const changeTreesIterator = changeTrees.entries();\n\n for (const [changeTree, changes] of changeTreesIterator) {\n const ref = changeTree.ref;\n\n const ctor = ref['constructor'];\n const encoder = ctor[$encoder];\n const filter = ctor[$filter];\n\n if (hasView) {\n if (!view.items.has(changeTree)) {\n view.invisible.add(changeTree);\n continue; // skip this change tree\n\n } else if (view.invisible.has(changeTree)) {\n view.invisible.delete(changeTree); // remove from invisible list\n }\n }\n\n // skip root `refId` if it's the first change tree\n if (it.offset !== initialOffset || changeTree !== rootChangeTree) {\n bytes[it.offset++] = SWITCH_TO_STRUCTURE & 255;\n encode.number(bytes, changeTree.refId, it);\n }\n\n const changesIterator = changes.entries();\n\n for (const [fieldIndex, operation] of changesIterator) {\n //\n // first pass (encodeAll), identify \"filtered\" operations without encoding them\n // they will be encoded per client, based on their view.\n //\n // TODO: how can we optimize filtering out \"encode all\" operations?\n // TODO: avoid checking if no view tags were defined\n //\n if (filter && !filter(ref, fieldIndex, view)) {\n // console.log(\"SKIP FIELD:\", { ref: changeTree.ref.constructor.name, fieldIndex, })\n\n // console.log(\"ADD AS INVISIBLE:\", fieldIndex, changeTree.ref.constructor.name)\n // view?.invisible.add(changeTree);\n continue;\n }\n\n // console.log(\"WILL ENCODE\", {\n // ref: changeTree.ref.constructor.name,\n // fieldIndex,\n // operation: OPERATION[operation],\n // });\n\n encoder(this, bytes, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);\n }\n }\n\n if (it.offset > bytes.byteLength) {\n const newSize = getNextPowerOf2(this.sharedBuffer.byteLength * 2);\n console.warn(\"@colyseus/schema encode buffer overflow. Current buffer size: \" + bytes.byteLength + \", encoding offset: \" + it.offset + \", new size: \" + newSize);\n\n //\n // resize buffer and re-encode (TODO: can we avoid re-encoding here?)\n //\n this.sharedBuffer = Buffer.allocUnsafeSlow(newSize);\n return this.encode({ offset: initialOffset }, view);\n\n } else {\n //\n // only clear changes after making sure buffer resize is not required.\n //\n if (!isEncodeAll && !hasView) {\n //\n // FIXME: avoid iterating over change trees twice.\n //\n this.onEndEncode(changeTrees);\n }\n\n // return bytes;\n return bytes.slice(0, it.offset);\n }\n }\n\n encodeAll(it: Iterator = { offset: 0 }) {\n // console.log(`encodeAll(), this.$root.allChanges (${this.$root.allChanges.size})`);\n\n // Array.from(this.$root.allChanges.entries()).map((item) => {\n // console.log(\"->\", item[0].refId, item[0].ref.toJSON());\n // });\n\n return this.encode(it, undefined, this.sharedBuffer, this.root.allChanges);\n }\n\n encodeAllView(view: StateView, sharedOffset: number, it: Iterator, bytes = this.sharedBuffer) {\n const viewOffset = it.offset;\n\n // console.log(`encodeAllView(), this.$root.allFilteredChanges (${this.$root.allFilteredChanges.size})`);\n // this.debugAllFilteredChanges();\n\n // try to encode \"filtered\" changes\n this.encode(it, view, bytes, this.root.allFilteredChanges);\n\n return Buffer.concat([\n bytes.slice(0, sharedOffset),\n bytes.slice(viewOffset, it.offset)\n ]);\n }\n\n\n // debugAllFilteredChanges() {\n // Array.from(this.$root.allFilteredChanges.entries()).map((item) => {\n // console.log(\"->\", { refId: item[0].refId }, item[0].ref.toJSON());\n // if (Array.isArray(item[0].ref.toJSON())) {\n // item[1].forEach((op, key) => {\n // console.log(\" ->\", { key, op: OPERATION[op] });\n // })\n // }\n // });\n // }\n\n encodeView(view: StateView, sharedOffset: number, it: Iterator, bytes = this.sharedBuffer) {\n const viewOffset = it.offset;\n\n // try to encode \"filtered\" changes\n this.encode(it, view, bytes, this.root.filteredChanges);\n\n // encode visibility changes (add/remove for this view)\n const viewChangesIterator = view.changes.entries();\n for (const [changeTree, changes] of viewChangesIterator) {\n if (changes.size === 0) {\n // FIXME: avoid having empty changes if no changes were made\n // console.log(\"changes.size === 0\", changeTree.ref.constructor.name);\n continue;\n }\n\n const ref = changeTree.ref;\n\n const ctor = ref['constructor'];\n const encoder = ctor[$encoder];\n\n bytes[it.offset++] = SWITCH_TO_STRUCTURE & 255;\n encode.number(bytes, changeTree.refId, it);\n\n const changesIterator = changes.entries();\n\n for (const [fieldIndex, operation] of changesIterator) {\n // isEncodeAll = false\n // hasView = true\n encoder(this, bytes, changeTree, fieldIndex, operation, it, false, true);\n }\n }\n\n //\n // TODO: only clear view changes after all views are encoded\n // (to allow re-using StateView's for multiple clients)\n //\n // clear \"view\" changes after encoding\n view.changes.clear();\n\n return Buffer.concat([\n bytes.slice(0, sharedOffset),\n bytes.slice(viewOffset, it.offset)\n ]);\n }\n\n onEndEncode(changeTrees = this.root.changes) {\n const changeTreesIterator = changeTrees.entries();\n for (const [changeTree, _] of changeTreesIterator) {\n changeTree.endEncode();\n }\n }\n\n discardChanges() {\n // discard shared changes\n if (this.root.changes.size > 0) {\n this.onEndEncode(this.root.changes);\n this.root.changes.clear();\n }\n // discard filtered changes\n if (this.root.filteredChanges.size > 0) {\n this.onEndEncode(this.root.filteredChanges);\n this.root.filteredChanges.clear();\n }\n }\n\n tryEncodeTypeId (bytes: Buffer, baseType: typeof Schema, targetType: typeof Schema, it: Iterator) {\n const baseTypeId = this.context.getTypeId(baseType);\n const targetTypeId = this.context.getTypeId(targetType);\n\n if (baseTypeId !== targetTypeId) {\n bytes[it.offset++] = TYPE_ID & 255;\n encode.number(bytes, targetTypeId, it);\n }\n }\n}"]}
1
+ {"version":3,"file":"Encoder.js","sourceRoot":"","sources":["../../src/encoder/Encoder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Schema } from \"../Schema\";\nimport { TypeContext } from \"../types/TypeContext\";\nimport { $changes, $encoder, $filter, $isNew, $onEncodeEnd } from \"../types/symbols\";\n\nimport * as encode from \"../encoding/encode\";\nimport type { Iterator } from \"../encoding/decode\";\n\nimport { OPERATION, SWITCH_TO_STRUCTURE, TYPE_ID } from '../encoding/spec';\nimport { Root } from \"./Root\";\nimport { getNextPowerOf2 } from \"../utils\";\n\nimport type { StateView } from \"./StateView\";\nimport type { Metadata } from \"../Metadata\";\nimport type { ChangeTree } from \"./ChangeTree\";\n\nexport class Encoder<T extends Schema = any> {\n static BUFFER_SIZE = 8 * 1024;// 8KB\n sharedBuffer = Buffer.allocUnsafeSlow(Encoder.BUFFER_SIZE);\n\n context: TypeContext;\n state: T;\n\n root: Root;\n\n constructor(state: T) {\n\n //\n // TODO: cache and restore \"Context\" based on root schema\n // (to avoid creating a new context for every new room)\n //\n this.context = new TypeContext(state.constructor as typeof Schema);\n this.root = new Root(this.context);\n\n this.setState(state);\n\n // console.log(\">>>>>>>>>>>>>>>> Encoder types\");\n // this.context.schemas.forEach((id, schema) => {\n // console.log(\"type:\", id, schema.name, Object.keys(schema[Symbol.metadata]));\n // });\n }\n\n protected setState(state: T) {\n this.state = state;\n this.state[$changes].setRoot(this.root);\n }\n\n encode(\n it: Iterator = { offset: 0 },\n view?: StateView,\n buffer = this.sharedBuffer,\n changeTrees = this.root.changes,\n isEncodeAll = this.root.allChanges === changeTrees,\n initialOffset = it.offset // cache current offset in case we need to resize the buffer\n ): Buffer {\n const hasView = (view !== undefined);\n const rootChangeTree = this.state[$changes];\n\n const shouldClearChanges = !isEncodeAll && !hasView;\n\n for (const [changeTree, changes] of changeTrees.entries()) {\n const ref = changeTree.ref;\n\n const ctor = ref['constructor'];\n const encoder = ctor[$encoder];\n const filter = ctor[$filter];\n\n // try { throw new Error(); } catch (e) {\n // // only print if not coming from Reflection.ts\n // if (!e.stack.includes(\"src/Reflection.ts\")) {\n // console.log(\"ChangeTree:\", { ref: ref.constructor.name, });\n // }\n // }\n\n if (hasView) {\n if (!view.items.has(changeTree)) {\n view.invisible.add(changeTree);\n continue; // skip this change tree\n\n } else if (view.invisible.has(changeTree)) {\n view.invisible.delete(changeTree); // remove from invisible list\n }\n }\n\n // skip root `refId` if it's the first change tree\n // (unless it \"hasView\", which will need to revisit the root)\n if (hasView || it.offset > initialOffset || changeTree !== rootChangeTree) {\n buffer[it.offset++] = SWITCH_TO_STRUCTURE & 255;\n encode.number(buffer, changeTree.refId, it);\n }\n\n const changesIterator = changes.entries();\n\n for (const [fieldIndex, operation] of changesIterator) {\n //\n // first pass (encodeAll), identify \"filtered\" operations without encoding them\n // they will be encoded per client, based on their view.\n //\n // TODO: how can we optimize filtering out \"encode all\" operations?\n // TODO: avoid checking if no view tags were defined\n //\n if (filter && !filter(ref, fieldIndex, view)) {\n // console.log(\"ADD AS INVISIBLE:\", fieldIndex, changeTree.ref.constructor.name)\n // view?.invisible.add(changeTree);\n continue;\n }\n\n // try { throw new Error(); } catch (e) {\n // // only print if not coming from Reflection.ts\n // if (!e.stack.includes(\"src/Reflection.ts\")) {\n // console.log(\"WILL ENCODE\", {\n // ref: changeTree.ref.constructor.name,\n // fieldIndex,\n // operation: OPERATION[operation],\n // });\n // }\n // }\n\n encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);\n }\n\n // if (shouldClearChanges) {\n // changeTree.endEncode();\n // }\n }\n\n if (it.offset > buffer.byteLength) {\n const newSize = getNextPowerOf2(buffer.byteLength * 2);\n console.warn(`@colyseus/schema buffer overflow. Encoded state is higher than default BUFFER_SIZE. Use the following to increase default BUFFER_SIZE:\n\n import { Encoder } from \"@colyseus/schema\";\n Encoder.BUFFER_SIZE = ${Math.round(newSize / 1024)} * 1024; // ${Math.round(newSize / 1024)} KB\n`);\n\n //\n // resize buffer and re-encode (TODO: can we avoid re-encoding here?)\n //\n buffer = Buffer.allocUnsafeSlow(newSize);\n\n // assign resized buffer to local sharedBuffer\n if (buffer === this.sharedBuffer) {\n this.sharedBuffer = buffer;\n }\n\n return this.encode({ offset: initialOffset }, view, buffer, changeTrees, isEncodeAll);\n\n } else {\n //\n // only clear changes after making sure buffer resize is not required.\n //\n if (shouldClearChanges) {\n //\n // FIXME: avoid iterating over change trees twice.\n //\n this.onEndEncode(changeTrees);\n }\n\n return buffer.subarray(0, it.offset);\n }\n }\n\n encodeAll(it: Iterator = { offset: 0 }, buffer: Buffer = this.sharedBuffer) {\n // console.log(`\\nencodeAll(), this.root.allChanges (${this.root.allChanges.size})`);\n // this.debugChanges(\"allChanges\");\n\n return this.encode(it, undefined, buffer, this.root.allChanges, true);\n }\n\n encodeAllView(view: StateView, sharedOffset: number, it: Iterator, bytes = this.sharedBuffer) {\n const viewOffset = it.offset;\n\n // console.log(`\\nencodeAllView(), this.root.allFilteredChanges (${this.root.allFilteredChanges.size})`);\n // this.debugChanges(\"allFilteredChanges\");\n\n // try to encode \"filtered\" changes\n this.encode(it, view, bytes, this.root.allFilteredChanges, true, viewOffset);\n\n return Buffer.concat([\n bytes.subarray(0, sharedOffset),\n bytes.subarray(viewOffset, it.offset)\n ]);\n }\n\n debugChanges(\n field: \"changes\" | \"allFilteredChanges\" | \"allChanges\" | \"filteredChanges\" | Map<ChangeTree, Map<number, OPERATION>>\n ) {\n const changeSet = (typeof (field) === \"string\")\n ? this.root[field]\n : field;\n\n Array.from(changeSet.entries()).map((item) => {\n const metadata: Metadata = item[0].ref.constructor[Symbol.metadata];\n console.log(\"->\", { ref: item[0].ref.constructor.name, refId: item[0].refId, changes: item[1].size });\n item[1].forEach((op, index) => {\n console.log(\" ->\", {\n index,\n field: metadata?.[index],\n op: OPERATION[op],\n });\n });\n });\n }\n\n encodeView(view: StateView, sharedOffset: number, it: Iterator, bytes = this.sharedBuffer) {\n const viewOffset = it.offset;\n\n // console.log(`\\nencodeView(), view.changes (${view.changes.size})`);\n // this.debugChanges(view.changes);\n\n // console.log(`\\nencodeView(), this.root.filteredChanges (${this.root.filteredChanges.size})`);\n // this.debugChanges(\"filteredChanges\");\n\n // encode visibility changes (add/remove for this view)\n const viewChangesIterator = view.changes.entries();\n for (const [changeTree, changes] of viewChangesIterator) {\n if (changes.size === 0) {\n // FIXME: avoid having empty changes if no changes were made\n // console.log(\"changes.size === 0\", changeTree.ref.constructor.name);\n continue;\n }\n\n const ref = changeTree.ref;\n\n const ctor = ref['constructor'];\n const encoder = ctor[$encoder];\n\n bytes[it.offset++] = SWITCH_TO_STRUCTURE & 255;\n encode.number(bytes, changeTree.refId, it);\n\n const changesIterator = changes.entries();\n\n for (const [fieldIndex, operation] of changesIterator) {\n // isEncodeAll = false\n // hasView = true\n encoder(this, bytes, changeTree, fieldIndex, operation, it, false, true);\n }\n }\n\n //\n // TODO: only clear view changes after all views are encoded\n // (to allow re-using StateView's for multiple clients)\n //\n // clear \"view\" changes after encoding\n view.changes.clear();\n\n // try to encode \"filtered\" changes\n this.encode(it, view, bytes, this.root.filteredChanges, false, viewOffset);\n\n return Buffer.concat([\n bytes.subarray(0, sharedOffset),\n bytes.subarray(viewOffset, it.offset)\n ]);\n }\n\n onEndEncode(changeTrees = this.root.changes) {\n const changeTreesIterator = changeTrees.entries();\n for (const [changeTree, _] of changeTreesIterator) {\n changeTree.endEncode();\n // changeTree.changes.clear();\n\n // // ArraySchema and MapSchema have a custom \"encode end\" method\n // changeTree.ref[$onEncodeEnd]?.();\n\n // // Not a new instance anymore\n // delete changeTree[$isNew];\n\n }\n }\n\n discardChanges() {\n // discard shared changes\n if (this.root.changes.size > 0) {\n this.onEndEncode(this.root.changes);\n this.root.changes.clear();\n }\n // discard filtered changes\n if (this.root.filteredChanges.size > 0) {\n this.onEndEncode(this.root.filteredChanges);\n this.root.filteredChanges.clear();\n }\n }\n\n tryEncodeTypeId (bytes: Buffer, baseType: typeof Schema, targetType: typeof Schema, it: Iterator) {\n const baseTypeId = this.context.getTypeId(baseType);\n const targetTypeId = this.context.getTypeId(targetType);\n\n if (baseTypeId !== targetTypeId) {\n bytes[it.offset++] = TYPE_ID & 255;\n encode.number(bytes, targetTypeId, it);\n }\n }\n}\n"]}