@colyseus/schema 3.0.0-alpha.25 → 3.0.0-alpha.26
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 +77 -85
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +77 -85
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +77 -85
- package/lib/Reflection.js +1 -3
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.d.ts +1 -1
- package/lib/Schema.js +2 -2
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.js +13 -5
- package/lib/annotations.js.map +1 -1
- package/lib/decoder/DecodeOperation.js +1 -0
- package/lib/decoder/DecodeOperation.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.js +3 -2
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +3 -3
- package/lib/encoder/Encoder.js +10 -11
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/StateView.d.ts +2 -2
- package/lib/encoder/StateView.js +45 -60
- package/lib/encoder/StateView.js.map +1 -1
- package/package.json +1 -1
- package/src/Reflection.ts +1 -3
- package/src/Schema.ts +2 -2
- package/src/annotations.ts +16 -5
- package/src/decoder/DecodeOperation.ts +4 -1
- package/src/decoder/Decoder.ts +3 -2
- package/src/encoder/ChangeTree.ts +4 -2
- package/src/encoder/Encoder.ts +11 -13
- package/src/encoder/StateView.ts +50 -69
package/build/cjs/index.js
CHANGED
|
@@ -329,7 +329,7 @@ class ChangeTree {
|
|
|
329
329
|
// MapSchema / ArraySchema, etc.
|
|
330
330
|
this.ref.forEach((value, key) => {
|
|
331
331
|
if (Metadata.isValidInstance(value)) {
|
|
332
|
-
callback(value[$changes], this.ref[$changes].indexes[key]);
|
|
332
|
+
callback(value[$changes], this.ref[$changes].indexes[key] ?? key);
|
|
333
333
|
}
|
|
334
334
|
});
|
|
335
335
|
}
|
|
@@ -357,8 +357,9 @@ class ChangeTree {
|
|
|
357
357
|
// TODO: are DELETE operations being encoded as ADD here ??
|
|
358
358
|
//
|
|
359
359
|
if (isFiltered) {
|
|
360
|
-
this.allFilteredChanges.set(index, exports.OPERATION.ADD);
|
|
361
360
|
this.root?.filteredChanges.set(this, this.filteredChanges);
|
|
361
|
+
this.allFilteredChanges.set(index, exports.OPERATION.ADD);
|
|
362
|
+
this.root?.allFilteredChanges.set(this, this.allFilteredChanges);
|
|
362
363
|
}
|
|
363
364
|
else {
|
|
364
365
|
this.allChanges.set(index, exports.OPERATION.ADD);
|
|
@@ -1405,6 +1406,7 @@ const decodeSchemaOperation = function (decoder, bytes, it, ref, allChanges) {
|
|
|
1405
1406
|
// skip early if field is not defined
|
|
1406
1407
|
const field = metadata[index];
|
|
1407
1408
|
if (field === undefined) {
|
|
1409
|
+
console.warn("@colyseus/schema: field not defined at", { index, ref: ref.constructor.name, metadata });
|
|
1408
1410
|
return DEFINITION_MISMATCH;
|
|
1409
1411
|
}
|
|
1410
1412
|
const { value, previousValue } = decodeValue(decoder, operation, ref, index, metadata[field].type, bytes, it, allChanges);
|
|
@@ -2427,13 +2429,13 @@ class TypeContext {
|
|
|
2427
2429
|
getTypeId(klass) {
|
|
2428
2430
|
return this.schemas.get(klass);
|
|
2429
2431
|
}
|
|
2430
|
-
discoverTypes(klass) {
|
|
2432
|
+
discoverTypes(klass, parentFieldViewTag) {
|
|
2431
2433
|
if (!this.add(klass)) {
|
|
2432
2434
|
return;
|
|
2433
2435
|
}
|
|
2434
2436
|
// add classes inherited from this base class
|
|
2435
2437
|
TypeContext.inheritedTypes.get(klass)?.forEach((child) => {
|
|
2436
|
-
this.discoverTypes(child);
|
|
2438
|
+
this.discoverTypes(child, parentFieldViewTag);
|
|
2437
2439
|
});
|
|
2438
2440
|
// skip if no fields are defined for this class.
|
|
2439
2441
|
if (klass[Symbol.metadata] === undefined) {
|
|
@@ -2446,7 +2448,15 @@ class TypeContext {
|
|
|
2446
2448
|
this.hasFilters = true;
|
|
2447
2449
|
}
|
|
2448
2450
|
for (const field in metadata) {
|
|
2451
|
+
//
|
|
2452
|
+
// Modify the field's metadata to include the parent field's view tag
|
|
2453
|
+
//
|
|
2454
|
+
if (parentFieldViewTag !== undefined &&
|
|
2455
|
+
metadata[field].tag === undefined) {
|
|
2456
|
+
metadata[field].tag = parentFieldViewTag;
|
|
2457
|
+
}
|
|
2449
2458
|
const fieldType = metadata[field].type;
|
|
2459
|
+
const viewTag = metadata[field].tag;
|
|
2450
2460
|
if (typeof (fieldType) === "string") {
|
|
2451
2461
|
continue;
|
|
2452
2462
|
}
|
|
@@ -2455,10 +2465,10 @@ class TypeContext {
|
|
|
2455
2465
|
if (type === "string") {
|
|
2456
2466
|
continue;
|
|
2457
2467
|
}
|
|
2458
|
-
this.discoverTypes(type);
|
|
2468
|
+
this.discoverTypes(type, viewTag);
|
|
2459
2469
|
}
|
|
2460
2470
|
else if (typeof (fieldType) === "function") {
|
|
2461
|
-
this.discoverTypes(fieldType);
|
|
2471
|
+
this.discoverTypes(fieldType, viewTag);
|
|
2462
2472
|
}
|
|
2463
2473
|
else {
|
|
2464
2474
|
const type = Object.values(fieldType)[0];
|
|
@@ -2466,7 +2476,7 @@ class TypeContext {
|
|
|
2466
2476
|
if (typeof (type) === "string") {
|
|
2467
2477
|
continue;
|
|
2468
2478
|
}
|
|
2469
|
-
this.discoverTypes(type);
|
|
2479
|
+
this.discoverTypes(type, viewTag);
|
|
2470
2480
|
}
|
|
2471
2481
|
}
|
|
2472
2482
|
}
|
|
@@ -3025,13 +3035,13 @@ class Schema {
|
|
|
3025
3035
|
}
|
|
3026
3036
|
return output;
|
|
3027
3037
|
}
|
|
3028
|
-
static debugChangesDeep(ref) {
|
|
3038
|
+
static debugChangesDeep(ref, changeSetName = "changes") {
|
|
3029
3039
|
let output = "";
|
|
3030
3040
|
const rootChangeTree = ref[$changes];
|
|
3031
3041
|
const changeTrees = new Map();
|
|
3032
3042
|
let totalInstances = 0;
|
|
3033
3043
|
let totalOperations = 0;
|
|
3034
|
-
for (const [changeTree, changes] of (rootChangeTree.root.
|
|
3044
|
+
for (const [changeTree, changes] of (rootChangeTree.root[changeSetName].entries())) {
|
|
3035
3045
|
let includeChangeTree = false;
|
|
3036
3046
|
let parentChangeTrees = [];
|
|
3037
3047
|
let parentChangeTree = changeTree.parent?.[$changes];
|
|
@@ -3434,26 +3444,26 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
3434
3444
|
|
|
3435
3445
|
class Encoder {
|
|
3436
3446
|
static { this.BUFFER_SIZE = 8 * 1024; } // 8KB
|
|
3437
|
-
constructor(
|
|
3447
|
+
constructor(state) {
|
|
3438
3448
|
this.sharedBuffer = Buffer.allocUnsafeSlow(Encoder.BUFFER_SIZE);
|
|
3449
|
+
this.root = new Root();
|
|
3439
3450
|
//
|
|
3440
3451
|
// TODO: cache and restore "Context" based on root schema
|
|
3441
3452
|
// (to avoid creating a new context for every new room)
|
|
3442
3453
|
//
|
|
3443
|
-
this.context = new TypeContext(
|
|
3444
|
-
this.
|
|
3454
|
+
this.context = new TypeContext(state.constructor);
|
|
3455
|
+
this.setState(state);
|
|
3445
3456
|
// console.log(">>>>>>>>>>>>>>>> Encoder types");
|
|
3446
3457
|
// this.context.schemas.forEach((id, schema) => {
|
|
3447
3458
|
// console.log("type:", id, schema.name, Object.keys(schema[Symbol.metadata]));
|
|
3448
3459
|
// });
|
|
3449
3460
|
}
|
|
3450
|
-
|
|
3451
|
-
this.root = new Root();
|
|
3461
|
+
setState(state) {
|
|
3452
3462
|
this.state = state;
|
|
3453
|
-
state[$changes].setRoot(this.root);
|
|
3463
|
+
this.state[$changes].setRoot(this.root);
|
|
3454
3464
|
}
|
|
3455
|
-
encode(it = { offset: 0 }, view, buffer = this.sharedBuffer, changeTrees = this.root.changes, isEncodeAll = this.root.allChanges === changeTrees
|
|
3456
|
-
|
|
3465
|
+
encode(it = { offset: 0 }, view, buffer = this.sharedBuffer, changeTrees = this.root.changes, isEncodeAll = this.root.allChanges === changeTrees, initialOffset = it.offset // cache current offset in case we need to resize the buffer
|
|
3466
|
+
) {
|
|
3457
3467
|
const hasView = (view !== undefined);
|
|
3458
3468
|
const rootChangeTree = this.state[$changes];
|
|
3459
3469
|
const changeTreesIterator = changeTrees.entries();
|
|
@@ -3492,7 +3502,6 @@ class Encoder {
|
|
|
3492
3502
|
// TODO: avoid checking if no view tags were defined
|
|
3493
3503
|
//
|
|
3494
3504
|
if (filter && !filter(ref, fieldIndex, view)) {
|
|
3495
|
-
// console.log("SKIP FIELD:", { ref: changeTree.ref.constructor.name, fieldIndex, })
|
|
3496
3505
|
// console.log("ADD AS INVISIBLE:", fieldIndex, changeTree.ref.constructor.name)
|
|
3497
3506
|
// view?.invisible.add(changeTree);
|
|
3498
3507
|
continue;
|
|
@@ -3570,8 +3579,6 @@ class Encoder {
|
|
|
3570
3579
|
}
|
|
3571
3580
|
encodeView(view, sharedOffset, it, bytes = this.sharedBuffer) {
|
|
3572
3581
|
const viewOffset = it.offset;
|
|
3573
|
-
// try to encode "filtered" changes
|
|
3574
|
-
this.encode(it, view, bytes, this.root.filteredChanges);
|
|
3575
3582
|
// encode visibility changes (add/remove for this view)
|
|
3576
3583
|
const viewChangesIterator = view.changes.entries();
|
|
3577
3584
|
for (const [changeTree, changes] of viewChangesIterator) {
|
|
@@ -3598,6 +3605,8 @@ class Encoder {
|
|
|
3598
3605
|
//
|
|
3599
3606
|
// clear "view" changes after encoding
|
|
3600
3607
|
view.changes.clear();
|
|
3608
|
+
// try to encode "filtered" changes
|
|
3609
|
+
this.encode(it, view, bytes, this.root.filteredChanges, false, viewOffset);
|
|
3601
3610
|
return Buffer.concat([
|
|
3602
3611
|
bytes.subarray(0, sharedOffset),
|
|
3603
3612
|
bytes.subarray(viewOffset, it.offset)
|
|
@@ -3770,14 +3779,14 @@ class ReferenceTracker {
|
|
|
3770
3779
|
class Decoder {
|
|
3771
3780
|
constructor(root, context) {
|
|
3772
3781
|
this.currentRefId = 0;
|
|
3773
|
-
this.
|
|
3782
|
+
this.setState(root);
|
|
3774
3783
|
this.context = context || new TypeContext(root.constructor);
|
|
3775
3784
|
// console.log(">>>>>>>>>>>>>>>> Decoder types");
|
|
3776
3785
|
// this.context.schemas.forEach((id, schema) => {
|
|
3777
3786
|
// console.log("type:", id, schema.name, Object.keys(schema[Symbol.metadata]));
|
|
3778
3787
|
// });
|
|
3779
3788
|
}
|
|
3780
|
-
|
|
3789
|
+
setState(root) {
|
|
3781
3790
|
this.state = root;
|
|
3782
3791
|
this.root = new ReferenceTracker();
|
|
3783
3792
|
this.root.addRef(0, root);
|
|
@@ -3906,9 +3915,7 @@ class Reflection extends Schema {
|
|
|
3906
3915
|
this.types = new ArraySchema();
|
|
3907
3916
|
}
|
|
3908
3917
|
static encode(instance, context, it = { offset: 0 }) {
|
|
3909
|
-
|
|
3910
|
-
context = new TypeContext(instance.constructor);
|
|
3911
|
-
}
|
|
3918
|
+
context ??= new TypeContext(instance.constructor);
|
|
3912
3919
|
const reflection = new Reflection();
|
|
3913
3920
|
const encoder = new Encoder(reflection);
|
|
3914
3921
|
const buildType = (currentType, metadata) => {
|
|
@@ -4290,26 +4297,21 @@ class StateView {
|
|
|
4290
4297
|
this.changes = new Map();
|
|
4291
4298
|
}
|
|
4292
4299
|
// TODO: allow to set multiple tags at once
|
|
4293
|
-
add(obj, tag = DEFAULT_VIEW_TAG) {
|
|
4300
|
+
add(obj, tag = DEFAULT_VIEW_TAG, checkIncludeParent = true) {
|
|
4294
4301
|
if (!obj[$changes]) {
|
|
4295
4302
|
console.warn("StateView#add(), invalid object:", obj);
|
|
4296
4303
|
return this;
|
|
4297
4304
|
}
|
|
4298
4305
|
// FIXME: ArraySchema/MapSchema does not have metadata
|
|
4299
4306
|
const metadata = obj.constructor[Symbol.metadata];
|
|
4300
|
-
|
|
4307
|
+
const changeTree = obj[$changes];
|
|
4301
4308
|
this.items.add(changeTree);
|
|
4302
|
-
//
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
this.add(change.ref, tag);
|
|
4309
|
-
});
|
|
4310
|
-
// add parent ChangeTree's, if they are invisible to this view
|
|
4311
|
-
// TODO: REFACTOR addParent()
|
|
4312
|
-
this.addParent(changeTree, tag);
|
|
4309
|
+
// add parent ChangeTree's
|
|
4310
|
+
// - if it was invisible to this view
|
|
4311
|
+
// - if it were previously filtered out
|
|
4312
|
+
if (checkIncludeParent && changeTree.parent) {
|
|
4313
|
+
this.addParent(changeTree.parent[$changes], changeTree.parentIndex, tag);
|
|
4314
|
+
}
|
|
4313
4315
|
//
|
|
4314
4316
|
// TODO: when adding an item of a MapSchema, the changes may not
|
|
4315
4317
|
// be set (only the parent's changes are set)
|
|
@@ -4341,73 +4343,63 @@ class StateView {
|
|
|
4341
4343
|
});
|
|
4342
4344
|
}
|
|
4343
4345
|
else {
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
// metadata?.[-3]?.[DEFAULT_VIEW_TAG]?.forEach((index) => {
|
|
4347
|
-
// if (changeTree.getChange(index) !== OPERATION.DELETE) {
|
|
4348
|
-
// changes.set(index, OPERATION.ADD);
|
|
4349
|
-
// }
|
|
4350
|
-
// });
|
|
4351
|
-
const allChangesSet = (changeTree.isFiltered || changeTree.isPartiallyFiltered)
|
|
4346
|
+
const isInvisible = this.invisible.has(changeTree);
|
|
4347
|
+
const changeSet = (changeTree.isFiltered || changeTree.isPartiallyFiltered)
|
|
4352
4348
|
? changeTree.allFilteredChanges
|
|
4353
4349
|
: changeTree.allChanges;
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4350
|
+
changeSet.forEach((op, index) => {
|
|
4351
|
+
const tagAtIndex = metadata?.[metadata?.[index]].tag;
|
|
4352
|
+
if ((isInvisible || // if "invisible", include all
|
|
4353
|
+
tagAtIndex === undefined || // "all change" with no tag
|
|
4354
|
+
tagAtIndex === tag // tagged property
|
|
4355
|
+
) &&
|
|
4356
|
+
op !== exports.OPERATION.DELETE) {
|
|
4357
|
+
changes.set(index, op);
|
|
4360
4358
|
}
|
|
4361
|
-
}
|
|
4362
|
-
}
|
|
4363
|
-
// TODO: avoid unnecessary iteration here
|
|
4364
|
-
while (changeTree.parent &&
|
|
4365
|
-
(changeTree = changeTree.parent[$changes]) &&
|
|
4366
|
-
(changeTree.isFiltered || changeTree.isPartiallyFiltered)) {
|
|
4367
|
-
this.items.add(changeTree);
|
|
4359
|
+
});
|
|
4368
4360
|
}
|
|
4361
|
+
// Add children of this ChangeTree to this view
|
|
4362
|
+
changeTree.forEachChild((change, index) => {
|
|
4363
|
+
// Do not ADD children that don't have the same tag
|
|
4364
|
+
if (metadata && metadata[metadata[index]].tag !== tag) {
|
|
4365
|
+
return;
|
|
4366
|
+
}
|
|
4367
|
+
this.add(change.ref, tag, false);
|
|
4368
|
+
});
|
|
4369
4369
|
return this;
|
|
4370
4370
|
}
|
|
4371
|
-
addParent(changeTree, tag) {
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4371
|
+
addParent(changeTree, parentIndex, tag) {
|
|
4372
|
+
// view must have all "changeTree" parent tree
|
|
4373
|
+
this.items.add(changeTree);
|
|
4374
|
+
// add parent's parent
|
|
4375
|
+
const parentChangeTree = changeTree.parent?.[$changes];
|
|
4376
|
+
if (parentChangeTree && (parentChangeTree.isFiltered || parentChangeTree.isPartiallyFiltered)) {
|
|
4377
|
+
this.addParent(parentChangeTree, changeTree.parentIndex, tag);
|
|
4375
4378
|
}
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
if (!this.invisible.has(parentChangeTree)) {
|
|
4379
|
-
// parent is already available, no need to add it!
|
|
4379
|
+
// parent is already available, no need to add it!
|
|
4380
|
+
if (!this.invisible.has(changeTree)) {
|
|
4380
4381
|
return;
|
|
4381
4382
|
}
|
|
4382
|
-
this.addParent(parentChangeTree, tag);
|
|
4383
4383
|
// add parent's tag properties
|
|
4384
|
-
if (
|
|
4385
|
-
let
|
|
4386
|
-
if (
|
|
4387
|
-
|
|
4388
|
-
this.changes.set(
|
|
4384
|
+
if (changeTree.getChange(parentIndex) !== exports.OPERATION.DELETE) {
|
|
4385
|
+
let changes = this.changes.get(changeTree);
|
|
4386
|
+
if (changes === undefined) {
|
|
4387
|
+
changes = new Map();
|
|
4388
|
+
this.changes.set(changeTree, changes);
|
|
4389
4389
|
}
|
|
4390
|
-
// console.log("add parent change", {
|
|
4391
|
-
// parentIndex,
|
|
4392
|
-
// parentChanges,
|
|
4393
|
-
// parentChange: (
|
|
4394
|
-
// parentChangeTree.getChange(parentIndex) &&
|
|
4395
|
-
// OPERATION[parentChangeTree.getChange(parentIndex)]
|
|
4396
|
-
// ),
|
|
4397
|
-
// })
|
|
4398
4390
|
if (!this.tags) {
|
|
4399
4391
|
this.tags = new WeakMap();
|
|
4400
4392
|
}
|
|
4401
4393
|
let tags;
|
|
4402
|
-
if (!this.tags.has(
|
|
4394
|
+
if (!this.tags.has(changeTree)) {
|
|
4403
4395
|
tags = new Set();
|
|
4404
|
-
this.tags.set(
|
|
4396
|
+
this.tags.set(changeTree, tags);
|
|
4405
4397
|
}
|
|
4406
4398
|
else {
|
|
4407
|
-
tags = this.tags.get(
|
|
4399
|
+
tags = this.tags.get(changeTree);
|
|
4408
4400
|
}
|
|
4409
4401
|
tags.add(tag);
|
|
4410
|
-
|
|
4402
|
+
changes.set(parentIndex, exports.OPERATION.ADD);
|
|
4411
4403
|
}
|
|
4412
4404
|
}
|
|
4413
4405
|
remove(obj, tag = DEFAULT_VIEW_TAG) {
|