@tamgl/colyseus-schema
Version:
Binary state serializer with delta encoding for games
143 lines • 5.43 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.encodeArray = exports.encodeKeyValueOperation = exports.encodeSchemaOperation = void 0;
exports.encodeValue = encodeValue;
const spec_1 = require("../encoding/spec");
const symbols_1 = require("../types/symbols");
const encode_1 = require("../encoding/encode");
function encodeValue(encoder, bytes, type, value, operation, it) {
if (typeof (type) === "string") {
encode_1.encode[type]?.(bytes, value, it);
}
else if (type[Symbol.metadata] !== undefined) {
//
// Encode refId for this instance.
// The actual instance is going to be encoded on next `changeTree` iteration.
//
encode_1.encode.number(bytes, value[symbols_1.$changes].refId, it);
// Try to encode inherited TYPE_ID if it's an ADD operation.
if ((operation & spec_1.OPERATION.ADD) === spec_1.OPERATION.ADD) {
encoder.tryEncodeTypeId(bytes, type, value.constructor, it);
}
}
else {
//
// Encode refId for this instance.
// The actual instance is going to be encoded on next `changeTree` iteration.
//
encode_1.encode.number(bytes, value[symbols_1.$changes].refId, it);
}
}
/**
* Used for Schema instances.
* @private
*/
const encodeSchemaOperation = function (encoder, bytes, changeTree, index, operation, it, _, __, metadata) {
// "compress" field index + operation
bytes[it.offset++] = (index | operation) & 255;
// Do not encode value for DELETE operations
if (operation === spec_1.OPERATION.DELETE) {
return;
}
const ref = changeTree.ref;
const field = metadata[index];
// TODO: inline this function call small performance gain
encodeValue(encoder, bytes, metadata[index].type, ref[field.name], operation, it);
};
exports.encodeSchemaOperation = encodeSchemaOperation;
/**
* Used for collections (MapSchema, CollectionSchema, SetSchema)
* @private
*/
const encodeKeyValueOperation = function (encoder, bytes, changeTree, index, operation, it) {
// encode operation
bytes[it.offset++] = operation & 255;
// custom operations
if (operation === spec_1.OPERATION.CLEAR) {
return;
}
// encode index
encode_1.encode.number(bytes, index, it);
// Do not encode value for DELETE operations
if (operation === spec_1.OPERATION.DELETE) {
return;
}
const ref = changeTree.ref;
//
// encode "alias" for dynamic fields (maps)
//
if ((operation & spec_1.OPERATION.ADD) === spec_1.OPERATION.ADD) { // ADD or DELETE_AND_ADD
if (typeof (ref['set']) === "function") {
//
// MapSchema dynamic key
//
const dynamicIndex = changeTree.ref['$indexes'].get(index);
encode_1.encode.string(bytes, dynamicIndex, it);
}
}
const type = ref[symbols_1.$childType];
const value = ref[symbols_1.$getByIndex](index);
// try { throw new Error(); } catch (e) {
// // only print if not coming from Reflection.ts
// if (!e.stack.includes("src/Reflection.ts")) {
// console.log("encodeKeyValueOperation -> ", {
// ref: changeTree.ref.constructor.name,
// field,
// operation: OPERATION[operation],
// value: value?.toJSON(),
// items: ref.toJSON(),
// });
// }
// }
// TODO: inline this function call small performance gain
encodeValue(encoder, bytes, type, value, operation, it);
};
exports.encodeKeyValueOperation = encodeKeyValueOperation;
/**
* Used for collections (MapSchema, ArraySchema, etc.)
* @private
*/
const encodeArray = function (encoder, bytes, changeTree, field, operation, it, isEncodeAll, hasView) {
const ref = changeTree.ref;
const useOperationByRefId = hasView && changeTree.isFiltered && (typeof (changeTree.getType(field)) !== "string");
let refOrIndex;
if (useOperationByRefId) {
refOrIndex = ref['tmpItems'][field][symbols_1.$changes].refId;
if (operation === spec_1.OPERATION.DELETE) {
operation = spec_1.OPERATION.DELETE_BY_REFID;
}
else if (operation === spec_1.OPERATION.ADD) {
operation = spec_1.OPERATION.ADD_BY_REFID;
}
}
else {
refOrIndex = field;
}
// encode operation
bytes[it.offset++] = operation & 255;
// custom operations
if (operation === spec_1.OPERATION.CLEAR ||
operation === spec_1.OPERATION.REVERSE) {
return;
}
// encode index
encode_1.encode.number(bytes, refOrIndex, it);
// Do not encode value for DELETE operations
if (operation === spec_1.OPERATION.DELETE || operation === spec_1.OPERATION.DELETE_BY_REFID) {
return;
}
const type = changeTree.getType(field);
const value = changeTree.getValue(field, isEncodeAll);
// console.log({ type, field, value });
// console.log("encodeArray -> ", {
// ref: changeTree.ref.constructor.name,
// field,
// operation: OPERATION[operation],
// value: value?.toJSON(),
// items: ref.toJSON(),
// });
// TODO: inline this function call small performance gain
encodeValue(encoder, bytes, type, value, operation, it);
};
exports.encodeArray = encodeArray;
//# sourceMappingURL=EncodeOperation.js.map