@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.
- package/README.md +131 -61
- package/build/cjs/index.js +966 -563
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +965 -562
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +966 -563
- package/lib/Metadata.d.ts +15 -4
- package/lib/Metadata.js +86 -18
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.d.ts +2 -3
- package/lib/Reflection.js +24 -28
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.d.ts +2 -2
- package/lib/Schema.js +28 -41
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +1 -21
- package/lib/annotations.js +73 -153
- package/lib/annotations.js.map +1 -1
- package/lib/bench_encode.d.ts +1 -0
- package/lib/bench_encode.js +142 -0
- package/lib/bench_encode.js.map +1 -0
- package/lib/codegen/api.js +1 -2
- package/lib/codegen/api.js.map +1 -1
- package/lib/codegen/languages/cpp.js +1 -2
- package/lib/codegen/languages/cpp.js.map +1 -1
- package/lib/codegen/languages/csharp.js +1 -2
- package/lib/codegen/languages/csharp.js.map +1 -1
- package/lib/codegen/languages/haxe.js +1 -2
- package/lib/codegen/languages/haxe.js.map +1 -1
- package/lib/codegen/languages/java.js +1 -2
- package/lib/codegen/languages/java.js.map +1 -1
- package/lib/codegen/languages/js.js +1 -2
- package/lib/codegen/languages/js.js.map +1 -1
- package/lib/codegen/languages/lua.js +1 -2
- package/lib/codegen/languages/lua.js.map +1 -1
- package/lib/codegen/languages/ts.js +1 -2
- package/lib/codegen/languages/ts.js.map +1 -1
- package/lib/codegen/parser.js +2 -3
- package/lib/codegen/parser.js.map +1 -1
- package/lib/codegen/types.js +3 -3
- package/lib/codegen/types.js.map +1 -1
- package/lib/debug.d.ts +1 -0
- package/lib/debug.js +52 -0
- package/lib/debug.js.map +1 -0
- package/lib/decoder/DecodeOperation.d.ts +0 -1
- package/lib/decoder/DecodeOperation.js +23 -11
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/Decoder.d.ts +6 -7
- package/lib/decoder/Decoder.js +8 -8
- package/lib/decoder/Decoder.js.map +1 -1
- package/lib/decoder/ReferenceTracker.js +3 -2
- package/lib/decoder/ReferenceTracker.js.map +1 -1
- package/lib/decoder/strategy/RawChanges.js +1 -2
- package/lib/decoder/strategy/RawChanges.js.map +1 -1
- package/lib/decoder/strategy/StateCallbacks.d.ts +44 -11
- package/lib/decoder/strategy/StateCallbacks.js +75 -65
- package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
- package/lib/encoder/ChangeTree.d.ts +9 -19
- package/lib/encoder/ChangeTree.js +129 -145
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.d.ts +1 -5
- package/lib/encoder/EncodeOperation.js +74 -58
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +10 -8
- package/lib/encoder/Encoder.js +89 -56
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +17 -0
- package/lib/encoder/Root.js +44 -0
- package/lib/encoder/Root.js.map +1 -0
- package/lib/encoder/StateView.d.ts +2 -2
- package/lib/encoder/StateView.js +49 -59
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/encoding/assert.d.ts +2 -1
- package/lib/encoding/assert.js +5 -5
- package/lib/encoding/assert.js.map +1 -1
- package/lib/encoding/decode.js +21 -22
- package/lib/encoding/decode.js.map +1 -1
- package/lib/encoding/encode.d.ts +2 -2
- package/lib/encoding/encode.js +40 -39
- package/lib/encoding/encode.js.map +1 -1
- package/lib/encoding/spec.d.ts +2 -1
- package/lib/encoding/spec.js +1 -0
- package/lib/encoding/spec.js.map +1 -1
- package/lib/index.d.ts +6 -3
- package/lib/index.js +18 -13
- package/lib/index.js.map +1 -1
- package/lib/types/TypeContext.d.ts +23 -0
- package/lib/types/TypeContext.js +102 -0
- package/lib/types/TypeContext.js.map +1 -0
- package/lib/types/custom/ArraySchema.d.ts +2 -2
- package/lib/types/custom/ArraySchema.js +6 -9
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/CollectionSchema.js +1 -0
- package/lib/types/custom/CollectionSchema.js.map +1 -1
- package/lib/types/custom/MapSchema.js +5 -0
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/lib/types/custom/SetSchema.js +1 -0
- package/lib/types/custom/SetSchema.js.map +1 -1
- package/lib/types/registry.js +3 -4
- package/lib/types/registry.js.map +1 -1
- package/lib/types/symbols.d.ts +1 -0
- package/lib/types/symbols.js +2 -1
- package/lib/types/symbols.js.map +1 -1
- package/lib/types/utils.js +1 -2
- package/lib/types/utils.js.map +1 -1
- package/lib/utils.js +3 -4
- package/lib/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/Metadata.ts +104 -26
- package/src/Reflection.ts +26 -28
- package/src/Schema.ts +35 -47
- package/src/annotations.ts +82 -176
- package/src/bench_encode.ts +121 -0
- package/src/debug.ts +56 -0
- package/src/decoder/DecodeOperation.ts +28 -11
- package/src/decoder/Decoder.ts +13 -11
- package/src/decoder/ReferenceTracker.ts +3 -2
- package/src/decoder/strategy/StateCallbacks.ts +152 -81
- package/src/encoder/ChangeTree.ts +147 -166
- package/src/encoder/EncodeOperation.ts +93 -70
- package/src/encoder/Encoder.ts +111 -65
- package/src/encoder/Root.ts +51 -0
- package/src/encoder/StateView.ts +53 -69
- package/src/encoding/assert.ts +4 -3
- package/src/encoding/decode.ts +1 -2
- package/src/encoding/encode.ts +25 -22
- package/src/encoding/spec.ts +1 -0
- package/src/index.ts +8 -14
- package/src/types/TypeContext.ts +122 -0
- package/src/types/custom/ArraySchema.ts +10 -2
- package/src/types/custom/CollectionSchema.ts +1 -0
- package/src/types/custom/MapSchema.ts +6 -0
- package/src/types/custom/SetSchema.ts +1 -0
- 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 =
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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 =
|
|
47
|
-
//
|
|
48
|
-
// ensure a ArraySchema has been provided
|
|
49
|
-
//
|
|
50
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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(
|
|
97
|
+
const dynamicIndex = changeTree.ref['$indexes'].get(index);
|
|
106
98
|
encode.string(bytes, dynamicIndex, it);
|
|
107
99
|
}
|
|
108
100
|
}
|
|
109
|
-
const type = changeTree.getType(
|
|
110
|
-
const value = changeTree.getValue(
|
|
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,
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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,
|
|
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,
|
|
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}"]}
|
package/lib/encoder/Encoder.d.ts
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
import type { Schema } from "../Schema";
|
|
3
|
-
import { TypeContext } from "../
|
|
2
|
+
import { TypeContext } from "../types/TypeContext";
|
|
4
3
|
import type { Iterator } from "../encoding/decode";
|
|
5
|
-
import {
|
|
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(
|
|
14
|
-
protected
|
|
15
|
-
encode(it?: Iterator, view?: StateView,
|
|
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<
|
|
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
|
}
|
package/lib/encoder/Encoder.js
CHANGED
|
@@ -1,43 +1,48 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Encoder = void 0;
|
|
4
|
-
const
|
|
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
|
|
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(
|
|
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
|
|
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
|
-
|
|
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,
|
|
31
|
-
|
|
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
|
|
36
|
-
for (const [changeTree, changes] of
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
|
|
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 >
|
|
79
|
-
const newSize = (0, utils_1.getNextPowerOf2)(
|
|
80
|
-
console.warn(
|
|
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
|
-
|
|
85
|
-
|
|
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 (
|
|
112
|
+
if (shouldClearChanges) {
|
|
92
113
|
//
|
|
93
114
|
// FIXME: avoid iterating over change trees twice.
|
|
94
115
|
//
|
|
95
116
|
this.onEndEncode(changeTrees);
|
|
96
117
|
}
|
|
97
|
-
|
|
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(
|
|
103
|
-
//
|
|
104
|
-
|
|
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(
|
|
111
|
-
// this.
|
|
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.
|
|
116
|
-
bytes.
|
|
133
|
+
bytes.subarray(0, sharedOffset),
|
|
134
|
+
bytes.subarray(viewOffset, it.offset)
|
|
117
135
|
]);
|
|
118
136
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
//
|
|
132
|
-
this.
|
|
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.
|
|
161
|
-
bytes.
|
|
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"]}
|