@colyseus/schema 3.0.0-alpha.9 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +148 -62
- package/bin/schema-debug +94 -0
- package/build/cjs/index.js +2222 -1513
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +2223 -1516
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +2225 -1516
- package/lib/Metadata.d.ts +21 -9
- package/lib/Metadata.js +169 -32
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.d.ts +19 -4
- package/lib/Reflection.js +66 -31
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.d.ts +12 -5
- package/lib/Schema.js +57 -56
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +31 -34
- package/lib/annotations.js +110 -160
- package/lib/annotations.js.map +1 -1
- package/lib/bench_encode.d.ts +1 -0
- package/lib/bench_encode.js +130 -0
- package/lib/bench_encode.js.map +1 -0
- package/lib/codegen/api.js +1 -2
- package/lib/codegen/api.js.map +1 -1
- package/lib/codegen/languages/cpp.js +1 -2
- package/lib/codegen/languages/cpp.js.map +1 -1
- package/lib/codegen/languages/csharp.js +9 -46
- package/lib/codegen/languages/csharp.js.map +1 -1
- package/lib/codegen/languages/haxe.js +4 -2
- package/lib/codegen/languages/haxe.js.map +1 -1
- package/lib/codegen/languages/java.js +1 -2
- package/lib/codegen/languages/java.js.map +1 -1
- package/lib/codegen/languages/js.js +1 -2
- package/lib/codegen/languages/js.js.map +1 -1
- package/lib/codegen/languages/lua.js +23 -25
- package/lib/codegen/languages/lua.js.map +1 -1
- package/lib/codegen/languages/ts.js +1 -2
- package/lib/codegen/languages/ts.js.map +1 -1
- package/lib/codegen/parser.js +85 -3
- package/lib/codegen/parser.js.map +1 -1
- package/lib/codegen/types.js +6 -3
- package/lib/codegen/types.js.map +1 -1
- package/lib/debug.d.ts +1 -0
- package/lib/debug.js +51 -0
- package/lib/debug.js.map +1 -0
- package/lib/decoder/DecodeOperation.d.ts +3 -4
- package/lib/decoder/DecodeOperation.js +35 -17
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/Decoder.d.ts +5 -6
- package/lib/decoder/Decoder.js +10 -10
- package/lib/decoder/Decoder.js.map +1 -1
- package/lib/decoder/ReferenceTracker.js +4 -2
- package/lib/decoder/ReferenceTracker.js.map +1 -1
- package/lib/decoder/strategy/RawChanges.js +1 -2
- package/lib/decoder/strategy/RawChanges.js.map +1 -1
- package/lib/decoder/strategy/StateCallbacks.d.ts +44 -11
- package/lib/decoder/strategy/StateCallbacks.js +74 -64
- package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
- package/lib/encoder/ChangeTree.d.ts +28 -20
- package/lib/encoder/ChangeTree.js +242 -188
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.d.ts +3 -6
- package/lib/encoder/EncodeOperation.js +51 -65
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +8 -7
- package/lib/encoder/Encoder.js +128 -79
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +22 -0
- package/lib/encoder/Root.js +81 -0
- package/lib/encoder/Root.js.map +1 -0
- package/lib/encoder/StateView.d.ts +7 -7
- package/lib/encoder/StateView.js +72 -74
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/encoding/assert.d.ts +7 -6
- package/lib/encoding/assert.js +13 -5
- package/lib/encoding/assert.js.map +1 -1
- package/lib/encoding/decode.d.ts +36 -19
- package/lib/encoding/decode.js +54 -84
- package/lib/encoding/decode.js.map +1 -1
- package/lib/encoding/encode.d.ts +36 -18
- package/lib/encoding/encode.js +61 -48
- package/lib/encoding/encode.js.map +1 -1
- package/lib/encoding/spec.d.ts +4 -5
- package/lib/encoding/spec.js +1 -2
- package/lib/encoding/spec.js.map +1 -1
- package/lib/index.d.ts +10 -9
- package/lib/index.js +24 -17
- package/lib/index.js.map +1 -1
- package/lib/types/HelperTypes.d.ts +34 -2
- package/lib/types/HelperTypes.js.map +1 -1
- package/lib/types/TypeContext.d.ts +29 -0
- package/lib/types/TypeContext.js +151 -0
- package/lib/types/TypeContext.js.map +1 -0
- package/lib/types/custom/ArraySchema.d.ts +2 -2
- package/lib/types/custom/ArraySchema.js +33 -22
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/CollectionSchema.d.ts +2 -2
- package/lib/types/custom/CollectionSchema.js +1 -0
- package/lib/types/custom/CollectionSchema.js.map +1 -1
- package/lib/types/custom/MapSchema.d.ts +18 -16
- package/lib/types/custom/MapSchema.js +12 -4
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/lib/types/custom/SetSchema.d.ts +2 -2
- package/lib/types/custom/SetSchema.js +1 -0
- package/lib/types/custom/SetSchema.js.map +1 -1
- package/lib/types/registry.d.ts +8 -1
- package/lib/types/registry.js +23 -6
- package/lib/types/registry.js.map +1 -1
- package/lib/types/symbols.d.ts +8 -5
- package/lib/types/symbols.js +9 -6
- package/lib/types/symbols.js.map +1 -1
- package/lib/types/utils.js +1 -2
- package/lib/types/utils.js.map +1 -1
- package/lib/utils.js +9 -7
- package/lib/utils.js.map +1 -1
- package/package.json +19 -18
- package/src/Metadata.ts +190 -42
- package/src/Reflection.ts +76 -38
- package/src/Schema.ts +72 -70
- package/src/annotations.ts +156 -202
- package/src/bench_encode.ts +108 -0
- package/src/codegen/languages/csharp.ts +8 -47
- package/src/codegen/languages/haxe.ts +4 -0
- package/src/codegen/languages/lua.ts +19 -27
- package/src/codegen/parser.ts +107 -0
- package/src/codegen/types.ts +1 -0
- package/src/debug.ts +55 -0
- package/src/decoder/DecodeOperation.ts +43 -15
- package/src/decoder/Decoder.ts +12 -10
- package/src/decoder/ReferenceTracker.ts +5 -3
- package/src/decoder/strategy/StateCallbacks.ts +152 -81
- package/src/encoder/ChangeTree.ts +282 -209
- package/src/encoder/EncodeOperation.ts +78 -78
- package/src/encoder/Encoder.ts +152 -87
- package/src/encoder/Root.ts +93 -0
- package/src/encoder/StateView.ts +80 -88
- package/src/encoding/assert.ts +17 -8
- package/src/encoding/decode.ts +73 -93
- package/src/encoding/encode.ts +76 -45
- package/src/encoding/spec.ts +3 -5
- package/src/index.ts +12 -20
- package/src/types/HelperTypes.ts +54 -2
- package/src/types/TypeContext.ts +175 -0
- package/src/types/custom/ArraySchema.ts +49 -19
- package/src/types/custom/CollectionSchema.ts +1 -0
- package/src/types/custom/MapSchema.ts +30 -17
- package/src/types/custom/SetSchema.ts +1 -0
- package/src/types/registry.ts +22 -3
- package/src/types/symbols.ts +10 -7
- package/src/utils.ts +7 -3
package/src/annotations.ts
CHANGED
|
@@ -3,15 +3,17 @@ import { Schema } from './Schema';
|
|
|
3
3
|
import { ArraySchema } from './types/custom/ArraySchema';
|
|
4
4
|
import { MapSchema } from './types/custom/MapSchema';
|
|
5
5
|
import { Metadata } from "./Metadata";
|
|
6
|
-
import { $changes, $childType, $track } from "./types/symbols";
|
|
6
|
+
import { $changes, $childType, $descriptors, $numFields, $track } from "./types/symbols";
|
|
7
7
|
import { TypeDefinition, getType } from "./types/registry";
|
|
8
8
|
import { OPERATION } from "./encoding/spec";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
import { TypeContext } from "./types/TypeContext";
|
|
10
|
+
import { assertInstanceType, assertType } from "./encoding/assert";
|
|
11
|
+
import type { Ref } from "./encoder/ChangeTree";
|
|
12
|
+
import type { DefinedSchemaType, InferValueType } from "./types/HelperTypes";
|
|
13
|
+
import type { CollectionSchema } from "./types/custom/CollectionSchema";
|
|
14
|
+
import type { SetSchema } from "./types/custom/SetSchema";
|
|
15
|
+
|
|
16
|
+
export type RawPrimitiveType = "string" |
|
|
15
17
|
"number" |
|
|
16
18
|
"boolean" |
|
|
17
19
|
"int8" |
|
|
@@ -24,15 +26,19 @@ export type PrimitiveType =
|
|
|
24
26
|
"uint64" |
|
|
25
27
|
"float32" |
|
|
26
28
|
"float64" |
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
"bigint64" |
|
|
30
|
+
"biguint64";
|
|
29
31
|
|
|
30
|
-
export type
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
|
35
|
-
| {
|
|
32
|
+
export type PrimitiveType = RawPrimitiveType | typeof Schema | object;
|
|
33
|
+
|
|
34
|
+
// TODO: infer "default" value type correctly.
|
|
35
|
+
export type DefinitionType<T extends PrimitiveType = PrimitiveType> = T
|
|
36
|
+
| T[]
|
|
37
|
+
| { type: T, default?: InferValueType<T>, view?: boolean | number }
|
|
38
|
+
| { array: T, default?: ArraySchema<InferValueType<T>>, view?: boolean | number }
|
|
39
|
+
| { map: T, default?: MapSchema<InferValueType<T>>, view?: boolean | number }
|
|
40
|
+
| { collection: T, default?: CollectionSchema<InferValueType<T>>, view?: boolean | number }
|
|
41
|
+
| { set: T, default?: SetSchema<InferValueType<T>>, view?: boolean | number };
|
|
36
42
|
|
|
37
43
|
export type Definition = { [field: string]: DefinitionType };
|
|
38
44
|
|
|
@@ -42,119 +48,8 @@ export interface TypeOptions {
|
|
|
42
48
|
|
|
43
49
|
export const DEFAULT_VIEW_TAG = -1;
|
|
44
50
|
|
|
45
|
-
export
|
|
46
|
-
|
|
47
|
-
schemas = new Map<typeof Schema, number>();
|
|
48
|
-
|
|
49
|
-
hasFilters: boolean = false;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* For inheritance support
|
|
53
|
-
* Keeps track of which classes extends which. (parent -> children)
|
|
54
|
-
*/
|
|
55
|
-
static inheritedTypes = new Map<typeof Schema, Set<typeof Schema>>();
|
|
56
|
-
|
|
57
|
-
static register(target: typeof Schema) {
|
|
58
|
-
const parent = Object.getPrototypeOf(target);
|
|
59
|
-
if (parent !== Schema) {
|
|
60
|
-
let inherits = TypeContext.inheritedTypes.get(parent);
|
|
61
|
-
if (!inherits) {
|
|
62
|
-
inherits = new Set<typeof Schema>();
|
|
63
|
-
TypeContext.inheritedTypes.set(parent, inherits);
|
|
64
|
-
}
|
|
65
|
-
inherits.add(target);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
constructor(rootClass?: typeof Schema) {
|
|
70
|
-
if (rootClass) {
|
|
71
|
-
this.discoverTypes(rootClass);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
has(schema: typeof Schema) {
|
|
76
|
-
return this.schemas.has(schema);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
get(typeid: number) {
|
|
80
|
-
return this.types[typeid];
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
add(schema: typeof Schema, typeid: number = this.schemas.size) {
|
|
84
|
-
// skip if already registered
|
|
85
|
-
if (this.schemas.has(schema)) {
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
this.types[typeid] = schema;
|
|
90
|
-
this.schemas.set(schema, typeid);
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
getTypeId(klass: typeof Schema) {
|
|
95
|
-
return this.schemas.get(klass);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
private discoverTypes(klass: typeof Schema) {
|
|
99
|
-
if (!this.add(klass)) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// add classes inherited from this base class
|
|
104
|
-
TypeContext.inheritedTypes.get(klass)?.forEach((child) => {
|
|
105
|
-
this.discoverTypes(child);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
// skip if no fields are defined for this class.
|
|
109
|
-
if (klass[Symbol.metadata] === undefined) {
|
|
110
|
-
klass[Symbol.metadata] = {};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// const metadata = Metadata.getFor(klass);
|
|
114
|
-
const metadata = klass[Symbol.metadata];
|
|
115
|
-
|
|
116
|
-
// if any schema/field has filters, mark "context" as having filters.
|
|
117
|
-
if (metadata[-2]) {
|
|
118
|
-
this.hasFilters = true;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
for (const field in metadata) {
|
|
122
|
-
const fieldType = metadata[field].type;
|
|
123
|
-
|
|
124
|
-
if (typeof(fieldType) === "string") {
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (Array.isArray(fieldType)) {
|
|
129
|
-
const type = fieldType[0];
|
|
130
|
-
if (type === "string") {
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
this.discoverTypes(type as typeof Schema);
|
|
134
|
-
|
|
135
|
-
} else if (typeof(fieldType) === "function") {
|
|
136
|
-
this.discoverTypes(fieldType);
|
|
137
|
-
|
|
138
|
-
} else {
|
|
139
|
-
const type = Object.values(fieldType)[0];
|
|
140
|
-
|
|
141
|
-
// skip primitive types
|
|
142
|
-
if (typeof(type) === "string") {
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
this.discoverTypes(type as typeof Schema);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export function entity(constructor, context: ClassDecoratorContext) {
|
|
153
|
-
if (!constructor._definition) {
|
|
154
|
-
// for inheritance support
|
|
155
|
-
TypeContext.register(constructor);
|
|
156
|
-
}
|
|
157
|
-
|
|
51
|
+
export function entity(constructor) {
|
|
52
|
+
TypeContext.register(constructor);
|
|
158
53
|
return constructor;
|
|
159
54
|
}
|
|
160
55
|
|
|
@@ -186,8 +81,8 @@ export function entity(constructor, context: ClassDecoratorContext) {
|
|
|
186
81
|
// // detect index for this field, considering inheritance
|
|
187
82
|
// //
|
|
188
83
|
// const parent = Object.getPrototypeOf(context.metadata);
|
|
189
|
-
// let fieldIndex: number = context.metadata[
|
|
190
|
-
// ?? (parent && parent[
|
|
84
|
+
// let fieldIndex: number = context.metadata[$numFields] // current structure already has fields defined
|
|
85
|
+
// ?? (parent && parent[$numFields]) // parent structure has fields defined
|
|
191
86
|
// ?? -1; // no fields defined
|
|
192
87
|
// fieldIndex++;
|
|
193
88
|
|
|
@@ -330,19 +225,22 @@ export function view<T> (tag: number = DEFAULT_VIEW_TAG) {
|
|
|
330
225
|
|
|
331
226
|
const parentClass = Object.getPrototypeOf(constructor);
|
|
332
227
|
const parentMetadata = parentClass[Symbol.metadata];
|
|
333
|
-
const metadata: Metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
334
228
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
229
|
+
// TODO: use Metadata.initialize()
|
|
230
|
+
const metadata: Metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
231
|
+
// const fieldIndex = metadata[fieldName];
|
|
232
|
+
|
|
233
|
+
// if (!metadata[fieldIndex]) {
|
|
234
|
+
// //
|
|
235
|
+
// // detect index for this field, considering inheritance
|
|
236
|
+
// //
|
|
237
|
+
// metadata[fieldIndex] = {
|
|
238
|
+
// type: undefined,
|
|
239
|
+
// index: (metadata[$numFields] // current structure already has fields defined
|
|
240
|
+
// ?? (parentMetadata && parentMetadata[$numFields]) // parent structure has fields defined
|
|
241
|
+
// ?? -1) + 1 // no fields defined
|
|
242
|
+
// }
|
|
243
|
+
// }
|
|
346
244
|
|
|
347
245
|
Metadata.setTag(metadata, fieldName, tag);
|
|
348
246
|
}
|
|
@@ -356,22 +254,24 @@ export function unreliable<T> (target: T, field: string) {
|
|
|
356
254
|
|
|
357
255
|
const parentClass = Object.getPrototypeOf(constructor);
|
|
358
256
|
const parentMetadata = parentClass[Symbol.metadata];
|
|
257
|
+
|
|
258
|
+
// TODO: use Metadata.initialize()
|
|
359
259
|
const metadata: Metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
360
260
|
|
|
361
|
-
if (!metadata[field]) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
261
|
+
// if (!metadata[field]) {
|
|
262
|
+
// //
|
|
263
|
+
// // detect index for this field, considering inheritance
|
|
264
|
+
// //
|
|
265
|
+
// metadata[field] = {
|
|
266
|
+
// type: undefined,
|
|
267
|
+
// index: (metadata[$numFields] // current structure already has fields defined
|
|
268
|
+
// ?? (parentMetadata && parentMetadata[$numFields]) // parent structure has fields defined
|
|
269
|
+
// ?? -1) + 1 // no fields defined
|
|
270
|
+
// }
|
|
271
|
+
// }
|
|
372
272
|
|
|
373
273
|
// add owned flag to the field
|
|
374
|
-
metadata[field].unreliable = true;
|
|
274
|
+
metadata[metadata[field]].unreliable = true;
|
|
375
275
|
}
|
|
376
276
|
|
|
377
277
|
export function type (
|
|
@@ -389,20 +289,20 @@ export function type (
|
|
|
389
289
|
TypeContext.register(constructor);
|
|
390
290
|
|
|
391
291
|
const parentClass = Object.getPrototypeOf(constructor);
|
|
392
|
-
const parentMetadata =
|
|
393
|
-
const metadata
|
|
292
|
+
const parentMetadata = parentClass[Symbol.metadata];
|
|
293
|
+
const metadata = Metadata.initialize(constructor);
|
|
394
294
|
|
|
395
|
-
let fieldIndex: number;
|
|
295
|
+
let fieldIndex: number = metadata[field];
|
|
396
296
|
|
|
397
297
|
/**
|
|
398
298
|
* skip if descriptor already exists for this field (`@deprecated()`)
|
|
399
299
|
*/
|
|
400
|
-
if (metadata[
|
|
401
|
-
if (metadata[
|
|
300
|
+
if (metadata[fieldIndex] !== undefined) {
|
|
301
|
+
if (metadata[fieldIndex].deprecated) {
|
|
402
302
|
// do not create accessors for deprecated properties.
|
|
403
303
|
return;
|
|
404
304
|
|
|
405
|
-
} else if (metadata[
|
|
305
|
+
} else if (metadata[fieldIndex].type !== undefined) {
|
|
406
306
|
// trying to define same property multiple times across inheritance.
|
|
407
307
|
// https://github.com/colyseus/colyseus-unity3d/issues/131#issuecomment-814308572
|
|
408
308
|
try {
|
|
@@ -412,28 +312,31 @@ export function type (
|
|
|
412
312
|
const definitionAtLine = e.stack.split("\n")[4].trim();
|
|
413
313
|
throw new Error(`${e.message} ${definitionAtLine}`);
|
|
414
314
|
}
|
|
415
|
-
|
|
416
|
-
} else {
|
|
417
|
-
fieldIndex = metadata[field].index;
|
|
418
315
|
}
|
|
419
316
|
|
|
420
317
|
} else {
|
|
421
318
|
//
|
|
422
319
|
// detect index for this field, considering inheritance
|
|
423
320
|
//
|
|
424
|
-
fieldIndex = metadata[
|
|
425
|
-
?? (parentMetadata && parentMetadata[
|
|
321
|
+
fieldIndex = metadata[$numFields] // current structure already has fields defined
|
|
322
|
+
?? (parentMetadata && parentMetadata[$numFields]) // parent structure has fields defined
|
|
426
323
|
?? -1; // no fields defined
|
|
427
324
|
fieldIndex++;
|
|
428
325
|
}
|
|
429
326
|
|
|
430
327
|
if (options && options.manual) {
|
|
431
|
-
Metadata.addField(
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
328
|
+
Metadata.addField(
|
|
329
|
+
metadata,
|
|
330
|
+
fieldIndex,
|
|
331
|
+
field,
|
|
332
|
+
type,
|
|
333
|
+
{
|
|
334
|
+
// do not declare getter/setter descriptor
|
|
335
|
+
enumerable: true,
|
|
336
|
+
configurable: true,
|
|
337
|
+
writable: true,
|
|
338
|
+
}
|
|
339
|
+
);
|
|
437
340
|
|
|
438
341
|
} else {
|
|
439
342
|
const complexTypeKlass = (Array.isArray(type))
|
|
@@ -449,7 +352,7 @@ export function type (
|
|
|
449
352
|
fieldIndex,
|
|
450
353
|
field,
|
|
451
354
|
type,
|
|
452
|
-
getPropertyDescriptor(`_${field}`, fieldIndex, childType, complexTypeKlass
|
|
355
|
+
getPropertyDescriptor(`_${field}`, fieldIndex, childType, complexTypeKlass)
|
|
453
356
|
);
|
|
454
357
|
}
|
|
455
358
|
}
|
|
@@ -460,13 +363,11 @@ export function getPropertyDescriptor(
|
|
|
460
363
|
fieldIndex: number,
|
|
461
364
|
type: DefinitionType,
|
|
462
365
|
complexTypeKlass: TypeDefinition,
|
|
463
|
-
metadata: Metadata,
|
|
464
|
-
field: string,
|
|
465
366
|
) {
|
|
466
367
|
return {
|
|
467
368
|
get: function () { return this[fieldCached]; },
|
|
468
369
|
set: function (this: Schema, value: any) {
|
|
469
|
-
const previousValue = this[fieldCached]
|
|
370
|
+
const previousValue = this[fieldCached] ?? undefined;
|
|
470
371
|
|
|
471
372
|
// skip if value is the same as cached.
|
|
472
373
|
if (value === previousValue) { return; }
|
|
@@ -487,30 +388,32 @@ export function getPropertyDescriptor(
|
|
|
487
388
|
}
|
|
488
389
|
|
|
489
390
|
value[$childType] = type;
|
|
391
|
+
|
|
392
|
+
} else if (typeof (type) !== "string") {
|
|
393
|
+
assertInstanceType(value, type as typeof Schema, this, fieldCached.substring(1));
|
|
394
|
+
|
|
395
|
+
} else {
|
|
396
|
+
assertType(value, type, this, fieldCached.substring(1));
|
|
490
397
|
}
|
|
491
398
|
|
|
399
|
+
const changeTree = this[$changes];
|
|
400
|
+
|
|
492
401
|
//
|
|
493
402
|
// Replacing existing "ref", remove it from root.
|
|
494
403
|
// TODO: if there are other references to this instance, we should not remove it from root.
|
|
495
404
|
//
|
|
496
405
|
if (previousValue !== undefined && previousValue[$changes]) {
|
|
497
|
-
|
|
406
|
+
changeTree.root?.remove(previousValue[$changes]);
|
|
498
407
|
}
|
|
499
408
|
|
|
500
409
|
// flag the change for encoding.
|
|
501
|
-
this.constructor[$track](
|
|
410
|
+
this.constructor[$track](changeTree, fieldIndex, OPERATION.ADD);
|
|
502
411
|
|
|
503
412
|
//
|
|
504
413
|
// call setParent() recursively for this and its child
|
|
505
414
|
// structures.
|
|
506
415
|
//
|
|
507
|
-
|
|
508
|
-
value[$changes].setParent(
|
|
509
|
-
this,
|
|
510
|
-
this[$changes].root,
|
|
511
|
-
metadata[field].index,
|
|
512
|
-
);
|
|
513
|
-
}
|
|
416
|
+
(value as Ref)[$changes]?.setParent(this, changeTree.root, fieldIndex);
|
|
514
417
|
|
|
515
418
|
} else if (previousValue !== undefined) {
|
|
516
419
|
//
|
|
@@ -542,23 +445,25 @@ export function deprecated(throws: boolean = true): PropertyDecorator {
|
|
|
542
445
|
const parentClass = Object.getPrototypeOf(constructor);
|
|
543
446
|
const parentMetadata = parentClass[Symbol.metadata];
|
|
544
447
|
const metadata: Metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
|
|
448
|
+
const fieldIndex = metadata[field];
|
|
449
|
+
|
|
450
|
+
// if (!metadata[field]) {
|
|
451
|
+
// //
|
|
452
|
+
// // detect index for this field, considering inheritance
|
|
453
|
+
// //
|
|
454
|
+
// metadata[field] = {
|
|
455
|
+
// type: undefined,
|
|
456
|
+
// index: (metadata[$numFields] // current structure already has fields defined
|
|
457
|
+
// ?? (parentMetadata && parentMetadata[$numFields]) // parent structure has fields defined
|
|
458
|
+
// ?? -1) + 1 // no fields defined
|
|
459
|
+
// }
|
|
460
|
+
// }
|
|
461
|
+
|
|
462
|
+
metadata[fieldIndex].deprecated = true;
|
|
559
463
|
|
|
560
464
|
if (throws) {
|
|
561
|
-
metadata[
|
|
465
|
+
metadata[$descriptors] ??= {};
|
|
466
|
+
metadata[$descriptors][field] = {
|
|
562
467
|
get: function () { throw new Error(`${field} is deprecated.`); },
|
|
563
468
|
set: function (this: Schema, value: any) { /* throw new Error(`${field} is deprecated.`); */ },
|
|
564
469
|
enumerable: false,
|
|
@@ -567,8 +472,8 @@ export function deprecated(throws: boolean = true): PropertyDecorator {
|
|
|
567
472
|
}
|
|
568
473
|
|
|
569
474
|
// flag metadata[field] as non-enumerable
|
|
570
|
-
Object.defineProperty(metadata,
|
|
571
|
-
value: metadata[
|
|
475
|
+
Object.defineProperty(metadata, fieldIndex, {
|
|
476
|
+
value: metadata[fieldIndex],
|
|
572
477
|
enumerable: false,
|
|
573
478
|
configurable: true
|
|
574
479
|
});
|
|
@@ -577,7 +482,7 @@ export function deprecated(throws: boolean = true): PropertyDecorator {
|
|
|
577
482
|
|
|
578
483
|
export function defineTypes(
|
|
579
484
|
target: typeof Schema,
|
|
580
|
-
fields:
|
|
485
|
+
fields: Definition,
|
|
581
486
|
options?: TypeOptions
|
|
582
487
|
) {
|
|
583
488
|
for (let field in fields) {
|
|
@@ -585,3 +490,52 @@ export function defineTypes(
|
|
|
585
490
|
}
|
|
586
491
|
return target;
|
|
587
492
|
}
|
|
493
|
+
|
|
494
|
+
export interface SchemaWithExtends<T extends Definition, P extends typeof Schema> extends DefinedSchemaType<T, P> {
|
|
495
|
+
extends: <T2 extends Definition>(
|
|
496
|
+
fields: T2,
|
|
497
|
+
name?: string
|
|
498
|
+
) => SchemaWithExtends<T & T2, typeof this>;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
export function schema<T extends Definition, P extends typeof Schema = typeof Schema>(
|
|
502
|
+
fields: T,
|
|
503
|
+
name?: string,
|
|
504
|
+
inherits: P = Schema as P
|
|
505
|
+
): SchemaWithExtends<T, P> {
|
|
506
|
+
const defaultValues: any = {};
|
|
507
|
+
const viewTagFields: any = {};
|
|
508
|
+
|
|
509
|
+
for (let fieldName in fields) {
|
|
510
|
+
const field = fields[fieldName] as DefinitionType;
|
|
511
|
+
if (typeof (field) === "object") {
|
|
512
|
+
if (field['default'] !== undefined) {
|
|
513
|
+
defaultValues[fieldName] = field['default'];
|
|
514
|
+
}
|
|
515
|
+
if (field['view'] !== undefined) {
|
|
516
|
+
viewTagFields[fieldName] = (typeof (field['view']) === "boolean")
|
|
517
|
+
? DEFAULT_VIEW_TAG
|
|
518
|
+
: field['view'];
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const klass = Metadata.setFields(class extends inherits {
|
|
524
|
+
constructor (...args: any[]) {
|
|
525
|
+
args[0] = Object.assign({}, defaultValues, args[0]);
|
|
526
|
+
super(...args);
|
|
527
|
+
}
|
|
528
|
+
}, fields) as SchemaWithExtends<T, P>;
|
|
529
|
+
|
|
530
|
+
for (let fieldName in viewTagFields) {
|
|
531
|
+
view(viewTagFields[fieldName])(klass.prototype, fieldName);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (name) {
|
|
535
|
+
Object.defineProperty(klass, "name", { value: name });
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
klass.extends = (fields, name) => schema(fields, name, klass);
|
|
539
|
+
|
|
540
|
+
return klass;
|
|
541
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { nanoid } from "nanoid";
|
|
2
|
+
import { Schema, type, MapSchema, ArraySchema, Encoder } from ".";
|
|
3
|
+
|
|
4
|
+
class Attribute extends Schema {
|
|
5
|
+
@type("string") name: string;
|
|
6
|
+
@type("number") value: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
class Item extends Schema {
|
|
10
|
+
@type("number") price: number;
|
|
11
|
+
@type([ Attribute ]) attributes = new ArraySchema<Attribute>();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class Position extends Schema {
|
|
15
|
+
@type("number") x: number;
|
|
16
|
+
@type("number") y: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class Player extends Schema {
|
|
20
|
+
@type(Position) position = new Position();
|
|
21
|
+
@type({ map: Item }) items = new MapSchema<Item>();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class State extends Schema {
|
|
25
|
+
@type({ map: Player }) players = new MapSchema<Player>();
|
|
26
|
+
@type("string") currentTurn;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const state = new State();
|
|
30
|
+
|
|
31
|
+
Encoder.BUFFER_SIZE = 4096 * 4096;
|
|
32
|
+
const encoder = new Encoder(state);
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
let now = Date.now();
|
|
36
|
+
|
|
37
|
+
// for (let i = 0; i < 10000; i++) {
|
|
38
|
+
// const player = new Player();
|
|
39
|
+
// state.players.set(`p-${nanoid()}`, player);
|
|
40
|
+
//
|
|
41
|
+
// player.position.x = (i + 1) * 100;
|
|
42
|
+
// player.position.y = (i + 1) * 100;
|
|
43
|
+
// for (let j = 0; j < 10; j++) {
|
|
44
|
+
// const item = new Item();
|
|
45
|
+
// player.items.set(`item-${j}`, item);
|
|
46
|
+
// item.price = (i + 1) * 50;
|
|
47
|
+
// for (let k = 0; k < 5; k++) {
|
|
48
|
+
// const attr = new Attribute();
|
|
49
|
+
// attr.name = `Attribute ${k}`;
|
|
50
|
+
// attr.value = k;
|
|
51
|
+
// item.attributes.push(attr);
|
|
52
|
+
// }
|
|
53
|
+
// }
|
|
54
|
+
// }
|
|
55
|
+
// console.log("time to make changes:", Date.now() - now);
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
// measure time to .encodeAll()
|
|
59
|
+
|
|
60
|
+
now = Date.now();
|
|
61
|
+
// for (let i = 0; i < 1000; i++) {
|
|
62
|
+
// encoder.encodeAll();
|
|
63
|
+
// }
|
|
64
|
+
// console.log(Date.now() - now);
|
|
65
|
+
|
|
66
|
+
const total = 100;
|
|
67
|
+
const allEncodes = Date.now();
|
|
68
|
+
|
|
69
|
+
let avgTimeToEncode = 0;
|
|
70
|
+
let avgTimeToMakeChanges = 0;
|
|
71
|
+
|
|
72
|
+
for (let i = 0; i < total; i++) {
|
|
73
|
+
now = Date.now();
|
|
74
|
+
for (let j = 0; j < 50; j++) {
|
|
75
|
+
const player = new Player();
|
|
76
|
+
state.players.set(`p-${nanoid()}`, player);
|
|
77
|
+
|
|
78
|
+
player.position.x = (j + 1) * 100;
|
|
79
|
+
player.position.y = (j + 1) * 100;
|
|
80
|
+
for (let k = 0; k < 10; k++) {
|
|
81
|
+
const item = new Item();
|
|
82
|
+
item.price = (j + 1) * 50;
|
|
83
|
+
for (let l = 0; l < 5; l++) {
|
|
84
|
+
const attr = new Attribute();
|
|
85
|
+
attr.name = `Attribute ${l}`;
|
|
86
|
+
attr.value = l;
|
|
87
|
+
item.attributes.push(attr);
|
|
88
|
+
}
|
|
89
|
+
player.items.set(`item-${k}`, item);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const timeToMakeChanges = Date.now() - now;
|
|
93
|
+
console.log("time to make changes:", timeToMakeChanges);
|
|
94
|
+
avgTimeToMakeChanges += timeToMakeChanges;
|
|
95
|
+
|
|
96
|
+
now = Date.now();
|
|
97
|
+
encoder.encode();
|
|
98
|
+
encoder.discardChanges();
|
|
99
|
+
|
|
100
|
+
const timeToEncode = Date.now() - now;
|
|
101
|
+
console.log("time to encode:", timeToEncode);
|
|
102
|
+
avgTimeToEncode += timeToEncode;
|
|
103
|
+
}
|
|
104
|
+
console.log("avg time to encode:", (avgTimeToEncode) / total);
|
|
105
|
+
console.log("avg time to make changes:", (avgTimeToMakeChanges) / total);
|
|
106
|
+
console.log("time for all encodes:", Date.now() - allEncodes);
|
|
107
|
+
|
|
108
|
+
console.log(Array.from(encoder.encodeAll()).length, "bytes");
|