Skip to content

Commit 222cfdd

Browse files
authored
Merge pull request #208 from colyseus/plain-schema-definition
Implement schema init() method
2 parents 3151dff + ad734db commit 222cfdd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+748
-337
lines changed

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@colyseus/schema",
3-
"version": "3.0.62",
3+
"version": "3.0.63",
44
"description": "Binary state serializer with delta encoding for games",
55
"bin": {
66
"schema-codegen": "bin/schema-codegen",
@@ -81,7 +81,7 @@
8181
"ts-node": "^10.9.2",
8282
"tslib": "^2.1.0",
8383
"tsx": "^3.13.0",
84-
"typescript": "^5.4.5"
84+
"typescript": "^5.9.3"
8585
},
8686
"nyc": {
8787
"extension": [

src/Metadata.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export type Metadata =
2222
{ [field: string]: number; } & // field name => field metadata
2323
{ [$descriptors]: { [field: string]: PropertyDescriptor } } // property descriptors
2424

25-
export function getNormalizedType(type: DefinitionType): DefinitionType {
25+
export function getNormalizedType(type: any): DefinitionType {
2626
if (Array.isArray(type)) {
2727
return { array: getNormalizedType(type[0]) };
2828

@@ -308,7 +308,7 @@ export const Metadata = {
308308

309309
getFields(klass: any) {
310310
const metadata: Metadata = klass[Symbol.metadata];
311-
const fields = {};
311+
const fields: any = {};
312312
for (let i = 0; i <= metadata[$numFields]; i++) {
313313
fields[metadata[i].name] = metadata[i].type;
314314
}

src/Reflection.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,11 @@ export class Reflection extends Schema {
117117
} else {
118118
fieldType = Object.keys(field.type)[0];
119119

120-
if (typeof (field.type[fieldType]) === "string") {
121-
fieldType += ":" + field.type[fieldType]; // array:string
120+
if (typeof (field.type[fieldType as keyof typeof field.type]) === "string") {
121+
fieldType += ":" + field.type[fieldType as keyof typeof field.type]; // array:string
122122

123123
} else {
124-
childTypeSchema = field.type[fieldType];
124+
childTypeSchema = field.type[fieldType as keyof typeof field.type];
125125
}
126126
}
127127

@@ -145,7 +145,8 @@ export class Reflection extends Schema {
145145
}
146146

147147
const buf = reflectionEncoder.encodeAll(it);
148-
return Buffer.from(buf, 0, it.offset);
148+
return buf.slice(0, it.offset)
149+
// return Buffer.from(buf, 0, it.offset);
149150
}
150151

151152
/**

src/Schema.ts

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
import { OPERATION } from './encoding/spec';
22
import { DEFAULT_VIEW_TAG, type DefinitionType } from "./annotations";
33

4-
import { NonFunctionPropNames, ToJSON } from './types/HelperTypes';
4+
import { AssignableProps, NonFunctionPropNames, ToJSON } from './types/HelperTypes';
55

6-
import { ChangeSet, ChangeSetName, ChangeTree, Ref } from './encoder/ChangeTree';
6+
import { ChangeSet, ChangeSetName, ChangeTree, IRef, Ref } from './encoder/ChangeTree';
77
import { $changes, $decoder, $deleteByIndex, $descriptors, $encoder, $filter, $getByIndex, $track } from './types/symbols';
88
import { StateView } from './encoder/StateView';
99

1010
import { encodeSchemaOperation } from './encoder/EncodeOperation';
1111
import { decodeSchemaOperation } from './decoder/DecodeOperation';
1212

1313
import type { Decoder } from './decoder/Decoder';
14-
import type { Metadata } from './Metadata';
14+
import type { Metadata, MetadataField } from './Metadata';
1515
import { getIndent } from './utils';
1616

1717
/**
1818
* Schema encoder / decoder
1919
*/
20-
export class Schema {
20+
export class Schema<C = any> implements IRef {
21+
static [Symbol.metadata]: Metadata;
2122
static [$encoder] = encodeSchemaOperation;
2223
static [$decoder] = decodeSchemaOperation;
2324

@@ -36,9 +37,7 @@ export class Schema {
3637
}
3738

3839
static is(type: DefinitionType) {
39-
return typeof(type[Symbol.metadata]) === "object";
40-
// const metadata = type[Symbol.metadata];
41-
// return metadata && Object.prototype.hasOwnProperty.call(metadata, -1);
40+
return typeof((type as typeof Schema)[Symbol.metadata]) === "object";
4241
}
4342

4443
/**
@@ -58,7 +57,7 @@ export class Schema {
5857
* - Then, the encoder iterates over all "owned" properties per instance and encodes them.
5958
*/
6059
static [$filter] (ref: Schema, index: number, view: StateView) {
61-
const metadata: Metadata = ref.constructor[Symbol.metadata];
60+
const metadata: Metadata = (ref.constructor as typeof Schema)[Symbol.metadata];
6261
const tag = metadata[index]?.tag;
6362

6463
if (view === undefined) {
@@ -81,7 +80,7 @@ export class Schema {
8180
}
8281

8382
// allow inherited classes to have a constructor
84-
constructor(...args: any[]) {
83+
constructor(arg?: C) {
8584
//
8685
// inline
8786
// Schema.initialize(this);
@@ -91,14 +90,14 @@ export class Schema {
9190
//
9291
// Assign initial values
9392
//
94-
if (args[0]) {
95-
Object.assign(this, args[0]);
93+
if (arg) {
94+
Object.assign(this, arg);
9695
}
9796
}
9897

99-
public assign(
100-
props: { [prop in NonFunctionPropNames<this>]?: this[prop] } | ToJSON<this>,
101-
) {
98+
public assign<T extends Partial<this>>(
99+
props: AssignableProps<T>,
100+
): this {
102101
Object.assign(this, props);
103102
return this;
104103
}
@@ -110,7 +109,7 @@ export class Schema {
110109
* @param operation OPERATION to perform (detected automatically)
111110
*/
112111
public setDirty<K extends NonFunctionPropNames<this>>(property: K | number, operation?: OPERATION) {
113-
const metadata: Metadata = this.constructor[Symbol.metadata];
112+
const metadata: Metadata = (this.constructor as typeof Schema)[Symbol.metadata];
114113
this[$changes].change(
115114
metadata[metadata[property as string]].index,
116115
operation
@@ -119,22 +118,21 @@ export class Schema {
119118

120119
clone (): this {
121120
const cloned = new ((this as any).constructor);
122-
const metadata: Metadata = this.constructor[Symbol.metadata];
121+
const metadata: Metadata = (this.constructor as typeof Schema)[Symbol.metadata];
123122

124123
//
125124
// TODO: clone all properties, not only annotated ones
126125
//
127126
// for (const field in this) {
128127
for (const fieldIndex in metadata) {
129-
// const field = metadata[metadata[fieldIndex]].name;
130-
const field = metadata[fieldIndex as any as number].name;
128+
const field = metadata[fieldIndex as any as number].name as keyof this;
131129

132130
if (
133131
typeof (this[field]) === "object" &&
134-
typeof (this[field]?.clone) === "function"
132+
typeof ((this[field] as any)?.clone) === "function"
135133
) {
136134
// deep clone
137-
cloned[field] = this[field].clone();
135+
cloned[field] = (this[field] as any).clone();
138136

139137
} else {
140138
// primitive values
@@ -145,11 +143,11 @@ export class Schema {
145143
return cloned;
146144
}
147145

148-
toJSON () {
149-
const obj: unknown = {};
146+
toJSON (this: any) {
147+
const obj: any = {};
150148
const metadata = this.constructor[Symbol.metadata];
151149
for (const index in metadata) {
152-
const field = metadata[index];
150+
const field = metadata[index] as MetadataField;
153151
const fieldName = field.name;
154152
if (!field.deprecated && this[fieldName] !== null && typeof (this[fieldName]) !== "undefined") {
155153
obj[fieldName] = (typeof (this[fieldName]['toJSON']) === "function")
@@ -168,14 +166,14 @@ export class Schema {
168166
this[$changes].discardAll();
169167
}
170168

171-
protected [$getByIndex](index: number) {
172-
const metadata: Metadata = this.constructor[Symbol.metadata];
173-
return this[metadata[index].name];
169+
[$getByIndex](index: number): any {
170+
const metadata: Metadata = (this.constructor as typeof Schema)[Symbol.metadata];
171+
return this[metadata[index].name as keyof this];
174172
}
175173

176-
protected [$deleteByIndex](index: number) {
177-
const metadata: Metadata = this.constructor[Symbol.metadata];
178-
this[metadata[index].name] = undefined;
174+
[$deleteByIndex](index: number): void {
175+
const metadata: Metadata = (this.constructor as typeof Schema)[Symbol.metadata];
176+
this[metadata[index].name as keyof this] = undefined;
179177
}
180178

181179
/**
@@ -185,7 +183,7 @@ export class Schema {
185183
* @param showContents display JSON contents of the instance
186184
* @returns
187185
*/
188-
static debugRefIds(ref: Ref, showContents: boolean = false, level: number = 0, decoder?: Decoder, keyPrefix: string = "") {
186+
static debugRefIds<T extends Schema>(ref: T, showContents: boolean = false, level: number = 0, decoder?: Decoder, keyPrefix: string = "") {
189187
const contents = (showContents) ? ` - ${JSON.stringify(ref.toJSON())}` : "";
190188
const changeTree: ChangeTree = ref[$changes];
191189

@@ -201,18 +199,18 @@ export class Schema {
201199

202200
changeTree.forEachChild((childChangeTree, indexOrKey) => {
203201
let key = indexOrKey;
204-
if (typeof indexOrKey === 'number' && ref['$indexes']) {
202+
if (typeof indexOrKey === 'number' && (ref as any)['$indexes']) {
205203
// MapSchema
206-
key = ref['$indexes'].get(indexOrKey) ?? indexOrKey;
204+
key = (ref as any)['$indexes'].get(indexOrKey) ?? indexOrKey;
207205
}
208-
const keyPrefix = (ref['forEach'] !== undefined && key !== undefined) ? `["${key}"]: ` : "";
206+
const keyPrefix = ((ref as any)['forEach'] !== undefined && key !== undefined) ? `["${key}"]: ` : "";
209207
output += this.debugRefIds(childChangeTree.ref, showContents, level + 1, decoder, keyPrefix);
210208
});
211209

212210
return output;
213211
}
214212

215-
static debugRefIdEncodingOrder(ref: Ref, changeSet: ChangeSetName = 'allChanges') {
213+
static debugRefIdEncodingOrder<T extends Ref>(ref: T, changeSet: ChangeSetName = 'allChanges') {
216214
let encodeOrder: number[] = [];
217215
let current = ref[$changes].root[changeSet].next;
218216
while (current) {
@@ -236,7 +234,7 @@ export class Schema {
236234
* @param isEncodeAll Return "full encode" instead of current change set.
237235
* @returns
238236
*/
239-
static debugChanges(instance: Ref, isEncodeAll: boolean = false) {
237+
static debugChanges<T extends Ref>(instance: T, isEncodeAll: boolean = false) {
240238
const changeTree: ChangeTree = instance[$changes];
241239

242240
const changeSet = (isEncodeAll) ? changeTree.allChanges : changeTree.changes;
@@ -278,7 +276,7 @@ export class Schema {
278276
return output;
279277
}
280278

281-
static debugChangesDeep(ref: Ref, changeSetName: "changes" | "allChanges" | "allFilteredChanges" | "filteredChanges" = "changes") {
279+
static debugChangesDeep<T extends Schema>(ref: T, changeSetName: "changes" | "allChanges" | "allFilteredChanges" | "filteredChanges" = "changes") {
282280
let output = "";
283281

284282
const rootChangeTree: ChangeTree = ref[$changes];
@@ -290,7 +288,7 @@ export class Schema {
290288

291289
// TODO: FIXME: this method is not working as expected
292290
for (const [refId, changes] of Object.entries(root[changeSetName])) {
293-
const changeTree = root.changeTrees[refId];
291+
const changeTree = root.changeTrees[refId as any as number];
294292
if (!changeTree) { continue; }
295293

296294
let includeChangeTree = false;

0 commit comments

Comments
 (0)