@colyseus/schema 3.0.0-alpha.31 → 3.0.0-alpha.33
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/build/cjs/index.js +41 -50
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +41 -50
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +41 -50
- package/lib/bench_encode.js +21 -40
- package/lib/bench_encode.js.map +1 -1
- package/lib/decoder/DecodeOperation.js +3 -1
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/encoder/ChangeTree.js +0 -1
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.js +8 -38
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.js +8 -4
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +2 -2
- package/lib/encoder/Root.js +22 -6
- package/lib/encoder/Root.js.map +1 -1
- package/package.json +1 -1
- package/src/bench_encode.ts +21 -43
- package/src/decoder/DecodeOperation.ts +8 -1
- package/src/encoder/ChangeTree.ts +0 -2
- package/src/encoder/EncodeOperation.ts +5 -31
- package/src/encoder/Encoder.ts +10 -5
- package/src/encoder/Root.ts +28 -6
|
@@ -5,21 +5,11 @@ exports.encodeValue = encodeValue;
|
|
|
5
5
|
const spec_1 = require("../encoding/spec");
|
|
6
6
|
const symbols_1 = require("../types/symbols");
|
|
7
7
|
const encode = require("../encoding/encode");
|
|
8
|
-
function encodeValue(encoder, bytes,
|
|
9
|
-
// ref: Ref,
|
|
10
|
-
type, value,
|
|
11
|
-
// field: string | number,
|
|
12
|
-
operation, it) {
|
|
8
|
+
function encodeValue(encoder, bytes, type, value, operation, it) {
|
|
13
9
|
if (typeof (type) === "string") {
|
|
14
|
-
//
|
|
15
|
-
// Primitive values
|
|
16
|
-
//
|
|
17
|
-
// assertType(value, type as string, ref as Schema, field);
|
|
18
10
|
encode[type]?.(bytes, value, it);
|
|
19
11
|
}
|
|
20
12
|
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);
|
|
23
13
|
//
|
|
24
14
|
// Encode refId for this instance.
|
|
25
15
|
// The actual instance is going to be encoded on next `changeTree` iteration.
|
|
@@ -31,14 +21,6 @@ operation, it) {
|
|
|
31
21
|
}
|
|
32
22
|
}
|
|
33
23
|
else {
|
|
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);
|
|
42
24
|
//
|
|
43
25
|
// Encode refId for this instance.
|
|
44
26
|
// The actual instance is going to be encoded on next `changeTree` iteration.
|
|
@@ -58,14 +40,10 @@ const encodeSchemaOperation = function (encoder, bytes, changeTree, index, opera
|
|
|
58
40
|
return;
|
|
59
41
|
}
|
|
60
42
|
const ref = changeTree.ref;
|
|
61
|
-
const metadata = ref
|
|
43
|
+
const metadata = ref.constructor[Symbol.metadata];
|
|
62
44
|
const field = metadata[index];
|
|
63
45
|
// TODO: inline this function call small performance gain
|
|
64
|
-
encodeValue(encoder, bytes,
|
|
65
|
-
// ref,
|
|
66
|
-
metadata[index].type, ref[field.name],
|
|
67
|
-
// index,
|
|
68
|
-
operation, it);
|
|
46
|
+
encodeValue(encoder, bytes, metadata[index].type, ref[field.name], operation, it);
|
|
69
47
|
};
|
|
70
48
|
exports.encodeSchemaOperation = encodeSchemaOperation;
|
|
71
49
|
/**
|
|
@@ -89,7 +67,7 @@ const encodeKeyValueOperation = function (encoder, bytes, changeTree, index, ope
|
|
|
89
67
|
//
|
|
90
68
|
// encode "alias" for dynamic fields (maps)
|
|
91
69
|
//
|
|
92
|
-
if ((operation & spec_1.OPERATION.ADD)
|
|
70
|
+
if ((operation & spec_1.OPERATION.ADD) === spec_1.OPERATION.ADD) { // ADD or DELETE_AND_ADD
|
|
93
71
|
if (typeof (ref['set']) === "function") {
|
|
94
72
|
//
|
|
95
73
|
// MapSchema dynamic key
|
|
@@ -98,8 +76,8 @@ const encodeKeyValueOperation = function (encoder, bytes, changeTree, index, ope
|
|
|
98
76
|
encode.string(bytes, dynamicIndex, it);
|
|
99
77
|
}
|
|
100
78
|
}
|
|
101
|
-
const type =
|
|
102
|
-
const value =
|
|
79
|
+
const type = ref[symbols_1.$childType];
|
|
80
|
+
const value = ref[symbols_1.$getByIndex](index);
|
|
103
81
|
// try { throw new Error(); } catch (e) {
|
|
104
82
|
// // only print if not coming from Reflection.ts
|
|
105
83
|
// if (!e.stack.includes("src/Reflection.ts")) {
|
|
@@ -113,11 +91,7 @@ const encodeKeyValueOperation = function (encoder, bytes, changeTree, index, ope
|
|
|
113
91
|
// }
|
|
114
92
|
// }
|
|
115
93
|
// TODO: inline this function call small performance gain
|
|
116
|
-
encodeValue(encoder, bytes,
|
|
117
|
-
// ref,
|
|
118
|
-
type, value,
|
|
119
|
-
// index,
|
|
120
|
-
operation, it);
|
|
94
|
+
encodeValue(encoder, bytes, type, value, operation, it);
|
|
121
95
|
};
|
|
122
96
|
exports.encodeKeyValueOperation = encodeKeyValueOperation;
|
|
123
97
|
/**
|
|
@@ -162,11 +136,7 @@ const encodeArray = function (encoder, bytes, changeTree, field, operation, it,
|
|
|
162
136
|
// items: ref.toJSON(),
|
|
163
137
|
// });
|
|
164
138
|
// TODO: inline this function call small performance gain
|
|
165
|
-
encodeValue(encoder, bytes,
|
|
166
|
-
// ref,
|
|
167
|
-
type, value,
|
|
168
|
-
// field,
|
|
169
|
-
operation, it);
|
|
139
|
+
encodeValue(encoder, bytes, type, value, operation, it);
|
|
170
140
|
};
|
|
171
141
|
exports.encodeArray = encodeArray;
|
|
172
142
|
//# 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\";\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
|
+
{"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, $childType, $getByIndex } 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 type: any,\n value: any,\n operation: OPERATION,\n it: Iterator,\n) {\n if (typeof (type) === \"string\") {\n encode[type]?.(bytes, value, it);\n\n } else if (type[Symbol.metadata] !== undefined) {\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 // 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 metadata[index].type,\n ref[field.name],\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 = ref[$childType];\n const value = ref[$getByIndex](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 type,\n value,\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 type,\n value,\n operation,\n it\n );\n}"]}
|
package/lib/encoder/Encoder.js
CHANGED
|
@@ -34,7 +34,7 @@ class Encoder {
|
|
|
34
34
|
const shouldClearChanges = !isEncodeAll && !hasView;
|
|
35
35
|
for (const [changeTree, changes] of changeTrees.entries()) {
|
|
36
36
|
const ref = changeTree.ref;
|
|
37
|
-
const ctor = ref
|
|
37
|
+
const ctor = ref.constructor;
|
|
38
38
|
const encoder = ctor[symbols_1.$encoder];
|
|
39
39
|
const filter = ctor[symbols_1.$filter];
|
|
40
40
|
// try { throw new Error(); } catch (e) {
|
|
@@ -58,8 +58,7 @@ class Encoder {
|
|
|
58
58
|
buffer[it.offset++] = spec_1.SWITCH_TO_STRUCTURE & 255;
|
|
59
59
|
encode.number(buffer, changeTree.refId, it);
|
|
60
60
|
}
|
|
61
|
-
const
|
|
62
|
-
for (const [fieldIndex, operation] of changesIterator) {
|
|
61
|
+
for (const [fieldIndex, operation] of changes.entries()) {
|
|
63
62
|
//
|
|
64
63
|
// first pass (encodeAll), identify "filtered" operations without encoding them
|
|
65
64
|
// they will be encoded per client, based on their view.
|
|
@@ -85,7 +84,12 @@ class Encoder {
|
|
|
85
84
|
encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);
|
|
86
85
|
}
|
|
87
86
|
// if (shouldClearChanges) {
|
|
88
|
-
// changeTree.endEncode();
|
|
87
|
+
// // changeTree.endEncode();
|
|
88
|
+
// changeTree.changes.clear();
|
|
89
|
+
// // ArraySchema and MapSchema have a custom "encode end" method
|
|
90
|
+
// changeTree.ref[$onEncodeEnd]?.();
|
|
91
|
+
// // Not a new instance anymore
|
|
92
|
+
// delete changeTree[$isNew];
|
|
89
93
|
// }
|
|
90
94
|
}
|
|
91
95
|
if (it.offset > buffer.byteLength) {
|
|
@@ -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 \"../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"]}
|
|
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 for (const [fieldIndex, operation] of changes.entries()) {\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 // 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 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"]}
|
package/lib/encoder/Root.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export declare class Root {
|
|
|
11
11
|
filteredChanges: Map<ChangeTree<any>, Map<number, OPERATION>>;
|
|
12
12
|
constructor(types: TypeContext);
|
|
13
13
|
getNextUniqueId(): number;
|
|
14
|
-
add(changeTree: ChangeTree):
|
|
15
|
-
remove(changeTree: ChangeTree):
|
|
14
|
+
add(changeTree: ChangeTree): number;
|
|
15
|
+
remove(changeTree: ChangeTree): number;
|
|
16
16
|
clear(): void;
|
|
17
17
|
}
|
package/lib/encoder/Root.js
CHANGED
|
@@ -17,24 +17,40 @@ class Root {
|
|
|
17
17
|
return this.nextUniqueId++;
|
|
18
18
|
}
|
|
19
19
|
add(changeTree) {
|
|
20
|
-
const
|
|
21
|
-
|
|
20
|
+
const previousRefCount = this.refCount.get(changeTree);
|
|
21
|
+
if (previousRefCount === 0) {
|
|
22
|
+
//
|
|
23
|
+
// When a ChangeTree is re-added, it means that it was previously removed.
|
|
24
|
+
// We need to re-add all changes to the `changes` map.
|
|
25
|
+
//
|
|
26
|
+
changeTree.allChanges.forEach((operation, index) => {
|
|
27
|
+
changeTree.changes.set(index, operation);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const refCount = (previousRefCount || 0) + 1;
|
|
31
|
+
this.refCount.set(changeTree, refCount);
|
|
32
|
+
return refCount;
|
|
22
33
|
}
|
|
23
34
|
remove(changeTree) {
|
|
24
|
-
const refCount = this.refCount.get(changeTree);
|
|
25
|
-
if (refCount <=
|
|
35
|
+
const refCount = (this.refCount.get(changeTree)) - 1;
|
|
36
|
+
if (refCount <= 0) {
|
|
37
|
+
//
|
|
38
|
+
// Only remove "root" reference if it's the last reference
|
|
39
|
+
//
|
|
40
|
+
changeTree.root = undefined;
|
|
26
41
|
this.allChanges.delete(changeTree);
|
|
27
42
|
this.changes.delete(changeTree);
|
|
28
43
|
if (changeTree.isFiltered || changeTree.isPartiallyFiltered) {
|
|
29
44
|
this.allFilteredChanges.delete(changeTree);
|
|
30
45
|
this.filteredChanges.delete(changeTree);
|
|
31
46
|
}
|
|
32
|
-
this.refCount.
|
|
47
|
+
this.refCount.set(changeTree, 0);
|
|
33
48
|
}
|
|
34
49
|
else {
|
|
35
|
-
this.refCount.set(changeTree, refCount
|
|
50
|
+
this.refCount.set(changeTree, refCount);
|
|
36
51
|
}
|
|
37
52
|
changeTree.forEachChild((child, _) => this.remove(child));
|
|
53
|
+
return refCount;
|
|
38
54
|
}
|
|
39
55
|
clear() {
|
|
40
56
|
this.changes.clear();
|
package/lib/encoder/Root.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Root.js","sourceRoot":"","sources":["../../src/encoder/Root.ts"],"names":[],"mappings":";;;AAIA,MAAa,IAAI;IAYb,YAAmB,KAAkB;QAAlB,UAAK,GAAL,KAAK,CAAa;QAX3B,iBAAY,GAAW,CAAC,CAAC;QACnC,aAAQ,GAAG,IAAI,OAAO,EAAsB,CAAC;QAE7C,cAAc;QACd,eAAU,GAAG,IAAI,GAAG,EAAsC,CAAC;QAC3D,uBAAkB,GAAG,IAAI,GAAG,EAAsC,CAAC;QAEnE,gCAAgC;QAChC,YAAO,GAAG,IAAI,GAAG,EAAsC,CAAC;QACxD,oBAAe,GAAG,IAAI,GAAG,EAAsC,CAAC;IAEvB,CAAC;IAE1C,eAAe;QACX,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;IAC/B,CAAC;IAED,GAAG,CAAC,UAAsB;QACtB,MAAM,
|
|
1
|
+
{"version":3,"file":"Root.js","sourceRoot":"","sources":["../../src/encoder/Root.ts"],"names":[],"mappings":";;;AAIA,MAAa,IAAI;IAYb,YAAmB,KAAkB;QAAlB,UAAK,GAAL,KAAK,CAAa;QAX3B,iBAAY,GAAW,CAAC,CAAC;QACnC,aAAQ,GAAG,IAAI,OAAO,EAAsB,CAAC;QAE7C,cAAc;QACd,eAAU,GAAG,IAAI,GAAG,EAAsC,CAAC;QAC3D,uBAAkB,GAAG,IAAI,GAAG,EAAsC,CAAC;QAEnE,gCAAgC;QAChC,YAAO,GAAG,IAAI,GAAG,EAAsC,CAAC;QACxD,oBAAe,GAAG,IAAI,GAAG,EAAsC,CAAC;IAEvB,CAAC;IAE1C,eAAe;QACX,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;IAC/B,CAAC;IAED,GAAG,CAAC,UAAsB;QACtB,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAEvD,IAAI,gBAAgB,KAAK,CAAC,EAAE,CAAC;YACzB,EAAE;YACF,0EAA0E;YAC1E,sDAAsD;YACtD,EAAE;YACF,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE;gBAC/C,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YAC7C,CAAC,CAAC,CAAC;QACP,CAAC;QAED,MAAM,QAAQ,GAAG,CAAC,gBAAgB,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAExC,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED,MAAM,CAAC,UAAsB;QACzB,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC;QAErD,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YAChB,EAAE;YACF,0DAA0D;YAC1D,EAAE;YACF,UAAU,CAAC,IAAI,GAAG,SAAS,CAAC;YAE5B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACnC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAEhC,IAAI,UAAU,CAAC,UAAU,IAAI,UAAU,CAAC,mBAAmB,EAAE,CAAC;gBAC1D,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBAC3C,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC5C,CAAC;YAED,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QAErC,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC5C,CAAC;QAED,UAAU,CAAC,YAAY,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAE1D,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED,KAAK;QACD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;CACJ;AApED,oBAoEC","sourcesContent":["import { OPERATION } from \"../encoding/spec\";\nimport { TypeContext } from \"../types/TypeContext\";\nimport { ChangeTree } from \"./ChangeTree\";\n\nexport class Root {\n protected nextUniqueId: number = 0;\n refCount = new WeakMap<ChangeTree, number>();\n\n // all changes\n allChanges = new Map<ChangeTree, Map<number, OPERATION>>();\n allFilteredChanges = new Map<ChangeTree, Map<number, OPERATION>>();\n\n // pending changes to be encoded\n changes = new Map<ChangeTree, Map<number, OPERATION>>();\n filteredChanges = new Map<ChangeTree, Map<number, OPERATION>>();\n\n constructor(public types: TypeContext) { }\n\n getNextUniqueId() {\n return this.nextUniqueId++;\n }\n\n add(changeTree: ChangeTree) {\n const previousRefCount = this.refCount.get(changeTree);\n\n if (previousRefCount === 0) {\n //\n // When a ChangeTree is re-added, it means that it was previously removed.\n // We need to re-add all changes to the `changes` map.\n //\n changeTree.allChanges.forEach((operation, index) => {\n changeTree.changes.set(index, operation);\n });\n }\n\n const refCount = (previousRefCount || 0) + 1;\n this.refCount.set(changeTree, refCount);\n\n return refCount;\n }\n\n remove(changeTree: ChangeTree) {\n const refCount = (this.refCount.get(changeTree)) - 1;\n\n if (refCount <= 0) {\n //\n // Only remove \"root\" reference if it's the last reference\n //\n changeTree.root = undefined;\n\n this.allChanges.delete(changeTree);\n this.changes.delete(changeTree);\n\n if (changeTree.isFiltered || changeTree.isPartiallyFiltered) {\n this.allFilteredChanges.delete(changeTree);\n this.filteredChanges.delete(changeTree);\n }\n\n this.refCount.set(changeTree, 0);\n\n } else {\n this.refCount.set(changeTree, refCount);\n }\n\n changeTree.forEachChild((child, _) => this.remove(child));\n\n return refCount;\n }\n\n clear() {\n this.changes.clear();\n }\n}\n"]}
|
package/package.json
CHANGED
package/src/bench_encode.ts
CHANGED
|
@@ -34,50 +34,28 @@ const state = new State();
|
|
|
34
34
|
Encoder.BUFFER_SIZE = 4096 * 4096;
|
|
35
35
|
const encoder = new Encoder(state);
|
|
36
36
|
|
|
37
|
-
// // SINGLE TESTING
|
|
38
|
-
// console.log("> Will create player...");
|
|
39
|
-
// const player = new Player();
|
|
40
|
-
// console.log("... players.set()")
|
|
41
|
-
// state.players.set(`p-${nanoid()}`, player);
|
|
42
|
-
// player.position.x = 100;
|
|
43
|
-
// player.position.y = 100;
|
|
44
|
-
// console.log("> Will create Item...");
|
|
45
|
-
// const item = new Item();
|
|
46
|
-
// item.price = 50;
|
|
47
|
-
|
|
48
|
-
// console.log("> Will create Attribute...");
|
|
49
|
-
// const attr = new Attribute();
|
|
50
|
-
// attr.name = `Attribute 1`;
|
|
51
|
-
// attr.value = 1;
|
|
52
|
-
// console.log("... item.attributes.push()")
|
|
53
|
-
// item.attributes.push(attr);
|
|
54
|
-
|
|
55
|
-
// console.log("... player.items.set()")
|
|
56
|
-
// player.items.set(`item-1`, item);
|
|
57
37
|
|
|
58
38
|
let now = Date.now();
|
|
59
|
-
for (let i = 0; i < 10000; i++) {
|
|
60
|
-
// for (let i = 0; i < 10; i++) {
|
|
61
|
-
const player = new Player();
|
|
62
|
-
state.players.set(`p-${nanoid()}`, player);
|
|
63
|
-
|
|
64
|
-
player.position.x = (i + 1) * 100;
|
|
65
|
-
player.position.y = (i + 1) * 100;
|
|
66
|
-
for (let j = 0; j < 10; j++) {
|
|
67
|
-
const item = new Item();
|
|
68
|
-
player.items.set(`item-${j}`, item);
|
|
69
|
-
item.price = (i + 1) * 50;
|
|
70
|
-
for (let k = 0; k < 5; k++) {
|
|
71
|
-
const attr = new Attribute();
|
|
72
|
-
attr.name = `Attribute ${k}`;
|
|
73
|
-
attr.value = k;
|
|
74
|
-
item.attributes.push(attr);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
console.log("time to make changes:", Date.now() - now);
|
|
79
39
|
|
|
80
|
-
//
|
|
40
|
+
// for (let i = 0; i < 10000; i++) {
|
|
41
|
+
// const player = new Player();
|
|
42
|
+
// state.players.set(`p-${nanoid()}`, player);
|
|
43
|
+
//
|
|
44
|
+
// player.position.x = (i + 1) * 100;
|
|
45
|
+
// player.position.y = (i + 1) * 100;
|
|
46
|
+
// for (let j = 0; j < 10; j++) {
|
|
47
|
+
// const item = new Item();
|
|
48
|
+
// player.items.set(`item-${j}`, item);
|
|
49
|
+
// item.price = (i + 1) * 50;
|
|
50
|
+
// for (let k = 0; k < 5; k++) {
|
|
51
|
+
// const attr = new Attribute();
|
|
52
|
+
// attr.name = `Attribute ${k}`;
|
|
53
|
+
// attr.value = k;
|
|
54
|
+
// item.attributes.push(attr);
|
|
55
|
+
// }
|
|
56
|
+
// }
|
|
57
|
+
// }
|
|
58
|
+
// console.log("time to make changes:", Date.now() - now);
|
|
81
59
|
|
|
82
60
|
|
|
83
61
|
// measure time to .encodeAll()
|
|
@@ -112,10 +90,10 @@ for (let i = 0; i < 100; i++) {
|
|
|
112
90
|
console.log("time to make changes:", Date.now() - now);
|
|
113
91
|
|
|
114
92
|
now = Date.now();
|
|
115
|
-
|
|
93
|
+
encoder.encode();
|
|
116
94
|
encoder.discardChanges();
|
|
117
95
|
console.log("time to encode:", Date.now() - now);
|
|
118
96
|
}
|
|
119
97
|
console.log("time for all encodes:", Date.now() - allEncodes);
|
|
120
98
|
|
|
121
|
-
|
|
99
|
+
console.log(Array.from(encoder.encodeAll()).length, "bytes");
|
|
@@ -105,7 +105,14 @@ export function decodeValue(
|
|
|
105
105
|
value = decoder.createInstanceOfType(childType);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
$root.addRef(
|
|
108
|
+
$root.addRef(
|
|
109
|
+
refId,
|
|
110
|
+
value,
|
|
111
|
+
(
|
|
112
|
+
value !== previousValue || // increment ref count if value has changed
|
|
113
|
+
(operation === OPERATION.DELETE_AND_ADD && value === previousValue) // increment ref count if the same instance is being added again
|
|
114
|
+
)
|
|
115
|
+
);
|
|
109
116
|
}
|
|
110
117
|
|
|
111
118
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OPERATION } from "../encoding/spec";
|
|
2
|
-
import { $changes } from "../types/symbols";
|
|
2
|
+
import { $changes, $childType, $getByIndex } from "../types/symbols";
|
|
3
3
|
import { getType } from "../types/registry";
|
|
4
4
|
|
|
5
5
|
import * as encode from "../encoding/encode";
|
|
@@ -28,25 +28,15 @@ export type EncodeOperation<T extends Ref = any> = (
|
|
|
28
28
|
export function encodeValue(
|
|
29
29
|
encoder: Encoder,
|
|
30
30
|
bytes: Buffer,
|
|
31
|
-
// ref: Ref,
|
|
32
31
|
type: any,
|
|
33
32
|
value: any,
|
|
34
|
-
// field: string | number,
|
|
35
33
|
operation: OPERATION,
|
|
36
34
|
it: Iterator,
|
|
37
35
|
) {
|
|
38
36
|
if (typeof (type) === "string") {
|
|
39
|
-
//
|
|
40
|
-
// Primitive values
|
|
41
|
-
//
|
|
42
|
-
// assertType(value, type as string, ref as Schema, field);
|
|
43
|
-
|
|
44
37
|
encode[type]?.(bytes, value, it);
|
|
45
38
|
|
|
46
39
|
} else if (type[Symbol.metadata] !== undefined) {
|
|
47
|
-
// // TODO: move this to the `@type()` annotation
|
|
48
|
-
// assertInstanceType(value, type as typeof Schema, ref as Schema, field);
|
|
49
|
-
|
|
50
40
|
//
|
|
51
41
|
// Encode refId for this instance.
|
|
52
42
|
// The actual instance is going to be encoded on next `changeTree` iteration.
|
|
@@ -59,16 +49,6 @@ export function encodeValue(
|
|
|
59
49
|
}
|
|
60
50
|
|
|
61
51
|
} else {
|
|
62
|
-
// //
|
|
63
|
-
// // Custom type (MapSchema, ArraySchema, etc)
|
|
64
|
-
// //
|
|
65
|
-
// const definition = getType(Object.keys(type)[0]);
|
|
66
|
-
|
|
67
|
-
// //
|
|
68
|
-
// // ensure a ArraySchema has been provided
|
|
69
|
-
// //
|
|
70
|
-
// assertInstanceType(ref[field], definition.constructor, ref as Schema, field);
|
|
71
|
-
|
|
72
52
|
//
|
|
73
53
|
// Encode refId for this instance.
|
|
74
54
|
// The actual instance is going to be encoded on next `changeTree` iteration.
|
|
@@ -98,17 +78,15 @@ export const encodeSchemaOperation: EncodeOperation = function (
|
|
|
98
78
|
}
|
|
99
79
|
|
|
100
80
|
const ref = changeTree.ref;
|
|
101
|
-
const metadata: Metadata = ref
|
|
81
|
+
const metadata: Metadata = ref.constructor[Symbol.metadata];
|
|
102
82
|
const field = metadata[index];
|
|
103
83
|
|
|
104
84
|
// TODO: inline this function call small performance gain
|
|
105
85
|
encodeValue(
|
|
106
86
|
encoder,
|
|
107
87
|
bytes,
|
|
108
|
-
// ref,
|
|
109
88
|
metadata[index].type,
|
|
110
89
|
ref[field.name],
|
|
111
|
-
// index,
|
|
112
90
|
operation,
|
|
113
91
|
it
|
|
114
92
|
);
|
|
@@ -147,7 +125,7 @@ export const encodeKeyValueOperation: EncodeOperation = function (
|
|
|
147
125
|
//
|
|
148
126
|
// encode "alias" for dynamic fields (maps)
|
|
149
127
|
//
|
|
150
|
-
if ((operation & OPERATION.ADD)
|
|
128
|
+
if ((operation & OPERATION.ADD) === OPERATION.ADD) { // ADD or DELETE_AND_ADD
|
|
151
129
|
if (typeof(ref['set']) === "function") {
|
|
152
130
|
//
|
|
153
131
|
// MapSchema dynamic key
|
|
@@ -157,8 +135,8 @@ export const encodeKeyValueOperation: EncodeOperation = function (
|
|
|
157
135
|
}
|
|
158
136
|
}
|
|
159
137
|
|
|
160
|
-
const type =
|
|
161
|
-
const value =
|
|
138
|
+
const type = ref[$childType];
|
|
139
|
+
const value = ref[$getByIndex](index);
|
|
162
140
|
|
|
163
141
|
// try { throw new Error(); } catch (e) {
|
|
164
142
|
// // only print if not coming from Reflection.ts
|
|
@@ -177,10 +155,8 @@ export const encodeKeyValueOperation: EncodeOperation = function (
|
|
|
177
155
|
encodeValue(
|
|
178
156
|
encoder,
|
|
179
157
|
bytes,
|
|
180
|
-
// ref,
|
|
181
158
|
type,
|
|
182
159
|
value,
|
|
183
|
-
// index,
|
|
184
160
|
operation,
|
|
185
161
|
it
|
|
186
162
|
);
|
|
@@ -250,10 +226,8 @@ export const encodeArray: EncodeOperation = function (
|
|
|
250
226
|
encodeValue(
|
|
251
227
|
encoder,
|
|
252
228
|
bytes,
|
|
253
|
-
// ref,
|
|
254
229
|
type,
|
|
255
230
|
value,
|
|
256
|
-
// field,
|
|
257
231
|
operation,
|
|
258
232
|
it
|
|
259
233
|
);
|
package/src/encoder/Encoder.ts
CHANGED
|
@@ -60,7 +60,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
60
60
|
for (const [changeTree, changes] of changeTrees.entries()) {
|
|
61
61
|
const ref = changeTree.ref;
|
|
62
62
|
|
|
63
|
-
const ctor = ref
|
|
63
|
+
const ctor = ref.constructor;
|
|
64
64
|
const encoder = ctor[$encoder];
|
|
65
65
|
const filter = ctor[$filter];
|
|
66
66
|
|
|
@@ -88,9 +88,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
88
88
|
encode.number(buffer, changeTree.refId, it);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
for (const [fieldIndex, operation] of changesIterator) {
|
|
91
|
+
for (const [fieldIndex, operation] of changes.entries()) {
|
|
94
92
|
//
|
|
95
93
|
// first pass (encodeAll), identify "filtered" operations without encoding them
|
|
96
94
|
// they will be encoded per client, based on their view.
|
|
@@ -119,7 +117,14 @@ export class Encoder<T extends Schema = any> {
|
|
|
119
117
|
}
|
|
120
118
|
|
|
121
119
|
// if (shouldClearChanges) {
|
|
122
|
-
// changeTree.endEncode();
|
|
120
|
+
// // changeTree.endEncode();
|
|
121
|
+
// changeTree.changes.clear();
|
|
122
|
+
|
|
123
|
+
// // ArraySchema and MapSchema have a custom "encode end" method
|
|
124
|
+
// changeTree.ref[$onEncodeEnd]?.();
|
|
125
|
+
|
|
126
|
+
// // Not a new instance anymore
|
|
127
|
+
// delete changeTree[$isNew];
|
|
123
128
|
// }
|
|
124
129
|
}
|
|
125
130
|
|