UNPKG

@tamgl/colyseus-schema

Version:

Binary state serializer with delta encoding for games

121 lines 4.78 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Decoder = void 0; const TypeContext_1 = require("../types/TypeContext"); const symbols_1 = require("../types/symbols"); const Schema_1 = require("../Schema"); const decode_1 = require("../encoding/decode"); const spec_1 = require("../encoding/spec"); const ReferenceTracker_1 = require("./ReferenceTracker"); const DecodeOperation_1 = require("./DecodeOperation"); class Decoder { constructor(root, context) { this.currentRefId = 0; this.setState(root); this.context = context || new TypeContext_1.TypeContext(root.constructor); // console.log(">>>>>>>>>>>>>>>> Decoder types"); // this.context.schemas.forEach((id, schema) => { // console.log("type:", id, schema.name, Object.keys(schema[Symbol.metadata])); // }); } setState(root) { this.state = root; this.root = new ReferenceTracker_1.ReferenceTracker(); this.root.addRef(0, root); } decode(bytes, it = { offset: 0 }, ref = this.state) { const allChanges = []; const $root = this.root; const totalBytes = bytes.byteLength; let decoder = ref['constructor'][symbols_1.$decoder]; this.currentRefId = 0; while (it.offset < totalBytes) { // // Peek ahead, check if it's a switch to a different structure // if (bytes[it.offset] == spec_1.SWITCH_TO_STRUCTURE) { it.offset++; const nextRefId = decode_1.decode.number(bytes, it); const nextRef = $root.refs.get(nextRefId); // // Trying to access a reference that haven't been decoded yet. // if (!nextRef) { console.error(`"refId" not found: ${nextRefId}`, { previousRef: ref, previousRefId: this.currentRefId }); console.warn("Please report this to the developers. All refIds =>"); console.warn(Schema_1.Schema.debugRefIdsDecoder(this)); this.skipCurrentStructure(bytes, it, totalBytes); } ref[symbols_1.$onDecodeEnd]?.(); this.currentRefId = nextRefId; ref = nextRef; decoder = ref.constructor[symbols_1.$decoder]; continue; } const result = decoder(this, bytes, it, ref, allChanges); if (result === DecodeOperation_1.DEFINITION_MISMATCH) { console.warn("@colyseus/schema: definition mismatch"); this.skipCurrentStructure(bytes, it, totalBytes); continue; } } // FIXME: DRY with SWITCH_TO_STRUCTURE block. ref[symbols_1.$onDecodeEnd]?.(); // trigger changes this.triggerChanges?.(allChanges); // drop references of unused schemas $root.garbageCollectDeletedRefs(); return allChanges; } skipCurrentStructure(bytes, it, totalBytes) { // // keep skipping next bytes until reaches a known structure // by local decoder. // const nextIterator = { offset: it.offset }; while (it.offset < totalBytes) { if (bytes[it.offset] === spec_1.SWITCH_TO_STRUCTURE) { nextIterator.offset = it.offset + 1; if (this.root.refs.has(decode_1.decode.number(bytes, nextIterator))) { break; } } it.offset++; } } getInstanceType(bytes, it, defaultType) { let type; if (bytes[it.offset] === spec_1.TYPE_ID) { it.offset++; const type_id = decode_1.decode.number(bytes, it); type = this.context.get(type_id); } return type || defaultType; } createInstanceOfType(type) { // let instance: Schema = new (type as any)(); // // assign root on $changes // instance[$changes].root = this.root[$changes].root; // return instance; return new type(); } removeChildRefs(ref, allChanges) { const needRemoveRef = typeof (ref[symbols_1.$childType]) !== "string"; const refId = this.root.refIds.get(ref); ref.forEach((value, key) => { allChanges.push({ ref: ref, refId, op: spec_1.OPERATION.DELETE, field: key, value: undefined, previousValue: value }); if (needRemoveRef) { this.root.removeRef(this.root.refIds.get(value)); } }); } } exports.Decoder = Decoder; //# sourceMappingURL=Decoder.js.map