@colyseus/schema 2.0.32 → 3.0.0-alpha.1
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 +3428 -2677
- package/build/cjs/index.js.map +1 -1
- package/build/esm/index.mjs +3324 -2445
- package/build/esm/index.mjs.map +1 -1
- package/build/umd/index.js +3428 -2677
- package/lib/Decoder.d.ts +16 -0
- package/lib/Decoder.js +182 -0
- package/lib/Decoder.js.map +1 -0
- package/lib/Encoder.d.ts +13 -0
- package/lib/Encoder.js +79 -0
- package/lib/Encoder.js.map +1 -0
- package/lib/Metadata.d.ts +36 -0
- package/lib/Metadata.js +91 -0
- package/lib/Metadata.js.map +1 -0
- package/lib/Reflection.d.ts +7 -5
- package/lib/Reflection.js +62 -58
- package/lib/Reflection.js.map +1 -1
- package/lib/Schema.d.ts +39 -51
- package/lib/Schema.js +189 -731
- package/lib/Schema.js.map +1 -1
- package/lib/annotations.d.ts +26 -45
- package/lib/annotations.js +363 -194
- package/lib/annotations.js.map +1 -1
- package/lib/changes/ChangeSet.d.ts +12 -0
- package/lib/changes/ChangeSet.js +35 -0
- package/lib/changes/ChangeSet.js.map +1 -0
- package/lib/changes/DecodeOperation.d.ts +15 -0
- package/lib/changes/DecodeOperation.js +186 -0
- package/lib/changes/DecodeOperation.js.map +1 -0
- package/lib/changes/EncodeOperation.d.ts +18 -0
- package/lib/changes/EncodeOperation.js +130 -0
- package/lib/changes/EncodeOperation.js.map +1 -0
- package/lib/changes/consts.d.ts +14 -0
- package/lib/changes/consts.js +18 -0
- package/lib/changes/consts.js.map +1 -0
- package/lib/decoder/DecodeOperation.d.ts +24 -0
- package/lib/decoder/DecodeOperation.js +256 -0
- package/lib/decoder/DecodeOperation.js.map +1 -0
- package/lib/decoder/Decoder.d.ts +21 -0
- package/lib/decoder/Decoder.js +114 -0
- package/lib/decoder/Decoder.js.map +1 -0
- package/lib/decoder/ReferenceTracker.d.ts +26 -0
- package/lib/decoder/ReferenceTracker.js +131 -0
- package/lib/decoder/ReferenceTracker.js.map +1 -0
- package/lib/decoder/strategy/RawChanges.d.ts +3 -0
- package/lib/decoder/strategy/RawChanges.js +8 -0
- package/lib/decoder/strategy/RawChanges.js.map +1 -0
- package/lib/decoder/strategy/StateCallbacks.d.ts +20 -0
- package/lib/decoder/strategy/StateCallbacks.js +240 -0
- package/lib/decoder/strategy/StateCallbacks.js.map +1 -0
- package/lib/decoding/decode.d.ts +48 -0
- package/lib/decoding/decode.js +267 -0
- package/lib/decoding/decode.js.map +1 -0
- package/lib/ecs.d.ts +11 -0
- package/lib/ecs.js +160 -0
- package/lib/ecs.js.map +1 -0
- package/lib/encoder/ChangeTree.d.ts +72 -0
- package/lib/encoder/ChangeTree.js +384 -0
- package/lib/encoder/ChangeTree.js.map +1 -0
- package/lib/encoder/EncodeOperation.d.ts +25 -0
- package/lib/encoder/EncodeOperation.js +156 -0
- package/lib/encoder/EncodeOperation.js.map +1 -0
- package/lib/encoder/Encoder.d.ts +23 -0
- package/lib/encoder/Encoder.js +192 -0
- package/lib/encoder/Encoder.js.map +1 -0
- package/lib/encoder/StateView.d.ts +21 -0
- package/lib/encoder/StateView.js +196 -0
- package/lib/encoder/StateView.js.map +1 -0
- package/lib/encoding/assert.d.ts +9 -0
- package/lib/encoding/assert.js +47 -0
- package/lib/encoding/assert.js.map +1 -0
- package/lib/encoding/decode.js +1 -1
- package/lib/encoding/decode.js.map +1 -1
- package/lib/encoding/encode.d.ts +19 -16
- package/lib/encoding/encode.js +88 -81
- package/lib/encoding/encode.js.map +1 -1
- package/lib/encoding/spec.d.ts +25 -0
- package/lib/encoding/spec.js +30 -0
- package/lib/encoding/spec.js.map +1 -0
- package/lib/index.d.ts +18 -10
- package/lib/index.js +39 -17
- package/lib/index.js.map +1 -1
- package/lib/symbol.shim.d.ts +6 -0
- package/lib/symbol.shim.js +4 -0
- package/lib/symbol.shim.js.map +1 -0
- package/lib/types/ArraySchema.d.ts +1 -1
- package/lib/types/ArraySchema.js +0 -7
- package/lib/types/ArraySchema.js.map +1 -1
- package/lib/types/HelperTypes.d.ts +10 -2
- package/lib/types/HelperTypes.js.map +1 -1
- package/lib/types/custom/ArraySchema.d.ts +245 -0
- package/lib/types/custom/ArraySchema.js +659 -0
- package/lib/types/custom/ArraySchema.js.map +1 -0
- package/lib/types/custom/CollectionSchema.d.ts +42 -0
- package/lib/types/custom/CollectionSchema.js +165 -0
- package/lib/types/custom/CollectionSchema.js.map +1 -0
- package/lib/types/custom/MapSchema.d.ts +43 -0
- package/lib/types/custom/MapSchema.js +200 -0
- package/lib/types/custom/MapSchema.js.map +1 -0
- package/lib/types/custom/SetSchema.d.ts +39 -0
- package/lib/types/custom/SetSchema.js +177 -0
- package/lib/types/custom/SetSchema.js.map +1 -0
- package/lib/types/registry.d.ts +6 -0
- package/lib/types/registry.js +19 -0
- package/lib/types/registry.js.map +1 -0
- package/lib/types/symbols.d.ts +29 -0
- package/lib/types/symbols.js +33 -0
- package/lib/types/symbols.js.map +1 -0
- package/lib/types/utils.d.ts +0 -8
- package/lib/types/utils.js +1 -33
- package/lib/types/utils.js.map +1 -1
- package/lib/usage.d.ts +1 -0
- package/lib/usage.js +22 -0
- package/lib/usage.js.map +1 -0
- package/lib/utils.d.ts +13 -2
- package/lib/utils.js +36 -15
- package/lib/utils.js.map +1 -1
- package/lib/v3.d.ts +1 -0
- package/lib/v3.js +427 -0
- package/lib/v3.js.map +1 -0
- package/lib/v3_bench.d.ts +1 -0
- package/lib/v3_bench.js +130 -0
- package/lib/v3_bench.js.map +1 -0
- package/lib/v3_experiment.d.ts +1 -0
- package/lib/v3_experiment.js +407 -0
- package/lib/v3_experiment.js.map +1 -0
- package/package.json +5 -5
- package/src/Metadata.ts +135 -0
- package/src/Reflection.ts +75 -66
- package/src/Schema.ts +213 -931
- package/src/annotations.ts +430 -243
- package/src/decoder/DecodeOperation.ts +372 -0
- package/src/decoder/Decoder.ts +155 -0
- package/src/decoder/ReferenceTracker.ts +151 -0
- package/src/decoder/strategy/RawChanges.ts +9 -0
- package/src/decoder/strategy/StateCallbacks.ts +326 -0
- package/src/encoder/ChangeTree.ts +492 -0
- package/src/encoder/EncodeOperation.ts +237 -0
- package/src/encoder/Encoder.ts +246 -0
- package/src/encoder/StateView.ts +229 -0
- package/src/encoding/assert.ts +58 -0
- package/src/encoding/decode.ts +1 -1
- package/src/encoding/encode.ts +91 -82
- package/src/encoding/spec.ts +29 -0
- package/src/index.ts +22 -19
- package/src/symbol.shim.ts +12 -0
- package/src/types/HelperTypes.ts +16 -2
- package/src/types/{ArraySchema.ts → custom/ArraySchema.ts} +342 -248
- package/src/types/{CollectionSchema.ts → custom/CollectionSchema.ts} +56 -46
- package/src/types/{MapSchema.ts → custom/MapSchema.ts} +88 -115
- package/src/types/{SetSchema.ts → custom/SetSchema.ts} +58 -47
- package/src/types/{typeRegistry.ts → registry.ts} +6 -6
- package/src/types/symbols.ts +36 -0
- package/src/types/utils.ts +0 -46
- package/src/utils.ts +50 -21
- package/src/v3_bench.ts +107 -0
- package/src/changes/ChangeTree.ts +0 -295
- package/src/changes/ReferenceTracker.ts +0 -91
- package/src/filters/index.ts +0 -23
- package/src/spec.ts +0 -49
package/src/annotations.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "./symbol.shim";
|
|
2
2
|
import { Schema } from './Schema';
|
|
3
|
-
import { ArraySchema
|
|
4
|
-
import { MapSchema
|
|
5
|
-
import {
|
|
3
|
+
import { ArraySchema } from './types/custom/ArraySchema';
|
|
4
|
+
import { MapSchema } from './types/custom/MapSchema';
|
|
5
|
+
import { Metadata } from "./Metadata";
|
|
6
|
+
import { $changes, $childType, $track } from "./types/symbols";
|
|
7
|
+
import { TypeDefinition, getType } from "./types/registry";
|
|
8
|
+
import { OPERATION } from "./encoding/spec";
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* Data types
|
|
@@ -21,7 +24,8 @@ export type PrimitiveType =
|
|
|
21
24
|
"uint64" |
|
|
22
25
|
"float32" |
|
|
23
26
|
"float64" |
|
|
24
|
-
typeof Schema
|
|
27
|
+
typeof Schema |
|
|
28
|
+
object;
|
|
25
29
|
|
|
26
30
|
export type DefinitionType = PrimitiveType
|
|
27
31
|
| PrimitiveType[]
|
|
@@ -31,149 +35,128 @@ export type DefinitionType = PrimitiveType
|
|
|
31
35
|
| { set: PrimitiveType };
|
|
32
36
|
|
|
33
37
|
export type Definition = { [field: string]: DefinitionType };
|
|
34
|
-
export type FilterCallback<
|
|
35
|
-
T extends Schema = any,
|
|
36
|
-
V = any,
|
|
37
|
-
R extends Schema = any
|
|
38
|
-
> = (
|
|
39
|
-
((this: T, client: ClientWithSessionId, value: V) => boolean) |
|
|
40
|
-
((this: T, client: ClientWithSessionId, value: V, root: R) => boolean)
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
export type FilterChildrenCallback<
|
|
44
|
-
T extends Schema = any,
|
|
45
|
-
K = any,
|
|
46
|
-
V = any,
|
|
47
|
-
R extends Schema = any
|
|
48
|
-
> = (
|
|
49
|
-
((this: T, client: ClientWithSessionId, key: K, value: V) => boolean) |
|
|
50
|
-
((this: T, client: ClientWithSessionId, key: K, value: V, root: R) => boolean)
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
export class SchemaDefinition {
|
|
54
|
-
schema: Definition;
|
|
55
38
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
indexes: { [field: string]: number } = {};
|
|
61
|
-
fieldsByIndex: { [index: number]: string } = {};
|
|
62
|
-
|
|
63
|
-
filters: { [field: string]: FilterCallback };
|
|
64
|
-
indexesWithFilters: number[];
|
|
65
|
-
childFilters: { [field: string]: FilterChildrenCallback }; // childFilters are used on Map, Array, Set items.
|
|
39
|
+
export interface TypeOptions {
|
|
40
|
+
manual?: boolean,
|
|
41
|
+
}
|
|
66
42
|
|
|
67
|
-
|
|
68
|
-
descriptors: PropertyDescriptorMap & ThisType<any> = {};
|
|
43
|
+
export const DEFAULT_VIEW_TAG = -1;
|
|
69
44
|
|
|
70
|
-
|
|
71
|
-
|
|
45
|
+
export class TypeContext {
|
|
46
|
+
types: {[id: number]: typeof Schema} = {};
|
|
47
|
+
schemas = new Map<typeof Schema, number>();
|
|
72
48
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
49
|
+
hasFilters: boolean = false;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* For inheritance support
|
|
53
|
+
* Keeps track of which classes extends which. (parent -> children)
|
|
54
|
+
*/
|
|
55
|
+
static inheritedTypes = new Map<typeof Schema, Set<typeof Schema>>();
|
|
56
|
+
|
|
57
|
+
static register(target: typeof Schema) {
|
|
58
|
+
const parent = Object.getPrototypeOf(target);
|
|
59
|
+
if (parent !== Schema) {
|
|
60
|
+
let inherits = TypeContext.inheritedTypes.get(parent);
|
|
61
|
+
if (!inherits) {
|
|
62
|
+
inherits = new Set<typeof Schema>();
|
|
63
|
+
TypeContext.inheritedTypes.set(parent, inherits);
|
|
64
|
+
}
|
|
65
|
+
inherits.add(target);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
79
68
|
|
|
80
|
-
|
|
69
|
+
constructor(rootClass?: typeof Schema) {
|
|
70
|
+
if (rootClass) {
|
|
71
|
+
this.discoverTypes(rootClass);
|
|
72
|
+
}
|
|
81
73
|
}
|
|
82
74
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
this.fieldsByIndex[index] = field;
|
|
86
|
-
this.indexes[field] = index;
|
|
87
|
-
this.schema[field] = (Array.isArray(type))
|
|
88
|
-
? { array: type[0] }
|
|
89
|
-
: type;
|
|
75
|
+
has(schema: typeof Schema) {
|
|
76
|
+
return this.schemas.has(schema);
|
|
90
77
|
}
|
|
91
78
|
|
|
92
|
-
|
|
93
|
-
return this.
|
|
79
|
+
get(typeid: number) {
|
|
80
|
+
return this.types[typeid];
|
|
94
81
|
}
|
|
95
82
|
|
|
96
|
-
|
|
97
|
-
if
|
|
98
|
-
|
|
99
|
-
|
|
83
|
+
add(schema: typeof Schema, typeid: number = this.schemas.size) {
|
|
84
|
+
// skip if already registered
|
|
85
|
+
if (this.schemas.has(schema)) {
|
|
86
|
+
return false;
|
|
100
87
|
}
|
|
101
|
-
|
|
102
|
-
this.
|
|
88
|
+
|
|
89
|
+
this.types[typeid] = schema;
|
|
90
|
+
this.schemas.set(schema, typeid);
|
|
103
91
|
return true;
|
|
104
92
|
}
|
|
105
93
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const type = this.schema[field];
|
|
109
|
-
|
|
110
|
-
if (getType(Object.keys(type)[0])) {
|
|
111
|
-
if (!this.childFilters) { this.childFilters = {}; }
|
|
112
|
-
|
|
113
|
-
this.childFilters[index] = cb;
|
|
114
|
-
return true;
|
|
115
|
-
|
|
116
|
-
} else {
|
|
117
|
-
console.warn(`@filterChildren: field '${field}' can't have children. Ignoring filter.`);
|
|
118
|
-
}
|
|
94
|
+
getTypeId(klass: typeof Schema) {
|
|
95
|
+
return this.schemas.get(klass);
|
|
119
96
|
}
|
|
120
97
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
98
|
+
private discoverTypes(klass: typeof Schema) {
|
|
99
|
+
if (!this.add(klass)) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
124
102
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
103
|
+
// add classes inherited from this base class
|
|
104
|
+
TypeContext.inheritedTypes.get(klass)?.forEach((child) => {
|
|
105
|
+
this.discoverTypes(child);
|
|
106
|
+
});
|
|
129
107
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
108
|
+
// skip if no fields are defined for this class.
|
|
109
|
+
if (klass[Symbol.metadata] === undefined) {
|
|
110
|
+
klass[Symbol.metadata] = {};
|
|
111
|
+
}
|
|
133
112
|
|
|
134
|
-
//
|
|
135
|
-
|
|
113
|
+
// const metadata = Metadata.getFor(klass);
|
|
114
|
+
const metadata = klass[Symbol.metadata];
|
|
136
115
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
116
|
+
// if any schema/field has filters, mark "context" as having filters.
|
|
117
|
+
if (metadata[-2]) {
|
|
118
|
+
this.hasFilters = true;
|
|
119
|
+
}
|
|
141
120
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
schemas = new Map<typeof Schema, number>();
|
|
145
|
-
useFilters = false;
|
|
121
|
+
for (const field in metadata) {
|
|
122
|
+
const fieldType = metadata[field].type;
|
|
146
123
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
124
|
+
if (typeof(fieldType) === "string") {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
150
127
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
128
|
+
if (Array.isArray(fieldType)) {
|
|
129
|
+
const type = fieldType[0];
|
|
130
|
+
if (type === "string") {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
this.discoverTypes(type as typeof Schema);
|
|
154
134
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
// support inheritance
|
|
158
|
-
schema._definition = SchemaDefinition.create(schema._definition);
|
|
135
|
+
} else if (typeof(fieldType) === "function") {
|
|
136
|
+
this.discoverTypes(fieldType);
|
|
159
137
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
this.schemas.set(schema, typeid);
|
|
163
|
-
}
|
|
138
|
+
} else {
|
|
139
|
+
const type = Object.values(fieldType)[0];
|
|
164
140
|
|
|
141
|
+
// skip primitive types
|
|
142
|
+
if (typeof(type) === "string") {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
165
145
|
|
|
166
|
-
|
|
167
|
-
return function (definition: DefinitionType) {
|
|
168
|
-
if (!options.context) {
|
|
169
|
-
options.context = new Context();
|
|
146
|
+
this.discoverTypes(type as typeof Schema);
|
|
170
147
|
}
|
|
171
|
-
return type(definition, options);
|
|
172
148
|
}
|
|
173
149
|
}
|
|
174
150
|
}
|
|
175
151
|
|
|
176
|
-
export
|
|
152
|
+
export function entity(constructor, context: ClassDecoratorContext) {
|
|
153
|
+
if (!constructor._definition) {
|
|
154
|
+
// for inheritance support
|
|
155
|
+
TypeContext.register(constructor);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return constructor;
|
|
159
|
+
}
|
|
177
160
|
|
|
178
161
|
/**
|
|
179
162
|
* [See documentation](https://docs.colyseus.io/state/schema/)
|
|
@@ -191,38 +174,235 @@ export const globalContext = new Context();
|
|
|
191
174
|
* \@type("string", { manual: true })
|
|
192
175
|
* ```
|
|
193
176
|
*/
|
|
177
|
+
// export function type(type: DefinitionType, options?: TypeOptions) {
|
|
178
|
+
// return function ({ get, set }, context: ClassAccessorDecoratorContext): ClassAccessorDecoratorResult<Schema, any> {
|
|
179
|
+
// if (context.kind !== "accessor") {
|
|
180
|
+
// throw new Error("@type() is only supported for class accessor properties");
|
|
181
|
+
// }
|
|
182
|
+
|
|
183
|
+
// const field = context.name.toString();
|
|
184
|
+
|
|
185
|
+
// //
|
|
186
|
+
// // detect index for this field, considering inheritance
|
|
187
|
+
// //
|
|
188
|
+
// const parent = Object.getPrototypeOf(context.metadata);
|
|
189
|
+
// let fieldIndex: number = context.metadata[-1] // current structure already has fields defined
|
|
190
|
+
// ?? (parent && parent[-1]) // parent structure has fields defined
|
|
191
|
+
// ?? -1; // no fields defined
|
|
192
|
+
// fieldIndex++;
|
|
193
|
+
|
|
194
|
+
// if (
|
|
195
|
+
// !parent && // the parent already initializes the `$changes` property
|
|
196
|
+
// !Metadata.hasFields(context.metadata)
|
|
197
|
+
// ) {
|
|
198
|
+
// context.addInitializer(function (this: Ref) {
|
|
199
|
+
// Object.defineProperty(this, $changes, {
|
|
200
|
+
// value: new ChangeTree(this),
|
|
201
|
+
// enumerable: false,
|
|
202
|
+
// writable: true
|
|
203
|
+
// });
|
|
204
|
+
// });
|
|
205
|
+
// }
|
|
206
|
+
|
|
207
|
+
// Metadata.addField(context.metadata, fieldIndex, field, type);
|
|
208
|
+
|
|
209
|
+
// const isArray = ArraySchema.is(type);
|
|
210
|
+
// const isMap = !isArray && MapSchema.is(type);
|
|
211
|
+
|
|
212
|
+
// // if (options && options.manual) {
|
|
213
|
+
// // // do not declare getter/setter descriptor
|
|
214
|
+
// // definition.descriptors[field] = {
|
|
215
|
+
// // enumerable: true,
|
|
216
|
+
// // configurable: true,
|
|
217
|
+
// // writable: true,
|
|
218
|
+
// // };
|
|
219
|
+
// // return;
|
|
220
|
+
// // }
|
|
221
|
+
|
|
222
|
+
// return {
|
|
223
|
+
// init(value) {
|
|
224
|
+
// // TODO: may need to convert ArraySchema/MapSchema here
|
|
225
|
+
|
|
226
|
+
// // do not flag change if value is undefined.
|
|
227
|
+
// if (value !== undefined) {
|
|
228
|
+
// this[$changes].change(fieldIndex);
|
|
229
|
+
|
|
230
|
+
// // automaticallty transform Array into ArraySchema
|
|
231
|
+
// if (isArray) {
|
|
232
|
+
// if (!(value instanceof ArraySchema)) {
|
|
233
|
+
// value = new ArraySchema(...value);
|
|
234
|
+
// }
|
|
235
|
+
// value[$childType] = Object.values(type)[0];
|
|
236
|
+
// }
|
|
237
|
+
|
|
238
|
+
// // automaticallty transform Map into MapSchema
|
|
239
|
+
// if (isMap) {
|
|
240
|
+
// if (!(value instanceof MapSchema)) {
|
|
241
|
+
// value = new MapSchema(value);
|
|
242
|
+
// }
|
|
243
|
+
// value[$childType] = Object.values(type)[0];
|
|
244
|
+
// }
|
|
245
|
+
|
|
246
|
+
// // try to turn provided structure into a Proxy
|
|
247
|
+
// if (value['$proxy'] === undefined) {
|
|
248
|
+
// if (isMap) {
|
|
249
|
+
// value = getMapProxy(value);
|
|
250
|
+
// }
|
|
251
|
+
// }
|
|
252
|
+
|
|
253
|
+
// }
|
|
254
|
+
|
|
255
|
+
// return value;
|
|
256
|
+
// },
|
|
257
|
+
|
|
258
|
+
// get() {
|
|
259
|
+
// return get.call(this);
|
|
260
|
+
// },
|
|
261
|
+
|
|
262
|
+
// set(value: any) {
|
|
263
|
+
// /**
|
|
264
|
+
// * Create Proxy for array or map items
|
|
265
|
+
// */
|
|
266
|
+
|
|
267
|
+
// // skip if value is the same as cached.
|
|
268
|
+
// if (value === get.call(this)) {
|
|
269
|
+
// return;
|
|
270
|
+
// }
|
|
271
|
+
|
|
272
|
+
// if (
|
|
273
|
+
// value !== undefined &&
|
|
274
|
+
// value !== null
|
|
275
|
+
// ) {
|
|
276
|
+
// // automaticallty transform Array into ArraySchema
|
|
277
|
+
// if (isArray) {
|
|
278
|
+
// if (!(value instanceof ArraySchema)) {
|
|
279
|
+
// value = new ArraySchema(...value);
|
|
280
|
+
// }
|
|
281
|
+
// value[$childType] = Object.values(type)[0];
|
|
282
|
+
// }
|
|
283
|
+
|
|
284
|
+
// // automaticallty transform Map into MapSchema
|
|
285
|
+
// if (isMap) {
|
|
286
|
+
// if (!(value instanceof MapSchema)) {
|
|
287
|
+
// value = new MapSchema(value);
|
|
288
|
+
// }
|
|
289
|
+
// value[$childType] = Object.values(type)[0];
|
|
290
|
+
// }
|
|
291
|
+
|
|
292
|
+
// // try to turn provided structure into a Proxy
|
|
293
|
+
// if (value['$proxy'] === undefined) {
|
|
294
|
+
// if (isMap) {
|
|
295
|
+
// value = getMapProxy(value);
|
|
296
|
+
// }
|
|
297
|
+
// }
|
|
298
|
+
|
|
299
|
+
// // flag the change for encoding.
|
|
300
|
+
// this[$changes].change(fieldIndex);
|
|
301
|
+
|
|
302
|
+
// //
|
|
303
|
+
// // call setParent() recursively for this and its child
|
|
304
|
+
// // structures.
|
|
305
|
+
// //
|
|
306
|
+
// if (value[$changes]) {
|
|
307
|
+
// value[$changes].setParent(
|
|
308
|
+
// this,
|
|
309
|
+
// this[$changes].root,
|
|
310
|
+
// Metadata.getIndex(context.metadata, field),
|
|
311
|
+
// );
|
|
312
|
+
// }
|
|
313
|
+
|
|
314
|
+
// } else if (get.call(this)) {
|
|
315
|
+
// //
|
|
316
|
+
// // Setting a field to `null` or `undefined` will delete it.
|
|
317
|
+
// //
|
|
318
|
+
// this[$changes].delete(field);
|
|
319
|
+
// }
|
|
320
|
+
|
|
321
|
+
// set.call(this, value);
|
|
322
|
+
// },
|
|
323
|
+
// };
|
|
324
|
+
// }
|
|
325
|
+
// }
|
|
326
|
+
|
|
327
|
+
export function view<T> (tag: number = DEFAULT_VIEW_TAG) {
|
|
328
|
+
return function(target: T, fieldName: string) {
|
|
329
|
+
const constructor = target.constructor as typeof Schema;
|
|
330
|
+
|
|
331
|
+
const parentClass = Object.getPrototypeOf(constructor);
|
|
332
|
+
const parentMetadata = parentClass[Symbol.metadata];
|
|
333
|
+
const metadata: Metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
334
|
+
|
|
335
|
+
if (!metadata[fieldName]) {
|
|
336
|
+
//
|
|
337
|
+
// detect index for this field, considering inheritance
|
|
338
|
+
//
|
|
339
|
+
metadata[fieldName] = {
|
|
340
|
+
type: undefined,
|
|
341
|
+
index: (metadata[-1] // current structure already has fields defined
|
|
342
|
+
?? (parentMetadata && parentMetadata[-1]) // parent structure has fields defined
|
|
343
|
+
?? -1) + 1 // no fields defined
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
Metadata.setTag(metadata, fieldName, tag);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export function unreliable<T> (target: T, field: string) {
|
|
352
|
+
//
|
|
353
|
+
// FIXME: the following block of code is repeated across `@type()`, `@deprecated()` and `@unreliable()` decorators.
|
|
354
|
+
//
|
|
355
|
+
const constructor = target.constructor as typeof Schema;
|
|
356
|
+
|
|
357
|
+
const parentClass = Object.getPrototypeOf(constructor);
|
|
358
|
+
const parentMetadata = parentClass[Symbol.metadata];
|
|
359
|
+
const metadata: Metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
360
|
+
|
|
361
|
+
if (!metadata[field]) {
|
|
362
|
+
//
|
|
363
|
+
// detect index for this field, considering inheritance
|
|
364
|
+
//
|
|
365
|
+
metadata[field] = {
|
|
366
|
+
type: undefined,
|
|
367
|
+
index: (metadata[-1] // current structure already has fields defined
|
|
368
|
+
?? (parentMetadata && parentMetadata[-1]) // parent structure has fields defined
|
|
369
|
+
?? -1) + 1 // no fields defined
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// add owned flag to the field
|
|
374
|
+
metadata[field].unreliable = true;
|
|
375
|
+
}
|
|
376
|
+
|
|
194
377
|
export function type (
|
|
195
378
|
type: DefinitionType,
|
|
196
|
-
options
|
|
379
|
+
options?: TypeOptions
|
|
197
380
|
): PropertyDecorator {
|
|
198
381
|
return function (target: typeof Schema, field: string) {
|
|
199
|
-
const context = options.context || globalContext;
|
|
200
382
|
const constructor = target.constructor as typeof Schema;
|
|
201
|
-
constructor._context = context;
|
|
202
383
|
|
|
203
384
|
if (!type) {
|
|
204
385
|
throw new Error(`${constructor.name}: @type() reference provided for "${field}" is undefined. Make sure you don't have any circular dependencies.`);
|
|
205
386
|
}
|
|
206
387
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
388
|
+
// for inheritance support
|
|
389
|
+
TypeContext.register(constructor);
|
|
390
|
+
|
|
391
|
+
const parentClass = Object.getPrototypeOf(constructor);
|
|
392
|
+
const parentMetadata = parentClass[Symbol.metadata];
|
|
393
|
+
const metadata: Metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
213
394
|
|
|
214
|
-
|
|
215
|
-
definition.addField(field, type);
|
|
395
|
+
let fieldIndex: number;
|
|
216
396
|
|
|
217
397
|
/**
|
|
218
398
|
* skip if descriptor already exists for this field (`@deprecated()`)
|
|
219
399
|
*/
|
|
220
|
-
if (
|
|
221
|
-
if (
|
|
400
|
+
if (metadata[field]) {
|
|
401
|
+
if (metadata[field].deprecated) {
|
|
222
402
|
// do not create accessors for deprecated properties.
|
|
223
403
|
return;
|
|
224
404
|
|
|
225
|
-
} else {
|
|
405
|
+
} else if (metadata[field].descriptor !== undefined) {
|
|
226
406
|
// trying to define same property multiple times across inheritance.
|
|
227
407
|
// https://github.com/colyseus/colyseus-unity3d/issues/131#issuecomment-814308572
|
|
228
408
|
try {
|
|
@@ -232,167 +412,174 @@ export function type (
|
|
|
232
412
|
const definitionAtLine = e.stack.split("\n")[4].trim();
|
|
233
413
|
throw new Error(`${e.message} ${definitionAtLine}`);
|
|
234
414
|
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const isArray = ArraySchema.is(type);
|
|
239
|
-
const isMap = !isArray && MapSchema.is(type);
|
|
240
415
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
// (See "should support an inheritance with a Schema type without fields" test)
|
|
244
|
-
if (typeof (type) !== "string" && !Schema.is(type)) {
|
|
245
|
-
const childType = Object.values(type)[0];
|
|
246
|
-
if (typeof (childType) !== "string" && !context.has(childType)) {
|
|
247
|
-
context.add(childType);
|
|
416
|
+
} else {
|
|
417
|
+
fieldIndex = metadata[field].index;
|
|
248
418
|
}
|
|
419
|
+
|
|
420
|
+
} else {
|
|
421
|
+
//
|
|
422
|
+
// detect index for this field, considering inheritance
|
|
423
|
+
//
|
|
424
|
+
fieldIndex = metadata[-1] // current structure already has fields defined
|
|
425
|
+
?? (parentMetadata && parentMetadata[-1]) // parent structure has fields defined
|
|
426
|
+
?? -1; // no fields defined
|
|
427
|
+
fieldIndex++;
|
|
249
428
|
}
|
|
250
429
|
|
|
251
|
-
if (options.manual) {
|
|
252
|
-
|
|
253
|
-
|
|
430
|
+
if (options && options.manual) {
|
|
431
|
+
Metadata.addField(metadata, fieldIndex, field, type, {
|
|
432
|
+
// do not declare getter/setter descriptor
|
|
254
433
|
enumerable: true,
|
|
255
434
|
configurable: true,
|
|
256
435
|
writable: true,
|
|
257
|
-
};
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
436
|
+
});
|
|
260
437
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
438
|
+
} else {
|
|
439
|
+
const complexTypeKlass = (Array.isArray(type))
|
|
440
|
+
? getType("array")
|
|
441
|
+
: (typeof(Object.keys(type)[0]) === "string") && getType(Object.keys(type)[0]);
|
|
442
|
+
|
|
443
|
+
const childType = (complexTypeKlass)
|
|
444
|
+
? Object.values(type)[0]
|
|
445
|
+
: type;
|
|
446
|
+
|
|
447
|
+
Metadata.addField(
|
|
448
|
+
metadata,
|
|
449
|
+
fieldIndex,
|
|
450
|
+
field,
|
|
451
|
+
type,
|
|
452
|
+
getPropertyDescriptor(`_${field}`, fieldIndex, childType, complexTypeKlass, metadata, field)
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
282
457
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
458
|
+
export function getPropertyDescriptor(
|
|
459
|
+
fieldCached: string,
|
|
460
|
+
fieldIndex: number,
|
|
461
|
+
type: DefinitionType,
|
|
462
|
+
complexTypeKlass: TypeDefinition,
|
|
463
|
+
metadata: Metadata,
|
|
464
|
+
field: string,
|
|
465
|
+
) {
|
|
466
|
+
return {
|
|
467
|
+
get: function () { return this[fieldCached]; },
|
|
468
|
+
set: function (this: Schema, value: any) {
|
|
469
|
+
const previousValue = this[fieldCached] || undefined;
|
|
470
|
+
|
|
471
|
+
// skip if value is the same as cached.
|
|
472
|
+
if (value === previousValue) { return; }
|
|
473
|
+
|
|
474
|
+
if (
|
|
475
|
+
value !== undefined &&
|
|
476
|
+
value !== null
|
|
477
|
+
) {
|
|
478
|
+
if (complexTypeKlass) {
|
|
287
479
|
// automaticallty transform Array into ArraySchema
|
|
288
|
-
if (
|
|
480
|
+
if (complexTypeKlass.constructor === ArraySchema && !(value instanceof ArraySchema)) {
|
|
289
481
|
value = new ArraySchema(...value);
|
|
290
482
|
}
|
|
291
483
|
|
|
292
484
|
// automaticallty transform Map into MapSchema
|
|
293
|
-
if (
|
|
485
|
+
if (complexTypeKlass.constructor === MapSchema && !(value instanceof MapSchema)) {
|
|
294
486
|
value = new MapSchema(value);
|
|
295
487
|
}
|
|
296
488
|
|
|
297
|
-
|
|
298
|
-
if (value['$proxy'] === undefined) {
|
|
299
|
-
if (isMap) {
|
|
300
|
-
value = getMapProxy(value);
|
|
301
|
-
|
|
302
|
-
} else if (isArray) {
|
|
303
|
-
value = getArrayProxy(value);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// flag the change for encoding.
|
|
308
|
-
this.$changes.change(field);
|
|
309
|
-
|
|
310
|
-
//
|
|
311
|
-
// call setParent() recursively for this and its child
|
|
312
|
-
// structures.
|
|
313
|
-
//
|
|
314
|
-
if (value['$changes']) {
|
|
315
|
-
(value['$changes'] as ChangeTree).setParent(
|
|
316
|
-
this,
|
|
317
|
-
this.$changes.root,
|
|
318
|
-
this._definition.indexes[field],
|
|
319
|
-
);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
} else if (this[fieldCached]) {
|
|
323
|
-
//
|
|
324
|
-
// Setting a field to `null` or `undefined` will delete it.
|
|
325
|
-
//
|
|
326
|
-
this.$changes.delete(field);
|
|
489
|
+
value[$childType] = type;
|
|
327
490
|
}
|
|
328
491
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
492
|
+
//
|
|
493
|
+
// Replacing existing "ref", remove it from root.
|
|
494
|
+
// TODO: if there are other references to this instance, we should not remove it from root.
|
|
495
|
+
//
|
|
496
|
+
if (previousValue !== undefined && previousValue[$changes]) {
|
|
497
|
+
this[$changes].root?.remove(previousValue[$changes]);
|
|
498
|
+
}
|
|
337
499
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
500
|
+
// flag the change for encoding.
|
|
501
|
+
this.constructor[$track](this[$changes], fieldIndex, OPERATION.ADD);
|
|
502
|
+
|
|
503
|
+
//
|
|
504
|
+
// call setParent() recursively for this and its child
|
|
505
|
+
// structures.
|
|
506
|
+
//
|
|
507
|
+
if (value[$changes]) {
|
|
508
|
+
value[$changes].setParent(
|
|
509
|
+
this,
|
|
510
|
+
this[$changes].root,
|
|
511
|
+
metadata[field].index,
|
|
512
|
+
);
|
|
513
|
+
}
|
|
341
514
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
515
|
+
} else if (previousValue !== undefined) {
|
|
516
|
+
//
|
|
517
|
+
// Setting a field to `null` or `undefined` will delete it.
|
|
518
|
+
//
|
|
519
|
+
this[$changes].delete(fieldIndex);
|
|
520
|
+
}
|
|
346
521
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
}
|
|
522
|
+
this[fieldCached] = value;
|
|
523
|
+
},
|
|
352
524
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const definition = constructor._definition;
|
|
357
|
-
if (definition.addChildrenFilter(field, cb)) {
|
|
358
|
-
constructor._context.useFilters = true;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
525
|
+
enumerable: true,
|
|
526
|
+
configurable: true
|
|
527
|
+
};
|
|
361
528
|
}
|
|
362
529
|
|
|
363
|
-
|
|
364
530
|
/**
|
|
365
531
|
* `@deprecated()` flag a field as deprecated.
|
|
366
532
|
* The previous `@type()` annotation should remain along with this one.
|
|
367
533
|
*/
|
|
368
534
|
|
|
369
535
|
export function deprecated(throws: boolean = true): PropertyDecorator {
|
|
370
|
-
return function (
|
|
371
|
-
|
|
372
|
-
|
|
536
|
+
return function (klass: typeof Schema, field: string) {
|
|
537
|
+
//
|
|
538
|
+
// FIXME: the following block of code is repeated across `@type()`, `@deprecated()` and `@unreliable()` decorators.
|
|
539
|
+
//
|
|
540
|
+
const constructor = klass.constructor as typeof Schema;
|
|
541
|
+
|
|
542
|
+
const parentClass = Object.getPrototypeOf(constructor);
|
|
543
|
+
const parentMetadata = parentClass[Symbol.metadata];
|
|
544
|
+
const metadata: Metadata = (constructor[Symbol.metadata] ??= Object.assign({}, constructor[Symbol.metadata], parentMetadata ?? Object.create(null)));
|
|
545
|
+
|
|
546
|
+
if (!metadata[field]) {
|
|
547
|
+
//
|
|
548
|
+
// detect index for this field, considering inheritance
|
|
549
|
+
//
|
|
550
|
+
metadata[field] = {
|
|
551
|
+
type: undefined,
|
|
552
|
+
index: (metadata[-1] // current structure already has fields defined
|
|
553
|
+
?? (parentMetadata && parentMetadata[-1]) // parent structure has fields defined
|
|
554
|
+
?? -1) + 1 // no fields defined
|
|
555
|
+
}
|
|
556
|
+
}
|
|
373
557
|
|
|
374
|
-
|
|
558
|
+
metadata[field].deprecated = true;
|
|
375
559
|
|
|
376
560
|
if (throws) {
|
|
377
|
-
|
|
561
|
+
metadata[field].descriptor = {
|
|
378
562
|
get: function () { throw new Error(`${field} is deprecated.`); },
|
|
379
563
|
set: function (this: Schema, value: any) { /* throw new Error(`${field} is deprecated.`); */ },
|
|
380
564
|
enumerable: false,
|
|
381
565
|
configurable: true
|
|
382
566
|
};
|
|
383
567
|
}
|
|
568
|
+
|
|
569
|
+
// flag metadata[field] as non-enumerable
|
|
570
|
+
Object.defineProperty(metadata, field, {
|
|
571
|
+
value: metadata[field],
|
|
572
|
+
enumerable: false,
|
|
573
|
+
configurable: true
|
|
574
|
+
});
|
|
384
575
|
}
|
|
385
576
|
}
|
|
386
577
|
|
|
387
578
|
export function defineTypes(
|
|
388
579
|
target: typeof Schema,
|
|
389
580
|
fields: { [property: string]: DefinitionType },
|
|
390
|
-
options
|
|
581
|
+
options?: TypeOptions
|
|
391
582
|
) {
|
|
392
|
-
if (!options.context) {
|
|
393
|
-
options.context = target._context || options.context || globalContext;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
583
|
for (let field in fields) {
|
|
397
584
|
type(fields[field], options)(target.prototype, field);
|
|
398
585
|
}
|