@colyseus/schema 3.0.0-alpha.15 → 3.0.0-alpha.16
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 +40 -23
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +40 -23
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +40 -23
- package/lib/bench_encode.d.ts +1 -0
- package/lib/bench_encode.js +93 -0
- package/lib/bench_encode.js.map +1 -0
- package/lib/decoder/DecodeOperation.js +18 -3
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/strategy/StateCallbacks.js +10 -10
- package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
- package/lib/encoder/EncodeOperation.js +14 -10
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoding/spec.d.ts +2 -1
- package/lib/encoding/spec.js +1 -0
- package/lib/encoding/spec.js.map +1 -1
- package/package.json +2 -2
- package/src/bench_encode.ts +66 -0
- package/src/decoder/DecodeOperation.ts +23 -3
- package/src/decoder/strategy/StateCallbacks.ts +11 -11
- package/src/encoder/EncodeOperation.ts +16 -12
- package/src/encoding/spec.ts +1 -0
package/lib/encoding/spec.d.ts
CHANGED
package/lib/encoding/spec.js
CHANGED
|
@@ -26,5 +26,6 @@ var OPERATION;
|
|
|
26
26
|
OPERATION[OPERATION["REVERSE"] = 15] = "REVERSE";
|
|
27
27
|
OPERATION[OPERATION["MOVE"] = 32] = "MOVE";
|
|
28
28
|
OPERATION[OPERATION["DELETE_BY_REFID"] = 33] = "DELETE_BY_REFID";
|
|
29
|
+
OPERATION[OPERATION["ADD_BY_REFID"] = 129] = "ADD_BY_REFID";
|
|
29
30
|
})(OPERATION || (exports.OPERATION = OPERATION = {}));
|
|
30
31
|
//# sourceMappingURL=spec.js.map
|
package/lib/encoding/spec.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec.js","sourceRoot":"","sources":["../../src/encoding/spec.ts"],"names":[],"mappings":";;;AAAa,QAAA,mBAAmB,GAAG,GAAG,CAAC,CAAC,4DAA4D;AACvF,QAAA,OAAO,GAAG,GAAG,CAAC;AAE3B;;GAEG;AACH,IAAY,
|
|
1
|
+
{"version":3,"file":"spec.js","sourceRoot":"","sources":["../../src/encoding/spec.ts"],"names":[],"mappings":";;;AAAa,QAAA,mBAAmB,GAAG,GAAG,CAAC,CAAC,4DAA4D;AACvF,QAAA,OAAO,GAAG,GAAG,CAAC;AAE3B;;GAEG;AACH,IAAY,SAuBX;AAvBD,WAAY,SAAS;IACjB,yCAAS,CAAA;IACT,+CAAW,CAAA;IACX,8CAAW,CAAA;IACX,gEAAoB,CAAA;IACpB,2DAAkB,CAAA;IAClB,+DAAoB,CAAA;IAEpB;;OAEG;IACH,4CAAU,CAAA;IAEV;;OAEG;IACH,0CAAS,CAAA;IACT,gDAAY,CAAA;IACZ,gDAAY,CAAA;IACZ,0CAAS,CAAA;IACT,gEAAoB,CAAA;IACpB,2DAAkB,CAAA;AAEtB,CAAC,EAvBW,SAAS,yBAAT,SAAS,QAuBpB","sourcesContent":["export const SWITCH_TO_STRUCTURE = 255; // (decoding collides with DELETE_AND_ADD + fieldIndex = 63)\nexport const TYPE_ID = 213;\n\n/**\n * Encoding Schema field operations.\n */\nexport enum OPERATION {\n ADD = 128, // (10000000) add new structure/primitive\n REPLACE = 0, // (00000001) replace structure/primitive\n DELETE = 64, // (01000000) delete field\n DELETE_AND_MOVE = 96, // () add new structure/primitive\n MOVE_AND_ADD = 160, // () add new structure/primitive\n DELETE_AND_ADD = 192, // (11000000) DELETE field, followed by an ADD\n\n /**\n * Collection operations\n */\n CLEAR = 10,\n\n /**\n * ArraySchema operations\n */\n PUSH = 11,\n UNSHIFT = 12,\n REVERSE = 15,\n MOVE = 32,\n DELETE_BY_REFID = 33, // This operation is only used at ENCODING time. During DECODING, DELETE_BY_REFID is converted to DELETE\n ADD_BY_REFID = 129,\n\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colyseus/schema",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.16",
|
|
4
4
|
"description": "Binary state serializer with delta encoding for games",
|
|
5
5
|
"bin": {
|
|
6
6
|
"schema-codegen": "./bin/schema-codegen"
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"source-map-support": "^0.5.13",
|
|
79
79
|
"ts-node": "^10.9.2",
|
|
80
80
|
"tslib": "^2.1.0",
|
|
81
|
-
"tsx": "^4.7
|
|
81
|
+
"tsx": "^4.15.7",
|
|
82
82
|
"typescript": "^5.3.3"
|
|
83
83
|
},
|
|
84
84
|
"nyc": {
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { nanoid } from "nanoid";
|
|
2
|
+
import { Schema, type, MapSchema, ArraySchema, Encoder } from ".";
|
|
3
|
+
import * as benchmark from "benchmark";
|
|
4
|
+
|
|
5
|
+
const suite = new benchmark.Suite();
|
|
6
|
+
|
|
7
|
+
class AttributeNew extends Schema {
|
|
8
|
+
@type("string") name: string;
|
|
9
|
+
@type("number") value: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
class ItemNew extends Schema {
|
|
13
|
+
@type("number") price: number;
|
|
14
|
+
@type([ AttributeNew ]) attributes = new ArraySchema<AttributeNew>();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class PositionNew extends Schema {
|
|
18
|
+
@type("number") x: number;
|
|
19
|
+
@type("number") y: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class PlayerNew extends Schema {
|
|
23
|
+
@type(PositionNew) position = new PositionNew();
|
|
24
|
+
@type({ map: ItemNew }) items = new MapSchema<ItemNew>();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class StateNew extends Schema {
|
|
28
|
+
@type({ map: PlayerNew }) players = new MapSchema<PlayerNew>();
|
|
29
|
+
@type("string") currentTurn;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const state = new StateNew();
|
|
33
|
+
|
|
34
|
+
for (let i = 0; i < 50; i++) {
|
|
35
|
+
const player = new PlayerNew();
|
|
36
|
+
state.players.set(`p-${nanoid()}`, player);
|
|
37
|
+
|
|
38
|
+
player.position.x = (i + 1) * 100;
|
|
39
|
+
player.position.y = (i + 1) * 100;
|
|
40
|
+
for (let j = 0; j < 10; j++) {
|
|
41
|
+
const item = new ItemNew();
|
|
42
|
+
item.price = (i + 1) * 50;
|
|
43
|
+
for (let k = 0; k < 5; k++) {
|
|
44
|
+
const attr = new AttributeNew();
|
|
45
|
+
attr.name = `Attribute ${k}`;
|
|
46
|
+
attr.value = k;
|
|
47
|
+
item.attributes.push(attr);
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
player.items.set(`item-${j}`, item);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
Encoder.BUFFER_SIZE = 1024 * 128;
|
|
56
|
+
const encoder = new Encoder(state);
|
|
57
|
+
|
|
58
|
+
// measure time to .encodeAll()
|
|
59
|
+
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
for (let i = 0; i < 1000; i++) {
|
|
62
|
+
encoder.encodeAll();
|
|
63
|
+
}
|
|
64
|
+
console.log(Date.now() - now);
|
|
65
|
+
|
|
66
|
+
console.log(Array.from(encoder.encodeAll()).join(","));
|
|
@@ -251,6 +251,7 @@ export const decodeKeyValueOperation: DecodeOperation = function (
|
|
|
251
251
|
dynamicIndex = ref['getIndex'](index);
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
+
|
|
254
255
|
const { value, previousValue } = decodeValue(
|
|
255
256
|
decoder,
|
|
256
257
|
operation,
|
|
@@ -303,7 +304,10 @@ export const decodeArray: DecodeOperation = function (
|
|
|
303
304
|
allChanges: DataChange[]
|
|
304
305
|
) {
|
|
305
306
|
// "uncompressed" index + operation (array/map items)
|
|
306
|
-
|
|
307
|
+
let operation = bytes[it.offset++];
|
|
308
|
+
|
|
309
|
+
let isSchemaChild: boolean;
|
|
310
|
+
let index: number;
|
|
307
311
|
|
|
308
312
|
if (operation === OPERATION.CLEAR) {
|
|
309
313
|
//
|
|
@@ -319,7 +323,7 @@ export const decodeArray: DecodeOperation = function (
|
|
|
319
323
|
// TODO: refactor here, try to follow same flow as below
|
|
320
324
|
const refId = decode.number(bytes, it);
|
|
321
325
|
const previousValue = decoder.root.refs.get(refId);
|
|
322
|
-
|
|
326
|
+
index = ref.findIndex((value) => value === previousValue);
|
|
323
327
|
ref[$deleteByIndex](index);
|
|
324
328
|
allChanges.push({
|
|
325
329
|
ref,
|
|
@@ -330,10 +334,26 @@ export const decodeArray: DecodeOperation = function (
|
|
|
330
334
|
value: undefined,
|
|
331
335
|
previousValue,
|
|
332
336
|
});
|
|
337
|
+
|
|
333
338
|
return;
|
|
339
|
+
|
|
340
|
+
} else if (operation === OPERATION.ADD_BY_REFID) {
|
|
341
|
+
isSchemaChild = true;
|
|
342
|
+
// operation = OPERATION.ADD;
|
|
343
|
+
|
|
344
|
+
const refId = decode.number(bytes, it);
|
|
345
|
+
const itemByRefId = decoder.root.refs.get(refId);
|
|
346
|
+
|
|
347
|
+
// use existing index, or push new value
|
|
348
|
+
index = (itemByRefId)
|
|
349
|
+
? ref.findIndex((value) => value === itemByRefId)
|
|
350
|
+
: ref.length;
|
|
351
|
+
|
|
352
|
+
} else {
|
|
353
|
+
isSchemaChild = false;
|
|
354
|
+
index = decode.number(bytes, it);
|
|
334
355
|
}
|
|
335
356
|
|
|
336
|
-
const index = decode.number(bytes, it);
|
|
337
357
|
const type = ref[$childType];
|
|
338
358
|
|
|
339
359
|
let dynamicIndex: number | string = index;
|
|
@@ -155,17 +155,7 @@ export function getStateCallbacks<T extends Schema>(decoder: Decoder<T>): GetCal
|
|
|
155
155
|
// Handle collection of items
|
|
156
156
|
//
|
|
157
157
|
|
|
158
|
-
if (change.op
|
|
159
|
-
// triger onAdd
|
|
160
|
-
|
|
161
|
-
isTriggeringOnAdd = true;
|
|
162
|
-
const addCallbacks = $callbacks[OPERATION.ADD];
|
|
163
|
-
for (let i = addCallbacks?.length - 1; i >= 0; i--) {
|
|
164
|
-
addCallbacks[i](change.value, change.dynamicIndex ?? change.field);
|
|
165
|
-
}
|
|
166
|
-
isTriggeringOnAdd = false;
|
|
167
|
-
|
|
168
|
-
} else if ((change.op & OPERATION.DELETE) === OPERATION.DELETE) {
|
|
158
|
+
if ((change.op & OPERATION.DELETE) === OPERATION.DELETE) {
|
|
169
159
|
//
|
|
170
160
|
// FIXME: `previousValue` should always be available.
|
|
171
161
|
//
|
|
@@ -185,6 +175,16 @@ export function getStateCallbacks<T extends Schema>(decoder: Decoder<T>): GetCal
|
|
|
185
175
|
addCallbacks[i](change.value, change.dynamicIndex ?? change.field);
|
|
186
176
|
}
|
|
187
177
|
}
|
|
178
|
+
|
|
179
|
+
} else if ((change.op & OPERATION.ADD) === OPERATION.ADD && change.previousValue === undefined) {
|
|
180
|
+
// triger onAdd
|
|
181
|
+
|
|
182
|
+
isTriggeringOnAdd = true;
|
|
183
|
+
const addCallbacks = $callbacks[OPERATION.ADD];
|
|
184
|
+
for (let i = addCallbacks?.length - 1; i >= 0; i--) {
|
|
185
|
+
addCallbacks[i](change.value, change.dynamicIndex ?? change.field);
|
|
186
|
+
}
|
|
187
|
+
isTriggeringOnAdd = false;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
// trigger onChange
|
|
@@ -204,18 +204,22 @@ export const encodeArray: EncodeOperation = function (
|
|
|
204
204
|
hasView: boolean,
|
|
205
205
|
) {
|
|
206
206
|
const ref = changeTree.ref;
|
|
207
|
+
const useOperationByRefId = hasView && changeTree.isFiltered && (typeof (changeTree.getType(field)) !== "string");
|
|
207
208
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
209
|
+
let refOrIndex: number;
|
|
210
|
+
|
|
211
|
+
if (useOperationByRefId) {
|
|
212
|
+
refOrIndex = ref['tmpItems'][field][$changes].refId;
|
|
213
|
+
|
|
214
|
+
if (operation === OPERATION.DELETE) {
|
|
215
|
+
operation = OPERATION.DELETE_BY_REFID;
|
|
216
|
+
|
|
217
|
+
} else if (operation === OPERATION.ADD) {
|
|
218
|
+
operation = OPERATION.ADD_BY_REFID;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
} else {
|
|
222
|
+
refOrIndex = field;
|
|
219
223
|
}
|
|
220
224
|
|
|
221
225
|
// encode operation
|
|
@@ -227,7 +231,7 @@ export const encodeArray: EncodeOperation = function (
|
|
|
227
231
|
}
|
|
228
232
|
|
|
229
233
|
// encode index
|
|
230
|
-
encode.number(bytes,
|
|
234
|
+
encode.number(bytes, refOrIndex, it);
|
|
231
235
|
|
|
232
236
|
// Do not encode value for DELETE operations
|
|
233
237
|
if (operation === OPERATION.DELETE) {
|