@colyseus/schema 3.0.57 → 3.0.60
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 +85 -33
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +85 -33
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +85 -33
- package/lib/decoder/Decoder.js +1 -3
- package/lib/decoder/Decoder.js.map +1 -1
- package/lib/encoder/ChangeTree.d.ts +1 -1
- package/lib/encoder/ChangeTree.js +4 -4
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/Encoder.js +2 -2
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +5 -2
- package/lib/encoder/Root.js +72 -23
- package/lib/encoder/Root.js.map +1 -1
- package/lib/types/custom/MapSchema.js +7 -2
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/package.json +1 -1
- package/src/decoder/Decoder.ts +1 -2
- package/src/encoder/ChangeTree.ts +5 -5
- package/src/encoder/Encoder.ts +3 -3
- package/src/encoder/Root.ts +81 -24
- package/src/types/custom/MapSchema.ts +7 -2
package/src/encoder/Root.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { OPERATION } from "../encoding/spec";
|
|
2
2
|
import { TypeContext } from "../types/TypeContext";
|
|
3
3
|
import { ChangeTree, setOperationAtIndex, ChangeTreeList, createChangeTreeList, ChangeSetName, type ChangeTreeNode } from "./ChangeTree";
|
|
4
|
+
import { $changes } from "../types/symbols";
|
|
4
5
|
|
|
5
6
|
export class Root {
|
|
6
7
|
protected nextUniqueId: number = 0;
|
|
@@ -83,8 +84,8 @@ export class Root {
|
|
|
83
84
|
this.remove(child);
|
|
84
85
|
|
|
85
86
|
} else if (child.parentChain) {
|
|
86
|
-
// re-assigning a child of the same root, move it to
|
|
87
|
-
this.
|
|
87
|
+
// re-assigning a child of the same root, move it next to parent
|
|
88
|
+
this.moveNextToParent(child);
|
|
88
89
|
}
|
|
89
90
|
}
|
|
90
91
|
});
|
|
@@ -94,36 +95,57 @@ export class Root {
|
|
|
94
95
|
|
|
95
96
|
//
|
|
96
97
|
// When losing a reference to an instance, it is best to move the
|
|
97
|
-
// ChangeTree to
|
|
98
|
+
// ChangeTree next to its parent in the encoding queue.
|
|
98
99
|
//
|
|
99
100
|
// This way, at decoding time, the instance that contains the
|
|
100
101
|
// ChangeTree will be available before the ChangeTree itself. If the
|
|
101
102
|
// containing instance is not available, the Decoder will throw
|
|
102
103
|
// "refId not found" error.
|
|
103
104
|
//
|
|
104
|
-
this.
|
|
105
|
-
changeTree.forEachChild((child, _) => this.moveToEndOfChanges(child));
|
|
105
|
+
this.recursivelyMoveNextToParent(changeTree);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
return refCount;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
recursivelyMoveNextToParent(changeTree: ChangeTree) {
|
|
112
|
+
this.moveNextToParent(changeTree);
|
|
113
|
+
changeTree.forEachChild((child, _) => this.recursivelyMoveNextToParent(child));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
moveNextToParent(changeTree: ChangeTree) {
|
|
112
117
|
if (changeTree.filteredChanges) {
|
|
113
|
-
this.
|
|
114
|
-
this.
|
|
118
|
+
this.moveNextToParentInChangeTreeList("filteredChanges", changeTree);
|
|
119
|
+
this.moveNextToParentInChangeTreeList("allFilteredChanges", changeTree);
|
|
115
120
|
} else {
|
|
116
|
-
this.
|
|
117
|
-
this.
|
|
121
|
+
this.moveNextToParentInChangeTreeList("changes", changeTree);
|
|
122
|
+
this.moveNextToParentInChangeTreeList("allChanges", changeTree);
|
|
118
123
|
}
|
|
119
124
|
}
|
|
120
125
|
|
|
121
|
-
|
|
126
|
+
moveNextToParentInChangeTreeList(changeSetName: ChangeSetName, changeTree: ChangeTree): void {
|
|
122
127
|
const changeSet = this[changeSetName];
|
|
123
128
|
const node = changeTree[changeSetName].queueRootNode;
|
|
124
|
-
if (!node
|
|
129
|
+
if (!node) return;
|
|
130
|
+
|
|
131
|
+
// Find the parent in the linked list
|
|
132
|
+
const parent = changeTree.parent;
|
|
133
|
+
if (!parent || !parent[$changes]) return;
|
|
134
|
+
|
|
135
|
+
const parentNode = parent[$changes][changeSetName]?.queueRootNode;
|
|
136
|
+
if (!parentNode || parentNode === node) return;
|
|
137
|
+
|
|
138
|
+
// Use cached positions - no iteration needed!
|
|
139
|
+
const parentPosition = parentNode.position;
|
|
140
|
+
const childPosition = node.position;
|
|
125
141
|
|
|
126
|
-
//
|
|
142
|
+
// If child is already after parent, no need to move
|
|
143
|
+
if (childPosition > parentPosition) return;
|
|
144
|
+
|
|
145
|
+
// Child is before parent, so we need to move it after parent
|
|
146
|
+
// This maintains decoding order (parent before child)
|
|
147
|
+
|
|
148
|
+
// Remove node from current position
|
|
127
149
|
if (node.prev) {
|
|
128
150
|
node.prev.next = node.next;
|
|
129
151
|
} else {
|
|
@@ -136,17 +158,20 @@ export class Root {
|
|
|
136
158
|
changeSet.tail = node.prev;
|
|
137
159
|
}
|
|
138
160
|
|
|
139
|
-
//
|
|
140
|
-
node.prev =
|
|
141
|
-
node.next =
|
|
161
|
+
// Insert node right after parent
|
|
162
|
+
node.prev = parentNode;
|
|
163
|
+
node.next = parentNode.next;
|
|
142
164
|
|
|
143
|
-
if (
|
|
144
|
-
|
|
165
|
+
if (parentNode.next) {
|
|
166
|
+
parentNode.next.prev = node;
|
|
145
167
|
} else {
|
|
146
|
-
changeSet.
|
|
168
|
+
changeSet.tail = node;
|
|
147
169
|
}
|
|
148
170
|
|
|
149
|
-
|
|
171
|
+
parentNode.next = node;
|
|
172
|
+
|
|
173
|
+
// Update positions after the move
|
|
174
|
+
this.updatePositionsAfterMove(changeSet, node, parentPosition + 1);
|
|
150
175
|
}
|
|
151
176
|
|
|
152
177
|
public enqueueChangeTree(
|
|
@@ -162,7 +187,12 @@ export class Root {
|
|
|
162
187
|
}
|
|
163
188
|
|
|
164
189
|
protected addToChangeTreeList(list: ChangeTreeList, changeTree: ChangeTree): ChangeTreeNode {
|
|
165
|
-
const node: ChangeTreeNode = {
|
|
190
|
+
const node: ChangeTreeNode = {
|
|
191
|
+
changeTree,
|
|
192
|
+
next: undefined,
|
|
193
|
+
prev: undefined,
|
|
194
|
+
position: list.tail ? list.tail.position + 1 : 0
|
|
195
|
+
};
|
|
166
196
|
|
|
167
197
|
if (!list.next) {
|
|
168
198
|
list.next = node;
|
|
@@ -173,16 +203,42 @@ export class Root {
|
|
|
173
203
|
list.tail = node;
|
|
174
204
|
}
|
|
175
205
|
|
|
176
|
-
list.length++;
|
|
177
|
-
|
|
178
206
|
return node;
|
|
179
207
|
}
|
|
180
208
|
|
|
209
|
+
protected updatePositionsAfterRemoval(list: ChangeTreeList, removedPosition: number) {
|
|
210
|
+
// Update positions for all nodes after the removed position
|
|
211
|
+
let current = list.next;
|
|
212
|
+
let position = 0;
|
|
213
|
+
|
|
214
|
+
while (current) {
|
|
215
|
+
if (position >= removedPosition) {
|
|
216
|
+
current.position = position;
|
|
217
|
+
}
|
|
218
|
+
current = current.next;
|
|
219
|
+
position++;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
protected updatePositionsAfterMove(list: ChangeTreeList, node: ChangeTreeNode, newPosition: number) {
|
|
224
|
+
// Recalculate all positions - this is more reliable than trying to be clever
|
|
225
|
+
let current = list.next;
|
|
226
|
+
let position = 0;
|
|
227
|
+
|
|
228
|
+
while (current) {
|
|
229
|
+
current.position = position;
|
|
230
|
+
current = current.next;
|
|
231
|
+
position++;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
181
235
|
public removeChangeFromChangeSet(changeSetName: ChangeSetName, changeTree: ChangeTree) {
|
|
182
236
|
const changeSet = this[changeSetName];
|
|
183
237
|
const node = changeTree[changeSetName].queueRootNode;
|
|
184
238
|
|
|
185
239
|
if (node && node.changeTree === changeTree) {
|
|
240
|
+
const removedPosition = node.position;
|
|
241
|
+
|
|
186
242
|
// Remove the node from the linked list
|
|
187
243
|
if (node.prev) {
|
|
188
244
|
node.prev.next = node.next;
|
|
@@ -196,7 +252,8 @@ export class Root {
|
|
|
196
252
|
changeSet.tail = node.prev;
|
|
197
253
|
}
|
|
198
254
|
|
|
199
|
-
|
|
255
|
+
// Update positions for nodes that came after the removed node
|
|
256
|
+
this.updatePositionsAfterRemoval(changeSet, removedPosition);
|
|
200
257
|
|
|
201
258
|
// Clear ChangeTree reference
|
|
202
259
|
changeTree[changeSetName].queueRootNode = undefined;
|
|
@@ -224,10 +224,15 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
|
|
|
224
224
|
protected [$onEncodeEnd]() {
|
|
225
225
|
const changeTree = this[$changes];
|
|
226
226
|
|
|
227
|
-
// cleanup changeTree.indexes
|
|
227
|
+
// - cleanup changeTree.indexes
|
|
228
|
+
// - cleanup $indexes
|
|
228
229
|
for (const indexStr in this.deletedItems) {
|
|
229
|
-
const
|
|
230
|
+
const index = parseInt(indexStr);
|
|
231
|
+
const key = this.$indexes.get(index);
|
|
232
|
+
// TODO: refactor this.
|
|
233
|
+
// it shouldn't be necessary to keep track of indexes both on changeTree and on $indexes
|
|
230
234
|
delete changeTree.indexes[key];
|
|
235
|
+
this.$indexes.delete(index);
|
|
231
236
|
}
|
|
232
237
|
|
|
233
238
|
this.deletedItems = {};
|