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