@colyseus/schema 3.0.0-alpha.28 → 3.0.0-alpha.29
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 +109 -84
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +109 -84
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +109 -84
- package/lib/Metadata.d.ts +3 -0
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.d.ts +1 -1
- package/lib/Reflection.js +4 -3
- package/lib/Reflection.js.map +1 -1
- package/lib/annotations.d.ts +0 -19
- package/lib/annotations.js +4 -106
- package/lib/annotations.js.map +1 -1
- package/lib/bench_encode.js +54 -27
- package/lib/bench_encode.js.map +1 -1
- package/lib/decoder/Decoder.d.ts +1 -1
- package/lib/decoder/Decoder.js +2 -2
- package/lib/decoder/Decoder.js.map +1 -1
- package/lib/encoder/ChangeTree.d.ts +1 -12
- package/lib/encoder/ChangeTree.js +24 -51
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +6 -5
- package/lib/encoder/Encoder.js +28 -19
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +17 -0
- package/lib/encoder/Root.js +44 -0
- package/lib/encoder/Root.js.map +1 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.js +3 -3
- package/lib/index.js.map +1 -1
- package/lib/types/TypeContext.d.ts +23 -0
- package/lib/types/TypeContext.js +109 -0
- package/lib/types/TypeContext.js.map +1 -0
- package/lib/types/custom/ArraySchema.js +0 -1
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/package.json +1 -1
- package/src/Metadata.ts +1 -0
- package/src/Reflection.ts +2 -1
- package/src/annotations.ts +1 -126
- package/src/bench_encode.ts +47 -16
- package/src/decoder/Decoder.ts +1 -1
- package/src/encoder/ChangeTree.ts +30 -59
- package/src/encoder/Encoder.ts +36 -23
- package/src/encoder/Root.ts +51 -0
- package/src/index.ts +3 -11
- package/src/types/TypeContext.ts +127 -0
- package/src/types/custom/ArraySchema.ts +0 -1
package/build/cjs/index.js
CHANGED
|
@@ -196,44 +196,6 @@ const Metadata = {
|
|
|
196
196
|
};
|
|
197
197
|
|
|
198
198
|
var _a$5;
|
|
199
|
-
class Root {
|
|
200
|
-
constructor() {
|
|
201
|
-
this.nextUniqueId = 0;
|
|
202
|
-
this.refCount = new WeakMap();
|
|
203
|
-
// all changes
|
|
204
|
-
this.allChanges = new Map();
|
|
205
|
-
this.allFilteredChanges = new Map();
|
|
206
|
-
// pending changes to be encoded
|
|
207
|
-
this.changes = new Map();
|
|
208
|
-
this.filteredChanges = new Map();
|
|
209
|
-
}
|
|
210
|
-
getNextUniqueId() {
|
|
211
|
-
return this.nextUniqueId++;
|
|
212
|
-
}
|
|
213
|
-
add(changeTree) {
|
|
214
|
-
const refCount = this.refCount.get(changeTree) || 0;
|
|
215
|
-
this.refCount.set(changeTree, refCount + 1);
|
|
216
|
-
}
|
|
217
|
-
remove(changeTree) {
|
|
218
|
-
const refCount = this.refCount.get(changeTree);
|
|
219
|
-
if (refCount <= 1) {
|
|
220
|
-
this.allChanges.delete(changeTree);
|
|
221
|
-
this.changes.delete(changeTree);
|
|
222
|
-
if (changeTree.isFiltered || changeTree.isPartiallyFiltered) {
|
|
223
|
-
this.allFilteredChanges.delete(changeTree);
|
|
224
|
-
this.filteredChanges.delete(changeTree);
|
|
225
|
-
}
|
|
226
|
-
this.refCount.delete(changeTree);
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
this.refCount.set(changeTree, refCount - 1);
|
|
230
|
-
}
|
|
231
|
-
changeTree.forEachChild((child, _) => this.remove(child));
|
|
232
|
-
}
|
|
233
|
-
clear() {
|
|
234
|
-
this.changes.clear();
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
199
|
class ChangeTree {
|
|
238
200
|
static { _a$5 = $isNew; }
|
|
239
201
|
;
|
|
@@ -265,8 +227,6 @@ class ChangeTree {
|
|
|
265
227
|
if (this.isFiltered || this.isPartiallyFiltered) {
|
|
266
228
|
this.root.allFilteredChanges.set(this, this.allFilteredChanges);
|
|
267
229
|
this.root.filteredChanges.set(this, this.filteredChanges);
|
|
268
|
-
// } else {
|
|
269
|
-
// this.root.allChanges.set(this, this.allChanges);
|
|
270
230
|
}
|
|
271
231
|
if (!this.isFiltered) {
|
|
272
232
|
this.root.allChanges.set(this, this.allChanges);
|
|
@@ -539,15 +499,30 @@ class ChangeTree {
|
|
|
539
499
|
checkIsFiltered(parent, parentIndex) {
|
|
540
500
|
// Detect if current structure has "filters" declared
|
|
541
501
|
this.isPartiallyFiltered = (this.ref['constructor']?.[Symbol.metadata]?.[-2] !== undefined);
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
502
|
+
if (parent && !Metadata.isValidInstance(parent)) {
|
|
503
|
+
const parentChangeTree = parent[$changes];
|
|
504
|
+
parent = parentChangeTree.parent;
|
|
505
|
+
parentIndex = parentChangeTree.parentIndex;
|
|
506
|
+
}
|
|
507
|
+
const parentMetadata = parent?.['constructor']?.[Symbol.metadata];
|
|
508
|
+
this.isFiltered = (parent &&
|
|
509
|
+
parentMetadata?.[-2]?.includes(parentIndex));
|
|
510
|
+
// this.isFiltered = this.ref['constructor']?.[Symbol.metadata]?.[-4];
|
|
511
|
+
// // Detect if parent has "filters" declared
|
|
512
|
+
// while (parent && !this.isFiltered) {
|
|
513
|
+
// const metadata: Metadata = parent['constructor'][Symbol.metadata];
|
|
514
|
+
// // this.isFiltered = metadata?.[-4];
|
|
515
|
+
// const fieldName = metadata?.[parentIndex];
|
|
516
|
+
// const isParentOwned = metadata?.[fieldName]?.tag !== undefined;
|
|
517
|
+
// this.isFiltered = isParentOwned || parent[$changes].isFiltered; // metadata?.[-2]
|
|
518
|
+
// parent = parent[$changes].parent;
|
|
519
|
+
// };
|
|
520
|
+
// console.log("ChangeTree.checkIsFiltered", {
|
|
521
|
+
// parent: parent?.constructor.name,
|
|
522
|
+
// ref: this.ref.constructor.name,
|
|
523
|
+
// isFiltered: this.isFiltered,
|
|
524
|
+
// isPartiallyFiltered: this.isPartiallyFiltered,
|
|
525
|
+
// });
|
|
551
526
|
//
|
|
552
527
|
// TODO: refactor this!
|
|
553
528
|
//
|
|
@@ -1688,7 +1663,6 @@ class ArraySchema {
|
|
|
1688
1663
|
}
|
|
1689
1664
|
const changeTree = this[$changes];
|
|
1690
1665
|
changeTree.indexedOperation(length, exports.OPERATION.ADD, this.items.length);
|
|
1691
|
-
// changeTree.indexes[length] = length;
|
|
1692
1666
|
this.items.push(value);
|
|
1693
1667
|
this.tmpItems.push(value);
|
|
1694
1668
|
//
|
|
@@ -2379,7 +2353,6 @@ class MapSchema {
|
|
|
2379
2353
|
}
|
|
2380
2354
|
registerType("map", { constructor: MapSchema });
|
|
2381
2355
|
|
|
2382
|
-
const DEFAULT_VIEW_TAG = -1;
|
|
2383
2356
|
class TypeContext {
|
|
2384
2357
|
/**
|
|
2385
2358
|
* For inheritance support
|
|
@@ -2401,6 +2374,7 @@ class TypeContext {
|
|
|
2401
2374
|
this.types = {};
|
|
2402
2375
|
this.schemas = new Map();
|
|
2403
2376
|
this.hasFilters = false;
|
|
2377
|
+
this.parentFiltered = {};
|
|
2404
2378
|
if (rootClass) {
|
|
2405
2379
|
this.discoverTypes(rootClass);
|
|
2406
2380
|
}
|
|
@@ -2429,32 +2403,32 @@ class TypeContext {
|
|
|
2429
2403
|
getTypeId(klass) {
|
|
2430
2404
|
return this.schemas.get(klass);
|
|
2431
2405
|
}
|
|
2432
|
-
discoverTypes(klass, parentFieldViewTag) {
|
|
2406
|
+
discoverTypes(klass, parentIndex, parentFieldViewTag) {
|
|
2433
2407
|
if (!this.add(klass)) {
|
|
2434
2408
|
return;
|
|
2435
2409
|
}
|
|
2436
2410
|
// add classes inherited from this base class
|
|
2437
2411
|
TypeContext.inheritedTypes.get(klass)?.forEach((child) => {
|
|
2438
|
-
this.discoverTypes(child, parentFieldViewTag);
|
|
2412
|
+
this.discoverTypes(child, parentIndex, parentFieldViewTag);
|
|
2439
2413
|
});
|
|
2440
|
-
|
|
2441
|
-
if (klass[Symbol.metadata] === undefined) {
|
|
2442
|
-
klass[Symbol.metadata] = {};
|
|
2443
|
-
}
|
|
2444
|
-
// const metadata = Metadata.getFor(klass);
|
|
2445
|
-
const metadata = klass[Symbol.metadata];
|
|
2414
|
+
const metadata = (klass[Symbol.metadata] ??= {});
|
|
2446
2415
|
// if any schema/field has filters, mark "context" as having filters.
|
|
2447
2416
|
if (metadata[-2]) {
|
|
2448
2417
|
this.hasFilters = true;
|
|
2449
2418
|
}
|
|
2419
|
+
if (parentFieldViewTag !== undefined) {
|
|
2420
|
+
this.parentFiltered[`${this.schemas.get(klass)}-${parentIndex}`] = true;
|
|
2421
|
+
}
|
|
2450
2422
|
for (const field in metadata) {
|
|
2451
|
-
//
|
|
2452
|
-
// Modify the field's metadata to include the parent field's view tag
|
|
2453
|
-
//
|
|
2454
|
-
if (
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2423
|
+
// //
|
|
2424
|
+
// // Modify the field's metadata to include the parent field's view tag
|
|
2425
|
+
// //
|
|
2426
|
+
// if (
|
|
2427
|
+
// parentFieldViewTag !== undefined &&
|
|
2428
|
+
// metadata[field].tag === undefined
|
|
2429
|
+
// ) {
|
|
2430
|
+
// metadata[field].tag = parentFieldViewTag;
|
|
2431
|
+
// }
|
|
2458
2432
|
const fieldType = metadata[field].type;
|
|
2459
2433
|
const viewTag = metadata[field].tag;
|
|
2460
2434
|
if (typeof (fieldType) === "string") {
|
|
@@ -2465,7 +2439,7 @@ class TypeContext {
|
|
|
2465
2439
|
if (type === "string") {
|
|
2466
2440
|
continue;
|
|
2467
2441
|
}
|
|
2468
|
-
this.discoverTypes(type, viewTag);
|
|
2442
|
+
this.discoverTypes(type, metadata[field].index, viewTag);
|
|
2469
2443
|
}
|
|
2470
2444
|
else if (typeof (fieldType) === "function") {
|
|
2471
2445
|
this.discoverTypes(fieldType, viewTag);
|
|
@@ -2476,11 +2450,13 @@ class TypeContext {
|
|
|
2476
2450
|
if (typeof (type) === "string") {
|
|
2477
2451
|
continue;
|
|
2478
2452
|
}
|
|
2479
|
-
this.discoverTypes(type, viewTag);
|
|
2453
|
+
this.discoverTypes(type, metadata[field].index, viewTag);
|
|
2480
2454
|
}
|
|
2481
2455
|
}
|
|
2482
2456
|
}
|
|
2483
2457
|
}
|
|
2458
|
+
|
|
2459
|
+
const DEFAULT_VIEW_TAG = -1;
|
|
2484
2460
|
/**
|
|
2485
2461
|
* [See documentation](https://docs.colyseus.io/state/schema/)
|
|
2486
2462
|
*
|
|
@@ -3442,16 +3418,56 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
3442
3418
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
3443
3419
|
};
|
|
3444
3420
|
|
|
3421
|
+
class Root {
|
|
3422
|
+
constructor(types) {
|
|
3423
|
+
this.types = types;
|
|
3424
|
+
this.nextUniqueId = 0;
|
|
3425
|
+
this.refCount = new WeakMap();
|
|
3426
|
+
// all changes
|
|
3427
|
+
this.allChanges = new Map();
|
|
3428
|
+
this.allFilteredChanges = new Map();
|
|
3429
|
+
// pending changes to be encoded
|
|
3430
|
+
this.changes = new Map();
|
|
3431
|
+
this.filteredChanges = new Map();
|
|
3432
|
+
}
|
|
3433
|
+
getNextUniqueId() {
|
|
3434
|
+
return this.nextUniqueId++;
|
|
3435
|
+
}
|
|
3436
|
+
add(changeTree) {
|
|
3437
|
+
const refCount = this.refCount.get(changeTree) || 0;
|
|
3438
|
+
this.refCount.set(changeTree, refCount + 1);
|
|
3439
|
+
}
|
|
3440
|
+
remove(changeTree) {
|
|
3441
|
+
const refCount = this.refCount.get(changeTree);
|
|
3442
|
+
if (refCount <= 1) {
|
|
3443
|
+
this.allChanges.delete(changeTree);
|
|
3444
|
+
this.changes.delete(changeTree);
|
|
3445
|
+
if (changeTree.isFiltered || changeTree.isPartiallyFiltered) {
|
|
3446
|
+
this.allFilteredChanges.delete(changeTree);
|
|
3447
|
+
this.filteredChanges.delete(changeTree);
|
|
3448
|
+
}
|
|
3449
|
+
this.refCount.delete(changeTree);
|
|
3450
|
+
}
|
|
3451
|
+
else {
|
|
3452
|
+
this.refCount.set(changeTree, refCount - 1);
|
|
3453
|
+
}
|
|
3454
|
+
changeTree.forEachChild((child, _) => this.remove(child));
|
|
3455
|
+
}
|
|
3456
|
+
clear() {
|
|
3457
|
+
this.changes.clear();
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
|
|
3445
3461
|
class Encoder {
|
|
3446
3462
|
static { this.BUFFER_SIZE = 8 * 1024; } // 8KB
|
|
3447
3463
|
constructor(state) {
|
|
3448
3464
|
this.sharedBuffer = Buffer.allocUnsafeSlow(Encoder.BUFFER_SIZE);
|
|
3449
|
-
this.root = new Root();
|
|
3450
3465
|
//
|
|
3451
3466
|
// TODO: cache and restore "Context" based on root schema
|
|
3452
3467
|
// (to avoid creating a new context for every new room)
|
|
3453
3468
|
//
|
|
3454
3469
|
this.context = new TypeContext(state.constructor);
|
|
3470
|
+
this.root = new Root(this.context);
|
|
3455
3471
|
this.setState(state);
|
|
3456
3472
|
// console.log(">>>>>>>>>>>>>>>> Encoder types");
|
|
3457
3473
|
// this.context.schemas.forEach((id, schema) => {
|
|
@@ -3488,7 +3504,8 @@ class Encoder {
|
|
|
3488
3504
|
}
|
|
3489
3505
|
}
|
|
3490
3506
|
// skip root `refId` if it's the first change tree
|
|
3491
|
-
|
|
3507
|
+
// (unless it "hasView", which will need to revisit the root)
|
|
3508
|
+
if (hasView || changeTree !== rootChangeTree) {
|
|
3492
3509
|
buffer[it.offset++] = SWITCH_TO_STRUCTURE & 255;
|
|
3493
3510
|
number$1(buffer, changeTree.refId, it);
|
|
3494
3511
|
}
|
|
@@ -3550,35 +3567,43 @@ class Encoder {
|
|
|
3550
3567
|
}
|
|
3551
3568
|
}
|
|
3552
3569
|
encodeAll(it = { offset: 0 }, buffer = this.sharedBuffer) {
|
|
3553
|
-
// console.log(
|
|
3554
|
-
//
|
|
3555
|
-
// console.log("->", { ref: item[0].ref.constructor.name, refId: item[0].refId, changes: item[1].size });
|
|
3556
|
-
// });
|
|
3570
|
+
// console.log(`\nencodeAll(), this.root.allChanges (${this.root.allChanges.size})`);
|
|
3571
|
+
// this.debugChanges("allChanges");
|
|
3557
3572
|
return this.encode(it, undefined, buffer, this.root.allChanges, true);
|
|
3558
3573
|
}
|
|
3559
3574
|
encodeAllView(view, sharedOffset, it, bytes = this.sharedBuffer) {
|
|
3560
3575
|
const viewOffset = it.offset;
|
|
3561
|
-
// console.log(
|
|
3562
|
-
// this.
|
|
3576
|
+
// console.log(`\nencodeAllView(), this.root.allFilteredChanges (${this.root.allFilteredChanges.size})`);
|
|
3577
|
+
// this.debugChanges("allFilteredChanges");
|
|
3563
3578
|
// try to encode "filtered" changes
|
|
3564
|
-
this.encode(it, view, bytes, this.root.allFilteredChanges, true);
|
|
3579
|
+
this.encode(it, view, bytes, this.root.allFilteredChanges, true, viewOffset);
|
|
3565
3580
|
return Buffer.concat([
|
|
3566
3581
|
bytes.subarray(0, sharedOffset),
|
|
3567
3582
|
bytes.subarray(viewOffset, it.offset)
|
|
3568
3583
|
]);
|
|
3569
3584
|
}
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3585
|
+
debugChanges(field) {
|
|
3586
|
+
const changeSet = (typeof (field) === "string")
|
|
3587
|
+
? this.root[field]
|
|
3588
|
+
: field;
|
|
3589
|
+
Array.from(changeSet.entries()).map((item) => {
|
|
3590
|
+
const metadata = item[0].ref.constructor[Symbol.metadata];
|
|
3591
|
+
console.log("->", { ref: item[0].ref.constructor.name, refId: item[0].refId, changes: item[1].size });
|
|
3592
|
+
item[1].forEach((op, index) => {
|
|
3593
|
+
console.log(" ->", {
|
|
3594
|
+
index,
|
|
3595
|
+
field: metadata?.[index],
|
|
3596
|
+
op: exports.OPERATION[op],
|
|
3576
3597
|
});
|
|
3577
|
-
}
|
|
3598
|
+
});
|
|
3578
3599
|
});
|
|
3579
3600
|
}
|
|
3580
3601
|
encodeView(view, sharedOffset, it, bytes = this.sharedBuffer) {
|
|
3581
3602
|
const viewOffset = it.offset;
|
|
3603
|
+
// console.log(`\nencodeView(), view.changes (${view.changes.size})`);
|
|
3604
|
+
// this.debugChanges(view.changes);
|
|
3605
|
+
// console.log(`\nencodeView(), this.root.filteredChanges (${this.root.filteredChanges.size})`);
|
|
3606
|
+
// this.debugChanges("filteredChanges");
|
|
3582
3607
|
// encode visibility changes (add/remove for this view)
|
|
3583
3608
|
const viewChangesIterator = view.changes.entries();
|
|
3584
3609
|
for (const [changeTree, changes] of viewChangesIterator) {
|