@colyseus/schema 4.0.1 → 4.0.3
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/{lib → build}/Metadata.d.ts +2 -2
- package/{lib → build}/Reflection.d.ts +13 -13
- package/{lib → build}/Schema.d.ts +10 -10
- package/{lib → build}/annotations.d.ts +10 -10
- package/build/codegen/languages/cpp.d.ts +3 -0
- package/build/codegen/languages/csharp.d.ts +4 -0
- package/build/codegen/languages/haxe.d.ts +3 -0
- package/{lib → build}/codegen/languages/java.d.ts +2 -2
- package/build/codegen/languages/js.d.ts +3 -0
- package/build/codegen/languages/lua.d.ts +3 -0
- package/build/codegen/languages/ts.d.ts +3 -0
- package/{lib → build}/codegen/parser.d.ts +1 -1
- package/{lib → build}/decoder/DecodeOperation.d.ts +5 -5
- package/{lib → build}/decoder/Decoder.d.ts +7 -7
- package/{lib → build}/decoder/ReferenceTracker.d.ts +1 -1
- package/{lib → build}/decoder/strategy/Callbacks.d.ts +11 -11
- package/{lib → build}/decoder/strategy/RawChanges.d.ts +2 -2
- package/{lib → build}/decoder/strategy/getDecoderStateCallbacks.d.ts +3 -3
- package/{lib → build}/encoder/ChangeTree.d.ts +11 -11
- package/{lib → build}/encoder/EncodeOperation.d.ts +5 -5
- package/{lib → build}/encoder/Encoder.d.ts +6 -6
- package/{lib → build}/encoder/Root.d.ts +2 -2
- package/{lib → build}/encoder/StateView.d.ts +1 -1
- package/{lib → build}/encoding/assert.d.ts +6 -6
- package/{lib → build}/encoding/decode.d.ts +1 -1
- package/{lib → build}/encoding/encode.d.ts +1 -1
- package/build/{cjs/index.js → index.cjs} +1 -1
- package/build/index.cjs.map +1 -0
- package/build/index.d.ts +32 -0
- package/build/index.mjs.map +1 -0
- package/{lib → build}/types/HelperTypes.d.ts +6 -6
- package/{lib → build}/types/TypeContext.d.ts +1 -1
- package/{lib → build}/types/custom/ArraySchema.d.ts +8 -8
- package/{lib → build}/types/custom/CollectionSchema.d.ts +7 -7
- package/{lib → build}/types/custom/MapSchema.d.ts +7 -7
- package/{lib → build}/types/custom/SetSchema.d.ts +7 -7
- package/{lib → build}/types/registry.d.ts +2 -2
- package/{lib → build}/utils.d.ts +1 -1
- package/package.json +15 -14
- package/src/Metadata.ts +5 -5
- package/src/Reflection.ts +7 -7
- package/src/Schema.ts +11 -11
- package/src/annotations.ts +13 -13
- package/src/codegen/api.ts +10 -3
- package/src/codegen/cli.ts +2 -2
- package/src/codegen/languages/cpp.ts +2 -2
- package/src/codegen/languages/csharp.ts +3 -3
- package/src/codegen/languages/haxe.ts +2 -2
- package/src/codegen/languages/java.ts +2 -2
- package/src/codegen/languages/js.ts +2 -2
- package/src/codegen/languages/lua.ts +2 -2
- package/src/codegen/languages/ts.ts +2 -2
- package/src/codegen/parser.ts +7 -2
- package/src/codegen/types.ts +5 -0
- package/src/decoder/DecodeOperation.ts +14 -14
- package/src/decoder/Decoder.ts +11 -11
- package/src/decoder/ReferenceTracker.ts +8 -8
- package/src/decoder/strategy/Callbacks.ts +12 -12
- package/src/decoder/strategy/RawChanges.ts +2 -2
- package/src/decoder/strategy/getDecoderStateCallbacks.ts +10 -10
- package/src/encoder/ChangeTree.ts +13 -13
- package/src/encoder/EncodeOperation.ts +9 -9
- package/src/encoder/Encoder.ts +10 -10
- package/src/encoder/Root.ts +4 -4
- package/src/encoder/StateView.ts +7 -7
- package/src/encoding/assert.ts +6 -6
- package/src/encoding/decode.ts +1 -1
- package/src/encoding/encode.ts +1 -1
- package/src/index.ts +27 -27
- package/src/types/HelperTypes.ts +6 -6
- package/src/types/TypeContext.ts +3 -3
- package/src/types/custom/ArraySchema.ts +11 -11
- package/src/types/custom/CollectionSchema.ts +9 -9
- package/src/types/custom/MapSchema.ts +10 -10
- package/src/types/custom/SetSchema.ts +9 -9
- package/src/types/registry.ts +3 -3
- package/src/utils.ts +3 -3
- package/src/v3_bench.ts +1 -1
- package/build/cjs/index.js.map +0 -1
- package/build/esm/index.mjs.map +0 -1
- package/lib/Metadata.js +0 -260
- package/lib/Metadata.js.map +0 -1
- package/lib/Reflection.js +0 -182
- package/lib/Reflection.js.map +0 -1
- package/lib/Schema.js +0 -356
- package/lib/Schema.js.map +0 -1
- package/lib/annotations.js +0 -484
- package/lib/annotations.js.map +0 -1
- package/lib/bench_encode.d.ts +0 -1
- package/lib/bench_encode.js +0 -126
- package/lib/bench_encode.js.map +0 -1
- package/lib/codegen/api.js +0 -87
- package/lib/codegen/api.js.map +0 -1
- package/lib/codegen/argv.js +0 -41
- package/lib/codegen/argv.js.map +0 -1
- package/lib/codegen/cli.js +0 -63
- package/lib/codegen/cli.js.map +0 -1
- package/lib/codegen/languages/cpp.d.ts +0 -3
- package/lib/codegen/languages/cpp.js +0 -261
- package/lib/codegen/languages/cpp.js.map +0 -1
- package/lib/codegen/languages/csharp.d.ts +0 -4
- package/lib/codegen/languages/csharp.js +0 -157
- package/lib/codegen/languages/csharp.js.map +0 -1
- package/lib/codegen/languages/haxe.d.ts +0 -3
- package/lib/codegen/languages/haxe.js +0 -103
- package/lib/codegen/languages/haxe.js.map +0 -1
- package/lib/codegen/languages/java.js +0 -103
- package/lib/codegen/languages/java.js.map +0 -1
- package/lib/codegen/languages/js.d.ts +0 -3
- package/lib/codegen/languages/js.js +0 -104
- package/lib/codegen/languages/js.js.map +0 -1
- package/lib/codegen/languages/lua.d.ts +0 -3
- package/lib/codegen/languages/lua.js +0 -106
- package/lib/codegen/languages/lua.js.map +0 -1
- package/lib/codegen/languages/ts.d.ts +0 -3
- package/lib/codegen/languages/ts.js +0 -119
- package/lib/codegen/languages/ts.js.map +0 -1
- package/lib/codegen/parser.js +0 -364
- package/lib/codegen/parser.js.map +0 -1
- package/lib/codegen/types.js +0 -181
- package/lib/codegen/types.js.map +0 -1
- package/lib/decoder/DecodeOperation.js +0 -255
- package/lib/decoder/DecodeOperation.js.map +0 -1
- package/lib/decoder/Decoder.js +0 -118
- package/lib/decoder/Decoder.js.map +0 -1
- package/lib/decoder/ReferenceTracker.js +0 -139
- package/lib/decoder/ReferenceTracker.js.map +0 -1
- package/lib/decoder/strategy/Callbacks.js +0 -340
- package/lib/decoder/strategy/Callbacks.js.map +0 -1
- package/lib/decoder/strategy/RawChanges.js +0 -7
- package/lib/decoder/strategy/RawChanges.js.map +0 -1
- package/lib/decoder/strategy/getDecoderStateCallbacks.js +0 -277
- package/lib/decoder/strategy/getDecoderStateCallbacks.js.map +0 -1
- package/lib/encoder/ChangeTree.js +0 -542
- package/lib/encoder/ChangeTree.js.map +0 -1
- package/lib/encoder/EncodeOperation.js +0 -139
- package/lib/encoder/EncodeOperation.js.map +0 -1
- package/lib/encoder/Encoder.js +0 -208
- package/lib/encoder/Encoder.js.map +0 -1
- package/lib/encoder/Root.js +0 -233
- package/lib/encoder/Root.js.map +0 -1
- package/lib/encoder/StateView.js +0 -284
- package/lib/encoder/StateView.js.map +0 -1
- package/lib/encoding/assert.js +0 -55
- package/lib/encoding/assert.js.map +0 -1
- package/lib/encoding/decode.js +0 -221
- package/lib/encoding/decode.js.map +0 -1
- package/lib/encoding/encode.js +0 -282
- package/lib/encoding/encode.js.map +0 -1
- package/lib/encoding/spec.js +0 -29
- package/lib/encoding/spec.js.map +0 -1
- package/lib/index.d.ts +0 -32
- package/lib/index.js +0 -81
- package/lib/index.js.map +0 -1
- package/lib/symbol.shim.js +0 -4
- package/lib/symbol.shim.js.map +0 -1
- package/lib/types/HelperTypes.js +0 -3
- package/lib/types/HelperTypes.js.map +0 -1
- package/lib/types/TypeContext.js +0 -147
- package/lib/types/TypeContext.js.map +0 -1
- package/lib/types/custom/ArraySchema.js +0 -737
- package/lib/types/custom/ArraySchema.js.map +0 -1
- package/lib/types/custom/CollectionSchema.js +0 -174
- package/lib/types/custom/CollectionSchema.js.map +0 -1
- package/lib/types/custom/MapSchema.js +0 -226
- package/lib/types/custom/MapSchema.js.map +0 -1
- package/lib/types/custom/SetSchema.js +0 -182
- package/lib/types/custom/SetSchema.js.map +0 -1
- package/lib/types/registry.js +0 -37
- package/lib/types/registry.js.map +0 -1
- package/lib/types/symbols.js +0 -37
- package/lib/types/symbols.js.map +0 -1
- package/lib/types/utils.js +0 -16
- package/lib/types/utils.js.map +0 -1
- package/lib/utils.js +0 -54
- package/lib/utils.js.map +0 -1
- package/lib/v3_bench.js +0 -130
- package/lib/v3_bench.js.map +0 -1
- package/src/bench_encode.ts +0 -64
- /package/{lib → build}/codegen/api.d.ts +0 -0
- /package/{lib → build}/codegen/argv.d.ts +0 -0
- /package/{lib → build}/codegen/cli.d.ts +0 -0
- /package/{lib → build}/codegen/types.d.ts +0 -0
- /package/{lib → build}/encoding/spec.d.ts +0 -0
- /package/build/{umd/index.js → index.js} +0 -0
- /package/build/{esm/index.mjs → index.mjs} +0 -0
- /package/{lib → build}/symbol.shim.d.ts +0 -0
- /package/{lib → build}/types/symbols.d.ts +0 -0
- /package/{lib → build}/types/utils.d.ts +0 -0
- /package/{lib → build}/v3_bench.d.ts +0 -0
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.encodeArray = exports.encodeKeyValueOperation = exports.encodeSchemaOperation = void 0;
|
|
4
|
-
exports.encodeValue = encodeValue;
|
|
5
|
-
const spec_1 = require("../encoding/spec");
|
|
6
|
-
const symbols_1 = require("../types/symbols");
|
|
7
|
-
const encode_1 = require("../encoding/encode");
|
|
8
|
-
function encodeValue(encoder, bytes, type, value, operation, it) {
|
|
9
|
-
if (typeof (type) === "string") {
|
|
10
|
-
encode_1.encode[type]?.(bytes, value, it);
|
|
11
|
-
}
|
|
12
|
-
else if (type[Symbol.metadata] !== undefined) {
|
|
13
|
-
//
|
|
14
|
-
// Encode refId for this instance.
|
|
15
|
-
// The actual instance is going to be encoded on next `changeTree` iteration.
|
|
16
|
-
//
|
|
17
|
-
encode_1.encode.number(bytes, value[symbols_1.$refId], it);
|
|
18
|
-
// Try to encode inherited TYPE_ID if it's an ADD operation.
|
|
19
|
-
if ((operation & spec_1.OPERATION.ADD) === spec_1.OPERATION.ADD) {
|
|
20
|
-
encoder.tryEncodeTypeId(bytes, type, value.constructor, it);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
//
|
|
25
|
-
// Encode refId for this instance.
|
|
26
|
-
// The actual instance is going to be encoded on next `changeTree` iteration.
|
|
27
|
-
//
|
|
28
|
-
encode_1.encode.number(bytes, value[symbols_1.$refId], it);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Used for Schema instances.
|
|
33
|
-
* @private
|
|
34
|
-
*/
|
|
35
|
-
const encodeSchemaOperation = function (encoder, bytes, changeTree, index, operation, it, _, __, metadata) {
|
|
36
|
-
// "compress" field index + operation
|
|
37
|
-
bytes[it.offset++] = (index | operation) & 255;
|
|
38
|
-
// Do not encode value for DELETE operations
|
|
39
|
-
if (operation === spec_1.OPERATION.DELETE) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
const ref = changeTree.ref;
|
|
43
|
-
const field = metadata[index];
|
|
44
|
-
// TODO: inline this function call small performance gain
|
|
45
|
-
encodeValue(encoder, bytes, metadata[index].type, ref[field.name], operation, it);
|
|
46
|
-
};
|
|
47
|
-
exports.encodeSchemaOperation = encodeSchemaOperation;
|
|
48
|
-
/**
|
|
49
|
-
* Used for collections (MapSchema, CollectionSchema, SetSchema)
|
|
50
|
-
* @private
|
|
51
|
-
*/
|
|
52
|
-
const encodeKeyValueOperation = function (encoder, bytes, changeTree, index, operation, it) {
|
|
53
|
-
// encode operation
|
|
54
|
-
bytes[it.offset++] = operation & 255;
|
|
55
|
-
// encode index
|
|
56
|
-
encode_1.encode.number(bytes, index, it);
|
|
57
|
-
// Do not encode value for DELETE operations
|
|
58
|
-
if (operation === spec_1.OPERATION.DELETE) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
const ref = changeTree.ref;
|
|
62
|
-
//
|
|
63
|
-
// encode "alias" for dynamic fields (maps)
|
|
64
|
-
//
|
|
65
|
-
if ((operation & spec_1.OPERATION.ADD) === spec_1.OPERATION.ADD) { // ADD or DELETE_AND_ADD
|
|
66
|
-
if (typeof (ref['set']) === "function") {
|
|
67
|
-
//
|
|
68
|
-
// MapSchema dynamic key
|
|
69
|
-
//
|
|
70
|
-
const dynamicIndex = changeTree.ref['$indexes'].get(index);
|
|
71
|
-
encode_1.encode.string(bytes, dynamicIndex, it);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
const type = ref[symbols_1.$childType];
|
|
75
|
-
const value = ref[symbols_1.$getByIndex](index);
|
|
76
|
-
// try { throw new Error(); } catch (e) {
|
|
77
|
-
// // only print if not coming from Reflection.ts
|
|
78
|
-
// if (!e.stack.includes("src/Reflection.ts")) {
|
|
79
|
-
// console.log("encodeKeyValueOperation -> ", {
|
|
80
|
-
// ref: changeTree.ref.constructor.name,
|
|
81
|
-
// field,
|
|
82
|
-
// operation: OPERATION[operation],
|
|
83
|
-
// value: value?.toJSON(),
|
|
84
|
-
// items: ref.toJSON(),
|
|
85
|
-
// });
|
|
86
|
-
// }
|
|
87
|
-
// }
|
|
88
|
-
// TODO: inline this function call small performance gain
|
|
89
|
-
encodeValue(encoder, bytes, type, value, operation, it);
|
|
90
|
-
};
|
|
91
|
-
exports.encodeKeyValueOperation = encodeKeyValueOperation;
|
|
92
|
-
/**
|
|
93
|
-
* Used for collections (MapSchema, ArraySchema, etc.)
|
|
94
|
-
* @private
|
|
95
|
-
*/
|
|
96
|
-
const encodeArray = function (encoder, bytes, changeTree, field, operation, it, isEncodeAll, hasView) {
|
|
97
|
-
const ref = changeTree.ref;
|
|
98
|
-
const useOperationByRefId = hasView && changeTree.isFiltered && (typeof (changeTree.getType(field)) !== "string");
|
|
99
|
-
let refOrIndex;
|
|
100
|
-
if (useOperationByRefId) {
|
|
101
|
-
const item = ref['tmpItems'][field];
|
|
102
|
-
// Skip encoding if item is undefined (e.g. when clear() is called)
|
|
103
|
-
if (!item) {
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
refOrIndex = item[symbols_1.$refId];
|
|
107
|
-
if (operation === spec_1.OPERATION.DELETE) {
|
|
108
|
-
operation = spec_1.OPERATION.DELETE_BY_REFID;
|
|
109
|
-
}
|
|
110
|
-
else if (operation === spec_1.OPERATION.ADD) {
|
|
111
|
-
operation = spec_1.OPERATION.ADD_BY_REFID;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
refOrIndex = field;
|
|
116
|
-
}
|
|
117
|
-
// encode operation
|
|
118
|
-
bytes[it.offset++] = operation & 255;
|
|
119
|
-
// encode index
|
|
120
|
-
encode_1.encode.number(bytes, refOrIndex, it);
|
|
121
|
-
// Do not encode value for DELETE operations
|
|
122
|
-
if (operation === spec_1.OPERATION.DELETE || operation === spec_1.OPERATION.DELETE_BY_REFID) {
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
const type = changeTree.getType(field);
|
|
126
|
-
const value = changeTree.getValue(field, isEncodeAll);
|
|
127
|
-
// console.log({ type, field, value });
|
|
128
|
-
// console.log("encodeArray -> ", {
|
|
129
|
-
// ref: changeTree.ref.constructor.name,
|
|
130
|
-
// field,
|
|
131
|
-
// operation: OPERATION[operation],
|
|
132
|
-
// value: value?.toJSON(),
|
|
133
|
-
// items: ref.toJSON(),
|
|
134
|
-
// });
|
|
135
|
-
// TODO: inline this function call small performance gain
|
|
136
|
-
encodeValue(encoder, bytes, type, value, operation, it);
|
|
137
|
-
};
|
|
138
|
-
exports.encodeArray = encodeArray;
|
|
139
|
-
//# sourceMappingURL=EncodeOperation.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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, $refId } from \"../types/symbols\";\n\nimport { encode } from \"../encoding/encode\";\n\nimport type { ChangeTree, Ref } from \"./ChangeTree\";\nimport type { Encoder } from \"./Encoder\";\nimport type { Schema } from \"../Schema\";\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: Uint8Array,\n changeTree: ChangeTree<T>,\n index: number,\n operation: OPERATION,\n it: Iterator,\n isEncodeAll: boolean,\n hasView: boolean,\n metadata?: Metadata,\n) => void;\n\nexport function encodeValue(\n encoder: Encoder,\n bytes: Uint8Array,\n type: any,\n value: any,\n operation: OPERATION,\n it: Iterator,\n) {\n if (typeof (type) === \"string\") {\n (encode as any)[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[$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[$refId], it);\n }\n}\n\n/**\n * Used for Schema instances.\n * @private\n */\nexport const encodeSchemaOperation: EncodeOperation = function <T extends Schema> (\n encoder: Encoder,\n bytes: Uint8Array,\n changeTree: ChangeTree<T>,\n index: number,\n operation: OPERATION,\n it: Iterator,\n _: any,\n __: any,\n metadata: Metadata,\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 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 as keyof T],\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: Uint8Array,\n changeTree: ChangeTree,\n index: number,\n operation: OPERATION,\n it: Iterator,\n) {\n // encode operation\n bytes[it.offset++] = operation & 255;\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: Uint8Array,\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 const item = ref['tmpItems'][field];\n\n // Skip encoding if item is undefined (e.g. when clear() is called)\n if (!item) { return; }\n\n refOrIndex = item[$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 // encode index\n encode.number(bytes, refOrIndex, it);\n\n // Do not encode value for DELETE operations\n if (operation === OPERATION.DELETE || operation === OPERATION.DELETE_BY_REFID) {\n return;\n }\n\n const type = changeTree.getType(field);\n const value = changeTree.getValue(field, isEncodeAll);\n\n // console.log({ type, field, value });\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
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Encoder = void 0;
|
|
4
|
-
const TypeContext_1 = require("../types/TypeContext");
|
|
5
|
-
const symbols_1 = require("../types/symbols");
|
|
6
|
-
const encode_1 = require("../encoding/encode");
|
|
7
|
-
const spec_1 = require("../encoding/spec");
|
|
8
|
-
const Root_1 = require("./Root");
|
|
9
|
-
const ChangeTree_1 = require("./ChangeTree");
|
|
10
|
-
function concatBytes(a, b) {
|
|
11
|
-
const result = new Uint8Array(a.length + b.length);
|
|
12
|
-
result.set(a, 0);
|
|
13
|
-
result.set(b, a.length);
|
|
14
|
-
return result;
|
|
15
|
-
}
|
|
16
|
-
class Encoder {
|
|
17
|
-
static { this.BUFFER_SIZE = 8 * 1024; } // 8KB
|
|
18
|
-
constructor(state) {
|
|
19
|
-
this.sharedBuffer = new Uint8Array(Encoder.BUFFER_SIZE);
|
|
20
|
-
//
|
|
21
|
-
// Use .cache() here to avoid re-creating a new context for every new room instance.
|
|
22
|
-
//
|
|
23
|
-
// We may need to make this optional in case of dynamically created
|
|
24
|
-
// schemas - which would lead to memory leaks
|
|
25
|
-
//
|
|
26
|
-
this.context = TypeContext_1.TypeContext.cache(state.constructor);
|
|
27
|
-
this.root = new Root_1.Root(this.context);
|
|
28
|
-
this.setState(state);
|
|
29
|
-
// console.log(">>>>>>>>>>>>>>>> Encoder types");
|
|
30
|
-
// this.context.schemas.forEach((id, schema) => {
|
|
31
|
-
// console.log("type:", id, schema.name, Object.keys(schema[Symbol.metadata]));
|
|
32
|
-
// });
|
|
33
|
-
}
|
|
34
|
-
setState(state) {
|
|
35
|
-
this.state = state;
|
|
36
|
-
this.state[symbols_1.$changes].setRoot(this.root);
|
|
37
|
-
}
|
|
38
|
-
encode(it = { offset: 0 }, view, buffer = this.sharedBuffer, changeSetName = "changes", isEncodeAll = changeSetName === "allChanges", initialOffset = it.offset // cache current offset in case we need to resize the buffer
|
|
39
|
-
) {
|
|
40
|
-
const hasView = (view !== undefined);
|
|
41
|
-
const rootChangeTree = this.state[symbols_1.$changes];
|
|
42
|
-
let current = this.root[changeSetName];
|
|
43
|
-
while (current = current.next) {
|
|
44
|
-
const changeTree = current.changeTree;
|
|
45
|
-
if (hasView) {
|
|
46
|
-
if (!view.isChangeTreeVisible(changeTree)) {
|
|
47
|
-
// console.log("MARK AS INVISIBLE:", { ref: changeTree.ref.constructor.name, refId: changeTree.ref[$refId], raw: changeTree.ref.toJSON() });
|
|
48
|
-
view.invisible.add(changeTree);
|
|
49
|
-
continue; // skip this change tree
|
|
50
|
-
}
|
|
51
|
-
view.invisible.delete(changeTree); // remove from invisible list
|
|
52
|
-
}
|
|
53
|
-
const changeSet = changeTree[changeSetName];
|
|
54
|
-
const ref = changeTree.ref;
|
|
55
|
-
// TODO: avoid iterating over change tree if no changes were made
|
|
56
|
-
const numChanges = changeSet.operations.length;
|
|
57
|
-
if (numChanges === 0) {
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
const ctor = ref.constructor;
|
|
61
|
-
const encoder = ctor[symbols_1.$encoder];
|
|
62
|
-
const filter = ctor[symbols_1.$filter];
|
|
63
|
-
const metadata = ctor[Symbol.metadata];
|
|
64
|
-
// skip root `refId` if it's the first change tree
|
|
65
|
-
// (unless it "hasView", which will need to revisit the root)
|
|
66
|
-
if (hasView || it.offset > initialOffset || changeTree !== rootChangeTree) {
|
|
67
|
-
buffer[it.offset++] = spec_1.SWITCH_TO_STRUCTURE & 255;
|
|
68
|
-
encode_1.encode.number(buffer, ref[symbols_1.$refId], it);
|
|
69
|
-
}
|
|
70
|
-
for (let j = 0; j < numChanges; j++) {
|
|
71
|
-
const fieldIndex = changeSet.operations[j];
|
|
72
|
-
if (fieldIndex < 0) {
|
|
73
|
-
// "pure" operation without fieldIndex (e.g. CLEAR, REVERSE, etc.)
|
|
74
|
-
// encode and continue early - no need to reach $filter check
|
|
75
|
-
buffer[it.offset++] = Math.abs(fieldIndex) & 255;
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
const operation = (isEncodeAll)
|
|
79
|
-
? spec_1.OPERATION.ADD
|
|
80
|
-
: changeTree.indexedOperations[fieldIndex];
|
|
81
|
-
//
|
|
82
|
-
// first pass (encodeAll), identify "filtered" operations without encoding them
|
|
83
|
-
// they will be encoded per client, based on their view.
|
|
84
|
-
//
|
|
85
|
-
// TODO: how can we optimize filtering out "encode all" operations?
|
|
86
|
-
// TODO: avoid checking if no view tags were defined
|
|
87
|
-
//
|
|
88
|
-
if (fieldIndex === undefined || operation === undefined || (filter && !filter(ref, fieldIndex, view))) {
|
|
89
|
-
// console.log("ADD AS INVISIBLE:", fieldIndex, changeTree.ref.constructor.name)
|
|
90
|
-
// view?.invisible.add(changeTree);
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView, metadata);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (it.offset > buffer.byteLength) {
|
|
97
|
-
// we can assume that n + 1 BUFFER_SIZE will suffice given that we are likely done with encoding at this point
|
|
98
|
-
// multiples of BUFFER_SIZE are faster to allocate than arbitrary sizes
|
|
99
|
-
const newSize = Math.ceil(it.offset / Encoder.BUFFER_SIZE) * Encoder.BUFFER_SIZE;
|
|
100
|
-
console.warn(`@colyseus/schema buffer overflow. Encoded state is higher than default BUFFER_SIZE. Use the following to increase default BUFFER_SIZE:
|
|
101
|
-
|
|
102
|
-
import { Encoder } from "@colyseus/schema";
|
|
103
|
-
Encoder.BUFFER_SIZE = ${Math.round(newSize / 1024)} * 1024; // ${Math.round(newSize / 1024)} KB
|
|
104
|
-
`);
|
|
105
|
-
//
|
|
106
|
-
// resize buffer and re-encode (TODO: can we avoid re-encoding here?)
|
|
107
|
-
// -> No we probably can't unless we catch the need for resize before encoding which is likely more computationally expensive than resizing on demand
|
|
108
|
-
//
|
|
109
|
-
const newBuffer = new Uint8Array(newSize);
|
|
110
|
-
newBuffer.set(buffer); // copy previous encoding steps beyond the initialOffset
|
|
111
|
-
buffer = newBuffer;
|
|
112
|
-
// assign resized buffer to local sharedBuffer
|
|
113
|
-
if (buffer === this.sharedBuffer) {
|
|
114
|
-
this.sharedBuffer = buffer;
|
|
115
|
-
}
|
|
116
|
-
return this.encode({ offset: initialOffset }, view, buffer, changeSetName, isEncodeAll);
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
return buffer.subarray(0, it.offset);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
encodeAll(it = { offset: 0 }, buffer = this.sharedBuffer) {
|
|
123
|
-
return this.encode(it, undefined, buffer, "allChanges", true);
|
|
124
|
-
}
|
|
125
|
-
encodeAllView(view, sharedOffset, it, bytes = this.sharedBuffer) {
|
|
126
|
-
const viewOffset = it.offset;
|
|
127
|
-
// try to encode "filtered" changes
|
|
128
|
-
this.encode(it, view, bytes, "allFilteredChanges", true, viewOffset);
|
|
129
|
-
return concatBytes(bytes.subarray(0, sharedOffset), bytes.subarray(viewOffset, it.offset));
|
|
130
|
-
}
|
|
131
|
-
encodeView(view, sharedOffset, it, bytes = this.sharedBuffer) {
|
|
132
|
-
const viewOffset = it.offset;
|
|
133
|
-
// encode visibility changes (add/remove for this view)
|
|
134
|
-
for (const [refId, changes] of view.changes) {
|
|
135
|
-
const changeTree = this.root.changeTrees[refId];
|
|
136
|
-
if (changeTree === undefined) {
|
|
137
|
-
// detached instance, remove from view and skip.
|
|
138
|
-
// console.log("detached instance, remove from view and skip.", refId);
|
|
139
|
-
view.changes.delete(refId);
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
const keys = Object.keys(changes);
|
|
143
|
-
if (keys.length === 0) {
|
|
144
|
-
// FIXME: avoid having empty changes if no changes were made
|
|
145
|
-
// console.log("changes.size === 0, skip", refId, changeTree.ref.constructor.name);
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
const ref = changeTree.ref;
|
|
149
|
-
const ctor = ref.constructor;
|
|
150
|
-
const encoder = ctor[symbols_1.$encoder];
|
|
151
|
-
const metadata = ctor[Symbol.metadata];
|
|
152
|
-
bytes[it.offset++] = spec_1.SWITCH_TO_STRUCTURE & 255;
|
|
153
|
-
encode_1.encode.number(bytes, ref[symbols_1.$refId], it);
|
|
154
|
-
for (let i = 0, numChanges = keys.length; i < numChanges; i++) {
|
|
155
|
-
const index = Number(keys[i]);
|
|
156
|
-
// workaround when using view.add() on item that has been deleted from state (see test "adding to view item that has been removed from state")
|
|
157
|
-
const value = changeTree.ref[symbols_1.$getByIndex](index);
|
|
158
|
-
const operation = (value !== undefined && changes[index]) || spec_1.OPERATION.DELETE;
|
|
159
|
-
// isEncodeAll = false
|
|
160
|
-
// hasView = true
|
|
161
|
-
encoder(this, bytes, changeTree, index, operation, it, false, true, metadata);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
//
|
|
165
|
-
// TODO: only clear view changes after all views are encoded
|
|
166
|
-
// (to allow re-using StateView's for multiple clients)
|
|
167
|
-
//
|
|
168
|
-
// clear "view" changes after encoding
|
|
169
|
-
view.changes.clear();
|
|
170
|
-
// try to encode "filtered" changes
|
|
171
|
-
this.encode(it, view, bytes, "filteredChanges", false, viewOffset);
|
|
172
|
-
return concatBytes(bytes.subarray(0, sharedOffset), bytes.subarray(viewOffset, it.offset));
|
|
173
|
-
}
|
|
174
|
-
discardChanges() {
|
|
175
|
-
// discard shared changes
|
|
176
|
-
let current = this.root.changes.next;
|
|
177
|
-
while (current) {
|
|
178
|
-
current.changeTree.endEncode('changes');
|
|
179
|
-
current = current.next;
|
|
180
|
-
}
|
|
181
|
-
this.root.changes = (0, ChangeTree_1.createChangeTreeList)();
|
|
182
|
-
// discard filtered changes
|
|
183
|
-
current = this.root.filteredChanges.next;
|
|
184
|
-
while (current) {
|
|
185
|
-
current.changeTree.endEncode('filteredChanges');
|
|
186
|
-
current = current.next;
|
|
187
|
-
}
|
|
188
|
-
this.root.filteredChanges = (0, ChangeTree_1.createChangeTreeList)();
|
|
189
|
-
}
|
|
190
|
-
tryEncodeTypeId(bytes, baseType, targetType, it) {
|
|
191
|
-
const baseTypeId = this.context.getTypeId(baseType);
|
|
192
|
-
const targetTypeId = this.context.getTypeId(targetType);
|
|
193
|
-
if (targetTypeId === undefined) {
|
|
194
|
-
console.warn(`@colyseus/schema WARNING: Class "${targetType.name}" is not registered on TypeRegistry - Please either tag the class with @entity or define a @type() field.`);
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
if (baseTypeId !== targetTypeId) {
|
|
198
|
-
bytes[it.offset++] = spec_1.TYPE_ID & 255;
|
|
199
|
-
encode_1.encode.number(bytes, targetTypeId, it);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
get hasChanges() {
|
|
203
|
-
return (this.root.changes.next !== undefined ||
|
|
204
|
-
this.root.filteredChanges.next !== undefined);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
exports.Encoder = Encoder;
|
|
208
|
-
//# sourceMappingURL=Encoder.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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, $getByIndex, $refId } from \"../types/symbols\";\n\nimport { 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\";\n\nimport type { StateView } from \"./StateView\";\nimport type { ChangeSetName, ChangeTree, ChangeTreeList, ChangeTreeNode } from \"./ChangeTree\";\nimport { createChangeTreeList } from \"./ChangeTree\";\n\nfunction concatBytes(a: Uint8Array, b: Uint8Array): Uint8Array {\n const result = new Uint8Array(a.length + b.length);\n result.set(a, 0);\n result.set(b, a.length);\n return result;\n}\n\nexport class Encoder<T extends Schema = any> {\n static BUFFER_SIZE = 8 * 1024; // 8KB\n sharedBuffer: Uint8Array = new Uint8Array(Encoder.BUFFER_SIZE);\n\n context: TypeContext;\n state: T;\n\n root: Root;\n\n constructor(state: T) {\n //\n // Use .cache() here to avoid re-creating a new context for every new room instance.\n //\n // We may need to make this optional in case of dynamically created\n // schemas - which would lead to memory leaks\n //\n this.context = TypeContext.cache(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: Uint8Array = this.sharedBuffer,\n changeSetName: ChangeSetName = \"changes\",\n isEncodeAll = changeSetName === \"allChanges\",\n initialOffset = it.offset // cache current offset in case we need to resize the buffer\n ): Uint8Array {\n const hasView = (view !== undefined);\n const rootChangeTree = this.state[$changes];\n\n let current: ChangeTreeList | ChangeTreeNode = this.root[changeSetName];\n\n while (current = current.next) {\n const changeTree = (current as ChangeTreeNode).changeTree;\n\n if (hasView) {\n if (!view.isChangeTreeVisible(changeTree)) {\n // console.log(\"MARK AS INVISIBLE:\", { ref: changeTree.ref.constructor.name, refId: changeTree.ref[$refId], raw: changeTree.ref.toJSON() });\n view.invisible.add(changeTree);\n continue; // skip this change tree\n }\n view.invisible.delete(changeTree); // remove from invisible list\n }\n\n const changeSet = changeTree[changeSetName];\n const ref = changeTree.ref;\n\n // TODO: avoid iterating over change tree if no changes were made\n const numChanges = changeSet.operations.length;\n if (numChanges === 0) { continue; }\n\n const ctor = ref.constructor;\n const encoder = ctor[$encoder];\n const filter = ctor[$filter];\n const metadata = ctor[Symbol.metadata];\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, ref[$refId], it);\n }\n\n for (let j = 0; j < numChanges; j++) {\n const fieldIndex = changeSet.operations[j];\n\n if (fieldIndex < 0) {\n // \"pure\" operation without fieldIndex (e.g. CLEAR, REVERSE, etc.)\n // encode and continue early - no need to reach $filter check\n buffer[it.offset++] = Math.abs(fieldIndex) & 255;\n continue;\n }\n\n const operation = (isEncodeAll)\n ? OPERATION.ADD\n : changeTree.indexedOperations[fieldIndex];\n\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 (fieldIndex === undefined || operation === undefined || (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 encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView, metadata);\n }\n }\n\n if (it.offset > buffer.byteLength) {\n // we can assume that n + 1 BUFFER_SIZE will suffice given that we are likely done with encoding at this point\n // multiples of BUFFER_SIZE are faster to allocate than arbitrary sizes\n const newSize = Math.ceil(it.offset / Encoder.BUFFER_SIZE) * Encoder.BUFFER_SIZE;\n\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 // -> No we probably can't unless we catch the need for resize before encoding which is likely more computationally expensive than resizing on demand\n //\n const newBuffer = new Uint8Array(newSize);\n newBuffer.set(buffer); // copy previous encoding steps beyond the initialOffset\n buffer = newBuffer;\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, changeSetName, isEncodeAll);\n\n } else {\n\n return buffer.subarray(0, it.offset);\n }\n }\n\n encodeAll(\n it: Iterator = { offset: 0 },\n buffer: Uint8Array = this.sharedBuffer\n ) {\n return this.encode(it, undefined, buffer, \"allChanges\", true);\n }\n\n encodeAllView(\n view: StateView,\n sharedOffset: number,\n it: Iterator,\n bytes: Uint8Array = this.sharedBuffer\n ) {\n const viewOffset = it.offset;\n\n // try to encode \"filtered\" changes\n this.encode(it, view, bytes, \"allFilteredChanges\", true, viewOffset);\n\n return concatBytes(\n bytes.subarray(0, sharedOffset),\n bytes.subarray(viewOffset, it.offset)\n );\n }\n\n encodeView(\n view: StateView,\n sharedOffset: number,\n it: Iterator,\n bytes: Uint8Array = this.sharedBuffer\n ) {\n const viewOffset = it.offset;\n\n // encode visibility changes (add/remove for this view)\n for (const [refId, changes] of view.changes) {\n const changeTree: ChangeTree = this.root.changeTrees[refId];\n\n if (changeTree === undefined) {\n // detached instance, remove from view and skip.\n // console.log(\"detached instance, remove from view and skip.\", refId);\n view.changes.delete(refId);\n continue;\n }\n\n const keys = Object.keys(changes);\n if (keys.length === 0) {\n // FIXME: avoid having empty changes if no changes were made\n // console.log(\"changes.size === 0, skip\", refId, 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 const metadata = ctor[Symbol.metadata];\n\n bytes[it.offset++] = SWITCH_TO_STRUCTURE & 255;\n encode.number(bytes, ref[$refId], it);\n\n for (let i = 0, numChanges = keys.length; i < numChanges; i++) {\n const index = Number(keys[i]);\n // workaround when using view.add() on item that has been deleted from state (see test \"adding to view item that has been removed from state\")\n const value = changeTree.ref[$getByIndex](index);\n const operation = (value !== undefined && changes[index]) || OPERATION.DELETE;\n\n // isEncodeAll = false\n // hasView = true\n encoder(this, bytes, changeTree, index, operation, it, false, true, metadata);\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, \"filteredChanges\", false, viewOffset);\n\n return concatBytes(\n bytes.subarray(0, sharedOffset),\n bytes.subarray(viewOffset, it.offset)\n );\n }\n\n discardChanges() {\n // discard shared changes\n let current = this.root.changes.next;\n while (current) {\n current.changeTree.endEncode('changes');\n current = current.next;\n }\n this.root.changes = createChangeTreeList();\n\n // discard filtered changes\n current = this.root.filteredChanges.next;\n while (current) {\n current.changeTree.endEncode('filteredChanges');\n current = current.next;\n }\n this.root.filteredChanges = createChangeTreeList();\n }\n\n tryEncodeTypeId(\n bytes: Uint8Array,\n baseType: typeof Schema,\n targetType: typeof Schema,\n it: Iterator\n ) {\n const baseTypeId = this.context.getTypeId(baseType);\n const targetTypeId = this.context.getTypeId(targetType);\n\n if (targetTypeId === undefined) {\n console.warn(`@colyseus/schema WARNING: Class \"${targetType.name}\" is not registered on TypeRegistry - Please either tag the class with @entity or define a @type() field.`);\n return;\n }\n\n if (baseTypeId !== targetTypeId) {\n bytes[it.offset++] = TYPE_ID & 255;\n encode.number(bytes, targetTypeId, it);\n }\n }\n\n get hasChanges() {\n return (\n this.root.changes.next !== undefined ||\n this.root.filteredChanges.next !== undefined\n );\n }\n}\n"]}
|
package/lib/encoder/Root.js
DELETED
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Root = void 0;
|
|
4
|
-
const spec_1 = require("../encoding/spec");
|
|
5
|
-
const ChangeTree_1 = require("./ChangeTree");
|
|
6
|
-
const symbols_1 = require("../types/symbols");
|
|
7
|
-
class Root {
|
|
8
|
-
constructor(types) {
|
|
9
|
-
this.types = types;
|
|
10
|
-
this.nextUniqueId = 0;
|
|
11
|
-
this.refCount = {};
|
|
12
|
-
this.changeTrees = {};
|
|
13
|
-
// all changes
|
|
14
|
-
this.allChanges = (0, ChangeTree_1.createChangeTreeList)();
|
|
15
|
-
this.allFilteredChanges = (0, ChangeTree_1.createChangeTreeList)(); // TODO: do not initialize it if filters are not used
|
|
16
|
-
// pending changes to be encoded
|
|
17
|
-
this.changes = (0, ChangeTree_1.createChangeTreeList)();
|
|
18
|
-
this.filteredChanges = (0, ChangeTree_1.createChangeTreeList)(); // TODO: do not initialize it if filters are not used
|
|
19
|
-
}
|
|
20
|
-
getNextUniqueId() {
|
|
21
|
-
return this.nextUniqueId++;
|
|
22
|
-
}
|
|
23
|
-
add(changeTree) {
|
|
24
|
-
const ref = changeTree.ref;
|
|
25
|
-
// Assign unique `refId` to ref if it doesn't have one yet.
|
|
26
|
-
if (ref[symbols_1.$refId] === undefined) {
|
|
27
|
-
ref[symbols_1.$refId] = this.getNextUniqueId();
|
|
28
|
-
}
|
|
29
|
-
const refId = ref[symbols_1.$refId];
|
|
30
|
-
const isNewChangeTree = (this.changeTrees[refId] === undefined);
|
|
31
|
-
if (isNewChangeTree) {
|
|
32
|
-
this.changeTrees[refId] = changeTree;
|
|
33
|
-
}
|
|
34
|
-
const previousRefCount = this.refCount[refId];
|
|
35
|
-
if (previousRefCount === 0) {
|
|
36
|
-
//
|
|
37
|
-
// When a ChangeTree is re-added, it means that it was previously removed.
|
|
38
|
-
// We need to re-add all changes to the `changes` map.
|
|
39
|
-
//
|
|
40
|
-
const ops = changeTree.allChanges.operations;
|
|
41
|
-
let len = ops.length;
|
|
42
|
-
while (len--) {
|
|
43
|
-
changeTree.indexedOperations[ops[len]] = spec_1.OPERATION.ADD;
|
|
44
|
-
(0, ChangeTree_1.setOperationAtIndex)(changeTree.changes, len);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
this.refCount[refId] = (previousRefCount || 0) + 1;
|
|
48
|
-
// console.log("ADD", { refId, ref: ref.constructor.name, refCount: this.refCount[refId], isNewChangeTree });
|
|
49
|
-
return isNewChangeTree;
|
|
50
|
-
}
|
|
51
|
-
remove(changeTree) {
|
|
52
|
-
const refId = changeTree.ref[symbols_1.$refId];
|
|
53
|
-
const refCount = (this.refCount[refId]) - 1;
|
|
54
|
-
// console.log("REMOVE", { refId, ref: changeTree.ref.constructor.name, refCount, needRemove: refCount <= 0 });
|
|
55
|
-
if (refCount <= 0) {
|
|
56
|
-
//
|
|
57
|
-
// Only remove "root" reference if it's the last reference
|
|
58
|
-
//
|
|
59
|
-
changeTree.root = undefined;
|
|
60
|
-
delete this.changeTrees[refId];
|
|
61
|
-
this.removeChangeFromChangeSet("allChanges", changeTree);
|
|
62
|
-
this.removeChangeFromChangeSet("changes", changeTree);
|
|
63
|
-
if (changeTree.filteredChanges) {
|
|
64
|
-
this.removeChangeFromChangeSet("allFilteredChanges", changeTree);
|
|
65
|
-
this.removeChangeFromChangeSet("filteredChanges", changeTree);
|
|
66
|
-
}
|
|
67
|
-
this.refCount[refId] = 0;
|
|
68
|
-
changeTree.forEachChild((child, _) => {
|
|
69
|
-
if (child.removeParent(changeTree.ref)) {
|
|
70
|
-
if ((child.parentChain === undefined || // no parent, remove it
|
|
71
|
-
(child.parentChain && this.refCount[child.ref[symbols_1.$refId]] > 0) // parent is still in use, but has more than one reference, remove it
|
|
72
|
-
)) {
|
|
73
|
-
this.remove(child);
|
|
74
|
-
}
|
|
75
|
-
else if (child.parentChain) {
|
|
76
|
-
// re-assigning a child of the same root, move it next to parent
|
|
77
|
-
this.moveNextToParent(child);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
this.refCount[refId] = refCount;
|
|
84
|
-
//
|
|
85
|
-
// When losing a reference to an instance, it is best to move the
|
|
86
|
-
// ChangeTree next to its parent in the encoding queue.
|
|
87
|
-
//
|
|
88
|
-
// This way, at decoding time, the instance that contains the
|
|
89
|
-
// ChangeTree will be available before the ChangeTree itself. If the
|
|
90
|
-
// containing instance is not available, the Decoder will throw
|
|
91
|
-
// "refId not found" error.
|
|
92
|
-
//
|
|
93
|
-
this.recursivelyMoveNextToParent(changeTree);
|
|
94
|
-
}
|
|
95
|
-
return refCount;
|
|
96
|
-
}
|
|
97
|
-
recursivelyMoveNextToParent(changeTree) {
|
|
98
|
-
this.moveNextToParent(changeTree);
|
|
99
|
-
changeTree.forEachChild((child, _) => this.recursivelyMoveNextToParent(child));
|
|
100
|
-
}
|
|
101
|
-
moveNextToParent(changeTree) {
|
|
102
|
-
if (changeTree.filteredChanges) {
|
|
103
|
-
this.moveNextToParentInChangeTreeList("filteredChanges", changeTree);
|
|
104
|
-
this.moveNextToParentInChangeTreeList("allFilteredChanges", changeTree);
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
this.moveNextToParentInChangeTreeList("changes", changeTree);
|
|
108
|
-
this.moveNextToParentInChangeTreeList("allChanges", changeTree);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
moveNextToParentInChangeTreeList(changeSetName, changeTree) {
|
|
112
|
-
const changeSet = this[changeSetName];
|
|
113
|
-
const node = changeTree[changeSetName].queueRootNode;
|
|
114
|
-
if (!node)
|
|
115
|
-
return;
|
|
116
|
-
// Find the parent in the linked list
|
|
117
|
-
const parent = changeTree.parent;
|
|
118
|
-
if (!parent || !parent[symbols_1.$changes])
|
|
119
|
-
return;
|
|
120
|
-
const parentNode = parent[symbols_1.$changes][changeSetName]?.queueRootNode;
|
|
121
|
-
if (!parentNode || parentNode === node)
|
|
122
|
-
return;
|
|
123
|
-
// Use cached positions - no iteration needed!
|
|
124
|
-
const parentPosition = parentNode.position;
|
|
125
|
-
const childPosition = node.position;
|
|
126
|
-
// If child is already after parent, no need to move
|
|
127
|
-
if (childPosition > parentPosition)
|
|
128
|
-
return;
|
|
129
|
-
// Child is before parent, so we need to move it after parent
|
|
130
|
-
// This maintains decoding order (parent before child)
|
|
131
|
-
// Remove node from current position
|
|
132
|
-
if (node.prev) {
|
|
133
|
-
node.prev.next = node.next;
|
|
134
|
-
}
|
|
135
|
-
else {
|
|
136
|
-
changeSet.next = node.next;
|
|
137
|
-
}
|
|
138
|
-
if (node.next) {
|
|
139
|
-
node.next.prev = node.prev;
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
changeSet.tail = node.prev;
|
|
143
|
-
}
|
|
144
|
-
// Insert node right after parent
|
|
145
|
-
node.prev = parentNode;
|
|
146
|
-
node.next = parentNode.next;
|
|
147
|
-
if (parentNode.next) {
|
|
148
|
-
parentNode.next.prev = node;
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
changeSet.tail = node;
|
|
152
|
-
}
|
|
153
|
-
parentNode.next = node;
|
|
154
|
-
// Update positions after the move
|
|
155
|
-
this.updatePositionsAfterMove(changeSet, node, parentPosition + 1);
|
|
156
|
-
}
|
|
157
|
-
enqueueChangeTree(changeTree, changeSet, queueRootNode = changeTree[changeSet].queueRootNode) {
|
|
158
|
-
// skip
|
|
159
|
-
if (queueRootNode) {
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
// Add to linked list if not already present
|
|
163
|
-
changeTree[changeSet].queueRootNode = this.addToChangeTreeList(this[changeSet], changeTree);
|
|
164
|
-
}
|
|
165
|
-
addToChangeTreeList(list, changeTree) {
|
|
166
|
-
const node = {
|
|
167
|
-
changeTree,
|
|
168
|
-
next: undefined,
|
|
169
|
-
prev: undefined,
|
|
170
|
-
position: list.tail ? list.tail.position + 1 : 0
|
|
171
|
-
};
|
|
172
|
-
if (!list.next) {
|
|
173
|
-
list.next = node;
|
|
174
|
-
list.tail = node;
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
node.prev = list.tail;
|
|
178
|
-
list.tail.next = node;
|
|
179
|
-
list.tail = node;
|
|
180
|
-
}
|
|
181
|
-
return node;
|
|
182
|
-
}
|
|
183
|
-
updatePositionsAfterRemoval(list, removedPosition) {
|
|
184
|
-
// Update positions for all nodes after the removed position
|
|
185
|
-
let current = list.next;
|
|
186
|
-
let position = 0;
|
|
187
|
-
while (current) {
|
|
188
|
-
if (position >= removedPosition) {
|
|
189
|
-
current.position = position;
|
|
190
|
-
}
|
|
191
|
-
current = current.next;
|
|
192
|
-
position++;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
updatePositionsAfterMove(list, node, newPosition) {
|
|
196
|
-
// Recalculate all positions - this is more reliable than trying to be clever
|
|
197
|
-
let current = list.next;
|
|
198
|
-
let position = 0;
|
|
199
|
-
while (current) {
|
|
200
|
-
current.position = position;
|
|
201
|
-
current = current.next;
|
|
202
|
-
position++;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
removeChangeFromChangeSet(changeSetName, changeTree) {
|
|
206
|
-
const changeSet = this[changeSetName];
|
|
207
|
-
const node = changeTree[changeSetName].queueRootNode;
|
|
208
|
-
if (node && node.changeTree === changeTree) {
|
|
209
|
-
const removedPosition = node.position;
|
|
210
|
-
// Remove the node from the linked list
|
|
211
|
-
if (node.prev) {
|
|
212
|
-
node.prev.next = node.next;
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
changeSet.next = node.next;
|
|
216
|
-
}
|
|
217
|
-
if (node.next) {
|
|
218
|
-
node.next.prev = node.prev;
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
changeSet.tail = node.prev;
|
|
222
|
-
}
|
|
223
|
-
// Update positions for nodes that came after the removed node
|
|
224
|
-
this.updatePositionsAfterRemoval(changeSet, removedPosition);
|
|
225
|
-
// Clear ChangeTree reference
|
|
226
|
-
changeTree[changeSetName].queueRootNode = undefined;
|
|
227
|
-
return true;
|
|
228
|
-
}
|
|
229
|
-
return false;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
exports.Root = Root;
|
|
233
|
-
//# sourceMappingURL=Root.js.map
|