@colyseus/schema 3.0.0-alpha.35 → 3.0.0-alpha.36
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 +148 -106
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +148 -106
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +148 -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.js +4 -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 +5 -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,6 +3893,10 @@ 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);
|
|
@@ -4137,10 +4166,16 @@ class Reflection extends Schema {
|
|
|
4137
4166
|
super(...arguments);
|
|
4138
4167
|
this.types = new ArraySchema();
|
|
4139
4168
|
}
|
|
4140
|
-
|
|
4141
|
-
|
|
4169
|
+
/**
|
|
4170
|
+
* Encodes the TypeContext of an Encoder into a buffer.
|
|
4171
|
+
*
|
|
4172
|
+
* @param context TypeContext instance
|
|
4173
|
+
* @param it
|
|
4174
|
+
* @returns
|
|
4175
|
+
*/
|
|
4176
|
+
static encode(context, it = { offset: 0 }) {
|
|
4142
4177
|
const reflection = new Reflection();
|
|
4143
|
-
const
|
|
4178
|
+
const reflectionEncoder = new Encoder(reflection);
|
|
4144
4179
|
const buildType = (currentType, metadata) => {
|
|
4145
4180
|
for (const fieldIndex in metadata) {
|
|
4146
4181
|
const index = Number(fieldIndex);
|
|
@@ -4194,9 +4229,16 @@ class Reflection extends Schema {
|
|
|
4194
4229
|
}
|
|
4195
4230
|
buildType(type, klass[Symbol.metadata]);
|
|
4196
4231
|
}
|
|
4197
|
-
const buf =
|
|
4232
|
+
const buf = reflectionEncoder.encodeAll(it);
|
|
4198
4233
|
return Buffer.from(buf, 0, it.offset);
|
|
4199
4234
|
}
|
|
4235
|
+
/**
|
|
4236
|
+
* Decodes the TypeContext from a buffer into a Decoder instance.
|
|
4237
|
+
*
|
|
4238
|
+
* @param bytes Reflection.encode() output
|
|
4239
|
+
* @param it
|
|
4240
|
+
* @returns Decoder instance
|
|
4241
|
+
*/
|
|
4200
4242
|
static decode(bytes, it) {
|
|
4201
4243
|
const reflection = new Reflection();
|
|
4202
4244
|
const reflectionDecoder = new Decoder(reflection);
|
|
@@ -4242,8 +4284,8 @@ class Reflection extends Schema {
|
|
|
4242
4284
|
}
|
|
4243
4285
|
});
|
|
4244
4286
|
});
|
|
4245
|
-
|
|
4246
|
-
return new (typeContext
|
|
4287
|
+
const state = new (typeContext.get(0))();
|
|
4288
|
+
return new Decoder(state, typeContext);
|
|
4247
4289
|
}
|
|
4248
4290
|
}
|
|
4249
4291
|
__decorate([
|