@colyseus/schema 3.0.42 → 3.0.43
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 +327 -185
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +327 -185
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +327 -185
- package/lib/Schema.d.ts +2 -1
- package/lib/Schema.js +21 -3
- package/lib/Schema.js.map +1 -1
- package/lib/bench_encode.d.ts +1 -0
- package/lib/bench_encode.js +130 -0
- package/lib/bench_encode.js.map +1 -0
- package/lib/debug.d.ts +1 -0
- package/lib/debug.js +51 -0
- package/lib/debug.js.map +1 -0
- package/lib/decoder/Decoder.js +7 -8
- package/lib/decoder/Decoder.js.map +1 -1
- package/lib/encoder/ChangeTree.d.ts +57 -7
- package/lib/encoder/ChangeTree.js +171 -106
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/Encoder.js +19 -20
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/Root.d.ts +8 -7
- package/lib/encoder/Root.js +81 -26
- package/lib/encoder/Root.js.map +1 -1
- package/lib/types/custom/ArraySchema.js +5 -3
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/custom/MapSchema.js +7 -2
- package/lib/types/custom/MapSchema.js.map +1 -1
- package/lib/types/symbols.d.ts +14 -14
- package/lib/types/symbols.js +14 -14
- package/lib/types/symbols.js.map +1 -1
- package/lib/utils.js +7 -3
- package/lib/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/Schema.ts +21 -5
- package/src/bench_encode.ts +108 -0
- package/src/debug.ts +55 -0
- package/src/decoder/Decoder.ts +8 -12
- package/src/encoder/ChangeTree.ts +201 -115
- package/src/encoder/Encoder.ts +21 -19
- package/src/encoder/Root.ts +87 -28
- package/src/types/custom/ArraySchema.ts +6 -4
- package/src/types/custom/MapSchema.ts +8 -2
- package/src/types/symbols.ts +14 -14
- package/src/utils.ts +9 -3
package/src/encoder/Encoder.ts
CHANGED
|
@@ -10,7 +10,8 @@ import { Root } from "./Root";
|
|
|
10
10
|
|
|
11
11
|
import type { StateView } from "./StateView";
|
|
12
12
|
import type { Metadata } from "../Metadata";
|
|
13
|
-
import type { ChangeSetName, ChangeTree } from "./ChangeTree";
|
|
13
|
+
import type { ChangeSetName, ChangeTree, ChangeTreeList, ChangeTreeNode } from "./ChangeTree";
|
|
14
|
+
import { createChangeTreeList } from "./ChangeTree";
|
|
14
15
|
|
|
15
16
|
export class Encoder<T extends Schema = any> {
|
|
16
17
|
static BUFFER_SIZE = (typeof(Buffer) !== "undefined") && Buffer.poolSize || 8 * 1024; // 8KB
|
|
@@ -54,11 +55,11 @@ export class Encoder<T extends Schema = any> {
|
|
|
54
55
|
): Buffer {
|
|
55
56
|
const hasView = (view !== undefined);
|
|
56
57
|
const rootChangeTree = this.state[$changes];
|
|
57
|
-
const changeTrees = this.root[changeSetName];
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
let current: ChangeTreeList | ChangeTreeNode = this.root[changeSetName];
|
|
60
|
+
|
|
61
|
+
while (current = current.next) {
|
|
62
|
+
const changeTree = current.changeTree;
|
|
62
63
|
|
|
63
64
|
if (hasView) {
|
|
64
65
|
if (!view.isChangeTreeVisible(changeTree)) {
|
|
@@ -166,7 +167,9 @@ export class Encoder<T extends Schema = any> {
|
|
|
166
167
|
? this.root[field]
|
|
167
168
|
: field;
|
|
168
169
|
|
|
169
|
-
rootChangeSet.
|
|
170
|
+
let current = rootChangeSet.next;
|
|
171
|
+
while (current) {
|
|
172
|
+
const changeTree = current.changeTree;
|
|
170
173
|
const changeSet = changeTree[field];
|
|
171
174
|
|
|
172
175
|
const metadata: Metadata = changeTree.ref.constructor[Symbol.metadata];
|
|
@@ -179,7 +182,8 @@ export class Encoder<T extends Schema = any> {
|
|
|
179
182
|
op: OPERATION[op],
|
|
180
183
|
});
|
|
181
184
|
}
|
|
182
|
-
|
|
185
|
+
current = current.next;
|
|
186
|
+
}
|
|
183
187
|
}
|
|
184
188
|
|
|
185
189
|
encodeView(view: StateView, sharedOffset: number, it: Iterator, bytes = this.sharedBuffer) {
|
|
@@ -242,22 +246,20 @@ export class Encoder<T extends Schema = any> {
|
|
|
242
246
|
|
|
243
247
|
discardChanges() {
|
|
244
248
|
// discard shared changes
|
|
245
|
-
let
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
250
|
-
this.root.changes.length = 0;
|
|
249
|
+
let current = this.root.changes.next;
|
|
250
|
+
while (current) {
|
|
251
|
+
current.changeTree.endEncode('changes');
|
|
252
|
+
current = current.next;
|
|
251
253
|
}
|
|
254
|
+
this.root.changes = createChangeTreeList();
|
|
252
255
|
|
|
253
256
|
// discard filtered changes
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
259
|
-
this.root.filteredChanges.length = 0;
|
|
257
|
+
current = this.root.filteredChanges.next;
|
|
258
|
+
while (current) {
|
|
259
|
+
current.changeTree.endEncode('filteredChanges');
|
|
260
|
+
current = current.next;
|
|
260
261
|
}
|
|
262
|
+
this.root.filteredChanges = createChangeTreeList();
|
|
261
263
|
}
|
|
262
264
|
|
|
263
265
|
tryEncodeTypeId (bytes: Buffer, baseType: typeof Schema, targetType: typeof Schema, it: Iterator) {
|
package/src/encoder/Root.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { OPERATION } from "../encoding/spec";
|
|
2
2
|
import { TypeContext } from "../types/TypeContext";
|
|
3
|
-
import {
|
|
4
|
-
import { ChangeTree, enqueueChangeTree, setOperationAtIndex } from "./ChangeTree";
|
|
3
|
+
import { ChangeTree, setOperationAtIndex, ChangeTreeList, createChangeTreeList, ChangeSetName } from "./ChangeTree";
|
|
5
4
|
|
|
6
5
|
export class Root {
|
|
7
6
|
protected nextUniqueId: number = 0;
|
|
@@ -10,12 +9,12 @@ export class Root {
|
|
|
10
9
|
changeTrees: {[refId: number]: ChangeTree} = {};
|
|
11
10
|
|
|
12
11
|
// all changes
|
|
13
|
-
allChanges:
|
|
14
|
-
allFilteredChanges:
|
|
12
|
+
allChanges: ChangeTreeList = createChangeTreeList();
|
|
13
|
+
allFilteredChanges: ChangeTreeList = createChangeTreeList();// TODO: do not initialize it if filters are not used
|
|
15
14
|
|
|
16
15
|
// pending changes to be encoded
|
|
17
|
-
changes:
|
|
18
|
-
filteredChanges:
|
|
16
|
+
changes: ChangeTreeList = createChangeTreeList();
|
|
17
|
+
filteredChanges: ChangeTreeList = createChangeTreeList();// TODO: do not initialize it if filters are not used
|
|
19
18
|
|
|
20
19
|
constructor(public types: TypeContext) { }
|
|
21
20
|
|
|
@@ -24,8 +23,10 @@ export class Root {
|
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
add(changeTree: ChangeTree) {
|
|
27
|
-
//
|
|
28
|
-
changeTree.
|
|
26
|
+
// Assign unique `refId` to changeTree if it doesn't have one yet.
|
|
27
|
+
if (changeTree.refId === undefined) {
|
|
28
|
+
changeTree.refId = this.getNextUniqueId();
|
|
29
|
+
}
|
|
29
30
|
|
|
30
31
|
const isNewChangeTree = (this.changeTrees[changeTree.refId] === undefined);
|
|
31
32
|
if (isNewChangeTree) { this.changeTrees[changeTree.refId] = changeTree; }
|
|
@@ -53,6 +54,7 @@ export class Root {
|
|
|
53
54
|
const refCount = (this.refCount[changeTree.refId]) - 1;
|
|
54
55
|
|
|
55
56
|
if (refCount <= 0) {
|
|
57
|
+
|
|
56
58
|
//
|
|
57
59
|
// Only remove "root" reference if it's the last reference
|
|
58
60
|
//
|
|
@@ -69,7 +71,20 @@ export class Root {
|
|
|
69
71
|
|
|
70
72
|
this.refCount[changeTree.refId] = 0;
|
|
71
73
|
|
|
72
|
-
changeTree.forEachChild((child, _) =>
|
|
74
|
+
changeTree.forEachChild((child, _) => {
|
|
75
|
+
if (child.removeParent(changeTree.ref)) {
|
|
76
|
+
if ((
|
|
77
|
+
child.parentChain === undefined || // no parent, remove it
|
|
78
|
+
(child.parentChain && this.refCount[child.refId] > 1) // parent is still in use, but has more than one reference, remove it
|
|
79
|
+
)) {
|
|
80
|
+
this.remove(child);
|
|
81
|
+
|
|
82
|
+
} else if (child.parentChain) {
|
|
83
|
+
// re-assigning a child of the same root, move it to the end
|
|
84
|
+
this.moveToEndOfChanges(child);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
73
88
|
|
|
74
89
|
} else {
|
|
75
90
|
this.refCount[changeTree.refId] = refCount;
|
|
@@ -83,35 +98,79 @@ export class Root {
|
|
|
83
98
|
// containing instance is not available, the Decoder will throw
|
|
84
99
|
// "refId not found" error.
|
|
85
100
|
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
enqueueChangeTree(this, changeTree, "filteredChanges");
|
|
89
|
-
} else {
|
|
90
|
-
this.removeChangeFromChangeSet("changes", changeTree);
|
|
91
|
-
enqueueChangeTree(this, changeTree, "changes");
|
|
92
|
-
}
|
|
101
|
+
this.moveToEndOfChanges(changeTree);
|
|
102
|
+
changeTree.forEachChild((child, _) => this.moveToEndOfChanges(child));
|
|
93
103
|
}
|
|
94
104
|
|
|
95
105
|
return refCount;
|
|
96
106
|
}
|
|
97
107
|
|
|
98
|
-
|
|
108
|
+
moveToEndOfChanges(changeTree: ChangeTree) {
|
|
109
|
+
if (changeTree.filteredChanges) {
|
|
110
|
+
this.moveToEndOfChangeTreeList("filteredChanges", changeTree);
|
|
111
|
+
this.moveToEndOfChangeTreeList("allFilteredChanges", changeTree);
|
|
112
|
+
} else {
|
|
113
|
+
this.moveToEndOfChangeTreeList("changes", changeTree);
|
|
114
|
+
this.moveToEndOfChangeTreeList("allChanges", changeTree);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
moveToEndOfChangeTreeList(changeSetName: ChangeSetName, changeTree: ChangeTree): void {
|
|
99
119
|
const changeSet = this[changeSetName];
|
|
100
|
-
const
|
|
120
|
+
const node = changeTree[changeSetName].queueRootNode;
|
|
121
|
+
if (!node || node === changeSet.tail) return;
|
|
101
122
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
123
|
+
// Remove from current position
|
|
124
|
+
if (node.prev) {
|
|
125
|
+
node.prev.next = node.next;
|
|
126
|
+
} else {
|
|
127
|
+
changeSet.next = node.next;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (node.next) {
|
|
131
|
+
node.next.prev = node.prev;
|
|
132
|
+
} else {
|
|
133
|
+
changeSet.tail = node.prev;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Add to end
|
|
137
|
+
node.prev = changeSet.tail;
|
|
138
|
+
node.next = undefined;
|
|
139
|
+
|
|
140
|
+
if (changeSet.tail) {
|
|
141
|
+
changeSet.tail.next = node;
|
|
142
|
+
} else {
|
|
143
|
+
changeSet.next = node;
|
|
106
144
|
}
|
|
107
145
|
|
|
108
|
-
|
|
109
|
-
// changeTree[changeSetName].queueRootIndex = -1;
|
|
110
|
-
// return true;
|
|
111
|
-
// }
|
|
146
|
+
changeSet.tail = node;
|
|
112
147
|
}
|
|
113
148
|
|
|
114
|
-
|
|
115
|
-
|
|
149
|
+
protected removeChangeFromChangeSet(changeSetName: ChangeSetName, changeTree: ChangeTree) {
|
|
150
|
+
const changeSet = this[changeSetName];
|
|
151
|
+
const node = changeTree[changeSetName].queueRootNode;
|
|
152
|
+
|
|
153
|
+
if (node && node.changeTree === changeTree) {
|
|
154
|
+
// Remove the node from the linked list
|
|
155
|
+
if (node.prev) {
|
|
156
|
+
node.prev.next = node.next;
|
|
157
|
+
} else {
|
|
158
|
+
changeSet.next = node.next;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (node.next) {
|
|
162
|
+
node.next.prev = node.prev;
|
|
163
|
+
} else {
|
|
164
|
+
changeSet.tail = node.prev;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
changeSet.length--;
|
|
168
|
+
|
|
169
|
+
// Clear ChangeTree reference
|
|
170
|
+
changeTree[changeSetName].queueRootNode = undefined;
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return false;
|
|
116
175
|
}
|
|
117
176
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { $changes, $childType, $decoder, $deleteByIndex, $onEncodeEnd, $encoder, $filter, $getByIndex, $onDecodeEnd } from "../symbols";
|
|
2
2
|
import type { Schema } from "../../Schema";
|
|
3
|
-
import { ChangeTree,
|
|
3
|
+
import { ChangeTree, enqueueChangeTree, setOperationAtIndex } from "../../encoder/ChangeTree";
|
|
4
4
|
import { OPERATION } from "../../encoding/spec";
|
|
5
5
|
import { registerType } from "../registry";
|
|
6
6
|
import { Collection } from "../HelperTypes";
|
|
@@ -156,8 +156,11 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
|
|
|
156
156
|
}
|
|
157
157
|
});
|
|
158
158
|
|
|
159
|
-
this
|
|
160
|
-
|
|
159
|
+
Object.defineProperty(this, $changes, {
|
|
160
|
+
value: new ChangeTree(proxy),
|
|
161
|
+
enumerable: false,
|
|
162
|
+
writable: true,
|
|
163
|
+
});
|
|
161
164
|
|
|
162
165
|
if (items.length > 0) {
|
|
163
166
|
this.push(...items);
|
|
@@ -351,7 +354,6 @@ export class ArraySchema<V = any> implements Array<V>, Collection<number, V> {
|
|
|
351
354
|
shift(): V | undefined {
|
|
352
355
|
if (this.items.length === 0) { return undefined; }
|
|
353
356
|
|
|
354
|
-
// const index = Number(Object.keys(changeTree.indexes)[0]);
|
|
355
357
|
const changeTree = this[$changes];
|
|
356
358
|
|
|
357
359
|
const index = this.tmpItems.findIndex(item => item === this.items[0]);
|
|
@@ -43,8 +43,14 @@ export class MapSchema<V=any, K extends string = string> implements Map<K, V>, C
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
constructor (initialValues?: Map<K, V> | Record<K, V>) {
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
const changeTree = new ChangeTree(this);
|
|
47
|
+
changeTree.indexes = {};
|
|
48
|
+
|
|
49
|
+
Object.defineProperty(this, $changes, {
|
|
50
|
+
value: changeTree,
|
|
51
|
+
enumerable: false,
|
|
52
|
+
writable: true,
|
|
53
|
+
});
|
|
48
54
|
|
|
49
55
|
if (initialValues) {
|
|
50
56
|
if (
|
package/src/types/symbols.ts
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
export const $track =
|
|
2
|
-
export const $encoder =
|
|
3
|
-
export const $decoder =
|
|
1
|
+
export const $track = "~track";
|
|
2
|
+
export const $encoder = "~encoder";
|
|
3
|
+
export const $decoder = "~decoder";
|
|
4
4
|
|
|
5
|
-
export const $filter =
|
|
5
|
+
export const $filter = "~filter";
|
|
6
6
|
|
|
7
|
-
export const $getByIndex =
|
|
8
|
-
export const $deleteByIndex =
|
|
7
|
+
export const $getByIndex = "~getByIndex";
|
|
8
|
+
export const $deleteByIndex = "~deleteByIndex";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Used to hold ChangeTree instances whitin the structures
|
|
12
12
|
*/
|
|
13
|
-
export const $changes =
|
|
13
|
+
export const $changes = '~changes';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Used to keep track of the type of the child elements of a collection
|
|
17
17
|
* (MapSchema, ArraySchema, etc.)
|
|
18
18
|
*/
|
|
19
|
-
export const $childType =
|
|
19
|
+
export const $childType = '~childType';
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Optional "discard" method for custom types (ArraySchema)
|
|
23
23
|
* (Discards changes for next serialization)
|
|
24
24
|
*/
|
|
25
|
-
export const $onEncodeEnd =
|
|
25
|
+
export const $onEncodeEnd = '~onEncodeEnd';
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* When decoding, this method is called after the instance is fully decoded
|
|
29
29
|
*/
|
|
30
|
-
export const $onDecodeEnd =
|
|
30
|
+
export const $onDecodeEnd = "~onDecodeEnd";
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Metadata
|
|
34
34
|
*/
|
|
35
|
-
export const $descriptors =
|
|
36
|
-
export const $numFields = "
|
|
37
|
-
export const $refTypeFieldIndexes = "
|
|
38
|
-
export const $viewFieldIndexes = "
|
|
35
|
+
export const $descriptors = "~descriptors";
|
|
36
|
+
export const $numFields = "~__numFields";
|
|
37
|
+
export const $refTypeFieldIndexes = "~__refTypeFieldIndexes";
|
|
38
|
+
export const $viewFieldIndexes = "~__viewFieldIndexes";
|
|
39
39
|
export const $fieldIndexesByViewTag = "$__fieldIndexesByViewTag";
|
package/src/utils.ts
CHANGED
|
@@ -28,9 +28,14 @@ export function dumpChanges(schema: Schema) {
|
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
// for (const refId in $root.changes) {
|
|
31
|
-
$root.changes.
|
|
31
|
+
let current = $root.changes.next;
|
|
32
|
+
while (current) {
|
|
33
|
+
const changeTree = current.changeTree;
|
|
32
34
|
// skip if ChangeTree is undefined
|
|
33
|
-
if (changeTree === undefined) {
|
|
35
|
+
if (changeTree === undefined) {
|
|
36
|
+
current = current.next;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
34
39
|
|
|
35
40
|
const changes = changeTree.indexedOperations;
|
|
36
41
|
|
|
@@ -41,7 +46,8 @@ export function dumpChanges(schema: Schema) {
|
|
|
41
46
|
if (!dump.ops[opName]) { dump.ops[opName] = 0; }
|
|
42
47
|
dump.ops[OPERATION[op]]++;
|
|
43
48
|
}
|
|
44
|
-
|
|
49
|
+
current = current.next;
|
|
50
|
+
}
|
|
45
51
|
|
|
46
52
|
return dump;
|
|
47
53
|
}
|