@colyseus/schema 3.0.26 → 3.0.28
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 +101 -44
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +101 -44
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +101 -46
- package/lib/Schema.js +1 -1
- package/lib/Schema.js.map +1 -1
- package/lib/encoder/ChangeTree.d.ts +4 -2
- package/lib/encoder/ChangeTree.js +45 -13
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.js +1 -0
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +2 -1
- package/lib/encoder/Encoder.js +6 -7
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/StateView.d.ts +1 -0
- package/lib/encoder/StateView.js +19 -0
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js.map +1 -1
- package/lib/types/custom/ArraySchema.js +44 -21
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/CollectionSchema.js +1 -1
- package/lib/types/custom/CollectionSchema.js.map +1 -1
- package/lib/types/custom/MapSchema.js +1 -1
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/package.json +1 -1
- package/src/Schema.ts +1 -1
- package/src/encoder/ChangeTree.ts +58 -15
- package/src/encoder/EncodeOperation.ts +2 -0
- package/src/encoder/Encoder.ts +8 -9
- package/src/encoder/StateView.ts +24 -0
- package/src/index.ts +1 -1
- package/src/types/custom/ArraySchema.ts +52 -24
- package/src/types/custom/CollectionSchema.ts +1 -1
- package/src/types/custom/MapSchema.ts +1 -1
package/build/esm/index.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import 'util';
|
|
2
|
+
|
|
1
3
|
const SWITCH_TO_STRUCTURE = 255; // (decoding collides with DELETE_AND_ADD + fieldIndex = 63)
|
|
2
4
|
const TYPE_ID = 213;
|
|
3
5
|
/**
|
|
@@ -971,10 +973,18 @@ function setOperationAtIndex(changeSet, index) {
|
|
|
971
973
|
}
|
|
972
974
|
}
|
|
973
975
|
function deleteOperationAtIndex(changeSet, index) {
|
|
974
|
-
|
|
975
|
-
if (operationsIndex
|
|
976
|
-
|
|
976
|
+
let operationsIndex = changeSet.indexes[index];
|
|
977
|
+
if (operationsIndex === undefined) {
|
|
978
|
+
//
|
|
979
|
+
// if index is not found, we need to find the last operation
|
|
980
|
+
// FIXME: this is not very efficient
|
|
981
|
+
//
|
|
982
|
+
// > See "should allow consecutive splices (same place)" tests
|
|
983
|
+
//
|
|
984
|
+
operationsIndex = Object.values(changeSet.indexes).at(-1);
|
|
985
|
+
index = Object.entries(changeSet.indexes).find(([_, value]) => value === operationsIndex)?.[0];
|
|
977
986
|
}
|
|
987
|
+
changeSet.operations[operationsIndex] = undefined;
|
|
978
988
|
delete changeSet.indexes[index];
|
|
979
989
|
}
|
|
980
990
|
function enqueueChangeTree(root, changeTree, changeSet, queueRootIndex = changeTree[changeSet].queueRootIndex) {
|
|
@@ -1159,14 +1169,9 @@ class ChangeTree {
|
|
|
1159
1169
|
}
|
|
1160
1170
|
_shiftAllChangeIndexes(shiftIndex, startIndex = 0, changeSet) {
|
|
1161
1171
|
const newIndexes = {};
|
|
1172
|
+
let newKey = 0;
|
|
1162
1173
|
for (const key in changeSet.indexes) {
|
|
1163
|
-
|
|
1164
|
-
if (index > startIndex) {
|
|
1165
|
-
newIndexes[Number(key) + shiftIndex] = index;
|
|
1166
|
-
}
|
|
1167
|
-
else {
|
|
1168
|
-
newIndexes[key] = index;
|
|
1169
|
-
}
|
|
1174
|
+
newIndexes[newKey++] = changeSet.indexes[key];
|
|
1170
1175
|
}
|
|
1171
1176
|
changeSet.indexes = newIndexes;
|
|
1172
1177
|
for (let i = 0; i < changeSet.operations.length; i++) {
|
|
@@ -1356,25 +1361,35 @@ class ChangeTree {
|
|
|
1356
1361
|
const refType = Metadata.isValidInstance(this.ref)
|
|
1357
1362
|
? this.ref.constructor
|
|
1358
1363
|
: this.ref[$childType];
|
|
1359
|
-
|
|
1360
|
-
|
|
1364
|
+
let parentChangeTree;
|
|
1365
|
+
let parentIsCollection = !Metadata.isValidInstance(parent);
|
|
1366
|
+
if (parentIsCollection) {
|
|
1367
|
+
parentChangeTree = parent[$changes];
|
|
1361
1368
|
parent = parentChangeTree.parent;
|
|
1362
1369
|
parentIndex = parentChangeTree.parentIndex;
|
|
1363
1370
|
}
|
|
1371
|
+
else {
|
|
1372
|
+
parentChangeTree = parent[$changes];
|
|
1373
|
+
}
|
|
1364
1374
|
const parentConstructor = parent.constructor;
|
|
1365
1375
|
let key = `${this.root.types.getTypeId(refType)}`;
|
|
1366
1376
|
if (parentConstructor) {
|
|
1367
1377
|
key += `-${this.root.types.schemas.get(parentConstructor)}`;
|
|
1368
1378
|
}
|
|
1369
1379
|
key += `-${parentIndex}`;
|
|
1380
|
+
const fieldHasViewTag = parentConstructor?.[Symbol.metadata]?.[$viewFieldIndexes]?.includes(parentIndex);
|
|
1370
1381
|
this.isFiltered = parent[$changes].isFiltered // in case parent is already filtered
|
|
1371
1382
|
|| this.root.types.parentFiltered[key]
|
|
1372
|
-
||
|
|
1383
|
+
|| fieldHasViewTag;
|
|
1373
1384
|
//
|
|
1374
1385
|
// "isFiltered" may not be imedialely available during `change()` due to the instance not being attached to the root yet.
|
|
1375
1386
|
// when it's available, we need to enqueue the "changes" changeset into the "filteredChanges" changeset.
|
|
1376
1387
|
//
|
|
1377
1388
|
if (this.isFiltered) {
|
|
1389
|
+
this.isVisibilitySharedWithParent = (parentChangeTree.isFiltered &&
|
|
1390
|
+
typeof (refType) !== "string" &&
|
|
1391
|
+
!fieldHasViewTag &&
|
|
1392
|
+
parentIsCollection);
|
|
1378
1393
|
if (!this.filteredChanges) {
|
|
1379
1394
|
this.filteredChanges = createChangeSet();
|
|
1380
1395
|
this.allFilteredChanges = createChangeSet();
|
|
@@ -1510,6 +1525,7 @@ const encodeArray = function (encoder, bytes, changeTree, field, operation, it,
|
|
|
1510
1525
|
}
|
|
1511
1526
|
const type = changeTree.getType(field);
|
|
1512
1527
|
const value = changeTree.getValue(field, isEncodeAll);
|
|
1528
|
+
// console.log({ type, field, value });
|
|
1513
1529
|
// console.log("encodeArray -> ", {
|
|
1514
1530
|
// ref: changeTree.ref.constructor.name,
|
|
1515
1531
|
// field,
|
|
@@ -1831,8 +1847,7 @@ class ArraySchema {
|
|
|
1831
1847
|
static [(_a$4 = $encoder, _b$4 = $decoder, $filter)](ref, index, view) {
|
|
1832
1848
|
return (!view ||
|
|
1833
1849
|
typeof (ref[$childType]) === "string" ||
|
|
1834
|
-
|
|
1835
|
-
view.visible.has(ref['tmpItems'][index]?.[$changes]));
|
|
1850
|
+
view.isChangeTreeVisible(ref['tmpItems'][index]?.[$changes]));
|
|
1836
1851
|
}
|
|
1837
1852
|
static is(type) {
|
|
1838
1853
|
return (
|
|
@@ -1988,8 +2003,6 @@ class ArraySchema {
|
|
|
1988
2003
|
return undefined;
|
|
1989
2004
|
}
|
|
1990
2005
|
this[$changes].delete(index, undefined, this.items.length - 1);
|
|
1991
|
-
// this.tmpItems[index] = undefined;
|
|
1992
|
-
// this.tmpItems.pop();
|
|
1993
2006
|
this.deletedIndexes[index] = true;
|
|
1994
2007
|
return this.items.pop();
|
|
1995
2008
|
}
|
|
@@ -2140,31 +2153,50 @@ class ArraySchema {
|
|
|
2140
2153
|
* @param deleteCount The number of elements to remove.
|
|
2141
2154
|
* @param insertItems Elements to insert into the array in place of the deleted elements.
|
|
2142
2155
|
*/
|
|
2143
|
-
splice(start, deleteCount
|
|
2156
|
+
splice(start, deleteCount, ...insertItems) {
|
|
2144
2157
|
const changeTree = this[$changes];
|
|
2158
|
+
const itemsLength = this.items.length;
|
|
2145
2159
|
const tmpItemsLength = this.tmpItems.length;
|
|
2146
2160
|
const insertCount = insertItems.length;
|
|
2147
2161
|
// build up-to-date list of indexes, excluding removed values.
|
|
2148
2162
|
const indexes = [];
|
|
2149
2163
|
for (let i = 0; i < tmpItemsLength; i++) {
|
|
2150
|
-
// if (this.tmpItems[i] !== undefined) {
|
|
2151
2164
|
if (this.deletedIndexes[i] !== true) {
|
|
2152
2165
|
indexes.push(i);
|
|
2153
2166
|
}
|
|
2154
2167
|
}
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2168
|
+
if (itemsLength > start) {
|
|
2169
|
+
// if deleteCount is not provided, delete all items from start to end
|
|
2170
|
+
if (deleteCount === undefined) {
|
|
2171
|
+
deleteCount = itemsLength - start;
|
|
2172
|
+
}
|
|
2173
|
+
//
|
|
2174
|
+
// delete operations at correct index
|
|
2175
|
+
//
|
|
2176
|
+
for (let i = start; i < start + deleteCount; i++) {
|
|
2177
|
+
const index = indexes[i];
|
|
2178
|
+
changeTree.delete(index, OPERATION.DELETE);
|
|
2179
|
+
this.deletedIndexes[index] = true;
|
|
2180
|
+
}
|
|
2161
2181
|
}
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2182
|
+
else {
|
|
2183
|
+
// not enough items to delete
|
|
2184
|
+
deleteCount = 0;
|
|
2185
|
+
}
|
|
2186
|
+
// insert operations
|
|
2187
|
+
if (insertCount > 0) {
|
|
2188
|
+
if (insertCount > deleteCount) {
|
|
2189
|
+
console.error("Inserting more elements than deleting during ArraySchema#splice()");
|
|
2190
|
+
throw new Error("ArraySchema#splice(): insertCount must be equal or lower than deleteCount.");
|
|
2191
|
+
}
|
|
2192
|
+
for (let i = 0; i < insertCount; i++) {
|
|
2193
|
+
const addIndex = (indexes[start] ?? itemsLength) + i;
|
|
2194
|
+
changeTree.indexedOperation(addIndex, (this.deletedIndexes[addIndex])
|
|
2195
|
+
? OPERATION.DELETE_AND_ADD
|
|
2196
|
+
: OPERATION.ADD);
|
|
2197
|
+
// set value's parent/root
|
|
2198
|
+
insertItems[i][$changes]?.setParent(this, changeTree.root, addIndex);
|
|
2199
|
+
}
|
|
2168
2200
|
}
|
|
2169
2201
|
//
|
|
2170
2202
|
// delete exceeding indexes from "allChanges"
|
|
@@ -2172,6 +2204,16 @@ class ArraySchema {
|
|
|
2172
2204
|
//
|
|
2173
2205
|
if (deleteCount > insertCount) {
|
|
2174
2206
|
changeTree.shiftAllChangeIndexes(-(deleteCount - insertCount), indexes[start + insertCount]);
|
|
2207
|
+
// debugChangeSet("AFTER SHIFT indexes", changeTree.allChanges);
|
|
2208
|
+
}
|
|
2209
|
+
//
|
|
2210
|
+
// FIXME: this code block is duplicated on ChangeTree
|
|
2211
|
+
//
|
|
2212
|
+
if (changeTree.filteredChanges !== undefined) {
|
|
2213
|
+
enqueueChangeTree(changeTree.root, changeTree, 'filteredChanges');
|
|
2214
|
+
}
|
|
2215
|
+
else {
|
|
2216
|
+
enqueueChangeTree(changeTree.root, changeTree, 'changes');
|
|
2175
2217
|
}
|
|
2176
2218
|
return this.items.splice(start, deleteCount, ...insertItems);
|
|
2177
2219
|
}
|
|
@@ -2427,9 +2469,6 @@ class ArraySchema {
|
|
|
2427
2469
|
: this.deletedIndexes[index]
|
|
2428
2470
|
? this.items[index]
|
|
2429
2471
|
: this.tmpItems[index] || this.items[index];
|
|
2430
|
-
// return (isEncodeAll)
|
|
2431
|
-
// ? this.items[index]
|
|
2432
|
-
// : this.tmpItems[index] ?? this.items[index];
|
|
2433
2472
|
}
|
|
2434
2473
|
[$deleteByIndex](index) {
|
|
2435
2474
|
this.items[index] = undefined;
|
|
@@ -2489,7 +2528,7 @@ class MapSchema {
|
|
|
2489
2528
|
static [(_a$3 = $encoder, _b$3 = $decoder, $filter)](ref, index, view) {
|
|
2490
2529
|
return (!view ||
|
|
2491
2530
|
typeof (ref[$childType]) === "string" ||
|
|
2492
|
-
view.
|
|
2531
|
+
view.isChangeTreeVisible((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
|
|
2493
2532
|
}
|
|
2494
2533
|
static is(type) {
|
|
2495
2534
|
return type['map'] !== undefined;
|
|
@@ -3106,7 +3145,7 @@ class Schema {
|
|
|
3106
3145
|
}
|
|
3107
3146
|
else if (tag === DEFAULT_VIEW_TAG) {
|
|
3108
3147
|
// view pass: default tag
|
|
3109
|
-
return view.
|
|
3148
|
+
return view.isChangeTreeVisible(ref[$changes]);
|
|
3110
3149
|
}
|
|
3111
3150
|
else {
|
|
3112
3151
|
// view pass: custom tag
|
|
@@ -3319,7 +3358,7 @@ class CollectionSchema {
|
|
|
3319
3358
|
static [(_a$1 = $encoder, _b$1 = $decoder, $filter)](ref, index, view) {
|
|
3320
3359
|
return (!view ||
|
|
3321
3360
|
typeof (ref[$childType]) === "string" ||
|
|
3322
|
-
view.
|
|
3361
|
+
view.isChangeTreeVisible((ref[$getByIndex](index) ?? ref.deletedItems[index])[$changes]));
|
|
3323
3362
|
}
|
|
3324
3363
|
static is(type) {
|
|
3325
3364
|
return type['collection'] !== undefined;
|
|
@@ -3793,18 +3832,17 @@ class Encoder {
|
|
|
3793
3832
|
continue;
|
|
3794
3833
|
}
|
|
3795
3834
|
if (hasView) {
|
|
3796
|
-
if (!view.
|
|
3835
|
+
if (!view.isChangeTreeVisible(changeTree)) {
|
|
3836
|
+
// console.log("MARK AS INVISIBLE:", { ref: changeTree.ref.constructor.name, refId: changeTree.refId, raw: changeTree.ref.toJSON() });
|
|
3797
3837
|
view.invisible.add(changeTree);
|
|
3798
3838
|
continue; // skip this change tree
|
|
3799
3839
|
}
|
|
3800
|
-
|
|
3801
|
-
view.invisible.delete(changeTree); // remove from invisible list
|
|
3802
|
-
}
|
|
3840
|
+
view.invisible.delete(changeTree); // remove from invisible list
|
|
3803
3841
|
}
|
|
3804
|
-
const
|
|
3842
|
+
const changeSet = changeTree[changeSetName];
|
|
3805
3843
|
const ref = changeTree.ref;
|
|
3806
3844
|
// TODO: avoid iterating over change tree if no changes were made
|
|
3807
|
-
const numChanges =
|
|
3845
|
+
const numChanges = changeSet.operations.length;
|
|
3808
3846
|
if (numChanges === 0) {
|
|
3809
3847
|
continue;
|
|
3810
3848
|
}
|
|
@@ -3819,7 +3857,7 @@ class Encoder {
|
|
|
3819
3857
|
encode.number(buffer, changeTree.refId, it);
|
|
3820
3858
|
}
|
|
3821
3859
|
for (let j = 0; j < numChanges; j++) {
|
|
3822
|
-
const fieldIndex =
|
|
3860
|
+
const fieldIndex = changeSet.operations[j];
|
|
3823
3861
|
const operation = (fieldIndex < 0)
|
|
3824
3862
|
? Math.abs(fieldIndex) // "pure" operation without fieldIndex (e.g. CLEAR, REVERSE, etc.)
|
|
3825
3863
|
: (isEncodeAll)
|
|
@@ -4933,6 +4971,25 @@ class StateView {
|
|
|
4933
4971
|
// clear items array
|
|
4934
4972
|
this.items.length = 0;
|
|
4935
4973
|
}
|
|
4974
|
+
isChangeTreeVisible(changeTree) {
|
|
4975
|
+
let isVisible = this.visible.has(changeTree);
|
|
4976
|
+
//
|
|
4977
|
+
// TODO: avoid checking for parent visibility, most of the time it's not needed
|
|
4978
|
+
// See test case: 'should not be required to manually call view.add() items to child arrays without @view() tag'
|
|
4979
|
+
//
|
|
4980
|
+
if (!isVisible && changeTree.isVisibilitySharedWithParent) {
|
|
4981
|
+
// console.log("CHECK AGAINST PARENT...", {
|
|
4982
|
+
// ref: changeTree.ref.constructor.name,
|
|
4983
|
+
// refId: changeTree.refId,
|
|
4984
|
+
// parent: changeTree.parent.constructor.name,
|
|
4985
|
+
// });
|
|
4986
|
+
if (this.visible.has(changeTree.parent[$changes])) {
|
|
4987
|
+
this.visible.add(changeTree);
|
|
4988
|
+
isVisible = true;
|
|
4989
|
+
}
|
|
4990
|
+
}
|
|
4991
|
+
return isVisible;
|
|
4992
|
+
}
|
|
4936
4993
|
}
|
|
4937
4994
|
|
|
4938
4995
|
registerType("map", { constructor: MapSchema });
|