@colyseus/schema 3.0.0-alpha.30 → 3.0.0-alpha.32
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 +389 -354
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +389 -354
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +389 -354
- package/lib/Metadata.d.ts +14 -5
- package/lib/Metadata.js +49 -20
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.js +4 -13
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.js +26 -39
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +1 -2
- package/lib/annotations.js +58 -52
- package/lib/annotations.js.map +1 -1
- package/lib/bench_encode.js +25 -22
- package/lib/bench_encode.js.map +1 -1
- package/lib/decoder/DecodeOperation.js +7 -9
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/ReferenceTracker.js +3 -2
- package/lib/decoder/ReferenceTracker.js.map +1 -1
- package/lib/decoder/strategy/StateCallbacks.js +4 -3
- package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
- package/lib/encoder/ChangeTree.d.ts +8 -7
- package/lib/encoder/ChangeTree.js +135 -117
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.d.ts +1 -4
- package/lib/encoder/EncodeOperation.js +17 -47
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.js +18 -6
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +2 -2
- package/lib/encoder/Root.js +18 -6
- package/lib/encoder/Root.js.map +1 -1
- package/lib/encoder/StateView.js +3 -3
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/encoding/assert.d.ts +2 -1
- package/lib/encoding/assert.js +2 -2
- package/lib/encoding/assert.js.map +1 -1
- package/lib/index.d.ts +1 -2
- package/lib/index.js +11 -10
- package/lib/index.js.map +1 -1
- package/lib/types/TypeContext.js +7 -14
- package/lib/types/TypeContext.js.map +1 -1
- package/lib/types/custom/ArraySchema.js +6 -0
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/CollectionSchema.js +1 -0
- package/lib/types/custom/CollectionSchema.js.map +1 -1
- package/lib/types/custom/MapSchema.js +5 -0
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/lib/types/custom/SetSchema.js +1 -0
- package/lib/types/custom/SetSchema.js.map +1 -1
- package/lib/types/symbols.d.ts +1 -0
- package/lib/types/symbols.js +2 -1
- package/lib/types/symbols.js.map +1 -1
- package/package.json +1 -1
- package/src/Metadata.ts +60 -29
- package/src/Reflection.ts +5 -15
- package/src/Schema.ts +33 -45
- package/src/annotations.ts +75 -67
- package/src/bench_encode.ts +29 -27
- package/src/decoder/DecodeOperation.ts +12 -11
- package/src/decoder/ReferenceTracker.ts +3 -2
- package/src/decoder/strategy/StateCallbacks.ts +4 -3
- package/src/encoder/ChangeTree.ts +154 -138
- package/src/encoder/EncodeOperation.ts +42 -62
- package/src/encoder/Encoder.ts +25 -8
- package/src/encoder/Root.ts +23 -6
- package/src/encoder/StateView.ts +4 -4
- package/src/encoding/assert.ts +4 -3
- package/src/index.ts +1 -4
- package/src/types/TypeContext.ts +10 -15
- package/src/types/custom/ArraySchema.ts +8 -0
- package/src/types/custom/CollectionSchema.ts +1 -0
- package/src/types/custom/MapSchema.ts +6 -0
- package/src/types/custom/SetSchema.ts +1 -0
- package/src/types/symbols.ts +2 -0
package/src/Schema.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { DEFAULT_VIEW_TAG, DefinitionType } from "./annotations";
|
|
|
4
4
|
import { NonFunctionPropNames, ToJSON } from './types/HelperTypes';
|
|
5
5
|
|
|
6
6
|
import { ChangeTree, Ref } from './encoder/ChangeTree';
|
|
7
|
-
import { $changes, $decoder, $deleteByIndex, $encoder, $filter, $getByIndex, $track } from './types/symbols';
|
|
7
|
+
import { $changes, $decoder, $deleteByIndex, $descriptors, $encoder, $filter, $getByIndex, $track } from './types/symbols';
|
|
8
8
|
import { StateView } from './encoder/StateView';
|
|
9
9
|
|
|
10
10
|
import { encodeSchemaOperation } from './encoder/EncodeOperation';
|
|
@@ -16,7 +16,6 @@ import { getIndent } from './utils';
|
|
|
16
16
|
* Schema encoder / decoder
|
|
17
17
|
*/
|
|
18
18
|
export abstract class Schema {
|
|
19
|
-
|
|
20
19
|
static [$encoder] = encodeSchemaOperation;
|
|
21
20
|
static [$decoder] = decodeSchemaOperation;
|
|
22
21
|
|
|
@@ -31,37 +30,7 @@ export abstract class Schema {
|
|
|
31
30
|
writable: true
|
|
32
31
|
});
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// Define property descriptors
|
|
37
|
-
for (const field in metadata) {
|
|
38
|
-
if (metadata[field].descriptor) {
|
|
39
|
-
// for encoder
|
|
40
|
-
Object.defineProperty(instance, `_${field}`, {
|
|
41
|
-
value: undefined,
|
|
42
|
-
writable: true,
|
|
43
|
-
enumerable: false,
|
|
44
|
-
configurable: true,
|
|
45
|
-
});
|
|
46
|
-
Object.defineProperty(instance, field, metadata[field].descriptor);
|
|
47
|
-
|
|
48
|
-
} else {
|
|
49
|
-
// for decoder
|
|
50
|
-
Object.defineProperty(instance, field, {
|
|
51
|
-
value: undefined,
|
|
52
|
-
writable: true,
|
|
53
|
-
enumerable: true,
|
|
54
|
-
configurable: true,
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Object.defineProperty(instance, field, {
|
|
59
|
-
// ...instance.constructor[Symbol.metadata][field].descriptor
|
|
60
|
-
// });
|
|
61
|
-
// if (args[0]?.hasOwnProperty(field)) {
|
|
62
|
-
// instance[field] = args[0][field];
|
|
63
|
-
// }
|
|
64
|
-
}
|
|
33
|
+
Object.defineProperties(instance, instance.constructor[Symbol.metadata]?.[$descriptors] || {});
|
|
65
34
|
}
|
|
66
35
|
|
|
67
36
|
static is(type: DefinitionType) {
|
|
@@ -88,7 +57,7 @@ export abstract class Schema {
|
|
|
88
57
|
*/
|
|
89
58
|
static [$filter] (ref: Schema, index: number, view: StateView) {
|
|
90
59
|
const metadata: Metadata = ref.constructor[Symbol.metadata];
|
|
91
|
-
const tag = metadata[
|
|
60
|
+
const tag = metadata[index]?.tag;
|
|
92
61
|
|
|
93
62
|
if (view === undefined) {
|
|
94
63
|
// shared pass/encode: encode if doesn't have a tag
|
|
@@ -111,13 +80,24 @@ export abstract class Schema {
|
|
|
111
80
|
|
|
112
81
|
// allow inherited classes to have a constructor
|
|
113
82
|
constructor(...args: any[]) {
|
|
114
|
-
|
|
83
|
+
//
|
|
84
|
+
// inline
|
|
85
|
+
// Schema.initialize(this);
|
|
86
|
+
//
|
|
87
|
+
|
|
88
|
+
Object.defineProperty(this, $changes, {
|
|
89
|
+
value: new ChangeTree(this),
|
|
90
|
+
enumerable: false,
|
|
91
|
+
writable: true
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
Object.defineProperties(this, this.constructor[Symbol.metadata]?.[$descriptors] || {});
|
|
115
95
|
|
|
116
96
|
//
|
|
117
97
|
// Assign initial values
|
|
118
98
|
//
|
|
119
99
|
if (args[0]) {
|
|
120
|
-
|
|
100
|
+
Object.assign(this, args[0]);
|
|
121
101
|
}
|
|
122
102
|
}
|
|
123
103
|
|
|
@@ -135,21 +115,25 @@ export abstract class Schema {
|
|
|
135
115
|
* @param operation OPERATION to perform (detected automatically)
|
|
136
116
|
*/
|
|
137
117
|
public setDirty<K extends NonFunctionPropNames<this>>(property: K | number, operation?: OPERATION) {
|
|
118
|
+
const metadata: Metadata = this.constructor[Symbol.metadata];
|
|
138
119
|
this[$changes].change(
|
|
139
|
-
|
|
120
|
+
metadata[metadata[property as string]].index,
|
|
140
121
|
operation
|
|
141
122
|
);
|
|
142
123
|
}
|
|
143
124
|
|
|
144
125
|
clone (): this {
|
|
145
126
|
const cloned = new ((this as any).constructor);
|
|
146
|
-
const metadata = this.constructor[Symbol.metadata];
|
|
127
|
+
const metadata: Metadata = this.constructor[Symbol.metadata];
|
|
147
128
|
|
|
148
129
|
//
|
|
149
130
|
// TODO: clone all properties, not only annotated ones
|
|
150
131
|
//
|
|
151
132
|
// for (const field in this) {
|
|
152
|
-
for (const
|
|
133
|
+
for (const fieldIndex in metadata) {
|
|
134
|
+
// const field = metadata[metadata[fieldIndex]].name;
|
|
135
|
+
const field = metadata[fieldIndex as any as number].name;
|
|
136
|
+
|
|
153
137
|
if (
|
|
154
138
|
typeof (this[field]) === "object" &&
|
|
155
139
|
typeof (this[field]?.clone) === "function"
|
|
@@ -162,15 +146,17 @@ export abstract class Schema {
|
|
|
162
146
|
cloned[field] = this[field];
|
|
163
147
|
}
|
|
164
148
|
}
|
|
149
|
+
|
|
165
150
|
return cloned;
|
|
166
151
|
}
|
|
167
152
|
|
|
168
153
|
toJSON () {
|
|
169
|
-
const metadata = this.constructor[Symbol.metadata];
|
|
170
|
-
|
|
171
154
|
const obj: unknown = {};
|
|
172
|
-
|
|
173
|
-
|
|
155
|
+
|
|
156
|
+
const metadata = this.constructor[Symbol.metadata];
|
|
157
|
+
for (const index in metadata) {
|
|
158
|
+
const field = metadata[index];
|
|
159
|
+
const fieldName = field.name;
|
|
174
160
|
if (!field.deprecated && this[fieldName] !== null && typeof (this[fieldName]) !== "undefined") {
|
|
175
161
|
obj[fieldName] = (typeof (this[fieldName]['toJSON']) === "function")
|
|
176
162
|
? this[fieldName]['toJSON']()
|
|
@@ -185,11 +171,13 @@ export abstract class Schema {
|
|
|
185
171
|
}
|
|
186
172
|
|
|
187
173
|
protected [$getByIndex](index: number) {
|
|
188
|
-
|
|
174
|
+
const metadata: Metadata = this.constructor[Symbol.metadata];
|
|
175
|
+
return this[metadata[index].name];
|
|
189
176
|
}
|
|
190
177
|
|
|
191
178
|
protected [$deleteByIndex](index: number) {
|
|
192
|
-
this
|
|
179
|
+
const metadata: Metadata = this.constructor[Symbol.metadata];
|
|
180
|
+
this[metadata[index].name] = undefined;
|
|
193
181
|
}
|
|
194
182
|
|
|
195
183
|
static debugRefIds(instance: Ref, jsonContents: boolean = true, level: number = 0) {
|
package/src/annotations.ts
CHANGED
|
@@ -3,10 +3,12 @@ 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, $track } from "./types/symbols";
|
|
7
7
|
import { TypeDefinition, getType } from "./types/registry";
|
|
8
8
|
import { OPERATION } from "./encoding/spec";
|
|
9
9
|
import { TypeContext } from "./types/TypeContext";
|
|
10
|
+
import { assertInstanceType, assertType } from "./encoding/assert";
|
|
11
|
+
import type { Ref } from "./encoder/ChangeTree";
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* Data types
|
|
@@ -227,18 +229,19 @@ export function view<T> (tag: number = DEFAULT_VIEW_TAG) {
|
|
|
227
229
|
|
|
228
230
|
// TODO: use Metadata.initialize()
|
|
229
231
|
const metadata: Metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
232
|
+
// const fieldIndex = metadata[fieldName];
|
|
233
|
+
|
|
234
|
+
// if (!metadata[fieldIndex]) {
|
|
235
|
+
// //
|
|
236
|
+
// // detect index for this field, considering inheritance
|
|
237
|
+
// //
|
|
238
|
+
// metadata[fieldIndex] = {
|
|
239
|
+
// type: undefined,
|
|
240
|
+
// index: (metadata[-1] // current structure already has fields defined
|
|
241
|
+
// ?? (parentMetadata && parentMetadata[-1]) // parent structure has fields defined
|
|
242
|
+
// ?? -1) + 1 // no fields defined
|
|
243
|
+
// }
|
|
244
|
+
// }
|
|
242
245
|
|
|
243
246
|
Metadata.setTag(metadata, fieldName, tag);
|
|
244
247
|
}
|
|
@@ -256,20 +259,20 @@ export function unreliable<T> (target: T, field: string) {
|
|
|
256
259
|
// TODO: use Metadata.initialize()
|
|
257
260
|
const metadata: Metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
258
261
|
|
|
259
|
-
if (!metadata[field]) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
262
|
+
// if (!metadata[field]) {
|
|
263
|
+
// //
|
|
264
|
+
// // detect index for this field, considering inheritance
|
|
265
|
+
// //
|
|
266
|
+
// metadata[field] = {
|
|
267
|
+
// type: undefined,
|
|
268
|
+
// index: (metadata[-1] // current structure already has fields defined
|
|
269
|
+
// ?? (parentMetadata && parentMetadata[-1]) // parent structure has fields defined
|
|
270
|
+
// ?? -1) + 1 // no fields defined
|
|
271
|
+
// }
|
|
272
|
+
// }
|
|
270
273
|
|
|
271
274
|
// add owned flag to the field
|
|
272
|
-
metadata[field].unreliable = true;
|
|
275
|
+
metadata[metadata[field]].unreliable = true;
|
|
273
276
|
}
|
|
274
277
|
|
|
275
278
|
export function type (
|
|
@@ -290,17 +293,17 @@ export function type (
|
|
|
290
293
|
const parentMetadata = parentClass && parentClass[Symbol.metadata];
|
|
291
294
|
const metadata = Metadata.initialize(constructor, parentMetadata);
|
|
292
295
|
|
|
293
|
-
let fieldIndex: number;
|
|
296
|
+
let fieldIndex: number = metadata[field];
|
|
294
297
|
|
|
295
298
|
/**
|
|
296
299
|
* skip if descriptor already exists for this field (`@deprecated()`)
|
|
297
300
|
*/
|
|
298
|
-
if (metadata[
|
|
299
|
-
if (metadata[
|
|
301
|
+
if (metadata[fieldIndex]) {
|
|
302
|
+
if (metadata[fieldIndex].deprecated) {
|
|
300
303
|
// do not create accessors for deprecated properties.
|
|
301
304
|
return;
|
|
302
305
|
|
|
303
|
-
} else if (metadata[
|
|
306
|
+
} else if (metadata[fieldIndex].type !== undefined) {
|
|
304
307
|
// trying to define same property multiple times across inheritance.
|
|
305
308
|
// https://github.com/colyseus/colyseus-unity3d/issues/131#issuecomment-814308572
|
|
306
309
|
try {
|
|
@@ -310,9 +313,6 @@ export function type (
|
|
|
310
313
|
const definitionAtLine = e.stack.split("\n")[4].trim();
|
|
311
314
|
throw new Error(`${e.message} ${definitionAtLine}`);
|
|
312
315
|
}
|
|
313
|
-
|
|
314
|
-
} else {
|
|
315
|
-
fieldIndex = metadata[field].index;
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
} else {
|
|
@@ -326,12 +326,18 @@ export function type (
|
|
|
326
326
|
}
|
|
327
327
|
|
|
328
328
|
if (options && options.manual) {
|
|
329
|
-
Metadata.addField(
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
329
|
+
Metadata.addField(
|
|
330
|
+
metadata,
|
|
331
|
+
fieldIndex,
|
|
332
|
+
field,
|
|
333
|
+
type,
|
|
334
|
+
{
|
|
335
|
+
// do not declare getter/setter descriptor
|
|
336
|
+
enumerable: true,
|
|
337
|
+
configurable: true,
|
|
338
|
+
writable: true,
|
|
339
|
+
}
|
|
340
|
+
);
|
|
335
341
|
|
|
336
342
|
} else {
|
|
337
343
|
const complexTypeKlass = (Array.isArray(type))
|
|
@@ -347,7 +353,7 @@ export function type (
|
|
|
347
353
|
fieldIndex,
|
|
348
354
|
field,
|
|
349
355
|
type,
|
|
350
|
-
getPropertyDescriptor(`_${field}`, fieldIndex, childType, complexTypeKlass
|
|
356
|
+
getPropertyDescriptor(`_${field}`, fieldIndex, childType, complexTypeKlass)
|
|
351
357
|
);
|
|
352
358
|
}
|
|
353
359
|
}
|
|
@@ -358,8 +364,6 @@ export function getPropertyDescriptor(
|
|
|
358
364
|
fieldIndex: number,
|
|
359
365
|
type: DefinitionType,
|
|
360
366
|
complexTypeKlass: TypeDefinition,
|
|
361
|
-
metadata: Metadata,
|
|
362
|
-
field: string,
|
|
363
367
|
) {
|
|
364
368
|
return {
|
|
365
369
|
get: function () { return this[fieldCached]; },
|
|
@@ -385,30 +389,32 @@ export function getPropertyDescriptor(
|
|
|
385
389
|
}
|
|
386
390
|
|
|
387
391
|
value[$childType] = type;
|
|
392
|
+
|
|
393
|
+
} else if (typeof (type) !== "string") {
|
|
394
|
+
assertInstanceType(value, type as typeof Schema, this, fieldCached.substring(1));
|
|
395
|
+
|
|
396
|
+
} else {
|
|
397
|
+
assertType(value, type, this, fieldCached.substring(1));
|
|
388
398
|
}
|
|
389
399
|
|
|
400
|
+
const changeTree = this[$changes];
|
|
401
|
+
|
|
390
402
|
//
|
|
391
403
|
// Replacing existing "ref", remove it from root.
|
|
392
404
|
// TODO: if there are other references to this instance, we should not remove it from root.
|
|
393
405
|
//
|
|
394
406
|
if (previousValue !== undefined && previousValue[$changes]) {
|
|
395
|
-
|
|
407
|
+
changeTree.root?.remove(previousValue[$changes]);
|
|
396
408
|
}
|
|
397
409
|
|
|
398
410
|
// flag the change for encoding.
|
|
399
|
-
this.constructor[$track](
|
|
411
|
+
this.constructor[$track](changeTree, fieldIndex, OPERATION.ADD);
|
|
400
412
|
|
|
401
413
|
//
|
|
402
414
|
// call setParent() recursively for this and its child
|
|
403
415
|
// structures.
|
|
404
416
|
//
|
|
405
|
-
|
|
406
|
-
value[$changes].setParent(
|
|
407
|
-
this,
|
|
408
|
-
this[$changes].root,
|
|
409
|
-
metadata[field].index,
|
|
410
|
-
);
|
|
411
|
-
}
|
|
417
|
+
(value as Ref)[$changes]?.setParent(this, changeTree.root, fieldIndex);
|
|
412
418
|
|
|
413
419
|
} else if (previousValue !== undefined) {
|
|
414
420
|
//
|
|
@@ -440,23 +446,25 @@ export function deprecated(throws: boolean = true): PropertyDecorator {
|
|
|
440
446
|
const parentClass = Object.getPrototypeOf(constructor);
|
|
441
447
|
const parentMetadata = parentClass[Symbol.metadata];
|
|
442
448
|
const metadata: Metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
|
|
449
|
+
const fieldIndex = metadata[field];
|
|
450
|
+
|
|
451
|
+
// if (!metadata[field]) {
|
|
452
|
+
// //
|
|
453
|
+
// // detect index for this field, considering inheritance
|
|
454
|
+
// //
|
|
455
|
+
// metadata[field] = {
|
|
456
|
+
// type: undefined,
|
|
457
|
+
// index: (metadata[-1] // current structure already has fields defined
|
|
458
|
+
// ?? (parentMetadata && parentMetadata[-1]) // parent structure has fields defined
|
|
459
|
+
// ?? -1) + 1 // no fields defined
|
|
460
|
+
// }
|
|
461
|
+
// }
|
|
462
|
+
|
|
463
|
+
metadata[fieldIndex].deprecated = true;
|
|
457
464
|
|
|
458
465
|
if (throws) {
|
|
459
|
-
metadata[
|
|
466
|
+
metadata[$descriptors] ??= {};
|
|
467
|
+
metadata[$descriptors][field] = {
|
|
460
468
|
get: function () { throw new Error(`${field} is deprecated.`); },
|
|
461
469
|
set: function (this: Schema, value: any) { /* throw new Error(`${field} is deprecated.`); */ },
|
|
462
470
|
enumerable: false,
|
|
@@ -465,8 +473,8 @@ export function deprecated(throws: boolean = true): PropertyDecorator {
|
|
|
465
473
|
}
|
|
466
474
|
|
|
467
475
|
// flag metadata[field] as non-enumerable
|
|
468
|
-
Object.defineProperty(metadata,
|
|
469
|
-
value: metadata[
|
|
476
|
+
Object.defineProperty(metadata, fieldIndex, {
|
|
477
|
+
value: metadata[fieldIndex],
|
|
470
478
|
enumerable: false,
|
|
471
479
|
configurable: true
|
|
472
480
|
});
|
package/src/bench_encode.ts
CHANGED
|
@@ -31,37 +31,40 @@ class State extends Schema {
|
|
|
31
31
|
|
|
32
32
|
const state = new State();
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
state.players.set(`p-${nanoid()}`, player);
|
|
37
|
-
|
|
38
|
-
player.position.x = (i + 1) * 100;
|
|
39
|
-
player.position.y = (i + 1) * 100;
|
|
40
|
-
for (let j = 0; j < 10; j++) {
|
|
41
|
-
const item = new Item();
|
|
42
|
-
item.price = (i + 1) * 50;
|
|
43
|
-
for (let k = 0; k < 5; k++) {
|
|
44
|
-
const attr = new Attribute();
|
|
45
|
-
attr.name = `Attribute ${k}`;
|
|
46
|
-
attr.value = k;
|
|
47
|
-
item.attributes.push(attr);
|
|
34
|
+
Encoder.BUFFER_SIZE = 4096 * 4096;
|
|
35
|
+
const encoder = new Encoder(state);
|
|
48
36
|
|
|
49
|
-
}
|
|
50
|
-
player.items.set(`item-${j}`, item);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
37
|
|
|
38
|
+
let now = Date.now();
|
|
39
|
+
|
|
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);
|
|
54
59
|
|
|
55
|
-
Encoder.BUFFER_SIZE = 4096 * 4096;
|
|
56
|
-
const encoder = new Encoder(state);
|
|
57
60
|
|
|
58
61
|
// measure time to .encodeAll()
|
|
59
62
|
|
|
60
|
-
|
|
61
|
-
for (let i = 0; i < 1000; i++) {
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
console.log(Date.now() - now);
|
|
63
|
+
now = Date.now();
|
|
64
|
+
// for (let i = 0; i < 1000; i++) {
|
|
65
|
+
// encoder.encodeAll();
|
|
66
|
+
// }
|
|
67
|
+
// console.log(Date.now() - now);
|
|
65
68
|
|
|
66
69
|
const allEncodes = Date.now();
|
|
67
70
|
for (let i = 0; i < 100; i++) {
|
|
@@ -80,7 +83,6 @@ for (let i = 0; i < 100; i++) {
|
|
|
80
83
|
attr.name = `Attribute ${l}`;
|
|
81
84
|
attr.value = l;
|
|
82
85
|
item.attributes.push(attr);
|
|
83
|
-
|
|
84
86
|
}
|
|
85
87
|
player.items.set(`item-${k}`, item);
|
|
86
88
|
}
|
|
@@ -94,4 +96,4 @@ for (let i = 0; i < 100; i++) {
|
|
|
94
96
|
}
|
|
95
97
|
console.log("time for all encodes:", Date.now() - allEncodes);
|
|
96
98
|
|
|
97
|
-
console.log(Array.from(encoder.encodeAll()).length, "bytes");
|
|
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
|
|
|
@@ -174,7 +181,7 @@ export const decodeSchemaOperation: DecodeOperation = function (
|
|
|
174
181
|
allChanges: DataChange[],
|
|
175
182
|
) {
|
|
176
183
|
const first_byte = bytes[it.offset++];
|
|
177
|
-
const metadata: Metadata = ref
|
|
184
|
+
const metadata: Metadata = ref.constructor[Symbol.metadata];
|
|
178
185
|
|
|
179
186
|
// "compressed" index + operation
|
|
180
187
|
const operation = (first_byte >> 6) << 6
|
|
@@ -192,14 +199,14 @@ export const decodeSchemaOperation: DecodeOperation = function (
|
|
|
192
199
|
operation,
|
|
193
200
|
ref,
|
|
194
201
|
index,
|
|
195
|
-
|
|
202
|
+
field.type,
|
|
196
203
|
bytes,
|
|
197
204
|
it,
|
|
198
205
|
allChanges,
|
|
199
206
|
);
|
|
200
207
|
|
|
201
208
|
if (value !== null && value !== undefined) {
|
|
202
|
-
ref[field] = value;
|
|
209
|
+
ref[field.name] = value;
|
|
203
210
|
}
|
|
204
211
|
|
|
205
212
|
// add change
|
|
@@ -208,7 +215,7 @@ export const decodeSchemaOperation: DecodeOperation = function (
|
|
|
208
215
|
ref,
|
|
209
216
|
refId: decoder.currentRefId,
|
|
210
217
|
op: operation,
|
|
211
|
-
field: field,
|
|
218
|
+
field: field.name,
|
|
212
219
|
value,
|
|
213
220
|
previousValue,
|
|
214
221
|
});
|
|
@@ -308,8 +315,6 @@ export const decodeArray: DecodeOperation = function (
|
|
|
308
315
|
) {
|
|
309
316
|
// "uncompressed" index + operation (array/map items)
|
|
310
317
|
let operation = bytes[it.offset++];
|
|
311
|
-
|
|
312
|
-
let isSchemaChild: boolean;
|
|
313
318
|
let index: number;
|
|
314
319
|
|
|
315
320
|
if (operation === OPERATION.CLEAR) {
|
|
@@ -341,9 +346,6 @@ export const decodeArray: DecodeOperation = function (
|
|
|
341
346
|
return;
|
|
342
347
|
|
|
343
348
|
} else if (operation === OPERATION.ADD_BY_REFID) {
|
|
344
|
-
isSchemaChild = true;
|
|
345
|
-
// operation = OPERATION.ADD;
|
|
346
|
-
|
|
347
349
|
const refId = decode.number(bytes, it);
|
|
348
350
|
const itemByRefId = decoder.root.refs.get(refId);
|
|
349
351
|
|
|
@@ -353,7 +355,6 @@ export const decodeArray: DecodeOperation = function (
|
|
|
353
355
|
: ref.length;
|
|
354
356
|
|
|
355
357
|
} else {
|
|
356
|
-
isSchemaChild = false;
|
|
357
358
|
index = decode.number(bytes, it);
|
|
358
359
|
}
|
|
359
360
|
|
|
@@ -98,8 +98,9 @@ export class ReferenceTracker {
|
|
|
98
98
|
// Ensure child schema instances have their references removed as well.
|
|
99
99
|
//
|
|
100
100
|
if (Metadata.isValidInstance(ref)) {
|
|
101
|
-
const metadata: Metadata = ref
|
|
102
|
-
for (const
|
|
101
|
+
const metadata: Metadata = ref.constructor[Symbol.metadata];
|
|
102
|
+
for (const index in metadata) {
|
|
103
|
+
const field = metadata[index as any as number].name;
|
|
103
104
|
const childRefId = typeof(ref[field]) === "object" && this.refIds.get(ref[field]);
|
|
104
105
|
if (childRefId) {
|
|
105
106
|
this.removeRef(childRefId);
|
|
@@ -264,7 +264,7 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
264
264
|
//
|
|
265
265
|
bindTo: function bindTo(targetObject: any, properties?: string[]) {
|
|
266
266
|
if (!properties) {
|
|
267
|
-
properties = Object.keys(metadata);
|
|
267
|
+
properties = Object.keys(metadata).map((index) => metadata[index as any as number].name);
|
|
268
268
|
}
|
|
269
269
|
return $root.addCallback(
|
|
270
270
|
$root.refIds.get(context.instance),
|
|
@@ -277,7 +277,8 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
277
277
|
}
|
|
278
278
|
}, {
|
|
279
279
|
get(target, prop: string) {
|
|
280
|
-
|
|
280
|
+
const metadataField = metadata[metadata[prop]];
|
|
281
|
+
if (metadataField) {
|
|
281
282
|
const instance = context.instance?.[prop];
|
|
282
283
|
const onInstanceAvailable: OnInstanceAvailableCallback = (
|
|
283
284
|
(callback: (ref: Ref, existing: boolean) => void) => {
|
|
@@ -297,7 +298,7 @@ export function getDecoderStateCallbacks<T extends Schema>(decoder: Decoder<T>):
|
|
|
297
298
|
}
|
|
298
299
|
}
|
|
299
300
|
);
|
|
300
|
-
return getProxy(
|
|
301
|
+
return getProxy(metadataField.type, {
|
|
301
302
|
// make sure refId is available, otherwise need to wait for the instance to be available.
|
|
302
303
|
instance: ($root.refIds.get(instance) && instance),
|
|
303
304
|
parentInstance: context.instance,
|