UNPKG

@tamgl/colyseus-schema

Version:

Binary state serializer with delta encoding for games

303 lines 8.91 kB
"use strict"; /** * Copyright (c) 2018 Endel Dreyer * Copyright (c) 2014 Ion Drive Software Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE */ Object.defineProperty(exports, "__esModule", { value: true }); exports.encode = void 0; /** * msgpack implementation highly based on notepack.io * https://github.com/darrachequesne/notepack */ let textEncoder; // @ts-ignore try { textEncoder = new TextEncoder(); } catch (e) { } // force little endian to facilitate decoding on multiple implementations const _isLittleEndian = true; // new Uint16Array(new Uint8Array([1, 0]).buffer)[0] === 1; const _convoBuffer = new ArrayBuffer(8); const _int32 = new Int32Array(_convoBuffer); const _float32 = new Float32Array(_convoBuffer); const _float64 = new Float64Array(_convoBuffer); const _int64 = new BigInt64Array(_convoBuffer); const hasBufferByteLength = (typeof Buffer !== 'undefined' && Buffer.byteLength); const utf8Length = (hasBufferByteLength) ? Buffer.byteLength // node : function (str, _) { var c = 0, length = 0; for (var i = 0, l = str.length; i < l; i++) { c = str.charCodeAt(i); if (c < 0x80) { length += 1; } else if (c < 0x800) { length += 2; } else if (c < 0xd800 || c >= 0xe000) { length += 3; } else { i++; length += 4; } } return length; }; function utf8Write(view, str, it) { var c = 0; for (var i = 0, l = str.length; i < l; i++) { c = str.charCodeAt(i); if (c < 0x80) { view[it.offset++] = c; } else if (c < 0x800) { view[it.offset] = 0xc0 | (c >> 6); view[it.offset + 1] = 0x80 | (c & 0x3f); it.offset += 2; } else if (c < 0xd800 || c >= 0xe000) { view[it.offset] = 0xe0 | (c >> 12); view[it.offset + 1] = 0x80 | (c >> 6 & 0x3f); view[it.offset + 2] = 0x80 | (c & 0x3f); it.offset += 3; } else { i++; c = 0x10000 + (((c & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff)); view[it.offset] = 0xf0 | (c >> 18); view[it.offset + 1] = 0x80 | (c >> 12 & 0x3f); view[it.offset + 2] = 0x80 | (c >> 6 & 0x3f); view[it.offset + 3] = 0x80 | (c & 0x3f); it.offset += 4; } } } function int8(bytes, value, it) { bytes[it.offset++] = value & 255; } ; function uint8(bytes, value, it) { bytes[it.offset++] = value & 255; } ; function int16(bytes, value, it) { bytes[it.offset++] = value & 255; bytes[it.offset++] = (value >> 8) & 255; } ; function uint16(bytes, value, it) { bytes[it.offset++] = value & 255; bytes[it.offset++] = (value >> 8) & 255; } ; function int32(bytes, value, it) { bytes[it.offset++] = value & 255; bytes[it.offset++] = (value >> 8) & 255; bytes[it.offset++] = (value >> 16) & 255; bytes[it.offset++] = (value >> 24) & 255; } ; function uint32(bytes, value, it) { const b4 = value >> 24; const b3 = value >> 16; const b2 = value >> 8; const b1 = value; bytes[it.offset++] = b1 & 255; bytes[it.offset++] = b2 & 255; bytes[it.offset++] = b3 & 255; bytes[it.offset++] = b4 & 255; } ; function int64(bytes, value, it) { const high = Math.floor(value / Math.pow(2, 32)); const low = value >>> 0; uint32(bytes, low, it); uint32(bytes, high, it); } ; function uint64(bytes, value, it) { const high = (value / Math.pow(2, 32)) >> 0; const low = value >>> 0; uint32(bytes, low, it); uint32(bytes, high, it); } ; function bigint64(bytes, value, it) { _int64[0] = BigInt.asIntN(64, value); int32(bytes, _int32[0], it); int32(bytes, _int32[1], it); } function biguint64(bytes, value, it) { _int64[0] = BigInt.asIntN(64, value); int32(bytes, _int32[0], it); int32(bytes, _int32[1], it); } function float32(bytes, value, it) { _float32[0] = value; int32(bytes, _int32[0], it); } function float64(bytes, value, it) { _float64[0] = value; int32(bytes, _int32[_isLittleEndian ? 0 : 1], it); int32(bytes, _int32[_isLittleEndian ? 1 : 0], it); } function boolean(bytes, value, it) { bytes[it.offset++] = value ? 1 : 0; // uint8 } ; function string(bytes, value, it) { // encode `null` strings as empty. if (!value) { value = ""; } let length = utf8Length(value, "utf8"); let size = 0; // fixstr if (length < 0x20) { bytes[it.offset++] = length | 0xa0; size = 1; } // str 8 else if (length < 0x100) { bytes[it.offset++] = 0xd9; bytes[it.offset++] = length % 255; size = 2; } // str 16 else if (length < 0x10000) { bytes[it.offset++] = 0xda; uint16(bytes, length, it); size = 3; } // str 32 else if (length < 0x100000000) { bytes[it.offset++] = 0xdb; uint32(bytes, length, it); size = 5; } else { throw new Error('String too long'); } utf8Write(bytes, value, it); return size + length; } function number(bytes, value, it) { if (isNaN(value)) { return number(bytes, 0, it); } else if (!isFinite(value)) { return number(bytes, (value > 0) ? Number.MAX_SAFE_INTEGER : -Number.MAX_SAFE_INTEGER, it); } else if (value !== (value | 0)) { if (Math.abs(value) <= 3.4028235e+38) { // range check _float32[0] = value; if (Math.abs(Math.abs(_float32[0]) - Math.abs(value)) < 1e-4) { // precision check; adjust 1e-n (n = precision) to in-/decrease acceptable precision loss // now we know value is in range for f32 and has acceptable precision for f32 bytes[it.offset++] = 0xca; float32(bytes, value, it); return 5; } } bytes[it.offset++] = 0xcb; float64(bytes, value, it); return 9; } if (value >= 0) { // positive fixnum if (value < 0x80) { bytes[it.offset++] = value & 255; // uint8 return 1; } // uint 8 if (value < 0x100) { bytes[it.offset++] = 0xcc; bytes[it.offset++] = value & 255; // uint8 return 2; } // uint 16 if (value < 0x10000) { bytes[it.offset++] = 0xcd; uint16(bytes, value, it); return 3; } // uint 32 if (value < 0x100000000) { bytes[it.offset++] = 0xce; uint32(bytes, value, it); return 5; } // uint 64 bytes[it.offset++] = 0xcf; uint64(bytes, value, it); return 9; } else { // negative fixnum if (value >= -0x20) { bytes[it.offset++] = 0xe0 | (value + 0x20); return 1; } // int 8 if (value >= -0x80) { bytes[it.offset++] = 0xd0; int8(bytes, value, it); return 2; } // int 16 if (value >= -0x8000) { bytes[it.offset++] = 0xd1; int16(bytes, value, it); return 3; } // int 32 if (value >= -0x80000000) { bytes[it.offset++] = 0xd2; int32(bytes, value, it); return 5; } // int 64 bytes[it.offset++] = 0xd3; int64(bytes, value, it); return 9; } } exports.encode = { int8, uint8, int16, uint16, int32, uint32, int64, uint64, bigint64, biguint64, float32, float64, boolean, string, number, utf8Write, utf8Length, }; //# sourceMappingURL=encode.js.map