@colyseus/schema 5.0.12 → 5.0.13
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/encoder/ChangeTree.d.ts +3 -0
- package/build/encoder/changeTree/parentChain.d.ts +9 -0
- package/build/index.cjs +75 -1
- package/build/index.cjs.map +1 -1
- package/build/index.js +75 -1
- package/build/index.mjs +75 -1
- package/build/index.mjs.map +1 -1
- package/build/types/custom/ArraySchema.d.ts +17 -0
- package/package.json +1 -1
- package/src/encoder/ChangeTree.ts +5 -0
- package/src/encoder/changeTree/parentChain.ts +29 -0
- package/src/types/custom/ArraySchema.ts +40 -1
|
@@ -251,6 +251,8 @@ export declare class ChangeTree<T extends Ref = any> implements ChangeRecorder {
|
|
|
251
251
|
get parent(): Ref | undefined;
|
|
252
252
|
get parentIndex(): number | undefined;
|
|
253
253
|
addParent(parent: Ref, index: number): void;
|
|
254
|
+
/** Re-point an existing parent's cached index after the parent reindexed. */
|
|
255
|
+
setParentIndex(parent: Ref, index: number): void;
|
|
254
256
|
/** @returns true if parent was found and removed */
|
|
255
257
|
removeParent(parent?: Ref): boolean;
|
|
256
258
|
findParent(predicate: (parent: Ref, index: number) => boolean): ParentChain | undefined;
|
|
@@ -288,6 +290,7 @@ export declare class UntrackedChangeTree {
|
|
|
288
290
|
operation(): void;
|
|
289
291
|
setParent(): void;
|
|
290
292
|
addParent(): void;
|
|
293
|
+
setParentIndex(): void;
|
|
291
294
|
removeParent(): boolean;
|
|
292
295
|
getChange(): number;
|
|
293
296
|
discard(): void;
|
|
@@ -5,6 +5,15 @@ import type { ChangeTree, ParentChain, Ref } from "../ChangeTree.js";
|
|
|
5
5
|
* behavior).
|
|
6
6
|
*/
|
|
7
7
|
export declare function addParent(tree: ChangeTree, parent: Ref, index: number): void;
|
|
8
|
+
/**
|
|
9
|
+
* Move `parent`'s existing chain entry to `index`, skipping the attachment
|
|
10
|
+
* work `addParent` does. `parent` must already be a parent of `tree`.
|
|
11
|
+
*
|
|
12
|
+
* Called by collections whose wire slots shift (ArraySchema): StateView
|
|
13
|
+
* addresses per-view ADD/DELETE by that index, so it has to follow the
|
|
14
|
+
* element it names.
|
|
15
|
+
*/
|
|
16
|
+
export declare function setParentIndex(tree: ChangeTree, parent: Ref, index: number): void;
|
|
8
17
|
/**
|
|
9
18
|
* Remove a parent from the chain.
|
|
10
19
|
* @returns true if parent was found and removed (Root.remove relies on this).
|
package/build/index.cjs
CHANGED
|
@@ -1914,6 +1914,34 @@ function addParent(tree, parent, index) {
|
|
|
1914
1914
|
tree._parentIndex = index;
|
|
1915
1915
|
}
|
|
1916
1916
|
}
|
|
1917
|
+
/**
|
|
1918
|
+
* Move `parent`'s existing chain entry to `index`, skipping the attachment
|
|
1919
|
+
* work `addParent` does. `parent` must already be a parent of `tree`.
|
|
1920
|
+
*
|
|
1921
|
+
* Called by collections whose wire slots shift (ArraySchema): StateView
|
|
1922
|
+
* addresses per-view ADD/DELETE by that index, so it has to follow the
|
|
1923
|
+
* element it names.
|
|
1924
|
+
*/
|
|
1925
|
+
function setParentIndex(tree, parent, index) {
|
|
1926
|
+
if (tree.extraParents === undefined) {
|
|
1927
|
+
tree._parentIndex = index; // sole parent, so it is `parent`
|
|
1928
|
+
return;
|
|
1929
|
+
}
|
|
1930
|
+
// Shared instance — move only the entry `parent` owns. Matching goes
|
|
1931
|
+
// through `$changes` because ArraySchema arrives proxied (see removeParent
|
|
1932
|
+
// below), and `extraParents` only ever fills by demoting `parentRef`, so
|
|
1933
|
+
// the inline parent is set here.
|
|
1934
|
+
if (tree.parentRef[$changes] === parent[$changes]) {
|
|
1935
|
+
tree._parentIndex = index;
|
|
1936
|
+
return;
|
|
1937
|
+
}
|
|
1938
|
+
for (let entry = tree.extraParents; entry !== undefined; entry = entry.next) {
|
|
1939
|
+
if (entry.ref[$changes] === parent[$changes]) {
|
|
1940
|
+
entry.index = index;
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1917
1945
|
/**
|
|
1918
1946
|
* Remove a parent from the chain.
|
|
1919
1947
|
* @returns true if parent was found and removed (Root.remove relies on this).
|
|
@@ -3158,6 +3186,8 @@ class ChangeTree {
|
|
|
3158
3186
|
get parent() { return this.parentRef; }
|
|
3159
3187
|
get parentIndex() { return this._parentIndex; }
|
|
3160
3188
|
addParent(parent, index) { addParent(this, parent, index); }
|
|
3189
|
+
/** Re-point an existing parent's cached index after the parent reindexed. */
|
|
3190
|
+
setParentIndex(parent, index) { setParentIndex(this, parent, index); }
|
|
3161
3191
|
/** @returns true if parent was found and removed */
|
|
3162
3192
|
removeParent(parent = this.parent) { return removeParent(this, parent); }
|
|
3163
3193
|
findParent(predicate) {
|
|
@@ -3202,6 +3232,7 @@ class UntrackedChangeTree {
|
|
|
3202
3232
|
operation() { }
|
|
3203
3233
|
setParent() { }
|
|
3204
3234
|
addParent() { }
|
|
3235
|
+
setParentIndex() { }
|
|
3205
3236
|
removeParent() { return false; }
|
|
3206
3237
|
getChange() { return 0; }
|
|
3207
3238
|
discard() { }
|
|
@@ -4257,6 +4288,40 @@ class ArraySchema {
|
|
|
4257
4288
|
// beyond the live range: appends land after the staged tmpItems tail
|
|
4258
4289
|
return tmpItems.length + (index - live);
|
|
4259
4290
|
}
|
|
4291
|
+
/**
|
|
4292
|
+
* Re-point children at their wire slot. `ChangeTree._parentIndex` caches
|
|
4293
|
+
* the slot a child holds in `tmpItems`, and StateView addresses per-view
|
|
4294
|
+
* ADD/DELETE with it — so a reorder that leaves it behind aims those ops
|
|
4295
|
+
* at whichever element inherited the slot (issue #231).
|
|
4296
|
+
*
|
|
4297
|
+
* The filter check is a correctness boundary, not a tunable: StateView is
|
|
4298
|
+
* the only reader and reaches the index only through a filtered array
|
|
4299
|
+
* (`addParentOf` bails on `hasFilteredFields`, `remove` on the child's
|
|
4300
|
+
* `isFiltered`). Everything else stops at the flag read instead of walking
|
|
4301
|
+
* its children every tick.
|
|
4302
|
+
*
|
|
4303
|
+
* Callers name the lowest slot that moved as `from`. Compaction cannot, so
|
|
4304
|
+
* it hands over the pre-compaction layout as `staged` and the unchanged
|
|
4305
|
+
* prefix is skipped instead. Either way tail churn walks nothing.
|
|
4306
|
+
*/
|
|
4307
|
+
$reindexChildren(from, staged) {
|
|
4308
|
+
if (!this[$changes].hasFilteredFields) {
|
|
4309
|
+
return;
|
|
4310
|
+
} // nothing will read the cache
|
|
4311
|
+
if (typeof this[$childType] === "string") {
|
|
4312
|
+
return;
|
|
4313
|
+
} // primitives have no child tree
|
|
4314
|
+
const tmpItems = this.tmpItems;
|
|
4315
|
+
const length = tmpItems.length;
|
|
4316
|
+
if (staged !== undefined) {
|
|
4317
|
+
while (from < length && tmpItems[from] === staged[from]) {
|
|
4318
|
+
from++;
|
|
4319
|
+
}
|
|
4320
|
+
}
|
|
4321
|
+
for (let i = from; i < length; i++) {
|
|
4322
|
+
tmpItems[i]?.[$changes]?.setParentIndex(this, i);
|
|
4323
|
+
}
|
|
4324
|
+
}
|
|
4260
4325
|
// encoding only. Returns the wire index the change was recorded at
|
|
4261
4326
|
// (undefined when nothing was recorded).
|
|
4262
4327
|
$changeAt(index, value) {
|
|
@@ -4368,6 +4433,7 @@ class ArraySchema {
|
|
|
4368
4433
|
self[$changes].operation(exports.OPERATION.REVERSE);
|
|
4369
4434
|
self.items.reverse();
|
|
4370
4435
|
self.tmpItems.reverse();
|
|
4436
|
+
self.$reindexChildren(0);
|
|
4371
4437
|
return this;
|
|
4372
4438
|
}
|
|
4373
4439
|
/**
|
|
@@ -4419,6 +4485,7 @@ class ArraySchema {
|
|
|
4419
4485
|
// wouldn't OPERATION.MOVE make more sense here?
|
|
4420
4486
|
sortedItems.forEach((_, i) => changeTree.change(i, exports.OPERATION.REPLACE));
|
|
4421
4487
|
self.tmpItems.sort(compareFn);
|
|
4488
|
+
self.$reindexChildren(0);
|
|
4422
4489
|
self.isMovingItems = false;
|
|
4423
4490
|
return this;
|
|
4424
4491
|
}
|
|
@@ -4500,6 +4567,7 @@ class ArraySchema {
|
|
|
4500
4567
|
deletedIndexes.unshift(...new Array(items.length).fill(false));
|
|
4501
4568
|
}
|
|
4502
4569
|
self.tmpItems.unshift(...items);
|
|
4570
|
+
self.$reindexChildren(items.length); // survivors only — the loop above placed the new items
|
|
4503
4571
|
return self.items.unshift(...items);
|
|
4504
4572
|
}
|
|
4505
4573
|
/**
|
|
@@ -4768,8 +4836,14 @@ class ArraySchema {
|
|
|
4768
4836
|
}
|
|
4769
4837
|
[$onEncodeEnd]() {
|
|
4770
4838
|
const self = this[$proxyTarget] ?? this;
|
|
4839
|
+
const staged = self.tmpItems;
|
|
4771
4840
|
self.tmpItems = self.items.slice();
|
|
4772
|
-
self.deletedIndexes.length
|
|
4841
|
+
if (self.deletedIndexes.length > 0) {
|
|
4842
|
+
// compaction just closed the staged holes — everything above the
|
|
4843
|
+
// lowest one slid down a slot
|
|
4844
|
+
self.$reindexChildren(0, staged);
|
|
4845
|
+
self.deletedIndexes.length = 0;
|
|
4846
|
+
}
|
|
4773
4847
|
}
|
|
4774
4848
|
[$onDecodeEnd]() {
|
|
4775
4849
|
const self = this[$proxyTarget] ?? this;
|