@colyseus/schema 3.0.11 → 3.0.12
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 +75 -84
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +75 -84
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +75 -84
- package/lib/Metadata.js +1 -2
- package/lib/Metadata.js.map +1 -1
- package/lib/annotations.js +4 -3
- package/lib/annotations.js.map +1 -1
- package/lib/decoder/DecodeOperation.js +0 -13
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +0 -1
- package/lib/encoder/Encoder.js +22 -30
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +1 -1
- package/lib/encoder/Root.js +1 -0
- package/lib/encoder/Root.js.map +1 -1
- package/lib/encoder/StateView.d.ts +2 -4
- package/lib/encoder/StateView.js +19 -13
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/types/custom/ArraySchema.js +5 -1
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/MapSchema.js +23 -22
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/package.json +1 -1
- package/src/Metadata.ts +1 -2
- package/src/annotations.ts +4 -4
- package/src/decoder/DecodeOperation.ts +0 -14
- package/src/encoder/ChangeTree.ts +0 -2
- package/src/encoder/Encoder.ts +25 -41
- package/src/encoder/Root.ts +1 -0
- package/src/encoder/StateView.ts +22 -15
- package/src/types/custom/ArraySchema.ts +8 -1
- package/src/types/custom/MapSchema.ts +24 -27
|
@@ -59,20 +59,6 @@ export function decodeValue(
|
|
|
59
59
|
//
|
|
60
60
|
if (operation !== OPERATION.DELETE_AND_ADD) {
|
|
61
61
|
ref[$deleteByIndex](index);
|
|
62
|
-
|
|
63
|
-
// //
|
|
64
|
-
// // FIXME: is this in the correct place?
|
|
65
|
-
// // (This is sounding like a workaround just for ArraySchema, see
|
|
66
|
-
// // "should splice and move" test on ArraySchema.test.ts)
|
|
67
|
-
// //
|
|
68
|
-
// allChanges.push({
|
|
69
|
-
// ref,
|
|
70
|
-
// refId: decoder.currentRefId,
|
|
71
|
-
// op: OPERATION.DELETE,
|
|
72
|
-
// field: index as unknown as string,
|
|
73
|
-
// value: undefined,
|
|
74
|
-
// previousValue,
|
|
75
|
-
// });
|
|
76
62
|
}
|
|
77
63
|
|
|
78
64
|
value = undefined;
|
|
@@ -11,8 +11,6 @@ import { Root } from "./Root";
|
|
|
11
11
|
import { Metadata } from "../Metadata";
|
|
12
12
|
import type { EncodeOperation } from "./EncodeOperation";
|
|
13
13
|
import type { DecodeOperation } from "../decoder/DecodeOperation";
|
|
14
|
-
import { TypeContext } from "../types/TypeContext";
|
|
15
|
-
import { ReferenceTracker } from "../decoder/ReferenceTracker";
|
|
16
14
|
|
|
17
15
|
declare global {
|
|
18
16
|
interface Object {
|
package/src/encoder/Encoder.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Schema } from "../Schema";
|
|
2
2
|
import { TypeContext } from "../types/TypeContext";
|
|
3
|
-
import { $changes, $encoder, $filter
|
|
3
|
+
import { $changes, $encoder, $filter } from "../types/symbols";
|
|
4
4
|
|
|
5
5
|
import { encode } from "../encoding/encode";
|
|
6
6
|
import type { Iterator } from "../encoding/decode";
|
|
@@ -58,14 +58,6 @@ export class Encoder<T extends Schema = any> {
|
|
|
58
58
|
for (let i = 0, numChangeTrees = changeTrees.length; i < numChangeTrees; i++) {
|
|
59
59
|
const changeTree = changeTrees[i];
|
|
60
60
|
|
|
61
|
-
const operations = changeTree[changeSetName];
|
|
62
|
-
const ref = changeTree.ref;
|
|
63
|
-
|
|
64
|
-
const ctor = ref.constructor;
|
|
65
|
-
const encoder = ctor[$encoder];
|
|
66
|
-
const filter = ctor[$filter];
|
|
67
|
-
const metadata = ctor[Symbol.metadata];
|
|
68
|
-
|
|
69
61
|
if (hasView) {
|
|
70
62
|
if (!view.items.has(changeTree)) {
|
|
71
63
|
view.invisible.add(changeTree);
|
|
@@ -76,6 +68,18 @@ export class Encoder<T extends Schema = any> {
|
|
|
76
68
|
}
|
|
77
69
|
}
|
|
78
70
|
|
|
71
|
+
const operations = changeTree[changeSetName];
|
|
72
|
+
const ref = changeTree.ref;
|
|
73
|
+
|
|
74
|
+
// TODO: avoid iterating over change tree if no changes were made
|
|
75
|
+
const numChanges = operations.operations.length;
|
|
76
|
+
if (numChanges === 0) { continue; }
|
|
77
|
+
|
|
78
|
+
const ctor = ref.constructor;
|
|
79
|
+
const encoder = ctor[$encoder];
|
|
80
|
+
const filter = ctor[$filter];
|
|
81
|
+
const metadata = ctor[Symbol.metadata];
|
|
82
|
+
|
|
79
83
|
// skip root `refId` if it's the first change tree
|
|
80
84
|
// (unless it "hasView", which will need to revisit the root)
|
|
81
85
|
if (hasView || it.offset > initialOffset || changeTree !== rootChangeTree) {
|
|
@@ -83,7 +87,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
83
87
|
encode.number(buffer, changeTree.refId, it);
|
|
84
88
|
}
|
|
85
89
|
|
|
86
|
-
for (let j = 0
|
|
90
|
+
for (let j = 0; j < numChanges; j++) {
|
|
87
91
|
const fieldIndex = operations.operations[j];
|
|
88
92
|
|
|
89
93
|
const operation = (fieldIndex < 0)
|
|
@@ -199,17 +203,18 @@ export class Encoder<T extends Schema = any> {
|
|
|
199
203
|
const viewOffset = it.offset;
|
|
200
204
|
|
|
201
205
|
// encode visibility changes (add/remove for this view)
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
for (let i = 0, numRefIds = refIds.length; i < numRefIds; i++) {
|
|
205
|
-
const refId = refIds[i];
|
|
206
|
-
const changes = view.changes[refId];
|
|
206
|
+
for (const [refId, changes] of view.changes) {
|
|
207
207
|
const changeTree = this.root.changeTrees[refId];
|
|
208
208
|
|
|
209
|
-
if (
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
209
|
+
if (changeTree === undefined) {
|
|
210
|
+
// detached instance, remove from view and skip.
|
|
211
|
+
view.changes.delete(refId);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const keys = Object.keys(changes);
|
|
216
|
+
if (keys.length === 0) {
|
|
217
|
+
// FIXME: avoid having empty changes if no changes were made
|
|
213
218
|
// console.log("changes.size === 0, skip", changeTree.ref.constructor.name);
|
|
214
219
|
continue;
|
|
215
220
|
}
|
|
@@ -223,7 +228,6 @@ export class Encoder<T extends Schema = any> {
|
|
|
223
228
|
bytes[it.offset++] = SWITCH_TO_STRUCTURE & 255;
|
|
224
229
|
encode.number(bytes, changeTree.refId, it);
|
|
225
230
|
|
|
226
|
-
const keys = Object.keys(changes);
|
|
227
231
|
for (let i = 0, numChanges = keys.length; i < numChanges; i++) {
|
|
228
232
|
const key = keys[i];
|
|
229
233
|
const operation = changes[key];
|
|
@@ -239,7 +243,7 @@ export class Encoder<T extends Schema = any> {
|
|
|
239
243
|
// (to allow re-using StateView's for multiple clients)
|
|
240
244
|
//
|
|
241
245
|
// clear "view" changes after encoding
|
|
242
|
-
view.changes
|
|
246
|
+
view.changes.clear();
|
|
243
247
|
|
|
244
248
|
// try to encode "filtered" changes
|
|
245
249
|
this.encode(it, view, bytes, "filteredChanges", false, viewOffset);
|
|
@@ -250,26 +254,6 @@ export class Encoder<T extends Schema = any> {
|
|
|
250
254
|
]);
|
|
251
255
|
}
|
|
252
256
|
|
|
253
|
-
onEndEncode(changeTrees = this.root.changes) {
|
|
254
|
-
// changeTrees.forEach(function(changeTree) {
|
|
255
|
-
// changeTree.endEncode();
|
|
256
|
-
// });
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
// for (const refId in changeTrees) {
|
|
260
|
-
// const changeTree = this.root.changeTrees[refId];
|
|
261
|
-
// changeTree.endEncode();
|
|
262
|
-
|
|
263
|
-
// // changeTree.changes.clear();
|
|
264
|
-
|
|
265
|
-
// // // ArraySchema and MapSchema have a custom "encode end" method
|
|
266
|
-
// // changeTree.ref[$onEncodeEnd]?.();
|
|
267
|
-
|
|
268
|
-
// // // Not a new instance anymore
|
|
269
|
-
// // delete changeTree[$isNew];
|
|
270
|
-
// }
|
|
271
|
-
}
|
|
272
|
-
|
|
273
257
|
discardChanges() {
|
|
274
258
|
// discard shared changes
|
|
275
259
|
let length = this.root.changes.length;
|
package/src/encoder/Root.ts
CHANGED
package/src/encoder/StateView.ts
CHANGED
|
@@ -25,7 +25,8 @@ export class StateView {
|
|
|
25
25
|
* Manual "ADD" operations for changes per ChangeTree, specific to this view.
|
|
26
26
|
* (This is used to force encoding a property, even if it was not changed)
|
|
27
27
|
*/
|
|
28
|
-
|
|
28
|
+
// TODO: use map here!? may fix encode ordering issue
|
|
29
|
+
changes = new Map<number, IndexedOperations>();
|
|
29
30
|
|
|
30
31
|
// TODO: allow to set multiple tags at once
|
|
31
32
|
add(obj: Ref, tag: number = DEFAULT_VIEW_TAG, checkIncludeParent: boolean = true) {
|
|
@@ -43,17 +44,17 @@ export class StateView {
|
|
|
43
44
|
// - if it was invisible to this view
|
|
44
45
|
// - if it were previously filtered out
|
|
45
46
|
if (checkIncludeParent && changeTree.parent) {
|
|
46
|
-
this.
|
|
47
|
+
this.addParentOf(changeTree, tag);
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
//
|
|
50
51
|
// TODO: when adding an item of a MapSchema, the changes may not
|
|
51
52
|
// be set (only the parent's changes are set)
|
|
52
53
|
//
|
|
53
|
-
let changes = this.changes
|
|
54
|
+
let changes = this.changes.get(changeTree.refId);
|
|
54
55
|
if (changes === undefined) {
|
|
55
56
|
changes = {};
|
|
56
|
-
this.changes
|
|
57
|
+
this.changes.set(changeTree.refId, changes);
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
// set tag
|
|
@@ -118,28 +119,34 @@ export class StateView {
|
|
|
118
119
|
return this;
|
|
119
120
|
}
|
|
120
121
|
|
|
121
|
-
protected
|
|
122
|
+
protected addParentOf(childChangeTree: ChangeTree, tag: number) {
|
|
123
|
+
const changeTree = childChangeTree.parent[$changes];
|
|
124
|
+
const parentIndex = childChangeTree.parentIndex;
|
|
125
|
+
|
|
122
126
|
// view must have all "changeTree" parent tree
|
|
123
127
|
this.items.add(changeTree);
|
|
124
128
|
|
|
125
129
|
// add parent's parent
|
|
126
130
|
const parentChangeTree: ChangeTree = changeTree.parent?.[$changes];
|
|
127
131
|
if (parentChangeTree && (parentChangeTree.filteredChanges !== undefined)) {
|
|
128
|
-
this.
|
|
132
|
+
this.addParentOf(changeTree, tag);
|
|
129
133
|
}
|
|
130
134
|
|
|
131
|
-
|
|
132
|
-
|
|
135
|
+
if (
|
|
136
|
+
// parent is already available, no need to add it!
|
|
137
|
+
!this.invisible.has(changeTree) &&
|
|
138
|
+
// item is being replaced, no need to add parent
|
|
139
|
+
changeTree.indexedOperations[parentIndex] !== OPERATION.DELETE_AND_ADD
|
|
140
|
+
) {
|
|
133
141
|
return;
|
|
134
142
|
}
|
|
135
143
|
|
|
136
144
|
// add parent's tag properties
|
|
137
145
|
if (changeTree.getChange(parentIndex) !== OPERATION.DELETE) {
|
|
138
|
-
|
|
139
|
-
let changes = this.changes[changeTree.refId];
|
|
146
|
+
let changes = this.changes.get(changeTree.refId);
|
|
140
147
|
if (changes === undefined) {
|
|
141
148
|
changes = {};
|
|
142
|
-
this.changes
|
|
149
|
+
this.changes.set(changeTree.refId, changes);
|
|
143
150
|
}
|
|
144
151
|
|
|
145
152
|
if (!this.tags) {
|
|
@@ -171,10 +178,10 @@ export class StateView {
|
|
|
171
178
|
const ref = changeTree.ref;
|
|
172
179
|
const metadata: Metadata = ref.constructor[Symbol.metadata];
|
|
173
180
|
|
|
174
|
-
let changes = this.changes
|
|
181
|
+
let changes = this.changes.get(changeTree.refId);
|
|
175
182
|
if (changes === undefined) {
|
|
176
183
|
changes = {};
|
|
177
|
-
this.changes
|
|
184
|
+
this.changes.set(changeTree.refId, changes);
|
|
178
185
|
}
|
|
179
186
|
|
|
180
187
|
if (tag === DEFAULT_VIEW_TAG) {
|
|
@@ -182,10 +189,10 @@ export class StateView {
|
|
|
182
189
|
const parent = changeTree.parent;
|
|
183
190
|
if (!Metadata.isValidInstance(parent)) {
|
|
184
191
|
const parentChangeTree = parent[$changes];
|
|
185
|
-
let changes = this.changes
|
|
192
|
+
let changes = this.changes.get(parentChangeTree.refId);
|
|
186
193
|
if (changes === undefined) {
|
|
187
194
|
changes = {};
|
|
188
|
-
this.changes
|
|
195
|
+
this.changes.set(parentChangeTree.refId, changes);
|
|
189
196
|
}
|
|
190
197
|
// DELETE / DELETE BY REF ID
|
|
191
198
|
changes[changeTree.parentIndex] = OPERATION.DELETE;
|
|
@@ -92,7 +92,8 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
|
|
|
92
92
|
if (setValue[$changes]) {
|
|
93
93
|
assertInstanceType(setValue, obj[$childType] as typeof Schema, obj, key);
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
const previousValue = obj.items[key as unknown as number];
|
|
96
|
+
if (previousValue !== undefined) {
|
|
96
97
|
if (setValue[$changes].isNew) {
|
|
97
98
|
this[$changes].indexedOperation(Number(key), OPERATION.MOVE_AND_ADD);
|
|
98
99
|
|
|
@@ -103,10 +104,16 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
|
|
|
103
104
|
this[$changes].indexedOperation(Number(key), OPERATION.MOVE);
|
|
104
105
|
}
|
|
105
106
|
}
|
|
107
|
+
|
|
108
|
+
// remove root reference from previous value
|
|
109
|
+
previousValue[$changes].root?.remove(previousValue[$changes]);
|
|
110
|
+
|
|
106
111
|
} else if (setValue[$changes].isNew) {
|
|
107
112
|
this[$changes].indexedOperation(Number(key), OPERATION.ADD);
|
|
108
113
|
}
|
|
109
114
|
|
|
115
|
+
setValue[$changes].setParent(this, obj[$changes].root, key);
|
|
116
|
+
|
|
110
117
|
} else {
|
|
111
118
|
obj.$changeAt(Number(key), setValue);
|
|
112
119
|
}
|
|
@@ -86,41 +86,38 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
|
|
|
86
86
|
key = key.toString() as K;
|
|
87
87
|
|
|
88
88
|
const changeTree = this[$changes];
|
|
89
|
+
const isRef = (value[$changes]) !== undefined;
|
|
89
90
|
|
|
90
|
-
|
|
91
|
-
|
|
91
|
+
let index: number;
|
|
92
|
+
let operation: OPERATION;
|
|
92
93
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
// IS REPLACE?
|
|
95
|
+
if (typeof(changeTree.indexes[key]) !== "undefined") {
|
|
96
|
+
index = changeTree.indexes[key];
|
|
97
|
+
operation = OPERATION.REPLACE;
|
|
96
98
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
const previousValue = this.$items.get(key);
|
|
100
|
+
if (previousValue === value) {
|
|
101
|
+
// if value is the same, avoid re-encoding it.
|
|
102
|
+
return;
|
|
100
103
|
|
|
101
|
-
|
|
104
|
+
} else if (isRef) {
|
|
105
|
+
// if is schema, force ADD operation if value differ from previous one.
|
|
106
|
+
operation = OPERATION.DELETE_AND_ADD;
|
|
107
|
+
|
|
108
|
+
// remove reference from previous value
|
|
109
|
+
if (previousValue !== undefined) {
|
|
110
|
+
previousValue[$changes].root?.remove(previousValue[$changes]);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
} else {
|
|
115
|
+
index = changeTree.indexes[$numFields] ?? 0;
|
|
116
|
+
operation = OPERATION.ADD;
|
|
102
117
|
|
|
103
|
-
//
|
|
104
|
-
// (encoding)
|
|
105
|
-
// set a unique id to relate directly with this key/value.
|
|
106
|
-
//
|
|
107
|
-
if (!isReplace) {
|
|
108
118
|
this.$indexes.set(index, key);
|
|
109
119
|
changeTree.indexes[key] = index;
|
|
110
120
|
changeTree.indexes[$numFields] = index + 1;
|
|
111
|
-
|
|
112
|
-
} else if (
|
|
113
|
-
!isRef &&
|
|
114
|
-
this.$items.get(key) === value
|
|
115
|
-
) {
|
|
116
|
-
// if value is the same, avoid re-encoding it.
|
|
117
|
-
return;
|
|
118
|
-
|
|
119
|
-
} else if (
|
|
120
|
-
isRef && // if is schema, force ADD operation if value differ from previous one.
|
|
121
|
-
this.$items.get(key) !== value
|
|
122
|
-
) {
|
|
123
|
-
operation = OPERATION.ADD;
|
|
124
121
|
}
|
|
125
122
|
|
|
126
123
|
this.$items.set(key, value);
|