@colyseus/schema 3.0.0-alpha.2 → 3.0.0-alpha.22
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/README.md +131 -61
- package/build/cjs/index.js +472 -150
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +471 -149
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +472 -150
- package/lib/Metadata.d.ts +2 -0
- package/lib/Metadata.js +39 -0
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.d.ts +1 -2
- package/lib/Reflection.js +28 -22
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.d.ts +1 -1
- package/lib/annotations.js +12 -10
- package/lib/annotations.js.map +1 -1
- 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/codegen/api.js +1 -2
- package/lib/codegen/api.js.map +1 -1
- package/lib/codegen/languages/cpp.js +1 -2
- package/lib/codegen/languages/cpp.js.map +1 -1
- package/lib/codegen/languages/csharp.js +1 -2
- package/lib/codegen/languages/csharp.js.map +1 -1
- package/lib/codegen/languages/haxe.js +1 -2
- package/lib/codegen/languages/haxe.js.map +1 -1
- package/lib/codegen/languages/java.js +1 -2
- package/lib/codegen/languages/java.js.map +1 -1
- package/lib/codegen/languages/js.js +1 -2
- package/lib/codegen/languages/js.js.map +1 -1
- package/lib/codegen/languages/lua.js +1 -2
- package/lib/codegen/languages/lua.js.map +1 -1
- package/lib/codegen/languages/ts.js +1 -2
- package/lib/codegen/languages/ts.js.map +1 -1
- package/lib/codegen/parser.js +2 -3
- package/lib/codegen/parser.js.map +1 -1
- package/lib/codegen/types.js +3 -3
- package/lib/codegen/types.js.map +1 -1
- package/lib/decoder/DecodeOperation.d.ts +0 -1
- package/lib/decoder/DecodeOperation.js +22 -7
- package/lib/decoder/DecodeOperation.js.map +1 -1
- package/lib/decoder/Decoder.d.ts +1 -2
- package/lib/decoder/Decoder.js +4 -4
- package/lib/decoder/Decoder.js.map +1 -1
- package/lib/decoder/strategy/RawChanges.js +1 -2
- package/lib/decoder/strategy/RawChanges.js.map +1 -1
- package/lib/decoder/strategy/StateCallbacks.d.ts +36 -7
- package/lib/decoder/strategy/StateCallbacks.js +39 -46
- package/lib/decoder/strategy/StateCallbacks.js.map +1 -1
- package/lib/encoder/ChangeTree.js +2 -5
- package/lib/encoder/ChangeTree.js.map +1 -1
- package/lib/encoder/EncodeOperation.d.ts +0 -1
- package/lib/encoder/EncodeOperation.js +29 -13
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +5 -4
- package/lib/encoder/Encoder.js +56 -38
- package/lib/encoder/Encoder.js.map +1 -1
- package/lib/encoder/StateView.js +11 -6
- package/lib/encoder/StateView.js.map +1 -1
- package/lib/encoding/assert.js +3 -3
- package/lib/encoding/assert.js.map +1 -1
- package/lib/encoding/decode.d.ts +21 -19
- package/lib/encoding/decode.js +24 -25
- package/lib/encoding/decode.js.map +1 -1
- package/lib/encoding/encode.d.ts +2 -2
- package/lib/encoding/encode.js +40 -39
- package/lib/encoding/encode.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/lib/index.d.ts +3 -0
- package/lib/index.js +5 -1
- package/lib/index.js.map +1 -1
- package/lib/types/custom/ArraySchema.d.ts +2 -2
- package/lib/types/custom/ArraySchema.js +0 -8
- package/lib/types/custom/ArraySchema.js.map +1 -1
- package/lib/types/registry.js +3 -4
- package/lib/types/registry.js.map +1 -1
- package/lib/types/utils.js +1 -2
- package/lib/types/utils.js.map +1 -1
- package/lib/utils.js +3 -4
- package/lib/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/Metadata.ts +47 -0
- package/src/Reflection.ts +31 -22
- package/src/annotations.ts +6 -2
- package/src/bench_encode.ts +66 -0
- package/src/decoder/DecodeOperation.ts +26 -6
- package/src/decoder/Decoder.ts +5 -5
- package/src/decoder/strategy/StateCallbacks.ts +93 -53
- package/src/encoder/ChangeTree.ts +2 -4
- package/src/encoder/EncodeOperation.ts +29 -12
- package/src/encoder/Encoder.ts +65 -41
- package/src/encoder/StateView.ts +10 -7
- package/src/encoding/decode.ts +24 -25
- package/src/encoding/encode.ts +25 -22
- package/src/encoding/spec.ts +1 -0
- package/src/index.ts +5 -0
- package/src/types/custom/ArraySchema.ts +2 -1
package/build/umd/index.js
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
OPERATION[OPERATION["REVERSE"] = 15] = "REVERSE";
|
|
30
30
|
OPERATION[OPERATION["MOVE"] = 32] = "MOVE";
|
|
31
31
|
OPERATION[OPERATION["DELETE_BY_REFID"] = 33] = "DELETE_BY_REFID";
|
|
32
|
+
OPERATION[OPERATION["ADD_BY_REFID"] = 129] = "ADD_BY_REFID";
|
|
32
33
|
})(exports.OPERATION || (exports.OPERATION = {}));
|
|
33
34
|
|
|
34
35
|
Symbol.metadata ??= Symbol.for("Symbol.metadata");
|
|
@@ -145,6 +146,45 @@
|
|
|
145
146
|
isDeprecated(metadata, field) {
|
|
146
147
|
return metadata[field].deprecated === true;
|
|
147
148
|
},
|
|
149
|
+
init(klass) {
|
|
150
|
+
//
|
|
151
|
+
// Used only to initialize an empty Schema (Encoder#constructor)
|
|
152
|
+
// TODO: remove/refactor this...
|
|
153
|
+
//
|
|
154
|
+
const metadata = {};
|
|
155
|
+
klass.constructor[Symbol.metadata] = metadata;
|
|
156
|
+
Object.defineProperty(metadata, -1, {
|
|
157
|
+
value: 0,
|
|
158
|
+
enumerable: false,
|
|
159
|
+
configurable: true,
|
|
160
|
+
});
|
|
161
|
+
},
|
|
162
|
+
initialize(constructor, parentMetadata) {
|
|
163
|
+
let metadata = constructor[Symbol.metadata] ?? Object.create(null);
|
|
164
|
+
// make sure inherited classes have their own metadata object.
|
|
165
|
+
if (constructor[Symbol.metadata] === parentMetadata) {
|
|
166
|
+
metadata = Object.create(null);
|
|
167
|
+
if (parentMetadata) {
|
|
168
|
+
// assign parent metadata to current
|
|
169
|
+
Object.assign(metadata, parentMetadata);
|
|
170
|
+
for (let i = 0; i <= parentMetadata[-1]; i++) {
|
|
171
|
+
Object.defineProperty(metadata, i, {
|
|
172
|
+
value: parentMetadata[i],
|
|
173
|
+
enumerable: false,
|
|
174
|
+
configurable: true,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
Object.defineProperty(metadata, -1, {
|
|
178
|
+
value: parentMetadata[-1],
|
|
179
|
+
enumerable: false,
|
|
180
|
+
configurable: true,
|
|
181
|
+
writable: true,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
constructor[Symbol.metadata] = metadata;
|
|
186
|
+
return metadata;
|
|
187
|
+
},
|
|
148
188
|
isValidInstance(klass) {
|
|
149
189
|
return (klass.constructor[Symbol.metadata] &&
|
|
150
190
|
Object.prototype.hasOwnProperty.call(klass.constructor[Symbol.metadata], -1));
|
|
@@ -264,14 +304,12 @@
|
|
|
264
304
|
this.checkIsFiltered(parent, parentIndex);
|
|
265
305
|
if (!this.isFiltered) {
|
|
266
306
|
this.root.changes.set(this, this.changes);
|
|
307
|
+
this.root.allChanges.set(this, this.allChanges);
|
|
267
308
|
}
|
|
268
309
|
if (this.isFiltered || this.isPartiallyFiltered) {
|
|
269
310
|
this.root.filteredChanges.set(this, this.filteredChanges);
|
|
270
311
|
this.root.allFilteredChanges.set(this, this.filteredChanges);
|
|
271
312
|
}
|
|
272
|
-
else {
|
|
273
|
-
this.root.allChanges.set(this, this.allChanges);
|
|
274
|
-
}
|
|
275
313
|
this.ensureRefId();
|
|
276
314
|
this.forEachChild((changeTree, atIndex) => {
|
|
277
315
|
changeTree.setParent(this.ref, root, atIndex);
|
|
@@ -363,7 +401,6 @@
|
|
|
363
401
|
}
|
|
364
402
|
_shiftAllChangeIndexes(shiftIndex, startIndex = 0, allChangeSet) {
|
|
365
403
|
Array.from(allChangeSet.entries()).forEach(([index, op]) => {
|
|
366
|
-
// console.log('shiftAllChangeIndexes', index >= startIndex, { index, op, shiftIndex, startIndex })
|
|
367
404
|
if (index >= startIndex) {
|
|
368
405
|
allChangeSet.delete(index);
|
|
369
406
|
allChangeSet.set(index + shiftIndex, op);
|
|
@@ -504,7 +541,7 @@
|
|
|
504
541
|
}
|
|
505
542
|
checkIsFiltered(parent, parentIndex) {
|
|
506
543
|
// Detect if current structure has "filters" declared
|
|
507
|
-
this.isPartiallyFiltered = this.ref['constructor']?.[Symbol.metadata]?.[-2];
|
|
544
|
+
this.isPartiallyFiltered = (this.ref['constructor']?.[Symbol.metadata]?.[-2] !== undefined);
|
|
508
545
|
// TODO: support "partially filtered", where the instance is visible, but only a field is not.
|
|
509
546
|
// Detect if parent has "filters" declared
|
|
510
547
|
while (parent && !this.isFiltered) {
|
|
@@ -565,26 +602,29 @@
|
|
|
565
602
|
textEncoder = new TextEncoder();
|
|
566
603
|
}
|
|
567
604
|
catch (e) { }
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
605
|
+
const hasBufferByteLength = (typeof Buffer !== 'undefined' && Buffer.byteLength);
|
|
606
|
+
const utf8Length = (hasBufferByteLength)
|
|
607
|
+
? Buffer.byteLength // node
|
|
608
|
+
: function (str, _) {
|
|
609
|
+
var c = 0, length = 0;
|
|
610
|
+
for (var i = 0, l = str.length; i < l; i++) {
|
|
611
|
+
c = str.charCodeAt(i);
|
|
612
|
+
if (c < 0x80) {
|
|
613
|
+
length += 1;
|
|
614
|
+
}
|
|
615
|
+
else if (c < 0x800) {
|
|
616
|
+
length += 2;
|
|
617
|
+
}
|
|
618
|
+
else if (c < 0xd800 || c >= 0xe000) {
|
|
619
|
+
length += 3;
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
i++;
|
|
623
|
+
length += 4;
|
|
624
|
+
}
|
|
584
625
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
}
|
|
626
|
+
return length;
|
|
627
|
+
};
|
|
588
628
|
function utf8Write(view, str, it) {
|
|
589
629
|
var c = 0;
|
|
590
630
|
for (var i = 0, l = str.length; i < l; i++) {
|
|
@@ -679,8 +719,7 @@
|
|
|
679
719
|
if (!value) {
|
|
680
720
|
value = "";
|
|
681
721
|
}
|
|
682
|
-
|
|
683
|
-
let length = Buffer.byteLength(value, "utf8");
|
|
722
|
+
let length = utf8Length(value, "utf8");
|
|
684
723
|
let size = 0;
|
|
685
724
|
// fixstr
|
|
686
725
|
if (length < 0x20) {
|
|
@@ -791,23 +830,23 @@
|
|
|
791
830
|
|
|
792
831
|
var encode = /*#__PURE__*/Object.freeze({
|
|
793
832
|
__proto__: null,
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
uint8: uint8$1,
|
|
833
|
+
boolean: boolean$1,
|
|
834
|
+
float32: float32$1,
|
|
835
|
+
float64: float64$1,
|
|
798
836
|
int16: int16$1,
|
|
799
|
-
uint16: uint16$1,
|
|
800
837
|
int32: int32$1,
|
|
801
|
-
uint32: uint32$1,
|
|
802
838
|
int64: int64$1,
|
|
839
|
+
int8: int8$1,
|
|
840
|
+
number: number$1,
|
|
841
|
+
string: string$1,
|
|
842
|
+
uint16: uint16$1,
|
|
843
|
+
uint32: uint32$1,
|
|
803
844
|
uint64: uint64$1,
|
|
804
|
-
|
|
805
|
-
|
|
845
|
+
uint8: uint8$1,
|
|
846
|
+
utf8Length: utf8Length,
|
|
847
|
+
utf8Write: utf8Write,
|
|
806
848
|
writeFloat32: writeFloat32,
|
|
807
|
-
writeFloat64: writeFloat64
|
|
808
|
-
boolean: boolean$1,
|
|
809
|
-
string: string$1,
|
|
810
|
-
number: number$1
|
|
849
|
+
writeFloat64: writeFloat64
|
|
811
850
|
});
|
|
812
851
|
|
|
813
852
|
class EncodeSchemaError extends Error {
|
|
@@ -949,6 +988,18 @@
|
|
|
949
988
|
}
|
|
950
989
|
const type = changeTree.getType(field);
|
|
951
990
|
const value = changeTree.getValue(field);
|
|
991
|
+
// try { throw new Error(); } catch (e) {
|
|
992
|
+
// // only print if not coming from Reflection.ts
|
|
993
|
+
// if (!e.stack.includes("src/Reflection.ts")) {
|
|
994
|
+
// console.log("encodeKeyValueOperation -> ", {
|
|
995
|
+
// ref: changeTree.ref.constructor.name,
|
|
996
|
+
// field,
|
|
997
|
+
// operation: OPERATION[operation],
|
|
998
|
+
// value: value?.toJSON(),
|
|
999
|
+
// items: ref.toJSON(),
|
|
1000
|
+
// });
|
|
1001
|
+
// }
|
|
1002
|
+
// }
|
|
952
1003
|
// TODO: inline this function call small performance gain
|
|
953
1004
|
encodeValue(encoder, bytes, ref, type, value, field, operation, it);
|
|
954
1005
|
};
|
|
@@ -958,15 +1009,19 @@
|
|
|
958
1009
|
*/
|
|
959
1010
|
const encodeArray = function (encoder, bytes, changeTree, field, operation, it, isEncodeAll, hasView) {
|
|
960
1011
|
const ref = changeTree.ref;
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1012
|
+
const useOperationByRefId = hasView && changeTree.isFiltered && (typeof (changeTree.getType(field)) !== "string");
|
|
1013
|
+
let refOrIndex;
|
|
1014
|
+
if (useOperationByRefId) {
|
|
1015
|
+
refOrIndex = ref['tmpItems'][field][$changes].refId;
|
|
1016
|
+
if (operation === exports.OPERATION.DELETE) {
|
|
1017
|
+
operation = exports.OPERATION.DELETE_BY_REFID;
|
|
1018
|
+
}
|
|
1019
|
+
else if (operation === exports.OPERATION.ADD) {
|
|
1020
|
+
operation = exports.OPERATION.ADD_BY_REFID;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
else {
|
|
1024
|
+
refOrIndex = field;
|
|
970
1025
|
}
|
|
971
1026
|
// encode operation
|
|
972
1027
|
bytes[it.offset++] = operation & 255;
|
|
@@ -975,7 +1030,7 @@
|
|
|
975
1030
|
return;
|
|
976
1031
|
}
|
|
977
1032
|
// encode index
|
|
978
|
-
number$1(bytes,
|
|
1033
|
+
number$1(bytes, refOrIndex, it);
|
|
979
1034
|
// Do not encode value for DELETE operations
|
|
980
1035
|
if (operation === exports.OPERATION.DELETE) {
|
|
981
1036
|
return;
|
|
@@ -1015,9 +1070,9 @@
|
|
|
1015
1070
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1016
1071
|
* SOFTWARE
|
|
1017
1072
|
*/
|
|
1018
|
-
function utf8Read(bytes,
|
|
1073
|
+
function utf8Read(bytes, it, length) {
|
|
1019
1074
|
var string = '', chr = 0;
|
|
1020
|
-
for (var i = offset, end = offset + length; i < end; i++) {
|
|
1075
|
+
for (var i = it.offset, end = it.offset + length; i < end; i++) {
|
|
1021
1076
|
var byte = bytes[i];
|
|
1022
1077
|
if ((byte & 0x80) === 0x00) {
|
|
1023
1078
|
string += String.fromCharCode(byte);
|
|
@@ -1052,6 +1107,7 @@
|
|
|
1052
1107
|
// (do not throw error to avoid server/client from crashing due to hack attemps)
|
|
1053
1108
|
// throw new Error('Invalid byte ' + byte.toString(16));
|
|
1054
1109
|
}
|
|
1110
|
+
it.offset += length;
|
|
1055
1111
|
return string;
|
|
1056
1112
|
}
|
|
1057
1113
|
function int8(bytes, it) {
|
|
@@ -1119,9 +1175,7 @@
|
|
|
1119
1175
|
else if (prefix === 0xdb) {
|
|
1120
1176
|
length = uint32(bytes, it);
|
|
1121
1177
|
}
|
|
1122
|
-
|
|
1123
|
-
it.offset += length;
|
|
1124
|
-
return value;
|
|
1178
|
+
return utf8Read(bytes, it, length);
|
|
1125
1179
|
}
|
|
1126
1180
|
function stringCheck(bytes, it) {
|
|
1127
1181
|
const prefix = bytes[it.offset];
|
|
@@ -1225,30 +1279,31 @@
|
|
|
1225
1279
|
|
|
1226
1280
|
var decode = /*#__PURE__*/Object.freeze({
|
|
1227
1281
|
__proto__: null,
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
int16: int16,
|
|
1231
|
-
uint16: uint16,
|
|
1232
|
-
int32: int32,
|
|
1233
|
-
uint32: uint32,
|
|
1282
|
+
arrayCheck: arrayCheck,
|
|
1283
|
+
boolean: boolean,
|
|
1234
1284
|
float32: float32,
|
|
1235
1285
|
float64: float64,
|
|
1286
|
+
int16: int16,
|
|
1287
|
+
int32: int32,
|
|
1236
1288
|
int64: int64,
|
|
1237
|
-
|
|
1289
|
+
int8: int8,
|
|
1290
|
+
number: number,
|
|
1291
|
+
numberCheck: numberCheck,
|
|
1238
1292
|
readFloat32: readFloat32,
|
|
1239
1293
|
readFloat64: readFloat64,
|
|
1240
|
-
boolean: boolean,
|
|
1241
1294
|
string: string,
|
|
1242
1295
|
stringCheck: stringCheck,
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1296
|
+
switchStructureCheck: switchStructureCheck,
|
|
1297
|
+
uint16: uint16,
|
|
1298
|
+
uint32: uint32,
|
|
1299
|
+
uint64: uint64,
|
|
1300
|
+
uint8: uint8,
|
|
1301
|
+
utf8Read: utf8Read
|
|
1247
1302
|
});
|
|
1248
1303
|
|
|
1249
1304
|
const DEFINITION_MISMATCH = -1;
|
|
1250
1305
|
function decodeValue(decoder, operation, ref, index, type, bytes, it, allChanges) {
|
|
1251
|
-
const $root = decoder
|
|
1306
|
+
const $root = decoder.root;
|
|
1252
1307
|
const previousValue = ref[$getByIndex](index);
|
|
1253
1308
|
let value;
|
|
1254
1309
|
if ((operation & exports.OPERATION.DELETE) === exports.OPERATION.DELETE) {
|
|
@@ -1434,7 +1489,8 @@
|
|
|
1434
1489
|
};
|
|
1435
1490
|
const decodeArray = function (decoder, bytes, it, ref, allChanges) {
|
|
1436
1491
|
// "uncompressed" index + operation (array/map items)
|
|
1437
|
-
|
|
1492
|
+
let operation = bytes[it.offset++];
|
|
1493
|
+
let index;
|
|
1438
1494
|
if (operation === exports.OPERATION.CLEAR) {
|
|
1439
1495
|
//
|
|
1440
1496
|
// When decoding:
|
|
@@ -1448,8 +1504,8 @@
|
|
|
1448
1504
|
else if (operation === exports.OPERATION.DELETE_BY_REFID) {
|
|
1449
1505
|
// TODO: refactor here, try to follow same flow as below
|
|
1450
1506
|
const refId = number(bytes, it);
|
|
1451
|
-
const previousValue = decoder
|
|
1452
|
-
|
|
1507
|
+
const previousValue = decoder.root.refs.get(refId);
|
|
1508
|
+
index = ref.findIndex((value) => value === previousValue);
|
|
1453
1509
|
ref[$deleteByIndex](index);
|
|
1454
1510
|
allChanges.push({
|
|
1455
1511
|
ref,
|
|
@@ -1462,7 +1518,18 @@
|
|
|
1462
1518
|
});
|
|
1463
1519
|
return;
|
|
1464
1520
|
}
|
|
1465
|
-
|
|
1521
|
+
else if (operation === exports.OPERATION.ADD_BY_REFID) {
|
|
1522
|
+
// operation = OPERATION.ADD;
|
|
1523
|
+
const refId = number(bytes, it);
|
|
1524
|
+
const itemByRefId = decoder.root.refs.get(refId);
|
|
1525
|
+
// use existing index, or push new value
|
|
1526
|
+
index = (itemByRefId)
|
|
1527
|
+
? ref.findIndex((value) => value === itemByRefId)
|
|
1528
|
+
: ref.length;
|
|
1529
|
+
}
|
|
1530
|
+
else {
|
|
1531
|
+
index = number(bytes, it);
|
|
1532
|
+
}
|
|
1466
1533
|
const type = ref[$childType];
|
|
1467
1534
|
let dynamicIndex = index;
|
|
1468
1535
|
const { value, previousValue } = decodeValue(decoder, operation, ref, index, type, bytes, it, allChanges);
|
|
@@ -1871,14 +1938,6 @@
|
|
|
1871
1938
|
lastIndexOf(searchElement, fromIndex = this.length - 1) {
|
|
1872
1939
|
return this.items.lastIndexOf(searchElement, fromIndex);
|
|
1873
1940
|
}
|
|
1874
|
-
/**
|
|
1875
|
-
* Determines whether all the members of an array satisfy the specified test.
|
|
1876
|
-
* @param callbackfn A function that accepts up to three arguments. The every method calls
|
|
1877
|
-
* the callbackfn function for each element in the array until the callbackfn returns a value
|
|
1878
|
-
* which is coercible to the Boolean value false, or until the end of the array.
|
|
1879
|
-
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
|
1880
|
-
* If thisArg is omitted, undefined is used as the this value.
|
|
1881
|
-
*/
|
|
1882
1941
|
every(callbackfn, thisArg) {
|
|
1883
1942
|
return this.items.every(callbackfn, thisArg);
|
|
1884
1943
|
}
|
|
@@ -2557,6 +2616,7 @@
|
|
|
2557
2616
|
const constructor = target.constructor;
|
|
2558
2617
|
const parentClass = Object.getPrototypeOf(constructor);
|
|
2559
2618
|
const parentMetadata = parentClass[Symbol.metadata];
|
|
2619
|
+
// TODO: use Metadata.initialize()
|
|
2560
2620
|
const metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
2561
2621
|
if (!metadata[fieldName]) {
|
|
2562
2622
|
//
|
|
@@ -2581,8 +2641,8 @@
|
|
|
2581
2641
|
// for inheritance support
|
|
2582
2642
|
TypeContext.register(constructor);
|
|
2583
2643
|
const parentClass = Object.getPrototypeOf(constructor);
|
|
2584
|
-
const parentMetadata = parentClass[Symbol.metadata];
|
|
2585
|
-
const metadata =
|
|
2644
|
+
const parentMetadata = parentClass && parentClass[Symbol.metadata];
|
|
2645
|
+
const metadata = Metadata.initialize(constructor, parentMetadata);
|
|
2586
2646
|
let fieldIndex;
|
|
2587
2647
|
/**
|
|
2588
2648
|
* skip if descriptor already exists for this field (`@deprecated()`)
|
|
@@ -3355,6 +3415,8 @@
|
|
|
3355
3415
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
3356
3416
|
PERFORMANCE OF THIS SOFTWARE.
|
|
3357
3417
|
***************************************************************************** */
|
|
3418
|
+
/* global Reflect, Promise, SuppressedError, Symbol */
|
|
3419
|
+
|
|
3358
3420
|
|
|
3359
3421
|
function __decorate(decorators, target, key, desc) {
|
|
3360
3422
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -3386,11 +3448,14 @@
|
|
|
3386
3448
|
setRoot(state) {
|
|
3387
3449
|
this.root = new Root();
|
|
3388
3450
|
this.state = state;
|
|
3451
|
+
// Workaround to allow using an empty Schema.
|
|
3452
|
+
if (state.constructor[Symbol.metadata] === undefined) {
|
|
3453
|
+
Metadata.init(state);
|
|
3454
|
+
}
|
|
3389
3455
|
state[$changes].setRoot(this.root);
|
|
3390
3456
|
}
|
|
3391
|
-
encode(it = { offset: 0 }, view,
|
|
3457
|
+
encode(it = { offset: 0 }, view, buffer = this.sharedBuffer, changeTrees = this.root.changes, isEncodeAll = this.root.allChanges === changeTrees) {
|
|
3392
3458
|
const initialOffset = it.offset; // cache current offset in case we need to resize the buffer
|
|
3393
|
-
const isEncodeAll = this.root.allChanges === changeTrees;
|
|
3394
3459
|
const hasView = (view !== undefined);
|
|
3395
3460
|
const rootChangeTree = this.state[$changes];
|
|
3396
3461
|
const changeTreesIterator = changeTrees.entries();
|
|
@@ -3399,6 +3464,12 @@
|
|
|
3399
3464
|
const ctor = ref['constructor'];
|
|
3400
3465
|
const encoder = ctor[$encoder];
|
|
3401
3466
|
const filter = ctor[$filter];
|
|
3467
|
+
// try { throw new Error(); } catch (e) {
|
|
3468
|
+
// // only print if not coming from Reflection.ts
|
|
3469
|
+
// if (!e.stack.includes("src/Reflection.ts")) {
|
|
3470
|
+
// console.log("ChangeTree:", { ref: ref.constructor.name, });
|
|
3471
|
+
// }
|
|
3472
|
+
// }
|
|
3402
3473
|
if (hasView) {
|
|
3403
3474
|
if (!view.items.has(changeTree)) {
|
|
3404
3475
|
view.invisible.add(changeTree);
|
|
@@ -3410,8 +3481,8 @@
|
|
|
3410
3481
|
}
|
|
3411
3482
|
// skip root `refId` if it's the first change tree
|
|
3412
3483
|
if (it.offset !== initialOffset || changeTree !== rootChangeTree) {
|
|
3413
|
-
|
|
3414
|
-
number$1(
|
|
3484
|
+
buffer[it.offset++] = SWITCH_TO_STRUCTURE & 255;
|
|
3485
|
+
number$1(buffer, changeTree.refId, it);
|
|
3415
3486
|
}
|
|
3416
3487
|
const changesIterator = changes.entries();
|
|
3417
3488
|
for (const [fieldIndex, operation] of changesIterator) {
|
|
@@ -3428,22 +3499,31 @@
|
|
|
3428
3499
|
// view?.invisible.add(changeTree);
|
|
3429
3500
|
continue;
|
|
3430
3501
|
}
|
|
3431
|
-
//
|
|
3432
|
-
//
|
|
3433
|
-
//
|
|
3434
|
-
//
|
|
3435
|
-
//
|
|
3436
|
-
|
|
3502
|
+
// try { throw new Error(); } catch (e) {
|
|
3503
|
+
// // only print if not coming from Reflection.ts
|
|
3504
|
+
// if (!e.stack.includes("src/Reflection.ts")) {
|
|
3505
|
+
// console.log("WILL ENCODE", {
|
|
3506
|
+
// ref: changeTree.ref.constructor.name,
|
|
3507
|
+
// fieldIndex,
|
|
3508
|
+
// operation: OPERATION[operation],
|
|
3509
|
+
// });
|
|
3510
|
+
// }
|
|
3511
|
+
// }
|
|
3512
|
+
encoder(this, buffer, changeTree, fieldIndex, operation, it, isEncodeAll, hasView);
|
|
3437
3513
|
}
|
|
3438
3514
|
}
|
|
3439
|
-
if (it.offset >
|
|
3440
|
-
const newSize = getNextPowerOf2(
|
|
3441
|
-
console.warn("@colyseus/schema encode buffer overflow. Current buffer size: " +
|
|
3515
|
+
if (it.offset > buffer.byteLength) {
|
|
3516
|
+
const newSize = getNextPowerOf2(buffer.byteLength * 2);
|
|
3517
|
+
console.warn("@colyseus/schema encode buffer overflow. Current buffer size: " + buffer.byteLength + ", encoding offset: " + it.offset + ", new size: " + newSize);
|
|
3442
3518
|
//
|
|
3443
3519
|
// resize buffer and re-encode (TODO: can we avoid re-encoding here?)
|
|
3444
3520
|
//
|
|
3445
|
-
|
|
3446
|
-
|
|
3521
|
+
buffer = Buffer.allocUnsafeSlow(newSize);
|
|
3522
|
+
// assign resized buffer to local sharedBuffer
|
|
3523
|
+
if (buffer === this.sharedBuffer) {
|
|
3524
|
+
this.sharedBuffer = buffer;
|
|
3525
|
+
}
|
|
3526
|
+
return this.encode({ offset: initialOffset }, view, buffer, changeTrees, isEncodeAll);
|
|
3447
3527
|
}
|
|
3448
3528
|
else {
|
|
3449
3529
|
//
|
|
@@ -3455,38 +3535,37 @@
|
|
|
3455
3535
|
//
|
|
3456
3536
|
this.onEndEncode(changeTrees);
|
|
3457
3537
|
}
|
|
3458
|
-
|
|
3459
|
-
return bytes.slice(0, it.offset);
|
|
3538
|
+
return buffer.subarray(0, it.offset);
|
|
3460
3539
|
}
|
|
3461
3540
|
}
|
|
3462
|
-
encodeAll(it = { offset: 0 }) {
|
|
3463
|
-
// console.log(`encodeAll(), this
|
|
3464
|
-
// Array.from(this
|
|
3465
|
-
// console.log("->", item[0].
|
|
3541
|
+
encodeAll(it = { offset: 0 }, buffer = this.sharedBuffer) {
|
|
3542
|
+
// console.log(`encodeAll(), this.root.allChanges (${this.root.allChanges.size})`);
|
|
3543
|
+
// Array.from(this.root.allChanges.entries()).map((item) => {
|
|
3544
|
+
// console.log("->", { ref: item[0].ref.constructor.name, refId: item[0].refId, changes: item[1].size });
|
|
3466
3545
|
// });
|
|
3467
|
-
return this.encode(it, undefined,
|
|
3546
|
+
return this.encode(it, undefined, buffer, this.root.allChanges, true);
|
|
3468
3547
|
}
|
|
3469
3548
|
encodeAllView(view, sharedOffset, it, bytes = this.sharedBuffer) {
|
|
3470
3549
|
const viewOffset = it.offset;
|
|
3471
|
-
// console.log(`encodeAllView(), this
|
|
3550
|
+
// console.log(`encodeAllView(), this.root.allFilteredChanges (${this.root.allFilteredChanges.size})`);
|
|
3472
3551
|
// this.debugAllFilteredChanges();
|
|
3473
3552
|
// try to encode "filtered" changes
|
|
3474
|
-
this.encode(it, view, bytes, this.root.allFilteredChanges);
|
|
3553
|
+
this.encode(it, view, bytes, this.root.allFilteredChanges, true);
|
|
3475
3554
|
return Buffer.concat([
|
|
3476
|
-
bytes.
|
|
3477
|
-
bytes.
|
|
3555
|
+
bytes.subarray(0, sharedOffset),
|
|
3556
|
+
bytes.subarray(viewOffset, it.offset)
|
|
3478
3557
|
]);
|
|
3479
3558
|
}
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3559
|
+
debugAllFilteredChanges() {
|
|
3560
|
+
Array.from(this.root.allFilteredChanges.entries()).map((item) => {
|
|
3561
|
+
console.log("->", { refId: item[0].refId, changes: item[1].size }, item[0].ref.toJSON());
|
|
3562
|
+
if (Array.isArray(item[0].ref.toJSON())) {
|
|
3563
|
+
item[1].forEach((op, key) => {
|
|
3564
|
+
console.log(" ->", { key, op: exports.OPERATION[op] });
|
|
3565
|
+
});
|
|
3566
|
+
}
|
|
3567
|
+
});
|
|
3568
|
+
}
|
|
3490
3569
|
encodeView(view, sharedOffset, it, bytes = this.sharedBuffer) {
|
|
3491
3570
|
const viewOffset = it.offset;
|
|
3492
3571
|
// try to encode "filtered" changes
|
|
@@ -3518,8 +3597,8 @@
|
|
|
3518
3597
|
// clear "view" changes after encoding
|
|
3519
3598
|
view.changes.clear();
|
|
3520
3599
|
return Buffer.concat([
|
|
3521
|
-
bytes.
|
|
3522
|
-
bytes.
|
|
3600
|
+
bytes.subarray(0, sharedOffset),
|
|
3601
|
+
bytes.subarray(viewOffset, it.offset)
|
|
3523
3602
|
]);
|
|
3524
3603
|
}
|
|
3525
3604
|
onEndEncode(changeTrees = this.root.changes) {
|
|
@@ -3698,12 +3777,12 @@
|
|
|
3698
3777
|
}
|
|
3699
3778
|
setRoot(root) {
|
|
3700
3779
|
this.state = root;
|
|
3701
|
-
this
|
|
3702
|
-
this
|
|
3780
|
+
this.root = new ReferenceTracker();
|
|
3781
|
+
this.root.addRef(0, root);
|
|
3703
3782
|
}
|
|
3704
3783
|
decode(bytes, it = { offset: 0 }, ref = this.state) {
|
|
3705
3784
|
const allChanges = [];
|
|
3706
|
-
const $root = this
|
|
3785
|
+
const $root = this.root;
|
|
3707
3786
|
const totalBytes = bytes.byteLength;
|
|
3708
3787
|
let decoder = ref['constructor'][$decoder];
|
|
3709
3788
|
this.currentRefId = 0;
|
|
@@ -3784,7 +3863,7 @@
|
|
|
3784
3863
|
previousValue: value
|
|
3785
3864
|
});
|
|
3786
3865
|
if (needRemoveRef) {
|
|
3787
|
-
this
|
|
3866
|
+
this.root.removeRef(this.root.refIds.get(value));
|
|
3788
3867
|
}
|
|
3789
3868
|
});
|
|
3790
3869
|
}
|
|
@@ -3824,7 +3903,7 @@
|
|
|
3824
3903
|
super(...arguments);
|
|
3825
3904
|
this.types = new ArraySchema();
|
|
3826
3905
|
}
|
|
3827
|
-
static encode(instance, context) {
|
|
3906
|
+
static encode(instance, context, it = { offset: 0 }) {
|
|
3828
3907
|
if (!context) {
|
|
3829
3908
|
context = new TypeContext(instance.constructor);
|
|
3830
3909
|
}
|
|
@@ -3881,7 +3960,6 @@
|
|
|
3881
3960
|
}
|
|
3882
3961
|
buildType(type, klass[Symbol.metadata]);
|
|
3883
3962
|
}
|
|
3884
|
-
const it = { offset: 0 };
|
|
3885
3963
|
const buf = encoder.encodeAll(it);
|
|
3886
3964
|
return Buffer.from(buf, 0, it.offset);
|
|
3887
3965
|
}
|
|
@@ -3889,59 +3967,298 @@
|
|
|
3889
3967
|
const reflection = new Reflection();
|
|
3890
3968
|
const reflectionDecoder = new Decoder(reflection);
|
|
3891
3969
|
reflectionDecoder.decode(bytes, it);
|
|
3892
|
-
const
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
const
|
|
3970
|
+
const typeContext = new TypeContext();
|
|
3971
|
+
// 1st pass, initialize metadata + inheritance
|
|
3972
|
+
reflection.types.forEach((reflectionType) => {
|
|
3973
|
+
const parentClass = typeContext.get(reflectionType.extendsId) ?? Schema;
|
|
3974
|
+
const schema = class _ extends parentClass {
|
|
3896
3975
|
};
|
|
3897
|
-
|
|
3898
|
-
const _metadata = parentKlass && parentKlass[Symbol.metadata] || Object.create(null);
|
|
3899
|
-
Object.defineProperty(schema, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
3976
|
+
const parentMetadata = parentClass[Symbol.metadata];
|
|
3900
3977
|
// register for inheritance support
|
|
3901
3978
|
TypeContext.register(schema);
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
return types;
|
|
3979
|
+
// for inheritance support
|
|
3980
|
+
Metadata.initialize(schema, parentMetadata);
|
|
3981
|
+
typeContext.add(schema, reflectionType.id);
|
|
3906
3982
|
}, {});
|
|
3983
|
+
// 2nd pass, set fields
|
|
3907
3984
|
reflection.types.forEach((reflectionType) => {
|
|
3908
|
-
const schemaType =
|
|
3985
|
+
const schemaType = typeContext.get(reflectionType.id);
|
|
3909
3986
|
const metadata = schemaType[Symbol.metadata];
|
|
3910
|
-
|
|
3911
|
-
const parentFieldIndex =
|
|
3987
|
+
// FIXME: use metadata[-1] to get field count
|
|
3988
|
+
const parentFieldIndex = 0;
|
|
3989
|
+
// console.log("--------------------");
|
|
3990
|
+
// // console.log("reflectionType", reflectionType.toJSON());
|
|
3991
|
+
// console.log("reflectionType.fields", reflectionType.fields.toJSON());
|
|
3992
|
+
// console.log("parentFieldIndex", parentFieldIndex);
|
|
3993
|
+
//
|
|
3994
|
+
// FIXME: set fields using parentKlass as well
|
|
3995
|
+
// currently the fields are duplicated on inherited classes
|
|
3996
|
+
//
|
|
3997
|
+
// // const parentKlass = reflection.types[reflectionType.extendsId];
|
|
3998
|
+
// // parentKlass.fields
|
|
3912
3999
|
reflectionType.fields.forEach((field, i) => {
|
|
3913
4000
|
const fieldIndex = parentFieldIndex + i;
|
|
3914
4001
|
if (field.referencedType !== undefined) {
|
|
3915
4002
|
let fieldType = field.type;
|
|
3916
|
-
let refType =
|
|
4003
|
+
let refType = typeContext.get(field.referencedType);
|
|
3917
4004
|
// map or array of primitive type (-1)
|
|
3918
4005
|
if (!refType) {
|
|
3919
4006
|
const typeInfo = field.type.split(":");
|
|
3920
4007
|
fieldType = typeInfo[0];
|
|
3921
|
-
refType = typeInfo[1];
|
|
4008
|
+
refType = typeInfo[1]; // string
|
|
3922
4009
|
}
|
|
3923
4010
|
if (fieldType === "ref") {
|
|
3924
|
-
// type(refType)(schemaType.prototype, field.name);
|
|
3925
4011
|
Metadata.addField(metadata, fieldIndex, field.name, refType);
|
|
3926
4012
|
}
|
|
3927
4013
|
else {
|
|
3928
|
-
// type({ [fieldType]: refType } as DefinitionType)(schemaType.prototype, field.name);
|
|
3929
4014
|
Metadata.addField(metadata, fieldIndex, field.name, { [fieldType]: refType });
|
|
3930
4015
|
}
|
|
3931
4016
|
}
|
|
3932
4017
|
else {
|
|
3933
|
-
// type(field.type as PrimitiveType)(schemaType.prototype, field.name);
|
|
3934
4018
|
Metadata.addField(metadata, fieldIndex, field.name, field.type);
|
|
3935
4019
|
}
|
|
3936
4020
|
});
|
|
3937
4021
|
});
|
|
3938
|
-
|
|
4022
|
+
// @ts-ignore
|
|
4023
|
+
return new (typeContext.get(0))();
|
|
3939
4024
|
}
|
|
3940
4025
|
}
|
|
3941
4026
|
__decorate([
|
|
3942
4027
|
type([ReflectionType])
|
|
3943
4028
|
], Reflection.prototype, "types", void 0);
|
|
3944
4029
|
|
|
4030
|
+
function getDecoderStateCallbacks(decoder) {
|
|
4031
|
+
const $root = decoder.root;
|
|
4032
|
+
const callbacks = $root.callbacks;
|
|
4033
|
+
let isTriggeringOnAdd = false;
|
|
4034
|
+
decoder.triggerChanges = function (allChanges) {
|
|
4035
|
+
const uniqueRefIds = new Set();
|
|
4036
|
+
for (let i = 0, l = allChanges.length; i < l; i++) {
|
|
4037
|
+
const change = allChanges[i];
|
|
4038
|
+
const refId = change.refId;
|
|
4039
|
+
const ref = change.ref;
|
|
4040
|
+
const $callbacks = callbacks[refId];
|
|
4041
|
+
if (!$callbacks) {
|
|
4042
|
+
continue;
|
|
4043
|
+
}
|
|
4044
|
+
//
|
|
4045
|
+
// trigger onRemove on child structure.
|
|
4046
|
+
//
|
|
4047
|
+
if ((change.op & exports.OPERATION.DELETE) === exports.OPERATION.DELETE &&
|
|
4048
|
+
change.previousValue instanceof Schema) {
|
|
4049
|
+
const deleteCallbacks = callbacks[$root.refIds.get(change.previousValue)]?.[exports.OPERATION.DELETE];
|
|
4050
|
+
for (let i = deleteCallbacks?.length - 1; i >= 0; i--) {
|
|
4051
|
+
deleteCallbacks[i]();
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4054
|
+
if (ref instanceof Schema) {
|
|
4055
|
+
//
|
|
4056
|
+
// Handle schema instance
|
|
4057
|
+
//
|
|
4058
|
+
if (!uniqueRefIds.has(refId)) {
|
|
4059
|
+
// trigger onChange
|
|
4060
|
+
const replaceCallbacks = $callbacks?.[exports.OPERATION.REPLACE];
|
|
4061
|
+
for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {
|
|
4062
|
+
replaceCallbacks[i]();
|
|
4063
|
+
// try {
|
|
4064
|
+
// } catch (e) {
|
|
4065
|
+
// console.error(e);
|
|
4066
|
+
// }
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
if ($callbacks.hasOwnProperty(change.field)) {
|
|
4070
|
+
const fieldCallbacks = $callbacks[change.field];
|
|
4071
|
+
for (let i = fieldCallbacks?.length - 1; i >= 0; i--) {
|
|
4072
|
+
fieldCallbacks[i](change.value, change.previousValue);
|
|
4073
|
+
// try {
|
|
4074
|
+
// } catch (e) {
|
|
4075
|
+
// console.error(e);
|
|
4076
|
+
// }
|
|
4077
|
+
}
|
|
4078
|
+
}
|
|
4079
|
+
}
|
|
4080
|
+
else {
|
|
4081
|
+
//
|
|
4082
|
+
// Handle collection of items
|
|
4083
|
+
//
|
|
4084
|
+
if ((change.op & exports.OPERATION.DELETE) === exports.OPERATION.DELETE) {
|
|
4085
|
+
//
|
|
4086
|
+
// FIXME: `previousValue` should always be available.
|
|
4087
|
+
//
|
|
4088
|
+
if (change.previousValue !== undefined) {
|
|
4089
|
+
// triger onRemove
|
|
4090
|
+
const deleteCallbacks = $callbacks[exports.OPERATION.DELETE];
|
|
4091
|
+
for (let i = deleteCallbacks?.length - 1; i >= 0; i--) {
|
|
4092
|
+
deleteCallbacks[i](change.previousValue, change.dynamicIndex ?? change.field);
|
|
4093
|
+
}
|
|
4094
|
+
}
|
|
4095
|
+
// Handle DELETE_AND_ADD operations
|
|
4096
|
+
// FIXME: should we set "isTriggeringOnAdd" here?
|
|
4097
|
+
if ((change.op & exports.OPERATION.ADD) === exports.OPERATION.ADD) {
|
|
4098
|
+
const addCallbacks = $callbacks[exports.OPERATION.ADD];
|
|
4099
|
+
for (let i = addCallbacks?.length - 1; i >= 0; i--) {
|
|
4100
|
+
addCallbacks[i](change.value, change.dynamicIndex ?? change.field);
|
|
4101
|
+
}
|
|
4102
|
+
}
|
|
4103
|
+
}
|
|
4104
|
+
else if ((change.op & exports.OPERATION.ADD) === exports.OPERATION.ADD && change.previousValue === undefined) {
|
|
4105
|
+
// triger onAdd
|
|
4106
|
+
isTriggeringOnAdd = true;
|
|
4107
|
+
const addCallbacks = $callbacks[exports.OPERATION.ADD];
|
|
4108
|
+
for (let i = addCallbacks?.length - 1; i >= 0; i--) {
|
|
4109
|
+
addCallbacks[i](change.value, change.dynamicIndex ?? change.field);
|
|
4110
|
+
}
|
|
4111
|
+
isTriggeringOnAdd = false;
|
|
4112
|
+
}
|
|
4113
|
+
// trigger onChange
|
|
4114
|
+
if (change.value !== change.previousValue) {
|
|
4115
|
+
const replaceCallbacks = $callbacks[exports.OPERATION.REPLACE];
|
|
4116
|
+
for (let i = replaceCallbacks?.length - 1; i >= 0; i--) {
|
|
4117
|
+
replaceCallbacks[i](change.value, change.dynamicIndex ?? change.field);
|
|
4118
|
+
}
|
|
4119
|
+
}
|
|
4120
|
+
}
|
|
4121
|
+
uniqueRefIds.add(refId);
|
|
4122
|
+
}
|
|
4123
|
+
};
|
|
4124
|
+
function getProxy(metadataOrType, context) {
|
|
4125
|
+
let metadata = context.instance?.constructor[Symbol.metadata] || metadataOrType;
|
|
4126
|
+
let isCollection = ((context.instance && typeof (context.instance['forEach']) === "function") ||
|
|
4127
|
+
(metadataOrType && typeof (metadataOrType[Symbol.metadata]) === "undefined"));
|
|
4128
|
+
if (metadata && !isCollection) {
|
|
4129
|
+
const onAdd = function (ref, prop, callback, immediate) {
|
|
4130
|
+
// immediate trigger
|
|
4131
|
+
if (immediate &&
|
|
4132
|
+
context.instance[prop] !== undefined &&
|
|
4133
|
+
!isTriggeringOnAdd // FIXME: This is a workaround (https://github.com/colyseus/schema/issues/147)
|
|
4134
|
+
) {
|
|
4135
|
+
callback(context.instance[prop], undefined);
|
|
4136
|
+
}
|
|
4137
|
+
return $root.addCallback($root.refIds.get(ref), prop, callback);
|
|
4138
|
+
};
|
|
4139
|
+
/**
|
|
4140
|
+
* Schema instances
|
|
4141
|
+
*/
|
|
4142
|
+
return new Proxy({
|
|
4143
|
+
listen: function listen(prop, callback, immediate = true) {
|
|
4144
|
+
if (context.instance) {
|
|
4145
|
+
return onAdd(context.instance, prop, callback, immediate);
|
|
4146
|
+
}
|
|
4147
|
+
else {
|
|
4148
|
+
// collection instance not received yet
|
|
4149
|
+
context.onInstanceAvailable((ref, existing) => onAdd(ref, prop, callback, immediate && existing));
|
|
4150
|
+
}
|
|
4151
|
+
},
|
|
4152
|
+
onChange: function onChange(callback) {
|
|
4153
|
+
return $root.addCallback($root.refIds.get(context.instance), exports.OPERATION.REPLACE, callback);
|
|
4154
|
+
},
|
|
4155
|
+
bindTo: function bindTo(targetObject, properties) {
|
|
4156
|
+
//
|
|
4157
|
+
// TODO: refactor this implementation. There is room for improvement here.
|
|
4158
|
+
//
|
|
4159
|
+
if (!properties) {
|
|
4160
|
+
properties = Object.keys(metadata);
|
|
4161
|
+
}
|
|
4162
|
+
return $root.addCallback($root.refIds.get(context.instance), exports.OPERATION.REPLACE, () => {
|
|
4163
|
+
properties.forEach((prop) => targetObject[prop] = context.instance[prop]);
|
|
4164
|
+
});
|
|
4165
|
+
}
|
|
4166
|
+
}, {
|
|
4167
|
+
get(target, prop) {
|
|
4168
|
+
if (metadata[prop]) {
|
|
4169
|
+
const instance = context.instance?.[prop];
|
|
4170
|
+
const onInstanceAvailable = ((callback) => {
|
|
4171
|
+
const unbind = $(context.instance).listen(prop, (value, _) => {
|
|
4172
|
+
callback(value, false);
|
|
4173
|
+
// FIXME: by "unbinding" the callback here,
|
|
4174
|
+
// it will not support when the server
|
|
4175
|
+
// re-instantiates the instance.
|
|
4176
|
+
//
|
|
4177
|
+
unbind?.();
|
|
4178
|
+
}, false);
|
|
4179
|
+
// has existing value
|
|
4180
|
+
if ($root.refIds.get(instance) !== undefined) {
|
|
4181
|
+
callback(instance, true);
|
|
4182
|
+
}
|
|
4183
|
+
});
|
|
4184
|
+
return getProxy(metadata[prop].type, {
|
|
4185
|
+
instance,
|
|
4186
|
+
parentInstance: context.instance,
|
|
4187
|
+
onInstanceAvailable,
|
|
4188
|
+
});
|
|
4189
|
+
}
|
|
4190
|
+
else {
|
|
4191
|
+
// accessing the function
|
|
4192
|
+
return target[prop];
|
|
4193
|
+
}
|
|
4194
|
+
},
|
|
4195
|
+
has(target, prop) { return metadata[prop] !== undefined; },
|
|
4196
|
+
set(_, _1, _2) { throw new Error("not allowed"); },
|
|
4197
|
+
deleteProperty(_, _1) { throw new Error("not allowed"); },
|
|
4198
|
+
});
|
|
4199
|
+
}
|
|
4200
|
+
else {
|
|
4201
|
+
/**
|
|
4202
|
+
* Collection instances
|
|
4203
|
+
*/
|
|
4204
|
+
const onAdd = function (ref, callback, immediate) {
|
|
4205
|
+
// Trigger callback on existing items
|
|
4206
|
+
if (immediate) {
|
|
4207
|
+
ref.forEach((v, k) => callback(v, k));
|
|
4208
|
+
}
|
|
4209
|
+
return $root.addCallback($root.refIds.get(ref), exports.OPERATION.ADD, callback);
|
|
4210
|
+
};
|
|
4211
|
+
const onRemove = function (ref, callback) {
|
|
4212
|
+
return $root.addCallback($root.refIds.get(ref), exports.OPERATION.DELETE, callback);
|
|
4213
|
+
};
|
|
4214
|
+
return new Proxy({
|
|
4215
|
+
onAdd: function (callback, immediate = true) {
|
|
4216
|
+
//
|
|
4217
|
+
// https://github.com/colyseus/schema/issues/147
|
|
4218
|
+
// If parent instance has "onAdd" registered, avoid triggering immediate callback.
|
|
4219
|
+
//
|
|
4220
|
+
// FIXME: "isTriggeringOnAdd" is a workaround. We should find a better way to handle this.
|
|
4221
|
+
//
|
|
4222
|
+
if (context.onInstanceAvailable) {
|
|
4223
|
+
// collection instance not received yet
|
|
4224
|
+
context.onInstanceAvailable((ref, existing) => onAdd(ref, callback, immediate && existing && !isTriggeringOnAdd));
|
|
4225
|
+
}
|
|
4226
|
+
else if (context.instance) {
|
|
4227
|
+
onAdd(context.instance, callback, immediate && !isTriggeringOnAdd);
|
|
4228
|
+
}
|
|
4229
|
+
},
|
|
4230
|
+
onRemove: function (callback) {
|
|
4231
|
+
if (context.onInstanceAvailable) {
|
|
4232
|
+
// collection instance not received yet
|
|
4233
|
+
context.onInstanceAvailable((ref) => onRemove(ref, callback));
|
|
4234
|
+
}
|
|
4235
|
+
else if (context.instance) {
|
|
4236
|
+
onRemove(context.instance, callback);
|
|
4237
|
+
}
|
|
4238
|
+
},
|
|
4239
|
+
}, {
|
|
4240
|
+
get(target, prop) {
|
|
4241
|
+
if (!target[prop]) {
|
|
4242
|
+
throw new Error(`Can't access '${prop}' through callback proxy. access the instance directly.`);
|
|
4243
|
+
}
|
|
4244
|
+
return target[prop];
|
|
4245
|
+
},
|
|
4246
|
+
has(target, prop) { return target[prop] !== undefined; },
|
|
4247
|
+
set(_, _1, _2) { throw new Error("not allowed"); },
|
|
4248
|
+
deleteProperty(_, _1) { throw new Error("not allowed"); },
|
|
4249
|
+
});
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
4252
|
+
function $(instance) {
|
|
4253
|
+
return getProxy(undefined, { instance });
|
|
4254
|
+
}
|
|
4255
|
+
return $;
|
|
4256
|
+
}
|
|
4257
|
+
|
|
4258
|
+
function getRawChangesCallback(decoder, callback) {
|
|
4259
|
+
decoder.triggerChanges = callback;
|
|
4260
|
+
}
|
|
4261
|
+
|
|
3945
4262
|
class StateView {
|
|
3946
4263
|
constructor() {
|
|
3947
4264
|
/**
|
|
@@ -3964,12 +4281,18 @@
|
|
|
3964
4281
|
console.warn("StateView#add(), invalid object:", obj);
|
|
3965
4282
|
return this;
|
|
3966
4283
|
}
|
|
4284
|
+
// FIXME: ArraySchema/MapSchema does not have metadata
|
|
4285
|
+
const metadata = obj.constructor[Symbol.metadata];
|
|
3967
4286
|
let changeTree = obj[$changes];
|
|
3968
4287
|
this.items.add(changeTree);
|
|
3969
4288
|
// Add children of this ChangeTree to this view
|
|
3970
|
-
changeTree.forEachChild((change,
|
|
3971
|
-
|
|
3972
|
-
|
|
4289
|
+
changeTree.forEachChild((change, index) => {
|
|
4290
|
+
// Do not ADD children that don't have the same tag
|
|
4291
|
+
if (metadata && metadata[metadata[index]].tag !== tag) {
|
|
4292
|
+
return;
|
|
4293
|
+
}
|
|
4294
|
+
this.add(change.ref, tag);
|
|
4295
|
+
});
|
|
3973
4296
|
// add parent ChangeTree's, if they are invisible to this view
|
|
3974
4297
|
// TODO: REFACTOR addParent()
|
|
3975
4298
|
this.addParent(changeTree, tag);
|
|
@@ -3996,7 +4319,6 @@
|
|
|
3996
4319
|
tags = this.tags.get(changeTree);
|
|
3997
4320
|
}
|
|
3998
4321
|
tags.add(tag);
|
|
3999
|
-
// console.log("BY TAG:", tag);
|
|
4000
4322
|
// Ref: add tagged properties
|
|
4001
4323
|
metadata?.[-3]?.[tag]?.forEach((index) => {
|
|
4002
4324
|
if (changeTree.getChange(index) !== exports.OPERATION.DELETE) {
|
|
@@ -4166,10 +4488,10 @@
|
|
|
4166
4488
|
exports.encode = encode;
|
|
4167
4489
|
exports.encodeKeyValueOperation = encodeArray;
|
|
4168
4490
|
exports.encodeSchemaOperation = encodeSchemaOperation;
|
|
4491
|
+
exports.getDecoderStateCallbacks = getDecoderStateCallbacks;
|
|
4492
|
+
exports.getRawChangesCallback = getRawChangesCallback;
|
|
4169
4493
|
exports.registerType = registerType;
|
|
4170
4494
|
exports.type = type;
|
|
4171
4495
|
exports.view = view;
|
|
4172
4496
|
|
|
4173
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4174
|
-
|
|
4175
4497
|
}));
|