@colyseus/schema
Advanced tools
Comparing version 0.3.7 to 0.3.8
import * as decode from "./encoding/decode"; | ||
import { ChangeTree } from './ChangeTree'; | ||
import { ArraySchema } from './types/ArraySchema'; | ||
@@ -34,12 +35,3 @@ /** | ||
static _descriptors: PropertyDescriptorMap & ThisType<any>; | ||
$changed: boolean; | ||
protected $allChanges: { | ||
[key: string]: any; | ||
}; | ||
protected $changes: { | ||
[key: string]: any; | ||
}; | ||
protected $parent: Schema; | ||
protected $parentField: string | (string | number | symbol)[]; | ||
protected $parentIndexChange: number; | ||
protected $changes: ChangeTree; | ||
onChange?(changes: DataChange[]): any; | ||
@@ -56,4 +48,3 @@ onRemove?(): any; | ||
}; | ||
markAsChanged(field: string, value?: Schema | any): void; | ||
markAsUnchanged(): void; | ||
readonly $changed: boolean; | ||
decode(bytes: any, it?: decode.Iterator): this; | ||
@@ -60,0 +51,0 @@ encode(root?: Schema, encodeAll?: boolean, client?: Client): any[]; |
@@ -25,2 +25,3 @@ "use strict"; | ||
var decode = require("./encoding/decode"); | ||
var ChangeTree_1 = require("./ChangeTree"); | ||
var ArraySchema_1 = require("./types/ArraySchema"); | ||
@@ -60,8 +61,3 @@ var MapSchema_1 = require("./types/MapSchema"); | ||
Object.defineProperties(this, { | ||
$changed: { value: false, enumerable: false, writable: true }, | ||
$changes: { value: {}, enumerable: false, writable: true }, | ||
$allChanges: { value: {}, enumerable: false, writable: true }, | ||
$parent: { value: undefined, enumerable: false, writable: true }, | ||
$parentField: { value: undefined, enumerable: false, writable: true }, | ||
$parentIndexChange: { value: undefined, enumerable: false, writable: true }, | ||
$changes: { value: new ChangeTree_1.ChangeTree(), enumerable: false, writable: true }, | ||
}); | ||
@@ -93,86 +89,7 @@ var descriptors = this._descriptors; | ||
}); | ||
Schema.prototype.markAsChanged = function (field, value) { | ||
var fieldSchema = this._schema[field]; | ||
this.$changed = true; | ||
if (value !== undefined) { | ||
if (value && | ||
Array.isArray(value.$parentField) || | ||
fieldSchema && (Array.isArray(fieldSchema) || fieldSchema.map)) { | ||
var $parentField = value && value.$parentField || []; | ||
// used for MAP/ARRAY | ||
var fieldName = ($parentField.length > 0) | ||
? $parentField[0] | ||
: field; | ||
var fieldKey = ($parentField.length > 0) | ||
? $parentField[1] | ||
: value; | ||
if (!this.$changes[fieldName]) { | ||
this.$changes[fieldName] = []; | ||
} | ||
if (!this.$allChanges[fieldName]) { | ||
this.$allChanges[fieldName] = []; | ||
} | ||
if (fieldKey !== undefined) { | ||
// do not store duplicates of changed fields | ||
if (this.$changes[fieldName].indexOf(fieldKey) === -1) { | ||
this.$changes[fieldName].push(fieldKey); | ||
} | ||
if (this.$allChanges[fieldName].indexOf(fieldKey) === -1) { | ||
this.$allChanges[fieldName].push(fieldKey); | ||
} | ||
} | ||
} | ||
else if (value && value.$parentField) { | ||
// used for direct type relationship | ||
this.$changes[value.$parentField] = value; | ||
this.$allChanges[value.$parentField] = value; | ||
} | ||
else { | ||
// basic types | ||
this.$changes[field] = this["_" + field]; | ||
this.$allChanges[field] = this["_" + field]; | ||
} | ||
} | ||
if (this.$parent) { | ||
this.$parent.markAsChanged(field, this); | ||
} | ||
}; | ||
Schema.prototype.markAsUnchanged = function () { | ||
var schema = this._schema; | ||
var changes = this.$changes; | ||
for (var field in changes) { | ||
var type_1 = schema[field]; | ||
var value = changes[field]; | ||
// skip unchagned fields | ||
if (value === undefined) { | ||
continue; | ||
} | ||
if (type_1._schema) { | ||
value.markAsUnchanged(); | ||
} | ||
else if (Array.isArray(type_1)) { | ||
// encode Array of type | ||
for (var i = 0, l = value.length; i < l; i++) { | ||
var index = value[i]; | ||
var item = this["_" + field][index]; | ||
if (typeof (type_1[0]) !== "string") { // is array of Schema | ||
item.markAsUnchanged(); | ||
} | ||
} | ||
} | ||
else if (type_1.map) { | ||
var keys = value; | ||
var mapKeys = Object.keys(this["_" + field]); | ||
for (var i = 0; i < keys.length; i++) { | ||
var key = mapKeys[keys[i]] || keys[i]; | ||
var item = this["_" + field][key]; | ||
if (item instanceof Schema) { | ||
item.markAsUnchanged(); | ||
} | ||
} | ||
} | ||
} | ||
this.$changed = false; | ||
this.$changes = {}; | ||
}; | ||
Object.defineProperty(Schema.prototype, "$changed", { | ||
get: function () { return this.$changes.changed; }, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Schema.prototype.decode = function (bytes, it) { | ||
@@ -195,7 +112,7 @@ if (it === void 0) { it = { offset: 0 }; } | ||
var field = fieldsByIndex[index]; | ||
var type_2 = schema[field]; | ||
var type_1 = schema[field]; | ||
var value = void 0; | ||
var change = void 0; // for triggering onChange | ||
var hasChange = false; | ||
if (type_2._schema) { | ||
if (type_1._schema) { | ||
if (decode.nilCheck(bytes, it)) { | ||
@@ -206,3 +123,3 @@ it.offset++; | ||
else { | ||
value = this_1["_" + field] || new type_2(); | ||
value = this_1["_" + field] || new type_1(); | ||
value.$parent = this_1; | ||
@@ -213,4 +130,4 @@ value.decode(bytes, it); | ||
} | ||
else if (Array.isArray(type_2)) { | ||
type_2 = type_2[0]; | ||
else if (Array.isArray(type_1)) { | ||
type_1 = type_1[0]; | ||
change = []; | ||
@@ -245,7 +162,7 @@ var valueRef_1 = this_1["_" + field] || new ArraySchema_1.ArraySchema(); | ||
} | ||
if (type_2.prototype instanceof Schema) { | ||
if (type_1.prototype instanceof Schema) { | ||
var item = void 0; | ||
var isNew = (hasIndexChange && indexChangedFrom === undefined && newIndex !== undefined); | ||
if (isNew) { | ||
item = new type_2(); | ||
item = new type_1(); | ||
} | ||
@@ -259,3 +176,3 @@ else if (indexChangedFrom !== undefined) { | ||
if (!item) { | ||
item = new type_2(); | ||
item = new type_1(); | ||
isNew = true; | ||
@@ -278,3 +195,3 @@ } | ||
else { | ||
value[newIndex] = decodePrimitiveType(type_2, bytes, it); | ||
value[newIndex] = decodePrimitiveType(type_1, bytes, it); | ||
} | ||
@@ -284,4 +201,4 @@ change.push(value[newIndex]); | ||
} | ||
else if (type_2.map) { | ||
type_2 = type_2.map; | ||
else if (type_1.map) { | ||
type_1 = type_1.map; | ||
var valueRef = this_1["_" + field] || new MapSchema_1.MapSchema(); | ||
@@ -316,3 +233,3 @@ value = valueRef.clone(); | ||
if (hasIndexChange && previousKey === undefined && hasMapIndex) { | ||
item = new type_2(); | ||
item = new type_1(); | ||
} | ||
@@ -325,4 +242,4 @@ else if (previousKey !== undefined) { | ||
} | ||
if (!item && type_2 !== "string") { | ||
item = new type_2(); | ||
if (!item && type_1 !== "string") { | ||
item = new type_1(); | ||
isNew = true; | ||
@@ -341,4 +258,4 @@ } | ||
} | ||
else if (type_2 === "string") { | ||
value[newKey] = decodePrimitiveType(type_2, bytes, it); | ||
else if (type_1 === "string") { | ||
value[newKey] = decodePrimitiveType(type_1, bytes, it); | ||
} | ||
@@ -359,3 +276,3 @@ else { | ||
else { | ||
value = decodePrimitiveType(type_2, bytes, it); | ||
value = decodePrimitiveType(type_1, bytes, it); | ||
hasChange = true; | ||
@@ -394,3 +311,3 @@ } | ||
// skip if nothing has changed | ||
if (!this.$changed && !encodeAll) { | ||
if (!this.$changes.changed && !encodeAll) { | ||
endStructure(); | ||
@@ -402,10 +319,11 @@ return encodedBytes; | ||
var filters = this._filters; | ||
var changes = (encodeAll) | ||
? this.$allChanges | ||
: this.$changes; | ||
for (var field in changes) { | ||
var bytes = []; | ||
var type_3 = schema[field]; | ||
var changes = (encodeAll || client) | ||
? this.$changes.allChanges | ||
: this.$changes.changes; | ||
for (var i = 0, l = changes.length; i < l; i++) { | ||
var field = changes[i]; | ||
var type_2 = schema[field]; | ||
var filter_1 = (filters && filters[field]); | ||
var value = (filter_1 && this.$allChanges[field]) || changes[field]; | ||
// const value = (filter && this.$allChanges[field]) || changes[field]; | ||
var value = this["_" + field]; | ||
var fieldIndex = indexes[field]; | ||
@@ -416,3 +334,4 @@ // skip unchagned fields | ||
} | ||
if (type_3._schema) { | ||
var bytes = []; | ||
if (type_2._schema) { | ||
if (client && filter_1) { | ||
@@ -440,11 +359,14 @@ // skip if not allowed by custom filter | ||
} | ||
else if (Array.isArray(type_3)) { | ||
else if (Array.isArray(type_2)) { | ||
encode.number(bytes, fieldIndex); | ||
// total of items in the array | ||
encode.number(bytes, this["_" + field].length); | ||
encode.number(bytes, value.length); | ||
var arrayChanges = (encodeAll || client) | ||
? value.$changes.allChanges | ||
: value.$changes.changes; | ||
// number of changed items | ||
encode.number(bytes, value.length); | ||
encode.number(bytes, arrayChanges.length); | ||
// encode Array of type | ||
for (var i = 0, l = value.length; i < l; i++) { | ||
var index = value[i]; | ||
for (var j = 0; j < arrayChanges.length; j++) { | ||
var index = arrayChanges[j]; | ||
var item = this["_" + field][index]; | ||
@@ -457,3 +379,3 @@ if (client && filter_1) { | ||
} | ||
if (typeof (type_3[0]) !== "string") { // is array of Schema | ||
if (typeof (type_2[0]) !== "string") { // is array of Schema | ||
encode.number(bytes, index); | ||
@@ -464,16 +386,12 @@ if (item === undefined) { | ||
} | ||
if (item.$parentIndexChange >= 0) { | ||
var indexChange = value.$changes.getIndexChange(item); | ||
if (indexChange !== undefined) { | ||
encode.uint8(bytes, spec_1.INDEX_CHANGE); | ||
encode.number(bytes, item.$parentIndexChange); | ||
item.$parentIndexChange = undefined; // reset | ||
encode.number(bytes, indexChange); | ||
} | ||
if (!item.$parent) { | ||
item.$parent = this; | ||
item.$parentField = [field, i]; | ||
} | ||
bytes = bytes.concat(item.encode(root, encodeAll, client)); | ||
} | ||
else { | ||
encode.number(bytes, i); | ||
if (!encodePrimitiveType(type_3[0], bytes, index)) { | ||
encode.number(bytes, index); | ||
if (!encodePrimitiveType(type_2[0], bytes, item)) { | ||
console.log("cannot encode", schema[field]); | ||
@@ -484,11 +402,15 @@ continue; | ||
} | ||
value.$changes.discard(); | ||
} | ||
else if (type_3.map) { | ||
else if (type_2.map) { | ||
// encode Map of type | ||
encode.number(bytes, fieldIndex); | ||
var keys = value; // TODO: during `encodeAll`, removed entries are not going to be encoded | ||
// TODO: during `encodeAll`, removed entries are not going to be encoded | ||
var keys = (encodeAll || client) | ||
? value.$changes.allChanges | ||
: value.$changes.changes; | ||
encode.number(bytes, keys.length); | ||
var mapKeys = Object.keys(this["_" + field]); | ||
for (var i = 0; i < keys.length; i++) { | ||
var key = mapKeys[keys[i]] || keys[i]; | ||
for (var i_1 = 0; i_1 < keys.length; i_1++) { | ||
var key = mapKeys[keys[i_1]] || keys[i_1]; | ||
var item = this["_" + field][key]; | ||
@@ -512,6 +434,6 @@ var mapItemIndex = this["_" + field]._indexes[key]; | ||
// encode index change | ||
if (item && item.$parentIndexChange >= 0) { | ||
var indexChange = value.$changes.getIndexChange(item); | ||
if (item && indexChange !== undefined) { | ||
encode.uint8(bytes, spec_1.INDEX_CHANGE); | ||
encode.number(bytes, item.$parentIndexChange); | ||
item.$parentIndexChange = undefined; // reset | ||
encode.number(bytes, this["_" + field]._indexes[indexChange]); | ||
} | ||
@@ -524,14 +446,8 @@ if (mapItemIndex !== undefined) { | ||
encode.string(bytes, key); | ||
// const mapKey = mapKeys.indexOf(key); | ||
// if (!client && mapKey >= 0) { | ||
// this[`_${field}`]._indexes[key] = mapKey; | ||
// } | ||
} | ||
if (item instanceof Schema) { | ||
item.$parent = this; | ||
item.$parentField = [field, keys[i]]; | ||
bytes = bytes.concat(item.encode(root, encodeAll, client)); | ||
} | ||
else if (item !== undefined) { | ||
encodePrimitiveType(type_3.map, bytes, item); | ||
encodePrimitiveType(type_2.map, bytes, item); | ||
} | ||
@@ -542,2 +458,3 @@ else { | ||
} | ||
value.$changes.discard(); | ||
// TODO: track array/map indexes per client? | ||
@@ -556,3 +473,3 @@ if (!client) { | ||
encode.number(bytes, fieldIndex); | ||
if (!encodePrimitiveType(type_3, bytes, value)) { | ||
if (!encodePrimitiveType(type_2, bytes, value)) { | ||
console.log("cannot encode", schema[field]); | ||
@@ -567,4 +484,3 @@ continue; | ||
if (!client) { | ||
this.$changed = false; | ||
this.$changes = {}; | ||
this.$changes.discard(); | ||
} | ||
@@ -779,3 +695,2 @@ return encodedBytes; | ||
set: function (value) { | ||
var _this = this; | ||
/** | ||
@@ -788,23 +703,22 @@ * Create Proxy for array or map items | ||
set: function (obj, prop, setValue) { | ||
if (prop !== "length") { | ||
if (prop !== "length" && prop !== "$changes") { | ||
// ensure new value has a parent | ||
var key = (isArray) ? Number(prop) : String(prop); | ||
if (setValue.$parentField && setValue.$parentField[1] !== key) { | ||
if (isMap) { | ||
var indexChange = _this["" + fieldCached]._indexes[setValue.$parentField[1]]; | ||
setValue.$parentIndexChange = indexChange; | ||
} | ||
else { | ||
setValue.$parentIndexChange = setValue.$parentField[1]; | ||
} | ||
var previousIndex = obj.$changes.getIndex(setValue); | ||
if (previousIndex !== undefined) { | ||
obj.$changes.mapIndexChange(setValue, previousIndex); | ||
} | ||
obj.$changes.mapIndex(setValue, key); | ||
if (setValue instanceof Schema) { | ||
setValue.$parent = _this; | ||
setValue.$parentField = [field, key]; | ||
_this.markAsChanged(field, setValue); | ||
// new items are flagged with all changes | ||
if (!setValue.$changes.parent) { | ||
setValue.$changes = new ChangeTree_1.ChangeTree(key, obj.$changes); | ||
setValue.$changes.changeAll(setValue); | ||
} | ||
} | ||
else { | ||
obj[prop] = setValue; | ||
_this.markAsChanged(field, obj); | ||
} | ||
// apply change on ArraySchema / MapSchema | ||
obj.$changes.change(key); | ||
} | ||
@@ -819,8 +733,10 @@ else if (setValue !== obj[prop]) { | ||
deleteProperty: function (obj, prop) { | ||
var previousValue = obj[prop]; | ||
var deletedValue = obj[prop]; | ||
// TODO: | ||
// remove deleteIndex of property being deleted as well. | ||
// obj.$changes.deleteIndex(deletedValue); | ||
// obj.$changes.deleteIndexChange(deletedValue); | ||
delete obj[prop]; | ||
// ensure new value has a parent | ||
if (previousValue && previousValue.$parent) { | ||
previousValue.$parent.markAsChanged(field, previousValue); | ||
} | ||
var key = (isArray) ? Number(prop) : String(prop); | ||
obj.$changes.change(key); | ||
return true; | ||
@@ -837,15 +753,11 @@ }, | ||
// directly assigning an array of items as value. | ||
var length = value.length; | ||
if (length === 0) { | ||
// FIXME: this is a bit confusing. | ||
// Needed to allow encoding an empty array. | ||
this.markAsChanged(field, { $parentField: [field] }); | ||
return; | ||
} | ||
for (var i = 0; i < length; i++) { | ||
this.$changes.change(field); | ||
value.$changes = new ChangeTree_1.ChangeTree(field, this.$changes); | ||
for (var i = 0; i < value.length; i++) { | ||
if (value[i] instanceof Schema) { | ||
value[i].$parent = this; | ||
value[i].$parentField = [field, i]; | ||
value[i].$changes = new ChangeTree_1.ChangeTree(i, value.$changes); | ||
value[i].$changes.changeAll(value[i]); | ||
} | ||
this.markAsChanged(field, value[i]); | ||
value.$changes.mapIndex(value[i], i); | ||
value.$changes.change(i); | ||
} | ||
@@ -855,11 +767,11 @@ } | ||
// directly assigning a map | ||
value.$changes = new ChangeTree_1.ChangeTree(field, this.$changes); | ||
this.$changes.change(field); | ||
for (var key in value) { | ||
if (value[key] instanceof Schema) { | ||
value[key].$parent = this; | ||
value[key].$parentField = [field, key]; | ||
this.markAsChanged(field, value[key]); | ||
value[key].$changes = new ChangeTree_1.ChangeTree(key, value.$changes); | ||
value[key].$changes.changeAll(value[key]); | ||
} | ||
else { | ||
this.markAsChanged(field, key); | ||
} | ||
value.$changes.mapIndex(value[key], key); | ||
value.$changes.change(key); | ||
} | ||
@@ -870,11 +782,11 @@ } | ||
// value may be set to null | ||
this.$changes.change(field); | ||
if (value) { | ||
value.$parent = this; | ||
value.$parentField = field; | ||
value.$changes = new ChangeTree_1.ChangeTree(field, this.$changes); | ||
value.$changes.changeAll(value); | ||
} | ||
this.markAsChanged(field, value); | ||
} | ||
else { | ||
// directly assigning a primitive type | ||
this.markAsChanged(field, value); | ||
this.$changes.change(field); | ||
} | ||
@@ -881,0 +793,0 @@ }, |
@@ -0,3 +1,5 @@ | ||
import { ChangeTree } from "../ChangeTree"; | ||
export declare class ArraySchema<T = any> extends Array<T> { | ||
static readonly [Symbol.species]: ArrayConstructor; | ||
protected $changes: ChangeTree; | ||
constructor(...items: T[]); | ||
@@ -4,0 +6,0 @@ clone: () => ArraySchema<T>; |
@@ -16,2 +16,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var ChangeTree_1 = require("../ChangeTree"); | ||
var ArraySchema = /** @class */ (function (_super) { | ||
@@ -27,2 +28,3 @@ __extends(ArraySchema, _super); | ||
Object.defineProperties(_this, { | ||
$changes: { value: new ChangeTree_1.ChangeTree(), enumerable: false, writable: true }, | ||
onAdd: { value: undefined, enumerable: false, writable: true }, | ||
@@ -29,0 +31,0 @@ onRemove: { value: undefined, enumerable: false, writable: true }, |
@@ -0,2 +1,4 @@ | ||
import { ChangeTree } from "../ChangeTree"; | ||
export declare class MapSchema<T = any> { | ||
protected $changes: ChangeTree; | ||
constructor(obj?: any); | ||
@@ -3,0 +5,0 @@ [key: string]: T | any; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var ChangeTree_1 = require("../ChangeTree"); | ||
var MapSchema = /** @class */ (function () { | ||
@@ -11,2 +12,3 @@ function MapSchema(obj) { | ||
Object.defineProperties(this, { | ||
$changes: { value: new ChangeTree_1.ChangeTree(), enumerable: false, writable: true }, | ||
onAdd: { value: undefined, enumerable: false, writable: true }, | ||
@@ -18,3 +20,2 @@ onRemove: { value: undefined, enumerable: false, writable: true }, | ||
var map = Object.assign(new MapSchema(), _this); | ||
; | ||
map.onAdd = _this.onAdd; | ||
@@ -21,0 +22,0 @@ map.onRemove = _this.onRemove; |
{ | ||
"name": "@colyseus/schema", | ||
"version": "0.3.7", | ||
"description": "Schema-based binary serializer / de-serializer. ", | ||
"version": "0.3.8", | ||
"description": "Schema-based binary serializer / de-serializer.", | ||
"main": "lib/index.js", | ||
@@ -27,2 +27,3 @@ "types": "lib/index.d.ts", | ||
"serialization", | ||
"serializer", | ||
"netcode" | ||
@@ -29,0 +30,0 @@ ], |
92983
32
2319