From 47c9182bed897a95633ad23e8347904f619cb486 Mon Sep 17 00:00:00 2001 From: James Causon Date: Fri, 25 Apr 2025 21:57:04 +0100 Subject: [PATCH] feat: replace cheerio and update build-and-shoot (#683) * Implement fast-xml-parser replacing cheerio for farmingsim * Add extra player raw fields * Update buildandshoot for server 0.75 which uses json. * Remove cheerio * Add changelog entry * Add notes for build and shoot query server * Update CHANGELOG.md * Update package.json to fix version * Update buildandshoot.js * update lock * Add specific key and value to bas config in note * Add spacing for import * Run eslint on bas protocol * Use includes for check. Add doc notes to games.js * Updates GAMES_LIST.md * fix: support stable and master * attempt to manually fix conflict * fix players * fix fx * Update CHANGELOG.md --------- Co-authored-by: CosminPerRam --- CHANGELOG.md | 2 + GAMES_LIST.md | 7 +- lib/games.js | 6 +- package-lock.json | 366 ++++------------------------------ package.json | 3 +- protocols/buildandshoot.js | 67 +++---- protocols/farmingsimulator.js | 78 +++++--- tools/generate_games_list.js | 4 +- 8 files changed, 129 insertions(+), 404 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20ad991..f6529b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ * Feat: Farming Simulator add response to raw object (#682) * Feat: Renown (2025) - Added support (#684 By @anthonyphysgun) * Fix: Terraria - add missing supported maxplayers field and raw field (By @GoodDays13 #686) +* Chore: Replace cheerio with fast-xml-parser (By @xCausxn #683) +* Fix: Build and Shoot protocol using the new json status server (By @xCausxn #683) ## 5.2.0 * Fix: Palworld not respecting query output players schema (#666) diff --git a/GAMES_LIST.md b/GAMES_LIST.md index 020dabe..f6a8744 100644 --- a/GAMES_LIST.md +++ b/GAMES_LIST.md @@ -17,7 +17,7 @@ | americasarmy3 | America's Army 3 | [Valve Protocol](#valve) | | aoc | Age of Chivalry | [Valve Protocol](#valve) | | aoe2 | Age of Empires 2 | | -| aosc | Ace of Spades Classic | | +| aosc | Ace of Spades Classic | [Notes](#aosc-buildandshoot) | | arma2 | ARMA 2 | [Valve Protocol](#valve) | | arma3 | ARMA 3 | [Valve Protocol](#valve) | | armagetronadvanced | Armagetron Advanced | | @@ -34,7 +34,7 @@ | baldursgate | Baldur's Gate | | | ballisticoverkill | Ballistic Overkill | [Valve Protocol](#valve) | | barotrauma | Barotrauma | [Valve Protocol](#valve) | -| bas | Build and Shoot | | +| bas | Build and Shoot | [Notes](#aosc-buildandshoot) | | basedefense | Base Defense | [Valve Protocol](#valve) | | battalion1944 | Battalion 1944 | [Valve Protocol](#valve) | | battlefield1942 | Battlefield 1942 | | @@ -544,3 +544,6 @@ Requires the `sv_exposePlayerIdentifiersInHttpEndpoint` convar to be `1` for the ### Counter-Strike 2 Does not provide players names, using a plugin like this [one](https://github.com/Source2ZE/ServerListPlayersFix) makes the query to return them. + +### Ace of Spades / Build and Shoot +Requires usage of the status query server enabled in the config.txt. `status_server.enabled` to `true` diff --git a/lib/games.js b/lib/games.js index 0429e74..65107f7 100644 --- a/lib/games.js +++ b/lib/games.js @@ -494,7 +494,8 @@ export const games = { protocol: 'buildandshoot' }, extra: { - old_id: 'buildandshoot' + old_id: 'buildandshoot', + doc_notes: 'aosc-buildandshoot' } }, aosc: { @@ -504,6 +505,9 @@ export const games = { port: 32887, port_query_offset: -1, protocol: 'buildandshoot' + }, + extra: { + doc_notes: 'aosc-buildandshoot' } }, cod: { diff --git a/package-lock.json b/package-lock.json index 7409e38..3645a82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "5.2.0", "license": "MIT", "dependencies": { - "cheerio": "1.0.0-rc.12", + "fast-xml-parser": "5.0.9", "gbxremote": "0.2.1", "got": "13.0.0", "iconv-lite": "0.6.3", @@ -22,7 +22,6 @@ "gamedig": "bin/gamedig.js" }, "devDependencies": { - "@types/cheerio": "^0.22.31", "@types/node": "^16.18.58", "esbuild": "^0.19.10", "esbuild-node-externals": "^1.12.0", @@ -559,15 +558,6 @@ "node": ">=14.16" } }, - "node_modules/@types/cheerio": { - "version": "0.22.31", - "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.31.tgz", - "integrity": "sha512-Kt7Cdjjdi2XWSfrZ53v4Of0wG3ZcmaegFXjMmz9tfNrZSkzzo36G0AL1YqSdcIA78Etjt6E609pt5h1xnQkPUw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/http-cache-semantics": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz", @@ -791,11 +781,6 @@ "readable-stream": "~1.0.2" } }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -893,42 +878,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", - "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - }, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -972,32 +921,6 @@ "node": ">= 8" } }, - "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1097,68 +1020,6 @@ "node": ">=6.0.0" } }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/es-abstract": { "version": "1.22.2", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", @@ -1732,6 +1593,23 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-xml-parser": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.0.9.tgz", + "integrity": "sha512-2mBwCiuW3ycKQQ6SOesSB8WeF+fIGb6I/GG5vU5/XEptwFFhp9PE8b9O7fbs2dpq9fXn4ULR3UsfydNUCntf5A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "dependencies": { + "strnum": "^2.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -2087,24 +1965,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", @@ -2595,17 +2455,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, "node_modules/object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", @@ -2764,29 +2613,6 @@ "node": ">=6" } }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", - "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", - "dependencies": { - "domhandler": "^5.0.2", - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -3257,6 +3083,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strnum": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.0.5.tgz", + "integrity": "sha512-YAT3K/sgpCUxhxNMrrdhtod3jckkpYwH6JAuwmUdXZsmzH1wUyzTMrrK2wYCEEqlKwrWDd35NeuUkbBy/1iK+Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ] + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3792,15 +3629,6 @@ "defer-to-connect": "^2.0.1" } }, - "@types/cheerio": { - "version": "0.22.31", - "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.31.tgz", - "integrity": "sha512-Kt7Cdjjdi2XWSfrZ53v4Of0wG3ZcmaegFXjMmz9tfNrZSkzzo36G0AL1YqSdcIA78Etjt6E609pt5h1xnQkPUw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/http-cache-semantics": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz", @@ -3964,11 +3792,6 @@ "readable-stream": "~1.0.2" } }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4044,33 +3867,6 @@ "supports-color": "^7.1.0" } }, - "cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", - "requires": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - } - }, - "cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "requires": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - } - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4108,23 +3904,6 @@ "which": "^2.0.1" } }, - "css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - } - }, - "css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" - }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -4191,44 +3970,6 @@ "esutils": "^2.0.2" } }, - "dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - } - }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" - }, - "domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "requires": { - "domelementtype": "^2.3.0" - } - }, - "domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "requires": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - } - }, - "entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" - }, "es-abstract": { "version": "1.22.2", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", @@ -4651,6 +4392,14 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "fast-xml-parser": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.0.9.tgz", + "integrity": "sha512-2mBwCiuW3ycKQQ6SOesSB8WeF+fIGb6I/GG5vU5/XEptwFFhp9PE8b9O7fbs2dpq9fXn4ULR3UsfydNUCntf5A==", + "requires": { + "strnum": "^2.0.5" + } + }, "fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -4904,17 +4653,6 @@ "has-symbols": "^1.0.2" } }, - "htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, "http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", @@ -5264,14 +5002,6 @@ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==" }, - "nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "requires": { - "boolbase": "^1.0.0" - } - }, "object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", @@ -5385,23 +5115,6 @@ "callsites": "^3.0.0" } }, - "parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "requires": { - "entities": "^4.4.0" - } - }, - "parse5-htmlparser2-tree-adapter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", - "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", - "requires": { - "domhandler": "^5.0.2", - "parse5": "^7.0.0" - } - }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5737,6 +5450,11 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "strnum": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.0.5.tgz", + "integrity": "sha512-YAT3K/sgpCUxhxNMrrdhtod3jckkpYwH6JAuwmUdXZsmzH1wUyzTMrrK2wYCEEqlKwrWDd35NeuUkbBy/1iK+Q==" + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", diff --git a/package.json b/package.json index 02d7e7a..4f5f6d7 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "README.md" ], "dependencies": { - "cheerio": "1.0.0-rc.12", + "fast-xml-parser": "5.0.9", "gbxremote": "0.2.1", "got": "13.0.0", "iconv-lite": "0.6.3", @@ -67,7 +67,6 @@ "varint": "6.0.0" }, "devDependencies": { - "@types/cheerio": "^0.22.31", "@types/node": "^16.18.58", "esbuild": "^0.19.10", "esbuild-node-externals": "^1.12.0", diff --git a/protocols/buildandshoot.js b/protocols/buildandshoot.js index 1b742da..3824af6 100644 --- a/protocols/buildandshoot.js +++ b/protocols/buildandshoot.js @@ -1,55 +1,42 @@ import Core from './core.js' -import * as cheerio from 'cheerio' +// We are doing some shenanigans here as we are trying to support the stable version and the git master version +// as in the latest (0.75) releases they are mixed up. export default class buildandshoot extends Core { async run (state) { - const body = await this.request({ - url: 'http://' + this.options.address + ':' + this.options.port + '/' + const request = await this.request({ + url: 'http://' + this.options.address + ':' + this.options.port + '/json', + responseType: 'json' }) - let m + state.name = request.serverName + state.map = request.map.name + state.version = request.serverVersion - m = body.match(/status server for (.*?)\.?[\r\n]/) - if (m) state.name = m[1] - - m = body.match(/Current uptime: (\d+)/) - if (m) state.raw.uptime = m[1] - - m = body.match(/currently running (.*?) by /) - if (m) state.map = m[1] - - m = body.match(/Current players: (\d+)\/(\d+)/) - if (m) { - state.numplayers = parseInt(m[1]) - state.maxplayers = m[2] + const bluePlayers = request.players?.blue || [] + const greenPlayers = request.players?.green || [] + let players = bluePlayers.concat(greenPlayers) + if (Array.isArray(request.players)) { + players = players.concat(request.players) } - m = body.match(/aos:\/\/[0-9]+:[0-9]+/) - if (m) { - state.connect = m[0] - } + state.numplayers = players.length + state.maxplayers = request.maxPlayers || request.players?.maxPlayers - const $ = cheerio.load(body) - $('#playerlist tbody tr').each((i, tr) => { - if (!$(tr).find('td').first().attr('colspan')) { + state.players = [] + for (const player of players) { + if (typeof player === 'string') { state.players.push({ - name: $(tr).find('td').eq(2).text(), - ping: $(tr).find('td').eq(3).text().trim(), - team: $(tr).find('td').eq(4).text().toLowerCase(), - score: parseInt($(tr).find('td').eq(5).text()) + name: player + }) + } else { + state.players.push({ + ...player, + name: player.name }) } - }) - /* - var m = this.options.address.match(/(\d+)\.(\d+)\.(\d+)\.(\d+)/); - if(m) { - var o1 = parseInt(m[1]); - var o2 = parseInt(m[2]); - var o3 = parseInt(m[3]); - var o4 = parseInt(m[4]); - var addr = o1+(o2<<8)+(o3<<16)+(o4<<24); - state.raw.url = 'aos://'+addr; - } - */ + } + + state.raw = request } } diff --git a/protocols/farmingsimulator.js b/protocols/farmingsimulator.js index e058228..9017881 100644 --- a/protocols/farmingsimulator.js +++ b/protocols/farmingsimulator.js @@ -1,5 +1,5 @@ import Core from './core.js' -import cheerio from 'cheerio' +import { XMLParser, XMLValidator } from 'fast-xml-parser' export default class farmingsimulator extends Core { async run (state) { @@ -11,47 +11,59 @@ export default class farmingsimulator extends Core { responseType: 'text' }) - const $ = cheerio.load(request, { - xmlMode: true - }) + const isValidXML = XMLValidator.validate(request) + if (!isValidXML) { + throw new Error('Invalid XML received from Farming Simulator Server') + } - const serverInfo = $('Server') - const playerInfo = serverInfo.find('Slots') + const parser = new XMLParser({ ignoreAttributes: false }) + const parsed = parser.parse(request) - state.name = serverInfo.attr('name') - state.map = serverInfo.attr('mapName') - state.numplayers = playerInfo.attr('numUsed') - state.maxplayers = playerInfo.attr('capacity') + const serverInfo = parsed.Server + const playerInfo = serverInfo.Slots - $('Player').each(function () { - if ($(this).attr('isUsed') === 'true') { - state.players.push({ - name: $(this).text(), - raw: { - isAdmin: $(this).attr('isAdmin') === 'true', - uptime: parseInt($(this).attr('uptime'), 10) - } - }) - } - }) + // Attributes in fast-xml-parser are prefixed with @_ + + state.name = serverInfo['@_name'] + state.map = serverInfo['@_mapName'] + state.numplayers = parseInt(playerInfo['@_numUsed'], 10) || 0 + state.maxplayers = parseInt(playerInfo['@_capacity'], 10) || 0 + + const players = playerInfo.Player + + for (const player of players) { + if (player['@_isUsed'] !== 'true') { continue } + + state.players.push({ + name: player['#text'], + isUsed: player['@_isUsed'] === 'true', + isAdmin: player['@_isAdmin'] === 'true', + uptime: parseInt(player['@_uptime'], 10), + x: parseFloat(player['@_x']), + y: parseFloat(player['@_y']), + z: parseFloat(player['@_z']) + }) + } state.raw = { data: request, mods: [] } - $('Mod').each(function () { - if ($(this).attr('name') !== undefined) { - state.raw.mods.push({ - name: $(this).text(), - short_name: $(this).attr('name'), - author: $(this).attr('author'), - version: $(this).attr('version'), - hash: $(this).attr('hash') - }) - } - }) + const mods = serverInfo.Mods.Mod - state.version = serverInfo.attr('version') + for (const mod of mods) { + if (mod['@_name'] == null) { continue } + + state.raw.mods.push({ + name: mod['#text'], + short_name: mod['@_name'], + author: mod['@_author'], + version: mod['@_version'], + hash: mod['@_hash'] + }) + } + + state.version = serverInfo['@_version'] } } diff --git a/tools/generate_games_list.js b/tools/generate_games_list.js index 7212ec1..ee16ac2 100644 --- a/tools/generate_games_list.js +++ b/tools/generate_games_list.js @@ -55,10 +55,10 @@ Object.entries(sortedGames).forEach(([id, game]) => { if (game?.extra?.doc_notes) { notes.push('[Notes](#' + game.extra.doc_notes + ')') } - if (game.options.protocol === 'valve' || game.options.protocol === 'dayz') { + if (['valve', 'dayz'].includes(game.options.protocol)) { notes.push('[Valve Protocol](#valve)') } - if (game.options.protocol === 'epic' || game.options.protocol === 'asa' || game.options.protocol === 'theisleevrima' || game.options.protocol === 'renown') { + if (['epic', 'asa', 'theisleevrima', 'renown'].includes(game.options.protocol)) { notes.push('[EOS Protocol](#epic)') } lineArray[HeaderType.Notes] = notes.join(', ')