@colyseus/schema 3.0.0-alpha.35 → 3.0.0-alpha.37
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 +152 -106
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +152 -106
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +152 -106
- package/lib/Metadata.d.ts +1 -1
- package/lib/Metadata.js +31 -4
- package/lib/Metadata.js.map +1 -1
- package/lib/Reflection.d.ts +17 -2
- package/lib/Reflection.js +19 -6
- package/lib/Reflection.js.map +1 -1
- package/lib/annotations.d.ts +1 -1
- package/lib/annotations.js +2 -5
- package/lib/annotations.js.map +1 -1
- package/lib/debug.js +1 -2
- package/lib/debug.js.map +1 -1
- package/lib/encoder/EncodeOperation.js.map +1 -1
- package/lib/encoder/Encoder.d.ts +1 -0
- package/lib/encoder/Encoder.js +8 -0
- package/lib/encoder/Encoder.js.map +1 -1
- package/package.json +1 -1
- package/src/Metadata.ts +30 -6
- package/src/Reflection.ts +21 -8
- package/src/annotations.ts +2 -6
- package/src/debug.ts +1 -2
- package/src/encoder/EncodeOperation.ts +0 -3
- package/src/encoder/Encoder.ts +12 -0
package/build/cjs/index.js
CHANGED
|
@@ -73,6 +73,102 @@ function getType(identifier) {
|
|
|
73
73
|
return registeredTypes[identifier];
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
class TypeContext {
|
|
77
|
+
/**
|
|
78
|
+
* For inheritance support
|
|
79
|
+
* Keeps track of which classes extends which. (parent -> children)
|
|
80
|
+
*/
|
|
81
|
+
static { this.inheritedTypes = new Map(); }
|
|
82
|
+
static register(target) {
|
|
83
|
+
const parent = Object.getPrototypeOf(target);
|
|
84
|
+
if (parent !== Schema) {
|
|
85
|
+
let inherits = TypeContext.inheritedTypes.get(parent);
|
|
86
|
+
if (!inherits) {
|
|
87
|
+
inherits = new Set();
|
|
88
|
+
TypeContext.inheritedTypes.set(parent, inherits);
|
|
89
|
+
}
|
|
90
|
+
inherits.add(target);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
constructor(rootClass) {
|
|
94
|
+
this.types = {};
|
|
95
|
+
this.schemas = new Map();
|
|
96
|
+
this.hasFilters = false;
|
|
97
|
+
this.parentFiltered = {};
|
|
98
|
+
if (rootClass) {
|
|
99
|
+
this.discoverTypes(rootClass);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
has(schema) {
|
|
103
|
+
return this.schemas.has(schema);
|
|
104
|
+
}
|
|
105
|
+
get(typeid) {
|
|
106
|
+
return this.types[typeid];
|
|
107
|
+
}
|
|
108
|
+
add(schema, typeid = this.schemas.size) {
|
|
109
|
+
// skip if already registered
|
|
110
|
+
if (this.schemas.has(schema)) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
this.types[typeid] = schema;
|
|
114
|
+
//
|
|
115
|
+
// Workaround to allow using an empty Schema (with no `@type()` fields)
|
|
116
|
+
//
|
|
117
|
+
if (schema[Symbol.metadata] === undefined) {
|
|
118
|
+
Metadata.init(schema);
|
|
119
|
+
}
|
|
120
|
+
this.schemas.set(schema, typeid);
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
getTypeId(klass) {
|
|
124
|
+
return this.schemas.get(klass);
|
|
125
|
+
}
|
|
126
|
+
discoverTypes(klass, parentIndex, parentFieldViewTag) {
|
|
127
|
+
if (!this.add(klass)) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
// add classes inherited from this base class
|
|
131
|
+
TypeContext.inheritedTypes.get(klass)?.forEach((child) => {
|
|
132
|
+
this.discoverTypes(child, parentIndex, parentFieldViewTag);
|
|
133
|
+
});
|
|
134
|
+
const metadata = (klass[Symbol.metadata] ??= {});
|
|
135
|
+
// if any schema/field has filters, mark "context" as having filters.
|
|
136
|
+
if (metadata[$viewFieldIndexes]) {
|
|
137
|
+
this.hasFilters = true;
|
|
138
|
+
}
|
|
139
|
+
if (parentFieldViewTag !== undefined) {
|
|
140
|
+
this.parentFiltered[`${this.schemas.get(klass)}-${parentIndex}`] = true;
|
|
141
|
+
}
|
|
142
|
+
for (const fieldIndex in metadata) {
|
|
143
|
+
const index = fieldIndex;
|
|
144
|
+
const fieldType = metadata[index].type;
|
|
145
|
+
const viewTag = metadata[index].tag;
|
|
146
|
+
if (typeof (fieldType) === "string") {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (Array.isArray(fieldType)) {
|
|
150
|
+
const type = fieldType[0];
|
|
151
|
+
// skip primitive types
|
|
152
|
+
if (type === "string") {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
this.discoverTypes(type, index, viewTag);
|
|
156
|
+
}
|
|
157
|
+
else if (typeof (fieldType) === "function") {
|
|
158
|
+
this.discoverTypes(fieldType, viewTag);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
const type = Object.values(fieldType)[0];
|
|
162
|
+
// skip primitive types
|
|
163
|
+
if (typeof (type) === "string") {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
this.discoverTypes(type, index, viewTag);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
76
172
|
const Metadata = {
|
|
77
173
|
addField(metadata, index, name, type, descriptor) {
|
|
78
174
|
if (index > 64) {
|
|
@@ -157,17 +253,42 @@ const Metadata = {
|
|
|
157
253
|
metadata[$fieldIndexesByViewTag][tag].push(index);
|
|
158
254
|
},
|
|
159
255
|
setFields(target, fields) {
|
|
160
|
-
|
|
161
|
-
|
|
256
|
+
// for inheritance support
|
|
257
|
+
const constructor = target.prototype.constructor;
|
|
258
|
+
TypeContext.register(constructor);
|
|
259
|
+
const parentClass = Object.getPrototypeOf(constructor);
|
|
260
|
+
const parentMetadata = parentClass && parentClass[Symbol.metadata];
|
|
261
|
+
const metadata = Metadata.initialize(constructor, parentMetadata);
|
|
262
|
+
// Use Schema's methods if not defined in the class
|
|
263
|
+
if (!constructor[$track]) {
|
|
264
|
+
constructor[$track] = Schema[$track];
|
|
265
|
+
}
|
|
266
|
+
if (!constructor[$encoder]) {
|
|
267
|
+
constructor[$encoder] = Schema[$encoder];
|
|
268
|
+
}
|
|
269
|
+
if (!constructor[$decoder]) {
|
|
270
|
+
constructor[$decoder] = Schema[$decoder];
|
|
271
|
+
}
|
|
272
|
+
if (!constructor.prototype.toJSON) {
|
|
273
|
+
constructor.prototype.toJSON = Schema.prototype.toJSON;
|
|
274
|
+
}
|
|
275
|
+
//
|
|
276
|
+
// detect index for this field, considering inheritance
|
|
277
|
+
//
|
|
278
|
+
let fieldIndex = metadata[$numFields] // current structure already has fields defined
|
|
279
|
+
?? (parentMetadata && parentMetadata[$numFields]) // parent structure has fields defined
|
|
280
|
+
?? -1; // no fields defined
|
|
281
|
+
fieldIndex++;
|
|
162
282
|
for (const field in fields) {
|
|
163
283
|
const type = fields[field];
|
|
164
284
|
// FIXME: this code is duplicated from @type() annotation
|
|
165
285
|
const complexTypeKlass = (Array.isArray(type))
|
|
166
286
|
? getType("array")
|
|
167
287
|
: (typeof (Object.keys(type)[0]) === "string") && getType(Object.keys(type)[0]);
|
|
168
|
-
Metadata.addField(metadata,
|
|
169
|
-
|
|
288
|
+
Metadata.addField(metadata, fieldIndex, field, type, getPropertyDescriptor(`_${field}`, fieldIndex, type, complexTypeKlass));
|
|
289
|
+
fieldIndex++;
|
|
170
290
|
}
|
|
291
|
+
return target;
|
|
171
292
|
},
|
|
172
293
|
isDeprecated(metadata, field) {
|
|
173
294
|
return metadata[field].deprecated === true;
|
|
@@ -2475,102 +2596,6 @@ class MapSchema {
|
|
|
2475
2596
|
}
|
|
2476
2597
|
registerType("map", { constructor: MapSchema });
|
|
2477
2598
|
|
|
2478
|
-
class TypeContext {
|
|
2479
|
-
/**
|
|
2480
|
-
* For inheritance support
|
|
2481
|
-
* Keeps track of which classes extends which. (parent -> children)
|
|
2482
|
-
*/
|
|
2483
|
-
static { this.inheritedTypes = new Map(); }
|
|
2484
|
-
static register(target) {
|
|
2485
|
-
const parent = Object.getPrototypeOf(target);
|
|
2486
|
-
if (parent !== Schema) {
|
|
2487
|
-
let inherits = TypeContext.inheritedTypes.get(parent);
|
|
2488
|
-
if (!inherits) {
|
|
2489
|
-
inherits = new Set();
|
|
2490
|
-
TypeContext.inheritedTypes.set(parent, inherits);
|
|
2491
|
-
}
|
|
2492
|
-
inherits.add(target);
|
|
2493
|
-
}
|
|
2494
|
-
}
|
|
2495
|
-
constructor(rootClass) {
|
|
2496
|
-
this.types = {};
|
|
2497
|
-
this.schemas = new Map();
|
|
2498
|
-
this.hasFilters = false;
|
|
2499
|
-
this.parentFiltered = {};
|
|
2500
|
-
if (rootClass) {
|
|
2501
|
-
this.discoverTypes(rootClass);
|
|
2502
|
-
}
|
|
2503
|
-
}
|
|
2504
|
-
has(schema) {
|
|
2505
|
-
return this.schemas.has(schema);
|
|
2506
|
-
}
|
|
2507
|
-
get(typeid) {
|
|
2508
|
-
return this.types[typeid];
|
|
2509
|
-
}
|
|
2510
|
-
add(schema, typeid = this.schemas.size) {
|
|
2511
|
-
// skip if already registered
|
|
2512
|
-
if (this.schemas.has(schema)) {
|
|
2513
|
-
return false;
|
|
2514
|
-
}
|
|
2515
|
-
this.types[typeid] = schema;
|
|
2516
|
-
//
|
|
2517
|
-
// Workaround to allow using an empty Schema (with no `@type()` fields)
|
|
2518
|
-
//
|
|
2519
|
-
if (schema[Symbol.metadata] === undefined) {
|
|
2520
|
-
Metadata.init(schema);
|
|
2521
|
-
}
|
|
2522
|
-
this.schemas.set(schema, typeid);
|
|
2523
|
-
return true;
|
|
2524
|
-
}
|
|
2525
|
-
getTypeId(klass) {
|
|
2526
|
-
return this.schemas.get(klass);
|
|
2527
|
-
}
|
|
2528
|
-
discoverTypes(klass, parentIndex, parentFieldViewTag) {
|
|
2529
|
-
if (!this.add(klass)) {
|
|
2530
|
-
return;
|
|
2531
|
-
}
|
|
2532
|
-
// add classes inherited from this base class
|
|
2533
|
-
TypeContext.inheritedTypes.get(klass)?.forEach((child) => {
|
|
2534
|
-
this.discoverTypes(child, parentIndex, parentFieldViewTag);
|
|
2535
|
-
});
|
|
2536
|
-
const metadata = (klass[Symbol.metadata] ??= {});
|
|
2537
|
-
// if any schema/field has filters, mark "context" as having filters.
|
|
2538
|
-
if (metadata[$viewFieldIndexes]) {
|
|
2539
|
-
this.hasFilters = true;
|
|
2540
|
-
}
|
|
2541
|
-
if (parentFieldViewTag !== undefined) {
|
|
2542
|
-
this.parentFiltered[`${this.schemas.get(klass)}-${parentIndex}`] = true;
|
|
2543
|
-
}
|
|
2544
|
-
for (const fieldIndex in metadata) {
|
|
2545
|
-
const index = fieldIndex;
|
|
2546
|
-
const fieldType = metadata[index].type;
|
|
2547
|
-
const viewTag = metadata[index].tag;
|
|
2548
|
-
if (typeof (fieldType) === "string") {
|
|
2549
|
-
continue;
|
|
2550
|
-
}
|
|
2551
|
-
if (Array.isArray(fieldType)) {
|
|
2552
|
-
const type = fieldType[0];
|
|
2553
|
-
// skip primitive types
|
|
2554
|
-
if (type === "string") {
|
|
2555
|
-
continue;
|
|
2556
|
-
}
|
|
2557
|
-
this.discoverTypes(type, index, viewTag);
|
|
2558
|
-
}
|
|
2559
|
-
else if (typeof (fieldType) === "function") {
|
|
2560
|
-
this.discoverTypes(fieldType, viewTag);
|
|
2561
|
-
}
|
|
2562
|
-
else {
|
|
2563
|
-
const type = Object.values(fieldType)[0];
|
|
2564
|
-
// skip primitive types
|
|
2565
|
-
if (typeof (type) === "string") {
|
|
2566
|
-
continue;
|
|
2567
|
-
}
|
|
2568
|
-
this.discoverTypes(type, index, viewTag);
|
|
2569
|
-
}
|
|
2570
|
-
}
|
|
2571
|
-
}
|
|
2572
|
-
}
|
|
2573
|
-
|
|
2574
2599
|
const DEFAULT_VIEW_TAG = -1;
|
|
2575
2600
|
/**
|
|
2576
2601
|
* [See documentation](https://docs.colyseus.io/state/schema/)
|
|
@@ -3868,11 +3893,19 @@ class Encoder {
|
|
|
3868
3893
|
tryEncodeTypeId(bytes, baseType, targetType, it) {
|
|
3869
3894
|
const baseTypeId = this.context.getTypeId(baseType);
|
|
3870
3895
|
const targetTypeId = this.context.getTypeId(targetType);
|
|
3896
|
+
if (targetTypeId === undefined) {
|
|
3897
|
+
console.warn(`@colyseus/schema WARNING: Class "${targetType.name}" is not registered on TypeRegistry - Please either tag the class with @entity or define a @type() field.`);
|
|
3898
|
+
return;
|
|
3899
|
+
}
|
|
3871
3900
|
if (baseTypeId !== targetTypeId) {
|
|
3872
3901
|
bytes[it.offset++] = TYPE_ID & 255;
|
|
3873
3902
|
number$1(bytes, targetTypeId, it);
|
|
3874
3903
|
}
|
|
3875
3904
|
}
|
|
3905
|
+
get hasChanges() {
|
|
3906
|
+
return (this.root.changes.length > 0 ||
|
|
3907
|
+
this.root.filteredChanges.length > 0);
|
|
3908
|
+
}
|
|
3876
3909
|
}
|
|
3877
3910
|
|
|
3878
3911
|
class DecodingWarning extends Error {
|
|
@@ -4137,10 +4170,16 @@ class Reflection extends Schema {
|
|
|
4137
4170
|
super(...arguments);
|
|
4138
4171
|
this.types = new ArraySchema();
|
|
4139
4172
|
}
|
|
4140
|
-
|
|
4141
|
-
|
|
4173
|
+
/**
|
|
4174
|
+
* Encodes the TypeContext of an Encoder into a buffer.
|
|
4175
|
+
*
|
|
4176
|
+
* @param context TypeContext instance
|
|
4177
|
+
* @param it
|
|
4178
|
+
* @returns
|
|
4179
|
+
*/
|
|
4180
|
+
static encode(context, it = { offset: 0 }) {
|
|
4142
4181
|
const reflection = new Reflection();
|
|
4143
|
-
const
|
|
4182
|
+
const reflectionEncoder = new Encoder(reflection);
|
|
4144
4183
|
const buildType = (currentType, metadata) => {
|
|
4145
4184
|
for (const fieldIndex in metadata) {
|
|
4146
4185
|
const index = Number(fieldIndex);
|
|
@@ -4194,9 +4233,16 @@ class Reflection extends Schema {
|
|
|
4194
4233
|
}
|
|
4195
4234
|
buildType(type, klass[Symbol.metadata]);
|
|
4196
4235
|
}
|
|
4197
|
-
const buf =
|
|
4236
|
+
const buf = reflectionEncoder.encodeAll(it);
|
|
4198
4237
|
return Buffer.from(buf, 0, it.offset);
|
|
4199
4238
|
}
|
|
4239
|
+
/**
|
|
4240
|
+
* Decodes the TypeContext from a buffer into a Decoder instance.
|
|
4241
|
+
*
|
|
4242
|
+
* @param bytes Reflection.encode() output
|
|
4243
|
+
* @param it
|
|
4244
|
+
* @returns Decoder instance
|
|
4245
|
+
*/
|
|
4200
4246
|
static decode(bytes, it) {
|
|
4201
4247
|
const reflection = new Reflection();
|
|
4202
4248
|
const reflectionDecoder = new Decoder(reflection);
|
|
@@ -4242,8 +4288,8 @@ class Reflection extends Schema {
|
|
|
4242
4288
|
}
|
|
4243
4289
|
});
|
|
4244
4290
|
});
|
|
4245
|
-
|
|
4246
|
-
return new (typeContext
|
|
4291
|
+
const state = new (typeContext.get(0))();
|
|
4292
|
+
return new Decoder(state, typeContext);
|
|
4247
4293
|
}
|
|
4248
4294
|
}
|
|
4249
4295
|
__decorate([
|