@colyseus/schema 3.0.35 → 3.0.37
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 +5 -5
- package/build/cjs/index.js +51 -31
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +51 -31
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +51 -31
- package/lib/Schema.d.ts +4 -0
- package/lib/Schema.js +9 -2
- package/lib/Schema.js.map +1 -1
- package/lib/decoder/ReferenceTracker.js +1 -1
- package/lib/decoder/ReferenceTracker.js.map +1 -1
- package/lib/encoder/ChangeTree.d.ts +1 -0
- package/lib/encoder/ChangeTree.js +28 -8
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/Root.js +1 -1
- package/lib/encoder/Root.js.map +1 -1
- package/lib/types/custom/ArraySchema.js +4 -19
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/CollectionSchema.js +4 -0
- package/lib/types/custom/CollectionSchema.js.map +1 -1
- package/lib/types/custom/MapSchema.js +4 -0
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/package.json +1 -1
- package/src/Schema.ts +10 -2
- package/src/decoder/ReferenceTracker.ts +2 -2
- package/src/encoder/ChangeTree.ts +27 -11
- package/src/encoder/Root.ts +2 -2
- package/src/types/custom/ArraySchema.ts +4 -22
- package/src/types/custom/CollectionSchema.ts +5 -0
- package/src/types/custom/MapSchema.ts +5 -0
package/README.md
CHANGED
|
@@ -246,9 +246,9 @@ const decoder = new Decoder(state);
|
|
|
246
246
|
decoder.decode(encodedBytes);
|
|
247
247
|
```
|
|
248
248
|
|
|
249
|
-
### Backwards/forwards
|
|
249
|
+
### Backwards/forwards compatibility
|
|
250
250
|
|
|
251
|
-
Backwards/
|
|
251
|
+
Backwards/forwards compatibility is possible by declaring new fields at the
|
|
252
252
|
end of existing structures, and earlier declarations to not be removed, but
|
|
253
253
|
be marked `@deprecated()` when needed.
|
|
254
254
|
|
|
@@ -307,10 +307,10 @@ Each Colyseus SDK has its own decoder implementation of the `@colyseus/schema` p
|
|
|
307
307
|
|
|
308
308
|
## Why
|
|
309
309
|
|
|
310
|
-
Initial
|
|
310
|
+
Initial thoughts/assumptions, for Colyseus:
|
|
311
311
|
- little to no bottleneck for detecting state changes.
|
|
312
|
-
- have a schema definition on both server and client
|
|
313
|
-
- better experience on
|
|
312
|
+
- have a schema definition on both the server and the client
|
|
313
|
+
- better experience on statically-typed languages (C#, C++)
|
|
314
314
|
- mutations should be cheap.
|
|
315
315
|
|
|
316
316
|
Practical Colyseus issues this should solve:
|
package/build/cjs/index.js
CHANGED
|
@@ -1032,19 +1032,35 @@ class ChangeTree {
|
|
|
1032
1032
|
setRoot(root) {
|
|
1033
1033
|
this.root = root;
|
|
1034
1034
|
this.checkIsFiltered(this.parent, this.parentIndex);
|
|
1035
|
+
//
|
|
1036
|
+
// TODO: refactor and possibly unify .setRoot() and .setParent()
|
|
1037
|
+
//
|
|
1035
1038
|
// Recursively set root on child structures
|
|
1036
1039
|
const metadata = this.ref.constructor[Symbol.metadata];
|
|
1037
1040
|
if (metadata) {
|
|
1038
1041
|
metadata[$refTypeFieldIndexes]?.forEach((index) => {
|
|
1039
1042
|
const field = metadata[index];
|
|
1040
|
-
const
|
|
1041
|
-
|
|
1043
|
+
const changeTree = this.ref[field.name]?.[$changes];
|
|
1044
|
+
if (changeTree) {
|
|
1045
|
+
if (changeTree.root !== root) {
|
|
1046
|
+
changeTree.setRoot(root);
|
|
1047
|
+
}
|
|
1048
|
+
else {
|
|
1049
|
+
root.add(changeTree); // increment refCount
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1042
1052
|
});
|
|
1043
1053
|
}
|
|
1044
1054
|
else if (this.ref[$childType] && typeof (this.ref[$childType]) !== "string") {
|
|
1045
1055
|
// MapSchema / ArraySchema, etc.
|
|
1046
1056
|
this.ref.forEach((value, key) => {
|
|
1047
|
-
value[$changes]
|
|
1057
|
+
const changeTree = value[$changes];
|
|
1058
|
+
if (changeTree.root !== root) {
|
|
1059
|
+
changeTree.setRoot(root);
|
|
1060
|
+
}
|
|
1061
|
+
else {
|
|
1062
|
+
root.add(changeTree); // increment refCount
|
|
1063
|
+
}
|
|
1048
1064
|
});
|
|
1049
1065
|
}
|
|
1050
1066
|
}
|
|
@@ -1068,14 +1084,19 @@ class ChangeTree {
|
|
|
1068
1084
|
if (metadata) {
|
|
1069
1085
|
metadata[$refTypeFieldIndexes]?.forEach((index) => {
|
|
1070
1086
|
const field = metadata[index];
|
|
1071
|
-
const
|
|
1072
|
-
|
|
1087
|
+
const changeTree = this.ref[field.name]?.[$changes];
|
|
1088
|
+
if (changeTree && changeTree.root !== root) {
|
|
1089
|
+
changeTree.setParent(this.ref, root, index);
|
|
1090
|
+
}
|
|
1073
1091
|
});
|
|
1074
1092
|
}
|
|
1075
1093
|
else if (this.ref[$childType] && typeof (this.ref[$childType]) !== "string") {
|
|
1076
1094
|
// MapSchema / ArraySchema, etc.
|
|
1077
1095
|
this.ref.forEach((value, key) => {
|
|
1078
|
-
value[$changes]
|
|
1096
|
+
const changeTree = value[$changes];
|
|
1097
|
+
if (changeTree.root !== root) {
|
|
1098
|
+
changeTree.setParent(this.ref, root, this.indexes[key] ?? key);
|
|
1099
|
+
}
|
|
1079
1100
|
});
|
|
1080
1101
|
}
|
|
1081
1102
|
}
|
|
@@ -1307,12 +1328,11 @@ class ChangeTree {
|
|
|
1307
1328
|
this.allFilteredChanges.indexes = {};
|
|
1308
1329
|
this.allFilteredChanges.operations.length = 0;
|
|
1309
1330
|
}
|
|
1310
|
-
// remove children references
|
|
1311
|
-
this.forEachChild((changeTree, _) => this.root?.remove(changeTree));
|
|
1312
1331
|
}
|
|
1313
1332
|
}
|
|
1314
1333
|
/**
|
|
1315
1334
|
* Recursively discard all changes from this, and child structures.
|
|
1335
|
+
* (Used in tests only)
|
|
1316
1336
|
*/
|
|
1317
1337
|
discardAll() {
|
|
1318
1338
|
const keys = Object.keys(this.indexedOperations);
|
|
@@ -1983,8 +2003,7 @@ class ArraySchema {
|
|
|
1983
2003
|
push(...values) {
|
|
1984
2004
|
let length = this.tmpItems.length;
|
|
1985
2005
|
const changeTree = this[$changes];
|
|
1986
|
-
|
|
1987
|
-
for (let i = 0, l = values.length; i < values.length; i++, length++) {
|
|
2006
|
+
for (let i = 0, l = values.length; i < l; i++, length++) {
|
|
1988
2007
|
const value = values[i];
|
|
1989
2008
|
if (value === undefined || value === null) {
|
|
1990
2009
|
// skip null values
|
|
@@ -2003,8 +2022,6 @@ class ArraySchema {
|
|
|
2003
2022
|
//
|
|
2004
2023
|
value[$changes]?.setParent(this, changeTree.root, length);
|
|
2005
2024
|
}
|
|
2006
|
-
// length++;
|
|
2007
|
-
// });
|
|
2008
2025
|
return length;
|
|
2009
2026
|
}
|
|
2010
2027
|
/**
|
|
@@ -2083,21 +2100,9 @@ class ArraySchema {
|
|
|
2083
2100
|
}
|
|
2084
2101
|
// discard previous operations.
|
|
2085
2102
|
const changeTree = this[$changes];
|
|
2086
|
-
//
|
|
2087
|
-
changeTree.forEachChild((
|
|
2088
|
-
changeTree.
|
|
2089
|
-
//
|
|
2090
|
-
// TODO: add tests with instance sharing + .clear()
|
|
2091
|
-
// FIXME: this.root? is required because it is being called at decoding time.
|
|
2092
|
-
//
|
|
2093
|
-
// TODO: do not use [$changes] at decoding time.
|
|
2094
|
-
//
|
|
2095
|
-
const root = changeTree.root;
|
|
2096
|
-
if (root !== undefined) {
|
|
2097
|
-
root.removeChangeFromChangeSet("changes", changeTree);
|
|
2098
|
-
root.removeChangeFromChangeSet("allChanges", changeTree);
|
|
2099
|
-
root.removeChangeFromChangeSet("allFilteredChanges", changeTree);
|
|
2100
|
-
}
|
|
2103
|
+
// remove children references
|
|
2104
|
+
changeTree.forEachChild((childChangeTree, _) => {
|
|
2105
|
+
changeTree.root?.remove(childChangeTree);
|
|
2101
2106
|
});
|
|
2102
2107
|
changeTree.discard(true);
|
|
2103
2108
|
changeTree.operation(exports.OPERATION.CLEAR);
|
|
@@ -2682,6 +2687,10 @@ class MapSchema {
|
|
|
2682
2687
|
// discard previous operations.
|
|
2683
2688
|
changeTree.discard(true);
|
|
2684
2689
|
changeTree.indexes = {};
|
|
2690
|
+
// remove children references
|
|
2691
|
+
changeTree.forEachChild((childChangeTree, _) => {
|
|
2692
|
+
changeTree.root?.remove(childChangeTree);
|
|
2693
|
+
});
|
|
2685
2694
|
// clear previous indexes
|
|
2686
2695
|
this.$indexes.clear();
|
|
2687
2696
|
// clear items
|
|
@@ -3279,6 +3288,10 @@ class Schema {
|
|
|
3279
3288
|
}
|
|
3280
3289
|
return obj;
|
|
3281
3290
|
}
|
|
3291
|
+
/**
|
|
3292
|
+
* Used in tests only
|
|
3293
|
+
* @internal
|
|
3294
|
+
*/
|
|
3282
3295
|
discardAllChanges() {
|
|
3283
3296
|
this[$changes].discardAll();
|
|
3284
3297
|
}
|
|
@@ -3301,8 +3314,11 @@ class Schema {
|
|
|
3301
3314
|
const contents = (showContents) ? ` - ${JSON.stringify(ref.toJSON())}` : "";
|
|
3302
3315
|
const changeTree = ref[$changes];
|
|
3303
3316
|
const refId = changeTree.refId;
|
|
3304
|
-
|
|
3305
|
-
|
|
3317
|
+
// log reference count if > 1
|
|
3318
|
+
const refCount = (changeTree.root?.refCount?.[refId] > 1)
|
|
3319
|
+
? ` [×${changeTree.root.refCount[refId]}]`
|
|
3320
|
+
: '';
|
|
3321
|
+
let output = `${getIndent(level)}${ref.constructor.name} (refId: ${refId})${refCount}${contents}\n`;
|
|
3306
3322
|
changeTree.forEachChild((childChangeTree) => output += this.debugRefIds(childChangeTree.ref, showContents, level + 1));
|
|
3307
3323
|
return output;
|
|
3308
3324
|
}
|
|
@@ -3487,6 +3503,10 @@ class CollectionSchema {
|
|
|
3487
3503
|
// discard previous operations.
|
|
3488
3504
|
changeTree.discard(true);
|
|
3489
3505
|
changeTree.indexes = {};
|
|
3506
|
+
// remove children references
|
|
3507
|
+
changeTree.forEachChild((childChangeTree, _) => {
|
|
3508
|
+
changeTree.root?.remove(childChangeTree);
|
|
3509
|
+
});
|
|
3490
3510
|
// clear previous indexes
|
|
3491
3511
|
this.$indexes.clear();
|
|
3492
3512
|
// clear items
|
|
@@ -3819,6 +3839,7 @@ class Root {
|
|
|
3819
3839
|
this.removeChangeFromChangeSet("filteredChanges", changeTree);
|
|
3820
3840
|
}
|
|
3821
3841
|
this.refCount[changeTree.refId] = 0;
|
|
3842
|
+
changeTree.forEachChild((child, _) => this.remove(child));
|
|
3822
3843
|
}
|
|
3823
3844
|
else {
|
|
3824
3845
|
this.refCount[changeTree.refId] = refCount;
|
|
@@ -3840,7 +3861,6 @@ class Root {
|
|
|
3840
3861
|
enqueueChangeTree(this, changeTree, "changes");
|
|
3841
3862
|
}
|
|
3842
3863
|
}
|
|
3843
|
-
changeTree.forEachChild((child, _) => this.remove(child));
|
|
3844
3864
|
return refCount;
|
|
3845
3865
|
}
|
|
3846
3866
|
removeChangeFromChangeSet(changeSetName, changeTree) {
|
|
@@ -4214,7 +4234,7 @@ class ReferenceTracker {
|
|
|
4214
4234
|
}
|
|
4215
4235
|
removeCallback(refId, field, callback) {
|
|
4216
4236
|
const index = this.callbacks?.[refId]?.[field]?.indexOf(callback);
|
|
4217
|
-
if (index !== -1) {
|
|
4237
|
+
if (index !== undefined && index !== -1) {
|
|
4218
4238
|
spliceOne(this.callbacks[refId][field], index);
|
|
4219
4239
|
}
|
|
4220
4240
|
}
|