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