@colyseus/schema
Advanced tools
Comparing version 0.1.5 to 0.1.6
import * as decode from "./msgpack/decode"; | ||
export declare type PrimitiveType = "string" | "number" | "int8" | "uint8" | "int16" | "uint16" | "int32" | "uint32" | "int64" | "uint64" | typeof Sync; | ||
export declare type SchemaType = (PrimitiveType | PrimitiveType[] | { | ||
map?: typeof Sync; | ||
export declare type PrimitiveType = "string" | "number" | "int8" | "uint8" | "int16" | "uint16" | "int32" | "uint32" | "int64" | "uint64" | typeof Schema; | ||
export declare type DefinitionType = (PrimitiveType | PrimitiveType[] | { | ||
map: PrimitiveType; | ||
}); | ||
export declare type Schema = { | ||
[field: string]: SchemaType; | ||
export declare type Definition = { | ||
[field: string]: DefinitionType; | ||
}; | ||
@@ -14,4 +14,4 @@ export interface DataChange { | ||
} | ||
export declare abstract class Sync { | ||
static _schema: Schema; | ||
export declare abstract class Schema { | ||
static _schema: Definition; | ||
static _indexes: { | ||
@@ -24,9 +24,9 @@ [field: string]: number; | ||
protected $changed: boolean; | ||
protected $parent: Sync; | ||
protected $parentField: string | (string | number)[]; | ||
protected $parent: Schema; | ||
protected $parentField: string | (string | number | symbol)[]; | ||
protected $parentIndexChange: number; | ||
onChange?(changes: DataChange[]): any; | ||
onRemove?(): any; | ||
markAsChanged(field: string, value?: Sync | any): void; | ||
readonly _schema: Schema; | ||
markAsChanged(field: string, value?: Schema | any): void; | ||
readonly _schema: Definition; | ||
readonly _indexes: { | ||
@@ -38,2 +38,2 @@ [field: string]: number; | ||
} | ||
export declare function sync(type: SchemaType): (target: any, field: string) => void; | ||
export declare function type(type: DefinitionType): (target: any, field: string) => void; |
@@ -25,14 +25,21 @@ "use strict"; | ||
} | ||
var Sync = /** @class */ (function () { | ||
function Sync() { | ||
var Schema = /** @class */ (function () { | ||
function Schema() { | ||
this.$changes = {}; | ||
this.$changed = false; | ||
} | ||
Sync.prototype.markAsChanged = function (field, value) { | ||
Schema.prototype.markAsChanged = function (field, value) { | ||
var fieldSchema = this._schema[field]; | ||
this.$changed = true; | ||
if (value) { | ||
if (Array.isArray(value.$parentField)) { | ||
if (Array.isArray(value.$parentField) || | ||
fieldSchema && (Array.isArray(fieldSchema) || fieldSchema.map)) { | ||
var $parentField = value.$parentField || []; | ||
// used for MAP/ARRAY | ||
var fieldName = value.$parentField[0]; | ||
var fieldKey = value.$parentField[1]; | ||
var fieldName = ($parentField.length > 0) | ||
? $parentField[0] | ||
: field; | ||
var fieldKey = ($parentField.length > 0) | ||
? $parentField[1] | ||
: value; | ||
if (!this.$changes[fieldName]) { | ||
@@ -60,3 +67,3 @@ this.$changes[fieldName] = []; | ||
}; | ||
Object.defineProperty(Sync.prototype, "_schema", { | ||
Object.defineProperty(Schema.prototype, "_schema", { | ||
get: function () { | ||
@@ -68,3 +75,3 @@ return this.constructor._schema; | ||
}); | ||
Object.defineProperty(Sync.prototype, "_indexes", { | ||
Object.defineProperty(Schema.prototype, "_indexes", { | ||
get: function () { | ||
@@ -76,3 +83,3 @@ return this.constructor._indexes; | ||
}); | ||
Sync.prototype.decode = function (bytes, it) { | ||
Schema.prototype.decode = function (bytes, it) { | ||
if (it === void 0) { it = { offset: 0 }; } | ||
@@ -95,8 +102,8 @@ var changes = []; | ||
} | ||
var type = schema[field]; | ||
var type_1 = schema[field]; | ||
var value = void 0; | ||
var change = void 0; // for triggering onChange | ||
var hasChange = false; | ||
if (type._schema) { | ||
value = this["_" + field] || new type(); | ||
if (type_1._schema) { | ||
value = this["_" + field] || new type_1(); | ||
value.$parent = this; | ||
@@ -106,4 +113,4 @@ value.decode(bytes, it); | ||
} | ||
else if (Array.isArray(type)) { | ||
type = type[0]; | ||
else if (Array.isArray(type_1)) { | ||
type_1 = type_1[0]; | ||
change = []; | ||
@@ -130,3 +137,3 @@ var valueRef = this["_" + field] || []; | ||
// const item = this[`_${field}`][newIndex]; | ||
// TODO: trigger `onRemove` on Sync object being removed. | ||
// TODO: trigger `onRemove` on Schema object being removed. | ||
it.offset++; | ||
@@ -142,6 +149,6 @@ continue; | ||
} | ||
if (type.prototype instanceof Sync) { | ||
if (type_1.prototype instanceof Schema) { | ||
var item = void 0; | ||
if (hasIndexChange && indexChangedFrom === undefined && newIndex !== undefined) { | ||
item = new type(); | ||
item = new type_1(); | ||
} | ||
@@ -155,3 +162,3 @@ else if (indexChangedFrom !== undefined) { | ||
if (!item) { | ||
item = new type(); | ||
item = new type_1(); | ||
} | ||
@@ -163,3 +170,3 @@ item.$parent = this; | ||
else { | ||
value[newIndex] = decodePrimitiveType(type, bytes, it); | ||
value[newIndex] = decodePrimitiveType(type_1, bytes, it); | ||
} | ||
@@ -169,4 +176,4 @@ change.push(value[newIndex]); | ||
} | ||
else if (type.map) { | ||
type = type.map; | ||
else if (type_1.map) { | ||
type_1 = type_1.map; | ||
var valueRef = this["_" + field] || {}; | ||
@@ -193,3 +200,3 @@ value = Object.assign({}, valueRef); | ||
if (hasIndexChange && previousKey === undefined && hasMapIndex) { | ||
item = new type(); | ||
item = new type_1(); | ||
} | ||
@@ -202,8 +209,8 @@ else if (previousKey !== undefined) { | ||
} | ||
if (!item) { | ||
item = new type(); | ||
if (!item && type_1 !== "string") { | ||
item = new type_1(); | ||
} | ||
if (decode.nilCheck(bytes, it)) { | ||
it.offset++; | ||
if (item.onRemove) { | ||
if (item && item.onRemove) { | ||
item.onRemove(); | ||
@@ -214,2 +221,5 @@ } | ||
} | ||
else if (type_1 === "string") { | ||
value[newKey] = decodePrimitiveType(type_1, bytes, it); | ||
} | ||
else { | ||
@@ -223,3 +233,3 @@ item.$parent = this; | ||
else { | ||
value = decodePrimitiveType(type, bytes, it); | ||
value = decodePrimitiveType(type_1, bytes, it); | ||
hasChange = true; | ||
@@ -242,3 +252,3 @@ } | ||
}; | ||
Sync.prototype.encode = function (root, encodedBytes) { | ||
Schema.prototype.encode = function (root, encodedBytes) { | ||
if (root === void 0) { root = true; } | ||
@@ -260,3 +270,3 @@ if (encodedBytes === void 0) { encodedBytes = []; } | ||
var bytes = []; | ||
var type = schema[field]; | ||
var type_2 = schema[field]; | ||
var value = this.$changes[field]; | ||
@@ -268,3 +278,3 @@ var fieldIndex = indexes[field]; | ||
} | ||
if (type._schema) { | ||
if (type_2._schema) { | ||
encode.number(bytes, fieldIndex); | ||
@@ -280,3 +290,3 @@ // encode child object | ||
} | ||
else if (Array.isArray(type)) { | ||
else if (Array.isArray(type_2)) { | ||
encode.number(bytes, fieldIndex); | ||
@@ -291,3 +301,3 @@ // total of items in the array | ||
var item = this["_" + field][index]; | ||
if (typeof (type[0]) !== "string") { // is array of Sync | ||
if (typeof (type_2[0]) !== "string") { // is array of Schema | ||
encode.number(bytes, index); | ||
@@ -311,3 +321,3 @@ if (item === undefined) { | ||
encode.number(bytes, i); | ||
if (!encodePrimitiveType(type[0], bytes, index)) { | ||
if (!encodePrimitiveType(type_2[0], bytes, index)) { | ||
console.log("cannot encode", schema[field]); | ||
@@ -319,3 +329,3 @@ continue; | ||
} | ||
else if (type.map) { | ||
else if (type_2.map) { | ||
encode.number(bytes, fieldIndex); | ||
@@ -343,3 +353,3 @@ // encode Map of type | ||
} | ||
if (item) { | ||
if (item instanceof Schema) { | ||
item.$parent = this; | ||
@@ -349,2 +359,5 @@ item.$parentField = [field, key]; | ||
} | ||
else if (item !== undefined) { | ||
encodePrimitiveType(type_2.map, bytes, item); | ||
} | ||
else { | ||
@@ -357,3 +370,3 @@ encode.uint8(bytes, spec_1.NIL); | ||
encode.number(bytes, fieldIndex); | ||
if (!encodePrimitiveType(type, bytes, value)) { | ||
if (!encodePrimitiveType(type_2, bytes, value)) { | ||
console.log("cannot encode", schema[field]); | ||
@@ -365,3 +378,3 @@ continue; | ||
} | ||
// flag end of Sync object structure | ||
// flag end of Schema object structure | ||
endStructure(); | ||
@@ -372,6 +385,6 @@ this.$changed = false; | ||
}; | ||
return Sync; | ||
return Schema; | ||
}()); | ||
exports.Sync = Sync; | ||
function sync(type) { | ||
exports.Schema = Schema; | ||
function type(type) { | ||
return function (target, field) { | ||
@@ -424,5 +437,12 @@ var constructor = target.constructor; | ||
} | ||
setValue.$parent = _this; | ||
setValue.$parentField = [field, key]; | ||
_this.markAsChanged(field, setValue); | ||
if (setValue instanceof Schema) { | ||
setValue.$parent = _this; | ||
setValue.$parentField = [field, key]; | ||
_this.markAsChanged(field, setValue); | ||
} | ||
else { | ||
obj[prop] = setValue; | ||
// console.log("setValue:", obj, setValue) | ||
_this.markAsChanged(field, obj); | ||
} | ||
} | ||
@@ -462,3 +482,3 @@ else if (setValue !== obj[prop]) { | ||
for (var i = 0; i < length; i++) { | ||
if (value[i] instanceof Sync) { | ||
if (value[i] instanceof Schema) { | ||
value[i].$parent = this; | ||
@@ -473,9 +493,14 @@ value[i].$parentField = [field, i]; | ||
for (var key in value) { | ||
value[key].$parent = this; | ||
value[key].$parentField = [field, key]; | ||
this.markAsChanged(field, value[key]); | ||
if (value[key] instanceof Schema) { | ||
value[key].$parent = this; | ||
value[key].$parentField = [field, key]; | ||
this.markAsChanged(field, value[key]); | ||
} | ||
else { | ||
this.markAsChanged(field, key); | ||
} | ||
} | ||
} | ||
else if (typeof (constructor._schema[field]) === "function") { | ||
// directly assigning a `Sync` object | ||
// directly assigning a `Schema` object | ||
value.$parent = this; | ||
@@ -495,2 +520,2 @@ value.$parentField = field; | ||
} | ||
exports.sync = sync; | ||
exports.type = type; |
@@ -1,1 +0,1 @@ | ||
export { Sync, sync, DataChange, PrimitiveType, Schema, SchemaType } from "./annotations"; | ||
export { Schema, type, DataChange, PrimitiveType, Definition, DefinitionType, } from "./annotations"; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var annotations_1 = require("./annotations"); | ||
exports.Sync = annotations_1.Sync; | ||
exports.sync = annotations_1.sync; | ||
exports.Schema = annotations_1.Schema; | ||
exports.type = annotations_1.type; |
{ | ||
"name": "@colyseus/schema", | ||
"version": "0.1.5", | ||
"version": "0.1.6", | ||
"description": "", | ||
@@ -11,3 +11,5 @@ "main": "lib/index.js", | ||
}, | ||
"files": ["lib"], | ||
"files": [ | ||
"lib" | ||
], | ||
"repository": { | ||
@@ -17,3 +19,8 @@ "url": "git://github.com/colyseus/schema.git", | ||
}, | ||
"keywords": ["schema", "binary", "serialization", "netcode"], | ||
"keywords": [ | ||
"schema", | ||
"binary", | ||
"serialization", | ||
"netcode" | ||
], | ||
"author": "Endel Dreyer", | ||
@@ -20,0 +27,0 @@ "license": "MIT", |
@@ -1,7 +0,21 @@ | ||
<img src="logo.png?raw=true" /> | ||
<div align="center"> | ||
<img src="logo.png?raw=true" /> | ||
<br> | ||
<br> | ||
<p> | ||
A binary schema-based serialization algorithm. <br> | ||
Although it was born to solve a <a href="https://github.com/colyseus/colyseus">Colyseus</a> issue, this library can be used standalone. | ||
</p> | ||
<a href="https://travis-ci.org/colyseus/schema"> | ||
<img src="https://img.shields.io/travis/colyseus/schema.svg?style=for-the-badge" alt="Build status" /> | ||
</a> | ||
<a href="https://patreon.com/endel" title="Donate to this project using Patreon"> | ||
<img src="https://img.shields.io/badge/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.herokuapp.com%2Fendel&style=for-the-badge" alt="Patreon donate button"/> | ||
</a> | ||
</div> | ||
> WORK-IN-PROGRESS EXPERIMENT OF A NEW SERIALIZATION ALGORITHM FOR [COLYSEUS](https://github.com/gamestdio/colyseus) | ||
![](https://img.shields.io/travis/colyseus/schema.svg?style=for-the-badge) | ||
Initial thoghts/assumptions: | ||
@@ -23,29 +37,29 @@ - no bottleneck to detect state changes. | ||
```typescript | ||
import { DataChange, Sync, sync } from '@colyseus/schema'; | ||
import { DataChange, Schema, type } from '@colyseus/schema'; | ||
export class Player extends Sync { | ||
@sync("string") | ||
export class Player extends Schema { | ||
@type("string") | ||
name: string; | ||
@sync("number") | ||
@type("number") | ||
x: number; | ||
@sync("number") | ||
@type("number") | ||
y: number; | ||
} | ||
export class State extends Sync { | ||
@sync('string') | ||
export class State extends Schema { | ||
@type('string') | ||
fieldString: string; | ||
@sync('number') // varint | ||
@type('number') // varint | ||
fieldNumber: number; | ||
@sync(Player) | ||
@type(Player) | ||
player: Player; | ||
@sync([ Player ]) | ||
@type([ Player ]) | ||
arrayOfPlayers: Player[]; | ||
@sync({ map: Player }) | ||
@type({ map: Player }) | ||
mapOfPlayers: { [id: string]: Player }; | ||
@@ -76,9 +90,9 @@ } | ||
- `@sync("string") name: string;` | ||
- `@sync("number") level: number;` | ||
- `@sync(Player) player: Player;` | ||
- `@sync([ Player ]) arrayOfPlayers: Player[];` | ||
- `@sync([ "number" ]) arrayOfNumbers: number[];` | ||
- `@sync([ "string" ]) arrayOfStrings: string[];` | ||
- `@sync({ map: Player }) mapOfPlayers: {[id: string]: Player};` | ||
- `@type("string") name: string;` | ||
- `@type("number") level: number;` | ||
- `@type(Player) player: Player;` | ||
- `@type([ Player ]) arrayOfPlayers: Player[];` | ||
- `@type([ "number" ]) arrayOfNumbers: number[];` | ||
- `@type([ "string" ]) arrayOfStrings: string[];` | ||
- `@type({ map: Player }) mapOfPlayers: {[id: string]: Player};` | ||
@@ -88,3 +102,3 @@ ## Limitations and best practices | ||
- Multi-dimensional arrays are not supported. | ||
- Maps are only supported for custom `Sync` types. | ||
- Maps are only supported for custom `Schema` types. | ||
- Array items must all have the same type as defined in the schema. | ||
@@ -91,0 +105,0 @@ - `@colyseus/schema` encodes only field values in the specified order. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
61401
1531
218