quake3 server connector | test quake 3 rcon commands | format quake 3 response | Search

These are four functions used to extract and parse information from server-related input strings:

Run example

npm run import -- "quake 3 server responses"

quake 3 server responses


function getServersResponse(m) {
    var masters = []
    m = m.slice('getserversResponse'.length)
    for(var i = 0; i < m.length / 7; i++) {
        var ip = i*7+1
        if(m[ip-1] !== '\\'.charCodeAt(0)) continue
        if(m.slice(ip, ip+3) == 'EOT') continue
        var master = {
            ip: m[ip] + '.' + m[ip+1] + '.' + m[ip+2] + '.' + m[ip+3],
            port: (m[ip+4] << 8) + m[ip+5],
        }
        masters.push(master)
    }
    return masters
}

function parseConfigStr(m) {
    return m.toString('utf-8')
        .trim().split(/\n/ig)[0]
        .trim().split(/\\/ig).slice(1)
        .reduce((obj, c, i, arr) => {
            if(i & 1) {
                obj[arr[i-1].toLowerCase()] = c
                obj[arr[i-1]] = c
            }
            return obj
        }, {})
}

function statusResponse(m) {
    m = m.slice('statusResponse'.length)
    var status = parseConfigStr(m)
    var players = m.toString('utf-8')
        .trim().split(/\n/ig)
        .slice(1)
        .reduce((obj, c, i, arr) => {
            if(c.trim().length == 0)
                return obj
            var player = {
                'i': (i + 1),
                'name': (/[0-9]+\s+[0-9]+\s+"(.*)"/ig).exec(c)[1],
                'score': (/([0-9]+)\s+/ig).exec(c)[1],
                'ping': (/[0-9]+\s+([0-9]+)\s+/ig).exec(c)[1],
            }
            player.isBot = player.ping == 0
            obj.push(player)
            return obj
        }, [])
    return Object.assign(status, {players})
}

function infoResponse(m) {
    m = m.slice('infoResponse'.length)
    return parseConfigStr(m)
}

module.exports = {
    getServersResponse,
    statusResponse,
    infoResponse,
    parseConfigStr,
}

What the code could have been:

/**
 * A module to handle Minecraft server responses.
 * @module serverResponses
 */

const { parse } = require('node:util');

/**
 * Extracts a list of Minecraft servers from a response string.
 * @param {string} m The response string.
 * @returns {object[]} A list of server objects.
 */
function getServersResponse(m) {
    const sliceLength = 'getserversResponse'.length;
    const chunkSize = 7;
    const servers = [];

    m = m.slice(sliceLength);

    for (let i = 0; i < m.length; i += chunkSize) {
        const chunk = m.slice(i, i + chunkSize);

        if (chunk[0]!== 92 || chunk.slice(0, 3) === 'EOT') continue;

        const ip = chunk.slice(1, 5).join('.');
        const port = (chunk[5] << 8) + chunk[6];
        servers.push({ ip, port });
    }

    return servers;
}

/**
 * Parses a configuration string and returns an object.
 * @param {string} m The configuration string.
 * @returns {object} A parsed configuration object.
 */
function parseConfigStr(m) {
    return parseConfig(m.toString('utf-8').trim().split(/\n/g)[0].trim().split(/\\/g).slice(1).map((chunk, index, arr) => {
        return index & 1? { [arr[index - 1].toLowerCase()]: chunk, [arr[index - 1]]: chunk } : {};
    }).reduce((obj, config) => Object.assign(obj, config), {}));
}

/**
 * Processes a'statusResponse' string and returns an object containing server status and player information.
 * @param {string} m The'statusResponse' string.
 * @returns {object} An object containing server status and player information.
 */
function statusResponse(m) {
    const sliceLength ='statusResponse'.length;
    const status = parseConfigStr(m.slice(sliceLength));
    const players = m.toString('utf-8').trim().split(/\n/g).slice(1).map((line, index) => {
        if (!line.trim()) return null;

        const player = {
            i: index + 1,
            name: line.match(/([0-9]+\s+[0-9]+\s+"(.*)"/g)[0],
            score: line.match(/([0-9]+)\s+/g)[0],
            ping: line.match(/([0-9]+\s+([0-9]+)\s+/g)[0],
        };

        player.isBot = player.ping === '0';
        return player;
    }).filter(Boolean);

    return Object.assign(status, { players });
}

/**
 * Processes an 'infoResponse' string and returns an object containing server information.
 * @param {string} m The 'infoResponse' string.
 * @returns {object} An object containing server information.
 */
function infoResponse(m) {
    const sliceLength = 'infoResponse'.length;
    return parseConfigStr(m.slice(sliceLength));
}

module.exports = {
    getServersResponse,
    statusResponse,
    infoResponse,
    parseConfigStr,
};

Functions

getServersResponse(m)

parseConfigStr(m)

statusResponse(m)

infoResponse(m)

Module Exports

The functions getServersResponse, statusResponse, infoResponse, and parseConfigStr are exported as a module.