UNPKG

craftping

Version:

A universal ping/query library for Minecraft servers.

182 lines (153 loc) 4.55 kB
export default class VarInt { static SEGMENT_BITS = 0x7F; static CONTINUE_BIT = 0x80; /** * Read a VarInt from a buffer * Based on https://wiki.vg/Protocol#VarInt_and_VarLong * * @param {Buffer} buffer * @param {number} offset * @return {[number, number]} - value, end offset */ static readVarInt(buffer, offset) { let value = 0; let currentByte = 0; let position = 0; while (true) { currentByte = buffer.readUInt8(offset++); value |= (currentByte & this.SEGMENT_BITS) << position; if ((currentByte & this.CONTINUE_BIT) === 0) { break; } position += 7; if (position >= 32) { throw new Error("VarInt is too big"); } } return [value, offset]; } /** * Read a VarLong from a buffer * Based on https://wiki.vg/Protocol#VarInt_and_VarLong * * @param {Buffer} buffer * @param {number} offset * @return {[BigInt, number]} - value, end offset */ static readVarLong(buffer, offset) { let value = BigInt(0); let currentByte = 0; let position = 0; while (true) { currentByte = buffer.readUInt8(offset++); value |= BigInt(currentByte & this.SEGMENT_BITS) << BigInt(position); if ((currentByte & this.CONTINUE_BIT) === 0) { break; } position += 7; if (position >= 64) { throw new Error("VarLong is too big"); } } // Negative number if larger than 2^63 if (value >= 0x8000000000000000n) { value -= 0x10000000000000000n; } return [value, offset]; } /** * Write a VarInt to a buffer * See https://wiki.vg/Protocol#VarInt_and_VarLong * * @param {Buffer} buffer * @param {number} offset * @param {number} value * @return {number} - end offset */ static writeVarInt(buffer, offset, value) { while (true) { if ((value & ~this.SEGMENT_BITS) === 0) { buffer.writeUInt8(value, offset++); return offset; } buffer.writeUInt8((value & this.SEGMENT_BITS) | this.CONTINUE_BIT, offset++); value >>>= 7; } } /** * Write a VarLong to a buffer * See https://wiki.vg/Protocol#VarInt_and_VarLong * * @param {Buffer} buffer * @param {number} offset * @param {BigInt} value * @return {number} - end offset */ static writeVarLong(buffer, offset, value) { while (true) { if ((value & ~BigInt(this.SEGMENT_BITS)) === 0n) { buffer.writeUInt8(Number(value), offset++); return offset; } buffer.writeUInt8(Number((value & BigInt(this.SEGMENT_BITS)) | BigInt(this.CONTINUE_BIT)), offset++); value = this.unsignedRightShiftLong(value, 7n); } } /** * @param {number} value * @return {Buffer} */ static encodeVarInt(value) { let length = this.byteLengthVarInt(value); let buffer = Buffer.alloc(length); this.writeVarInt(buffer, 0, value); return buffer; } /** * @param {BigInt} value * @return {Buffer} */ static encodeVarLong(value) { let length = this.byteLengthVarLong(value); let buffer = Buffer.alloc(length); this.writeVarLong(buffer, 0, value); return buffer; } /** * Calculate the byte length of a VarInt * * @param {number} value * @return {number} */ static byteLengthVarInt(value) { let length = 0; do { length++; value >>>= 7; } while (value !== 0); return length; } /** * Calculate the byte length of a VarLong * * @param {BigInt} value * @return {number} */ static byteLengthVarLong(value) { let length = 0; do { length++; value = this.unsignedRightShiftLong(value, 7n); } while (value !== 0n); return length; } /** * Perform an unsigned right shift on a BigInt, assuming it is a 64-bit integer * * @param {BigInt} value * @param {BigInt} shift */ static unsignedRightShiftLong(value, shift) { return value >> shift & 0x01FFFFFFFFFFFFFFn } }