Merge branch 'master' into fat/add-game-type-alias

This commit is contained in:
Pedro Ivo Hudson 2024-02-09 21:09:50 -03:00
commit c317cfc760
25 changed files with 2008 additions and 431 deletions

1
.gitignore vendored
View File

@ -2,5 +2,6 @@
/npm-debug.log
/*.iml
/.idea
/dist
# Deno bin/gamedig executable
gamedig

View File

@ -1,28 +1,49 @@
## To Be Released...
## 5.0.0-beta.3
* Euro Truck Simulator 2 (2012) - Added support (By @podrivo #523)
* Eco - Fixed querying servers using reverse queries and player names (By @Vito0912 #526)
* Factorio (2016) - Added support (By @Vito0912 #527)
* Farming Simulator 22 (2021) - Added support (By @Vito0912 #531)
* Farming Simulator 19 (2018) - Added support (By @Vito0912 #531)
## 5.0.0-beta.2
* Fixed support for projects using `require`.
## 5.0.0-beta.1
* Fixed numplayers on Palworld not beeing accurate
* Enshrouded - Added support (By @GuilhermeWerner #512).
* Fixed typo in standard port on Palworld (By jammsen #515)
* Re-added support for projects using `require` (By @GuilhermeWerner #519).
* Duke Nukem Forever 2001 (2022) - Added support (By @podrivo #499)
## 5.0.0-beta.0
### Breaking Changes
#### Package
* Node.js 16.20 is now required (from 14).
* Made the library a `module`.
* Removed `GameResolver`, moved the `GameDig` class in a separate file.
* Modified exports, now the library exports `games` and `protocols` alongside the `GameDig` class.
* Many game ids have changed, see the [migrate ids](MIGRATE_IDS.md) file for more info regarding this.
* A game always has these fields: `name`, `release_year` and `options` (which always contains `port`/`port_query`/`port_query_offset` and `protocol`) and could contain `extra.old_id`.
* `maxAttempts` has been renamed to `maxRetries`.
#### Games
* Almost all games ids have been changed to follow a standard, see [CONTRIBUTING.md#naming](https://github.com/gamedig/node-gamedig/blob/5ae12dd494c927abcbe43352609d9aa34a54753c/CONTRIBUTING.md?plain=1#L27C3-L27C3).
* Removed `minecraftping` (as it was deprecated and the same thing as `minecraft`) and
`minecraftpe` (deprecated, which is now the same as `mbe` (Minecraft Bedrock Edition)).
* Removed the `games.txt` file, the games definitions are now stored in-code (exported on `games`).
### Other changes
#### Package
* Removed the `games.txt` file, the games definitions are now stored in-code.
* Replaced usage of deprecated `substr` with `substring`.
* Replaced deprecated internal `punycode` with the [punycode](https://www.npmjs.com/package/punycode) package.
* Updated dependencies:
* * [got](https://github.com/sindresorhus/got) from 12.1 to 13.
* * [minimist](https://github.com/minimistjs/minimist) from 1.2.6 to 1.2.8.
* * [long](https://github.com/dcodeIO/long.js) from 5.2.0 to 5.2.3.
* * @types/node from 14.18.13 to 16.18.58.
* * [cheerio](https://github.com/cheeriojs/cheerio) from 1.0.0-rc.10 to 1.0.0-rc.12.
* [got](https://github.com/sindresorhus/got) from 12.1 to 13.
* [minimist](https://github.com/minimistjs/minimist) from 1.2.6 to 1.2.8.
* [long](https://github.com/dcodeIO/long.js) from 5.2.0 to 5.2.3.
* @types/node from 14.18.13 to 16.18.58.
* [cheerio](https://github.com/cheeriojs/cheerio) from 1.0.0-rc.10 to 1.0.0-rc.12.
* Added eslint which spotted some unused variables and other lints.
* CLI: Resolved incorrect error message when querying with a non-existent protocol name.
* Added Deno support: the library and CLI can now be experimentally used with the [Deno runtime](https://deno.com)
@ -36,16 +57,26 @@
* `stripColors` (defaults to `true`) for protocols that strips colors: unreal2, savage2, quake3, nadeo, gamespy2, doom3, armagetron.
* `requestRulesRequired` (defaults to `false`) Valve games only. `requestRules` is always required to have a response or the query will timeout.
* `requestPlayersRequired` (defaults to `false`) Valve games only. Querying players is always required to have a response or the query will timeout. Some [games](GAMES_LIST.md) may not provide a players response.
* `noBreadthOrder` (defaults to `false`). If multiple attempts are to be made, disable doing one of each type until reaching the retry count.
* `checkOldIDs` (defaults to `false`). Query will check for older game type IDs. See [migration](MIGRATION.md) document.
* Now documented: `address` (defaults to `undefined`) Override the IP address of the server skipping DNS resolution. When set, host will not be resolved, instead address will be connected to. However, some protocols still use host for other reasons e.g. as part of the query.
* `maxAttempts` has been renamed to `maxRetries`.
#### Games
* Removed the players::setNum method, the library will no longer add empty players as
placeholders in the `players` fields.
* Valve: dont skip players with no name and keep state.raw.players.
* Stabilized field `numplayers`.
* Add note about EOS Protocol not providing players data.
* V Rising (2022) - Updated `options.port_query_offset` to `[1, 15]` (#438).
* Minecraft (2009) - Add note about players data.
* Fixed Project Cars and Project Cars 2 port offsets.
* Fixed Wurm Unlimited port_query being missnamed.
* BeamMP (2021) - Added support.
* Xonotic (2011) - Added support.
* Call of Duty: Black Ops 3 (2015) - Added support.
* Unreal 2: The Awakening - XMP - Added support.
* Palworld - Added support (By @jonathanprl, #495).
* The Isle Evrima - Added support (By @GuilhermeWerner, #501).
### 4.3.1
* Fixed support for the Minecraft [Better Compatibility Checker](https://www.curseforge.com/minecraft/mc-mods/better-compatibility-checker) Mod (By @Douile, #436).

View File

@ -20,7 +20,7 @@
| armagetronadvanced | Armagetron Advanced | |
| armareforger | ARMA: Reforger | [Valve Protocol](#valve) |
| armaresistance | ARMA: Resistance | |
| asa | Ark: Survival Ascended | |
| asa | Ark: Survival Ascended | [EOS Protocol](#epic) |
| ase | Ark: Survival Evolved | [Valve Protocol](#valve) |
| asr08 | Arca Sim Racing '08 | |
| assettocorsa | Assetto Corsa | |
@ -59,9 +59,9 @@
| cod2 | Call of Duty 2 | |
| cod3 | Call of Duty 3 | |
| cod4mw | Call of Duty 4: Modern Warfare | |
| codbo3 | Call of Duty: Black Ops 3 | [Valve Protocol](#valve) |
| codenamecure | Codename CURE | [Valve Protocol](#valve) |
| codenameeagle | Codename Eagle | |
| codbo3 | Call of Duty: Black Ops 3 | |
| codmw2 | Call of Duty: Modern Warfare 2 | |
| codmw3 | Call of Duty: Modern Warfare 3 | [Valve Protocol](#valve) |
| coduo | Call of Duty: United Offensive | |
@ -101,6 +101,7 @@
| discord | Discord | [Notes](#discord) |
| dmomam | Dark Messiah of Might and Magic | [Valve Protocol](#valve) |
| dod | Day of Defeat | [Valve Protocol](#valve) |
| dnf2001 | Duke Nukem Forever 2001 | |
| dods | Day of Defeat: Source | [Valve Protocol](#valve) |
| doi | Day of Infamy | [Valve Protocol](#valve) |
| doom3 | Doom 3 | |
@ -114,10 +115,15 @@
| egs | Empyrion - Galactic Survival | [Valve Protocol](#valve) |
| eldewrito | Halo Online (ElDewrito) | |
| empiresmod | Empires Mod | [Valve Protocol](#valve) |
| enshrouded | Enshrouded | [Valve Protocol](#valve) |
| etqw | Enemy Territory: Quake Wars | |
| ets2 | Euro Truck Simulator 2 | [Valve Protocol](#valve) |
| f1c9902 | F1 Challenge '99-'02 | |
| factorio | Factorio | |
| farcry | Far Cry | |
| farcry2 | Far Cry 2 | |
| farmingsimulator19 | Farming Simulator 19 | [Notes](#farmingsimulator) |
| farmingsimulator22 | Farming Simulator 22 | [Notes](#farmingsimulator) |
| fear | F.E.A.R. | |
| ffow | Frontlines: Fuel of War | |
| fof | Fistful of Frags | [Valve Protocol](#valve) |
@ -164,14 +170,14 @@
| kpctnc | Kiss: Psycho Circus: The Nightmare Child | |
| kreedzclimbing | Kreedz Climbing | [Valve Protocol](#valve) |
| kspd | Kerbal Space Program - DMP | |
| left4dead | Left 4 Dead | [Valve Protocol](#valve) |
| left4dead2 | Left 4 Dead 2 | [Valve Protocol](#valve) |
| l4d | Left 4 Dead | [Valve Protocol](#valve) |
| l4d2 | Left 4 Dead 2 | [Valve Protocol](#valve) |
| m2m | Mafia II - Multiplayer | |
| m2o | Mafia II - Online | |
| mbe | Minecraft: Bedrock Edition | |
| medievalengineers | Medieval Engineers | [Valve Protocol](#valve) |
| mgm | Mumble - GT Murmur | [Notes](#mumble) |
| minecraft | Minecraft | |
| minecraft | Minecraft | [Notes](#minecraft) |
| mnc | Monday Night Combat | [Valve Protocol](#valve) |
| moh | Medal of Honor | |
| moha | Medal of Honor: Airborne | |
@ -203,6 +209,7 @@
| openarena | OpenArena | |
| openttd | OpenTTD | |
| painkiller | Painkiller | |
| palworld | Palworld | [EOS Protocol](#epic) |
| pce | Primal Carnage: Extinction | [Valve Protocol](#valve) |
| pixark | PixARK | [Valve Protocol](#valve) |
| postal2 | Postal 2 | |
@ -270,6 +277,7 @@
| swjkja | Star Wars Jedi Knight: Jedi Academy | |
| swrc | Star Wars: Republic Commando | |
| synergy | Synergy | [Valve Protocol](#valve) |
| t1s | Tribes 1: Starsiege | |
| tacticalops | Tactical Ops | |
| tcgraw | Tom Clancy's Ghost Recon Advanced Warfighter | |
| tcgraw2 | Tom Clancy's Ghost Recon Advanced Warfighter 2 | |
@ -278,13 +286,14 @@
| teamspeak2 | Teamspeak 2 | |
| teamspeak3 | Teamspeak 3 | [Notes](#teamspeak3) |
| terminus | Terminus | |
| terrariatshosck | Terraria - TShock | [Notes](#terraria) |
| terrariatshock | Terraria - TShock | [Notes](#terraria) |
| tfc | Team Fortress Classic | [Valve Protocol](#valve) |
| theforest | The Forest | [Valve Protocol](#valve) |
| theforrest | The Forrest | [Valve Protocol](#valve) |
| thefront | The Front | [Valve Protocol](#valve) |
| thehidden | The Hidden | [Valve Protocol](#valve) |
| theisle | The Isle | [Valve Protocol](#valve) |
| tie | The Isle Evrima | [EOS Protocol](#epic) |
| theship | The Ship | [Valve Protocol](#valve) |
| thespecialists | The Specialists | [Valve Protocol](#valve) |
| thps3 | Tony Hawk's Pro Skater 3 | |
@ -296,10 +305,10 @@
| trackmania2 | Trackmania 2 | [Notes](#nadeo-shootmania--trackmania--etc) |
| trackmaniaforever | Trackmania Forever | [Notes](#nadeo-shootmania--trackmania--etc) |
| tremulous | Tremulous | |
| tribes1starsiege | Tribes 1: Starsiege | |
| tribesvengeance | Tribes: Vengeance | |
| tron20 | Tron 2.0 | |
| turok2 | Turok 2 | |
| u2tax | Unreal 2: The Awakening - XMP | |
| universalcombat | Universal Combat | |
| unreal | Unreal | |
| unrealtournament | Unreal Tournament | |
@ -322,6 +331,7 @@
| wolfenstein | Wolfenstein | |
| wot | Wheel of Time | |
| wurmunlimited | Wurm Unlimited | [Valve Protocol](#valve) |
| xonotic | Xonotic | |
| xpandrally | Xpand Rally | |
| zombiemaster | Zombie Master | [Valve Protocol](#valve) |
| zps | Zombie Panic: Source | [Valve Protocol](#valve) |
@ -333,18 +343,12 @@
* Assault Cube
* Cube 2: Sauerbraten
* Blood Frontier
* Alien vs Predator
* Armed Assault 2: Operation Arrowhead
* Battlefield Bad Company 2: Vietnam
* BFRIS
* Call of Duty: Black Ops 1 and 2 (no documentation, may require rcon)
* Crysis Warhead
* Days of War
* DirtyBomb
* Doom - Skulltag
* Doom - ZDaemon
* ECO Global Survival ([Ref](https://github.com/Austinb/GameQ/blob/v3/src/GameQ/Protocols/Eco.php))
* Farming Simulator
* Freelancer
* Ghost Recon
* GRAV Online
@ -370,10 +374,8 @@
* Tibia ([Ref](https://github.com/Austinb/GameQ/blob/v3/src/GameQ/Protocols/Tibia.php))
* Titanfall
* Tribes 2
* Unreal 2 XMP
* World in Conflict
* World Opponent Network
* Wurm Unlimited
> Want support for one of these games? Please open an issue to show your interest!
> __Know how to code?__ Protocol details for many of the games above are documented
@ -383,18 +385,8 @@
> Don't see your game listed here?
>
> First, let us know, so we can fix it. Then, you can try using some common query
> protocols directly by using one of these server types:
> * protocol-ase
> * protocol-battlefield
> * protocol-doom3
> * protocol-gamespy1
> * protocol-gamespy2
> * protocol-gamespy3
> * protocol-nadeo
> * protocol-quake2
> * protocol-quake3
> * protocol-unreal2
> * protocol-valve
> protocols directly from the [protocols folder](/protocols). We also have a little tool
> that could come in handy, [attempt protocols](/tools/attempt_protocols.js)
Games with Additional Notes
---
@ -443,12 +435,25 @@ Valheim servers will only respond to queries if they are started in public mode
### <a name="dayz"></a>DayZ
DayZ stores some of it's servers information inside the `tags` attribute. Make sure to set `requestRules: true` to access it. Some data inside `dayzMods` attribute may be fuzzy, due to how mods are loaded into the servers. Players can be fetched, but will not show ingame names. Alternatively, some servers may have a [third party tool](https://dayzsalauncher.com/#/tools) that you can use to get the mods information. If it's installed, you can access it via browser with the game servers IP:PORT, but add up 10 to the port. (eg. if game port is 2302 then use 2312).
### <a name="valve"></a>Valve Protocol
For many valve games, additional 'rules' may be fetched into the unstable `raw` field by passing the additional
option: `requestRules: true`. Beware that this may increase query time.
### <a name="thefront"></a>The Front
Responses with wrong `name` (gives out a steamid instead of the server name) and `maxplayers` (always 200, whatever the config would be) field values.
### <a name="conanexiles">Conan Exiles
Conan Exiles never responds to player query.
### <a name="minecraft">Minecraft
Many Minecraft servers do not respond with players data.
### <a name='farmingsimulator'>Farming Simulator
Farming Simulator servers need a token (reffered as code in the game). It can be obtained at your server's web interface (http://ip:port/settings.html). It can be passed to GameDig with the additional option: `token`. It does only work for your own server.
The response includes much information about the server. Currently, only the fields about server information (name, map, version, etc.), players and mods are parsed.
Protocols with Additional Notes
---
### <a name="valve"></a>Valve Protocol
For many valve games, additional 'rules' may be fetched into the unstable `raw` field by passing the additional
option: `requestRules: true`. Beware that this may increase query time.
### <a name="epic"></a>Epic Online Services (EOS) Protocol
EOS does not provide players data.

149
MIGRATE_IDS.md Normal file
View File

@ -0,0 +1,149 @@
# Migrating game ids from v4 to v5
**Tip**: Checkout the [changelog](CHANGELOG.md) file to see all changes.
## Game IDs
The naming system used to determine the Game IDs have been updated in `v5` and some IDs have been changed.
This means some ids will not work as they could have been changed to something else, see the table below to check which one is which.
(*Don't see your id here? That means it stayed the same.*)
**Note**: If you are heavily using the old ids, just pass the `checkOldIDs` as true in options (or `--checkOldIDs` via the CLI) to also use them.
**Warning**: We strongly recommend that you update your game id, as these older IDs will eventually not be supported anymore and will be removed.
### Old IDs Table
| v4 | | v5 |
|:---------------------|:--|:---------------------|
| americasarmypg | → | aapg |
| 7d2d | → | sdtd |
| americasarmypg | → | aapg |
| as | → | actionsource |
| ageofchivalry | → | aoc |
| arkse | → | ase |
| arcasimracing | → | asr08 |
| arma | → | aaa |
| arma2oa | → | a2oa |
| armacwa | → | acwa |
| armar | → | armaresistance |
| armare | → | armareforger |
| armagetron | → | armagetronadvanced |
| bat1944 | → | battalion1944 |
| bf1942 | → | battlefield1942 |
| bfv | → | battlefieldvietnam |
| bf2 | → | battlefield2 |
| bf2142 | → | battlefield2142 |
| bfbc2 | → | bbc2 |
| bf3 | → | battlefield3 |
| bf4 | → | battlefield4 |
| bfh | → | battlefieldhardline |
| bd | → | basedefense |
| bs | → | bladesymphony |
| buildandshoot | → | bas |
| cod4 | → | cod4mw |
| callofjuarez | → | coj |
| chivalry | → | cmw |
| commandos3 | → | c3db |
| cacrenegade | → | cacr |
| contactjack | → | contractjack |
| cs15 | → | counterstrike15 |
| cs16 | → | counterstrike16 |
| cs2 | → | counterstrike2 |
| crossracing | → | crce |
| darkesthour | → | dhe4445 |
| daysofwar | → | dow |
| deadlydozenpt | → | ddpt |
| dh2005 | → | deerhunter2005 |
| dinodday | → | ddd |
| dirttrackracing2 | → | dtr2 |
| dmc | → | deathmatchclassic |
| dnl | → | dal |
| drakan | → | dootf |
| dys | → | dystopia |
| em | → | empiresmod |
| empyrion | → | egs |
| f12002 | → | formulaone2002 |
| flashpointresistance | → | ofr |
| fivem | → | gta5f |
| forrest | → | theforrest |
| graw | → | tcgraw |
| graw2 | → | tcgraw2 |
| giantscitizenkabuto | → | gck |
| ges | → | goldeneyesource |
| gore | → | gus |
| hldm | → | hld |
| hldms | → | hlds |
| hlopfor | → | hlof |
| hl2dm | → | hl2d |
| hidden | → | thehidden |
| had2 | → | hiddendangerous2 |
| igi2 | → | i2cs |
| il2 | → | il2sturmovik |
| insurgencymic | → | imic |
| isle | → | theisle |
| jamesbondnightfire | → | jb007n |
| jc2mp | → | jc2m |
| jc3mp | → | jc3m |
| kingpin | → | kloc |
| kisspc | → | kpctnc |
| kspdmp | → | kspd |
| kzmod | → | kreedzclimbing |
| left4dead | → | l4d |
| left4dead2 | → | l4d2 |
| m2mp | → | m2m |
| mohsh | → | mohaas |
| mohbt | → | mohaab |
| mohab | → | moha |
| moh2010 | → | moh |
| mohwf | → | mohw |
| minecraftbe | → | mbe |
| mtavc | → | gtavcmta |
| mtasa | → | gtasamta |
| ns | → | naturalselection |
| ns2 | → | naturalselection2 |
| nwn | → | neverwinternights |
| nwn2 | → | neverwinternights2 |
| nolf | → | tonolf |
| nolf2 | → | nolf2asihw |
| pvkii | → | pvak2 |
| ps | → | postscriptum |
| primalcarnage | → | pce |
| pc | → | projectcars |
| pc2 | → | projectcars2 |
| prbf2 | → | prb2 |
| przomboid | → | projectzomboid |
| quake1 | → | quake |
| quake3 | → | q3a |
| ragdollkungfu | → | rdkf |
| r6 | → | rainbowsix |
| r6roguespear | → | rs2rs |
| r6ravenshield | → | rs3rs |
| redorchestraost | → | roo4145 |
| redm | → | rdr2r |
| riseofnations | → | ron |
| rs2 | → | rs2v |
| samp | → | gtasam |
| saomp | → | gtasao |
| savage2 | → | s2ats |
| ss | → | serioussam |
| ss2 | → | serioussam2 |
| ship | → | theship |
| sinep | → | sinepisodes |
| sonsoftheforest | → | sotf |
| swbf | → | swb |
| swbf2 | → | swb2 |
| swjk | → | swjkja |
| swjk2 | → | swjk2jo |
| takeonhelicopters | → | toh |
| tf2 | → | teamfortress2 |
| terraria | → | terrariatshosck |
| tribes1 | → | t1s |
| ut | → | unrealtournament |
| ut2003 | → | unrealtournament2003 |
| ut2004 | → | unrealtournament2004 |
| ut3 | → | unrealtournament3 |
| v8supercar | → | v8sc |
| vcmp | → | vcm |
| vs | → | vampireslayer |
| wheeloftime | → | wot |
| wolfenstein2009 | → | wolfenstein |
| wolfensteinet | → | wet |
| wurm | → | wurmunlimited |

View File

@ -8,22 +8,27 @@ If a server makes its status publically available, GameDig can fetch it for you.
Support is available on the [Discord](https://discord.gg/NVCMn3tnxH) for questions, or [GitHub](https://github.com/gamedig/node-gamedig/issues) for bugs.
**Are you updating from v4 to v5?** Many game ids have changed.
Make sure to check if your game's ID is in the [id migration document](MIGRATE_IDS.md) and don't forget to check the [changelog](CHANGELOG.md) file.
## Games List
**node-GameDig** can query over 310 games + a few services!
**node-GameDig** can query over 320 games + a few services!
See the [GAMES_LIST.md](GAMES_LIST.md) file for the currently supported titles, not yet supported titles and notes about some of them.
## Usage from Node.js
Install using your favorite package manager: `npm install gamedig`, then use!
```js
import GameDig from 'gamedig';
import { GameDig } from 'gamedig';
// Or if you're using CommonJS:
// const { GameDig } = require('gamedig');
GameDig.query({
type: 'minecraft',
host: 'mc.example.com'
host: 'mc.hypixel.net'
}).then((state) => {
console.log(state);
}).catch((error) => {
console.log("Server is offline");
console.log(`Server is offline, error: ${error}`);
});
```
Confused on how this works, or you want to see more? Checkout the [examples](/examples) folder!
@ -52,6 +57,8 @@ Confused on how this works, or you want to see more? Checkout the [examples](/ex
| **requestPlayersRequired** | boolean | false | Valve games only. Querying players is always required to have a response or the query will timeout. Some [games](GAMES_LIST.md) may not provide a players response. |
| **stripColors** | boolean | true | Enables stripping colors for protocols: unreal2, savage2, quake3, nadeo, gamespy2, doom3, armagetron. |
| **portCache** | boolean | true | After you queried a server, the second time you query that exact server (identified by specified ip and port), first add an attempt to query with the last successful port. |
| **noBreadthOrder** | boolean | false | Enable the behaviour of retrying an attempt X times followed by the next attempt X times, otherwise try attempt A, then B, then A, then B until reaching the X retry count of each. |
| **checkOldIDs** | boolean | false | Also checks the old ids amongst the current ones. |
## Query Response
@ -62,9 +69,9 @@ The returned state object will contain the following keys:
| **name** | string | Server name. |
| **map** | string | Server map. |
| **password** | boolean | If a password is required. |
| **numplayers** | number | Number of players connected. Data via [A2S_INFO](https://developer.valvesoftware.com/wiki/Server_queries#A2S_INFO). |
| **numplayers** | number | Number of players connected. |
| **maxplayers** | number | Maximum number of connected players. |
| **players** | array of objects | Note that this could be of a different length compared to **numplayers**. Data via [A2S_PLAYER](https://developer.valvesoftware.com/wiki/Server_queries#A2S_PLAYER). |
| **players** | array of objects | Note that this could be of a different length compared to **numplayers**. |
| **players.name** | string | If the player's name is unknown, the string will be empty. |
| **players.raw** | object | Additional information about the player if available. |
| **bots** | array of objects | Same schema as `players`. |

View File

@ -6,8 +6,8 @@ import Minimist from 'minimist'
import { GameDig } from './../lib/index.js'
const argv = Minimist(process.argv.slice(2), {
boolean: ['pretty', 'debug', 'givenPortOnly', 'requestRules', 'requestRulesRequired', 'requestPlayersRequired', 'stripColors', 'portCache'],
string: ['guildId', 'listenUdpPort', 'ipFamily'],
boolean: ['pretty', 'debug', 'givenPortOnly', 'requestRules', 'requestRulesRequired', 'requestPlayersRequired', 'stripColors', 'portCache', 'noBreadthOrder', 'checkOldIDs'],
string: ['guildId', 'listenUdpPort', 'ipFamily', 'token'],
default: {
stripColors: true,
portCache: true

View File

@ -3,7 +3,9 @@ import { GameDig } from '../lib/index.js'
GameDig.query({
type: 'minecraft',
host: 'mc.hypixel.net'
host: 'mc.hypixel.net',
port: 25565, // lets us explicitly specify the query port of this server
givenPortOnly: true // the library will attempt multiple ports in order to ensure success, to avoid this pass this option
}).then((state) => {
console.log(state)
}).catch((error) => {

13
examples/require.cjs Normal file
View File

@ -0,0 +1,13 @@
const { GameDig } = require('../dist/index.cjs')
// Instead of '../dist/index.cjs' you would have here 'gamedig'.
GameDig.query({
type: 'minecraft',
host: 'mc.hypixel.net',
port: 25565, // lets us explicitly specify the query port of this server
givenPortOnly: true // the library will attempt multiple ports in order to ensure success, to avoid this pass this option
}).then((state) => {
console.log(state)
}).catch((error) => {
console.log(`Server is offline, error: ${error}`)
})

View File

@ -8,6 +8,7 @@ const defaultOptions = {
maxRetries: 1,
stripColors: true,
portCache: true,
noBreadthOrder: false,
ipFamily: 0
}
@ -31,7 +32,7 @@ export default class QueryRunner {
port_query: gameQueryPort,
port_query_offset: gameQueryPortOffset,
...gameOptions
} = lookup(userOptions.type)
} = lookup(userOptions)
const attempts = []
const optionsCollection = {
@ -76,22 +77,29 @@ export default class QueryRunner {
const numRetries = userOptions.maxRetries || gameOptions.maxRetries || defaultOptions.maxRetries
const retries = Array.from({ length: numRetries }, (x, i) => i)
const attemptOrder = []
if (optionsCollection.noBreadthOrder) {
attempts.forEach(attempt => retries.forEach(retry => attemptOrder.push({ attempt, retry })))
} else {
retries.forEach(retry => attempts.forEach(attempt => attemptOrder.push({ attempt, retry })))
}
let attemptNum = 0
const errors = []
for (const attempt of attempts) {
for (let retry = 0; retry < numRetries; retry++) {
attemptNum++
for (const { attempt, retry } of attemptOrder) {
attemptNum++
try {
const response = await this._attempt(attempt)
if (attempt.portCache) {
this.portCache[`${userOptions.address}:${userOptions.port}`] = attempt.port
}
return response
} catch (e) {
e.stack = 'Attempt #' + attemptNum + ' - Port=' + attempt.port + ' Retry=' + (retry) + ':\n' + e.stack
errors.push(e)
try {
const response = await this._attempt(attempt)
if (attempt.portCache) {
this.portCache[`${userOptions.address}:${userOptions.port}`] = attempt.port
}
return response
} catch (e) {
e.stack = 'Attempt #' + attemptNum + ' - Port=' + attempt.port + ' Retry=' + (retry) + ':\n' + e.stack
errors.push(e)
}
}

View File

@ -1,6 +1,8 @@
import { games } from './games.js'
export const lookup = (type) => {
export const lookup = (options) => {
const type = options.type
if (!type) { throw Error('No game specified') }
if (type.startsWith('protocol-')) {
@ -15,6 +17,14 @@ export const lookup = (type) => {
if (games[id].alias) game = games[id]
})
if (options.checkOldIDs) {
Object.keys(games).forEach((id) => {
if (games[id]?.extra?.old_id === type) {
game = games[id]
}
})
}
if (!game) { throw Error('Invalid game: ' + type) }
return game.options

File diff suppressed because it is too large Load Diff

642
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "gamedig",
"version": "4.1.0",
"version": "5.0.0-beta.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "gamedig",
"version": "4.1.0",
"version": "5.0.0-beta.0",
"license": "MIT",
"dependencies": {
"cheerio": "^1.0.0-rc.12",
@ -25,6 +25,8 @@
"devDependencies": {
"@types/cheerio": "^0.22.31",
"@types/node": "^16.18.58",
"esbuild": "^0.19.10",
"esbuild-node-externals": "^1.12.0",
"eslint": "^8.49.0",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.28.1",
@ -44,6 +46,374 @@
"node": ">=0.10.0"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
"integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz",
"integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz",
"integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz",
"integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz",
"integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz",
"integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz",
"integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz",
"integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz",
"integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz",
"integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz",
"integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz",
"integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==",
"cpu": [
"loong64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz",
"integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==",
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz",
"integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz",
"integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz",
"integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz",
"integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz",
"integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz",
"integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz",
"integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz",
"integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz",
"integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz",
"integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@ -883,6 +1253,60 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/esbuild": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
"integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
"dev": true,
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.19.12",
"@esbuild/android-arm": "0.19.12",
"@esbuild/android-arm64": "0.19.12",
"@esbuild/android-x64": "0.19.12",
"@esbuild/darwin-arm64": "0.19.12",
"@esbuild/darwin-x64": "0.19.12",
"@esbuild/freebsd-arm64": "0.19.12",
"@esbuild/freebsd-x64": "0.19.12",
"@esbuild/linux-arm": "0.19.12",
"@esbuild/linux-arm64": "0.19.12",
"@esbuild/linux-ia32": "0.19.12",
"@esbuild/linux-loong64": "0.19.12",
"@esbuild/linux-mips64el": "0.19.12",
"@esbuild/linux-ppc64": "0.19.12",
"@esbuild/linux-riscv64": "0.19.12",
"@esbuild/linux-s390x": "0.19.12",
"@esbuild/linux-x64": "0.19.12",
"@esbuild/netbsd-x64": "0.19.12",
"@esbuild/openbsd-x64": "0.19.12",
"@esbuild/sunos-x64": "0.19.12",
"@esbuild/win32-arm64": "0.19.12",
"@esbuild/win32-ia32": "0.19.12",
"@esbuild/win32-x64": "0.19.12"
}
},
"node_modules/esbuild-node-externals": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/esbuild-node-externals/-/esbuild-node-externals-1.12.0.tgz",
"integrity": "sha512-0rQM4N9QZwnLetzkUCOHj7Dj+YkD2IlHJIO/+3bb/AOAyDPG4D4tSTdli4QjrXRfPIffS5zAUrhxSbeyqmXhAg==",
"dev": true,
"dependencies": {
"find-up": "^5.0.0",
"tslib": "^2.4.1"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"esbuild": "0.12 - 0.19"
}
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@ -2875,6 +3299,12 @@
"strip-bom": "^3.0.0"
}
},
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
"dev": true
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@ -3101,6 +3531,167 @@
"integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
"dev": true
},
"@esbuild/aix-ppc64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
"integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==",
"dev": true,
"optional": true
},
"@esbuild/android-arm": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz",
"integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==",
"dev": true,
"optional": true
},
"@esbuild/android-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz",
"integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==",
"dev": true,
"optional": true
},
"@esbuild/android-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz",
"integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==",
"dev": true,
"optional": true
},
"@esbuild/darwin-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz",
"integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==",
"dev": true,
"optional": true
},
"@esbuild/darwin-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz",
"integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==",
"dev": true,
"optional": true
},
"@esbuild/freebsd-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz",
"integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==",
"dev": true,
"optional": true
},
"@esbuild/freebsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz",
"integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==",
"dev": true,
"optional": true
},
"@esbuild/linux-arm": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz",
"integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==",
"dev": true,
"optional": true
},
"@esbuild/linux-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz",
"integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==",
"dev": true,
"optional": true
},
"@esbuild/linux-ia32": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz",
"integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==",
"dev": true,
"optional": true
},
"@esbuild/linux-loong64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz",
"integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==",
"dev": true,
"optional": true
},
"@esbuild/linux-mips64el": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz",
"integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==",
"dev": true,
"optional": true
},
"@esbuild/linux-ppc64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz",
"integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==",
"dev": true,
"optional": true
},
"@esbuild/linux-riscv64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz",
"integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==",
"dev": true,
"optional": true
},
"@esbuild/linux-s390x": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz",
"integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==",
"dev": true,
"optional": true
},
"@esbuild/linux-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz",
"integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==",
"dev": true,
"optional": true
},
"@esbuild/netbsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz",
"integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==",
"dev": true,
"optional": true
},
"@esbuild/openbsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz",
"integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==",
"dev": true,
"optional": true
},
"@esbuild/sunos-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz",
"integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==",
"dev": true,
"optional": true
},
"@esbuild/win32-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz",
"integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==",
"dev": true,
"optional": true
},
"@esbuild/win32-ia32": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz",
"integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==",
"dev": true,
"optional": true
},
"@esbuild/win32-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz",
"integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==",
"dev": true,
"optional": true
},
"@eslint-community/eslint-utils": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@ -3716,6 +4307,47 @@
"is-symbol": "^1.0.2"
}
},
"esbuild": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
"integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
"dev": true,
"requires": {
"@esbuild/aix-ppc64": "0.19.12",
"@esbuild/android-arm": "0.19.12",
"@esbuild/android-arm64": "0.19.12",
"@esbuild/android-x64": "0.19.12",
"@esbuild/darwin-arm64": "0.19.12",
"@esbuild/darwin-x64": "0.19.12",
"@esbuild/freebsd-arm64": "0.19.12",
"@esbuild/freebsd-x64": "0.19.12",
"@esbuild/linux-arm": "0.19.12",
"@esbuild/linux-arm64": "0.19.12",
"@esbuild/linux-ia32": "0.19.12",
"@esbuild/linux-loong64": "0.19.12",
"@esbuild/linux-mips64el": "0.19.12",
"@esbuild/linux-ppc64": "0.19.12",
"@esbuild/linux-riscv64": "0.19.12",
"@esbuild/linux-s390x": "0.19.12",
"@esbuild/linux-x64": "0.19.12",
"@esbuild/netbsd-x64": "0.19.12",
"@esbuild/openbsd-x64": "0.19.12",
"@esbuild/sunos-x64": "0.19.12",
"@esbuild/win32-arm64": "0.19.12",
"@esbuild/win32-ia32": "0.19.12",
"@esbuild/win32-x64": "0.19.12"
}
},
"esbuild-node-externals": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/esbuild-node-externals/-/esbuild-node-externals-1.12.0.tgz",
"integrity": "sha512-0rQM4N9QZwnLetzkUCOHj7Dj+YkD2IlHJIO/+3bb/AOAyDPG4D4tSTdli4QjrXRfPIffS5zAUrhxSbeyqmXhAg==",
"dev": true,
"requires": {
"find-up": "^5.0.0",
"tslib": "^2.4.1"
}
},
"escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@ -5137,6 +5769,12 @@
"strip-bom": "^3.0.0"
}
},
"tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
"dev": true
},
"type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",

View File

@ -3,7 +3,9 @@
"description": "Query for the status of any game server in Node.JS",
"scripts": {
"lint:check": "eslint .",
"lint:fix": "eslint --fix ."
"lint:fix": "eslint --fix .",
"prepare": "npm run build",
"build": "node tools/esbuild.js"
},
"keywords": [
"srcds",
@ -25,9 +27,12 @@
"minecraft"
],
"type": "module",
"main": "lib/index.js",
"exports": {
"import": "./lib/index.js",
"require": "./dist/index.cjs"
},
"author": "GameDig Contributors",
"version": "4.1.0",
"version": "5.0.0-beta.2",
"repository": {
"type": "git",
"url": "https://github.com/gamedig/node-gamedig.git"
@ -43,6 +48,7 @@
"gamedig": "bin/gamedig.js"
},
"files": [
"dist/index.cjs",
"bin/gamedig.js",
"lib/",
"protocols/",
@ -65,6 +71,8 @@
"devDependencies": {
"@types/cheerio": "^0.22.31",
"@types/node": "^16.18.58",
"esbuild": "^0.19.10",
"esbuild-node-externals": "^1.12.0",
"eslint": "^8.49.0",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.28.1",

View File

@ -5,16 +5,17 @@ export default class eco extends Core {
if (!this.options.port) this.options.port = 3001
const request = await this.request({
url: `http://${this.options.address}:${this.options.port}/frontpage`,
url: `http://${this.options.host}:${this.options.port}/frontpage`,
responseType: 'json'
})
const serverInfo = request.Info
state.name = serverInfo.Description
state.numplayers = serverInfo.OnlinePlayers;
state.numplayers = serverInfo.OnlinePlayers
state.maxplayers = serverInfo.TotalPlayers
state.password = serverInfo.HasPassword
state.gamePort = serverInfo.GamePort
state.players = serverInfo.OnlinePlayersNames?.map(name => ({ name, raw: {} })) || []
state.raw = serverInfo
}
}

View File

@ -15,6 +15,9 @@ export default class Epic extends Core {
this.clientSecret = null
this.deploymentId = null
this.epicApi = 'https://api.epicgames.dev'
this.authByExternalToken = false // Some games require a client access token to POST to the matchmaking endpoint.
this.deviceIdAccessToken = null
this.accessToken = null
// Don't use the tcp ping probing
@ -22,13 +25,18 @@ export default class Epic extends Core {
}
async run (state) {
await this.getAccessToken()
if (this.authByExternalToken) {
await this.getExternalAccessToken()
} else {
await this.getClientAccessToken()
}
await this.queryInfo(state)
await this.cleanup(state)
}
async getAccessToken () {
this.logger.debug('Requesting acess token ...')
async getClientAccessToken () {
this.logger.debug('Requesting client access token ...')
const url = `${this.epicApi}/auth/v1/oauth/token`
const body = `grant_type=client_credentials&deployment_id=${this.deploymentId}`
@ -43,6 +51,50 @@ export default class Epic extends Core {
this.accessToken = response.access_token
}
async _getDeviceIdToken () {
this.logger.debug('Requesting deviceId access token ...')
const url = `${this.epicApi}/auth/v1/accounts/deviceid`
const body = 'deviceModel=PC'
const headers = {
Authorization: `Basic ${Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64')}`,
'Content-Type': 'application/x-www-form-urlencoded'
}
this.logger.debug(`POST: ${url}`)
const response = await this.request({ url, body, headers, method: 'POST', responseType: 'json' })
return response.access_token
}
async getExternalAccessToken () {
this.logger.debug('Requesting external access token ...')
const deviceIdToken = await this._getDeviceIdToken()
const url = `${this.epicApi}/auth/v1/oauth/token`
const bodyParts = [
'grant_type=external_auth',
'external_auth_type=deviceid_access_token',
`external_auth_token=${deviceIdToken}`,
'nonce=ABCHFA3qgUCJ1XTPAoGDEF', // This is required but can be set to anything
`deployment_id=${this.deploymentId}`,
'display_name=User'
]
const body = bodyParts.join('&')
const headers = {
Authorization: `Basic ${Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64')}`,
'Content-Type': 'application/x-www-form-urlencoded'
}
this.logger.debug(`POST: ${url}`)
const response = await this.request({ url, body, headers, method: 'POST', responseType: 'json' })
this.accessToken = response.access_token
}
async queryInfo (state) {
const url = `${this.epicApi}/matchmaking/v1/${this.deploymentId}/filter`
const body = {
@ -65,7 +117,8 @@ export default class Epic extends Core {
// Epic returns a list of sessions, we need to find the one with the desired port.
const hasDesiredPort = (session) => session.attributes.ADDRESSBOUND_s === `0.0.0.0:${this.options.port}` ||
session.attributes.ADDRESSBOUND_s === `${this.options.address}:${this.options.port}`
session.attributes.ADDRESSBOUND_s === `${this.options.address}:${this.options.port}` ||
session.attributes.GAMESERVER_PORT_l === this.options.port
const desiredServer = response.sessions.find(hasDesiredPort)

23
protocols/factorio.js Normal file
View File

@ -0,0 +1,23 @@
import Core from './core.js'
export default class factorio extends Core {
async run (state) {
if (!this.options.port) this.options.port = 34197
this.usedTcp = true
const serverInfo = await this.request({
url: `https://multiplayer.factorio.com/get-game-details/${this.options.address}:${this.options.port}`,
responseType: 'json'
})
const players = serverInfo.players || [] // the 'players' field is undefined if there are no players
state.name = serverInfo.name
state.password = serverInfo.has_password
state.numplayers = players.length
state.maxplayers = serverInfo.max_players
state.players = players.map(player => ({ name: player, raw: {} }))
state.raw = serverInfo
}
}

View File

@ -0,0 +1,55 @@
import Core from './core.js'
import cheerio from 'cheerio'
export default class farmingsimulator extends Core {
async run (state) {
if (!this.options.port) this.options.port = 8080
if (!this.options.token) throw new Error(`No token provided. You can get it from http://${this.options.host}:${this.options.port}/settings.html`)
const request = await this.request({
url: `http://${this.options.host}:${this.options.port}/feed/dedicated-server-stats.xml?code=${this.options.token}`,
responseType: 'text'
})
const $ = cheerio.load(request, {
xmlMode: true
})
const serverInfo = $('Server')
const playerInfo = serverInfo.find('Slots')
state.name = serverInfo.attr('name')
state.map = serverInfo.attr('mapName')
state.numplayers = playerInfo.attr('numUsed')
state.maxplayers = playerInfo.attr('capacity')
$('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)
}
})
}
})
state.raw.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')
})
}
})
state.raw.version = serverInfo.attr('version')
// TODO: Add state.raw
}
}

View File

@ -10,6 +10,8 @@ import doom3 from './doom3.js'
import eco from './eco.js'
import eldewrito from './eldewrito.js'
import epic from './epic.js'
import factorio from './factorio.js'
import farmingsimulator from './farmingsimulator.js'
import ffow from './ffow.js'
import fivem from './fivem.js'
import gamespy1 from './gamespy1.js'
@ -29,6 +31,7 @@ import mumble from './mumble.js'
import mumbleping from './mumbleping.js'
import nadeo from './nadeo.js'
import openttd from './openttd.js'
import palworld from './palworld.js'
import quake1 from './quake1.js'
import quake2 from './quake2.js'
import quake3 from './quake3.js'
@ -51,11 +54,12 @@ import warsow from './warsow.js'
import beammpmaster from './beammpmaster.js'
import beammp from './beammp.js'
import dayz from './dayz.js'
import theisleevrima from './theisleevrima.js'
export {
armagetron, ase, asa, assettocorsa, battlefield, buildandshoot, cs2d, discord, doom3, eco, epic, ffow, fivem, gamespy1,
gamespy2, gamespy3, geneshift, goldsrc, hexen2, jc2mp, kspdmp, mafia2mp, mafia2online, minecraft,
minecraftbedrock, minecraftvanilla, mumble, mumbleping, nadeo, openttd, quake1, quake2, quake3, rfactor, samp,
armagetron, ase, asa, assettocorsa, battlefield, buildandshoot, cs2d, discord, doom3, eco, epic, factorio, farmingsimulator, ffow,
fivem, gamespy1, gamespy2, gamespy3, geneshift, goldsrc, hexen2, jc2mp, kspdmp, mafia2mp, mafia2online, minecraft,
minecraftbedrock, minecraftvanilla, mumble, mumbleping, nadeo, openttd, palworld, quake1, quake2, quake3, rfactor, samp,
savage2, starmade, starsiege, teamspeak2, teamspeak3, terraria, tribes1, tribes1master, unreal2, ut3, valve,
vcmp, ventrilo, warsow, eldewrito, beammpmaster, beammp, dayz
vcmp, ventrilo, warsow, eldewrito, beammpmaster, beammp, dayz, theisleevrima
}

19
protocols/palworld.js Normal file
View File

@ -0,0 +1,19 @@
import Epic from './epic.js'
export default class palworld extends Epic {
constructor () {
super()
// OAuth2 credentials extracted from Palworld files.
this.clientId = 'xyza78916PZ5DF0fAahu4tnrKKyFpqRE'
this.clientSecret = 'j0NapLEPm3R3EOrlQiM8cRLKq3Rt02ZVVwT0SkZstSg'
this.deploymentId = '0a18471f93d448e2a1f60e47e03d3413'
this.authByExternalToken = true
}
async run (state) {
await super.run(state)
state.name = state.raw.attributes.NAME_s
state.numplayers = state.raw.attributes.PLAYERS_l
}
}

View File

@ -0,0 +1,18 @@
import Epic from './epic.js'
export default class theisleevrima extends Epic {
constructor () {
super()
// OAuth2 credentials extracted from The Isle Evrima files.
this.clientId = 'xyza7891gk5PRo3J7G9puCJGFJjmEguW'
this.clientSecret = 'pKWl6t5i9NJK8gTpVlAxzENZ65P8hYzodV8Dqe5Rlc8'
this.deploymentId = '6db6bea492f94b1bbdfcdfe3e4f898dc'
}
async run (state) {
await super.run(state)
state.name = state.raw.attributes.SERVERNAME_s
state.map = state.raw.attributes.MAP_NAME_s
}
}

View File

@ -31,7 +31,7 @@ const run = async () => {
...options,
type: `protocol-${protocol}`
})
console.log(response)
console.log(`Success on '${protocol}':`, response)
process.exit()
} catch (e) {
console.log(`Error on '${protocol}': ${e}`)

15
tools/esbuild.js Normal file
View File

@ -0,0 +1,15 @@
import { build } from 'esbuild'
import { nodeExternalsPlugin } from 'esbuild-node-externals'
const buildConfig = {
entryPoints: ['lib/index.js'],
platform: 'node',
target: 'node16',
bundle: true,
outfile: 'dist/index.cjs',
format: 'cjs',
// got is a esm module, so we need to add it to the allowList, to include it in the bundle.
plugins: [nodeExternalsPlugin({ allowList: ['got'] })]
}
build(buildConfig).then(() => { }).catch(() => { process.exit(1) })

View File

@ -0,0 +1,30 @@
import { games } from '../lib/games.js'
const ids = Object.keys(games)
Object.keys(games).forEach((key) => {
if (games[key].extra && games[key].extra.old_id) {
const idOld = games[key].extra.old_id
ids.push(idOld)
}
})
function hasDuplicates(obj) {
const uniqueSet = new Set()
for (const item of obj) {
if (uniqueSet.has(item)) {
console.log('Duplicate:', item)
return true
}
uniqueSet.add(item)
}
return false
}
if (hasDuplicates(ids)) {
console.log('Duplicates found.')
} else {
console.log('No duplicates found.')
}

View File

@ -38,6 +38,9 @@ for (const id in sortedGames) {
if (game.options.protocol === 'valve' || game.options.protocol === 'dayz') {
notes.push('[Valve Protocol](#valve)')
}
if (game.options.protocol === 'epic' || game.options.protocol === 'asa' || game.options.protocol === 'palworld' || game.options.protocol === 'theisleevrima') {
notes.push('[EOS Protocol](#epic)')
}
if (notes.length) {
generated += ' | ' + notes.join(', ')
}

View File

@ -1,18 +1,18 @@
import { spawnSync } from 'node:child_process';
import process from 'node:process';
import { spawnSync } from 'node:child_process'
import process from 'node:process'
// Import directly from file so that this script works without dependencies installed.
import { games } from './../lib/games.js';
import { games } from './../lib/games.js'
const ID_TEST_BIN = process.env["GAMEDIG_ID_TESTER"] || "gamedig-id-tests";
const ID_TEST_BIN = process.env.GAMEDIG_ID_TESTER || 'gamedig-id-tests'
const result = spawnSync(ID_TEST_BIN, {
input: JSON.stringify(games),
stdio: ['pipe', 'inherit', 'inherit'],
});
input: JSON.stringify(games),
stdio: ['pipe', 'inherit', 'inherit']
})
if (result.error) {
throw result.error;
throw result.error
}
process.exit(result.status);
process.exit(result.status)