mirror of
https://github.com/tribufu/node-gamedig
synced 2026-06-01 09:42:41 +00:00
Merge remote-tracking branch 'origin/master' into proto-discord
# Conflicts: # README.md # bin/gamedig.js
This commit is contained in:
commit
576062e88b
28 changed files with 1014 additions and 808 deletions
167
CHANGELOG.md
Normal file
167
CHANGELOG.md
Normal file
|
|
@ -0,0 +1,167 @@
|
||||||
|
### 3.0.3
|
||||||
|
* Greatly improve gamespy1 protocol, with additional error handling and xserverquery support.
|
||||||
|
|
||||||
|
### 3.0.2
|
||||||
|
* Fix player name extraction for Unreal Tournament (1999) and possibly
|
||||||
|
other gamespy1 games.
|
||||||
|
|
||||||
|
### 3.0.1
|
||||||
|
* Clarified that nodejs 12 is now required for gamedig 3
|
||||||
|
* Fixed misc player fields not going into `raw` subobject in `assettocorsa`, `fivem`, and `gamespy2`
|
||||||
|
|
||||||
|
### 3.0.0
|
||||||
|
Major Changes:
|
||||||
|
* **NodeJS 12 is now required**
|
||||||
|
* The `name` field is now guaranteed to exist on all player objects. If a player's name is unknown, the `name` will be an empty string.
|
||||||
|
* All non-`name` player fields have been moved into a `raw` sub-field. This means that, like the `raw` subobject of the parent
|
||||||
|
response, all non-`name` fields are now considered to be unstable and may be changed during minor releases of GameDig.
|
||||||
|
* "Rules" are no longer queried for `valve` protocol games by default. Many games do not respond to this query anyways (meaning we have to wait
|
||||||
|
for timeout), and its contents is often not even used since it only exists in the raw subfield. If you depend on rules,
|
||||||
|
you may pass the `requestRules: true` option to re-enable them.
|
||||||
|
* The `raw.steamappid` and `raw.gameid` fields for valve games have been consolidated into `raw.appId`.
|
||||||
|
|
||||||
|
### 2.0.28
|
||||||
|
* Added Valheim (2021)
|
||||||
|
|
||||||
|
### 2.0.27
|
||||||
|
* Reduced chance of protocol collisions between gamespy3 and minecraftbedrock
|
||||||
|
|
||||||
|
### 2.0.26
|
||||||
|
* Added support for the native minecraft bedrock protocol, since some
|
||||||
|
bedrock servers apparently do not respond to the gamespy3 protocol.
|
||||||
|
|
||||||
|
### 2.0.25
|
||||||
|
* Support challenges in A2S_INFO (upcoming change to valve protocol)
|
||||||
|
|
||||||
|
### 2.0.24
|
||||||
|
* Add Savage 2: A Tortured Soul (2008)
|
||||||
|
|
||||||
|
### 2.0.23
|
||||||
|
* Fix Conan Exiles and other games which don't respond to the valve player query
|
||||||
|
* Add givenPortOnly query option for users that require extreme optimization
|
||||||
|
|
||||||
|
### 2.0.22
|
||||||
|
* Updated dependencies
|
||||||
|
|
||||||
|
### 2.0.21
|
||||||
|
* Added Assetto Corsa (2014)
|
||||||
|
* Fixed password flag for Squad
|
||||||
|
* Added Mordhau (2019)
|
||||||
|
* Fixed player count being incorrect in minecraftvanilla protocol in some cases
|
||||||
|
* Updated dependencies
|
||||||
|
* Replaced deprecated Request http library with Got
|
||||||
|
|
||||||
|
### 2.0.20
|
||||||
|
* Fixed minecraft protocol never throwing exceptions
|
||||||
|
|
||||||
|
### 2.0.19
|
||||||
|
* Added Days of War (2017)
|
||||||
|
* Added The Forrest (2014)
|
||||||
|
* Added Just Cause 3 Multiplayer (2017)
|
||||||
|
* Added Project Reality: Battlefield 2 (2005)
|
||||||
|
* Added Quake Live (2010)
|
||||||
|
* Added Contagion (2011)
|
||||||
|
* Added Empyrion: Galactic Survival (2015)
|
||||||
|
* Added PixARK (2018)
|
||||||
|
|
||||||
|
### 2.0.16, 2.0.17, 2.0.18
|
||||||
|
* Various improvements to killing floor / unreal2 protocol
|
||||||
|
|
||||||
|
### 2.0.15
|
||||||
|
* Added Hell Let Loose
|
||||||
|
* Added Rising Storm 2: Vietnam
|
||||||
|
* Added Squad
|
||||||
|
* Fixed DNS lookup not working in some situations when dns.lookup unexpectedly returns a string
|
||||||
|
* Improved minecraft protocol for non-vanilla server implementations (bedrock, waterfall, bungeecord)
|
||||||
|
* Updated dependencies
|
||||||
|
|
||||||
|
### 2.0.14
|
||||||
|
* Node 8 compatibility fixes
|
||||||
|
|
||||||
|
### 2.0.13
|
||||||
|
* Improved logging
|
||||||
|
|
||||||
|
### 2.0.12
|
||||||
|
* Servers are now limited to 10000 players to prevent OOM
|
||||||
|
* Improvements to Starmade (2012)
|
||||||
|
* Added Atlas (2018)
|
||||||
|
|
||||||
|
### 2.0.11
|
||||||
|
* Added Acra Sim Racing
|
||||||
|
* Added Mafia 2: Online
|
||||||
|
|
||||||
|
### 2.0.10
|
||||||
|
* Added rFactor
|
||||||
|
|
||||||
|
### 2.0.9
|
||||||
|
* Added Vice City: Multiplayer
|
||||||
|
|
||||||
|
### 2.0.8
|
||||||
|
* Improve out-of-order packet handling for gamespy1 protocol
|
||||||
|
* Work-around for buggy duplicate player reporting from bf1942 servers
|
||||||
|
* Report team names rather than IDs when possible for gamespy1 protocol
|
||||||
|
|
||||||
|
### 2.0.7
|
||||||
|
* Prevent tcp socket errors from dumping straight to console
|
||||||
|
|
||||||
|
### 2.0.6
|
||||||
|
* Added support for host domains requiring Punycode encoding (special characters)
|
||||||
|
|
||||||
|
### 2.0.5
|
||||||
|
* Added support for Counter-Strike: 2D
|
||||||
|
|
||||||
|
### 2.0.4
|
||||||
|
* Added details about new 2.0 reponse fields to the README.
|
||||||
|
|
||||||
|
### 2.0.3
|
||||||
|
* Added support for Insurgency: Sandstorm
|
||||||
|
|
||||||
|
### 2.0.2
|
||||||
|
* Added support for Starsiege 2009 (starsiege)
|
||||||
|
|
||||||
|
### 2.0.1
|
||||||
|
* Updated readme games list for 2.0
|
||||||
|
* Fixed csgo default port
|
||||||
|
|
||||||
|
### 2.0.0
|
||||||
|
|
||||||
|
##### Breaking API changes
|
||||||
|
* **Node 8 is now required**
|
||||||
|
* Removed the `port_query` option. You can now pass either the server's game port **or** query port in the `port` option, and
|
||||||
|
GameDig will automatically discover the proper port to query. Passing the query port is more likely be successful in
|
||||||
|
unusual cases, as otherwise it must be automatically derived from the game port.
|
||||||
|
* Removed `callback` parameter from Gamedig.query. Only promises are now supported. If you would like to continue
|
||||||
|
using callbacks, you can use node's `util.callbackify` function to convert the method to callback format.
|
||||||
|
* Removed `query` field from response object, as it was poorly documented and unstable.
|
||||||
|
* Removed `notes` field from options / response object. Data can be passed through a standard javascript context if needed.
|
||||||
|
|
||||||
|
##### Minor Changes
|
||||||
|
* Rewrote core to use promises extensively for better error-handling. Async chains have been dramatically simplified
|
||||||
|
by using async/await across the codebase, eliminating callback chains and the 'async' dependency.
|
||||||
|
* Replaced `--output pretty` cli parameter with `--pretty`.
|
||||||
|
* You can now query from CLI using shorthand syntax: `gamedig --type <gameid> <ip>[:<port>]`
|
||||||
|
* UDP socket is only opened if needed by a query.
|
||||||
|
* Automatic query port detection -- If provided with a non-standard port, gamedig will attempt to discover if it is a
|
||||||
|
game port or query port by querying twice: once to the port provided, and once to the port including the game's query
|
||||||
|
port offset (if available).
|
||||||
|
* Added new `connect` field to the response object. This will typically include the game's `ip:port` (the port will reflect the server's
|
||||||
|
game port, even if you passed in a query port in your request). For some games, this may be a server ID or connection url
|
||||||
|
if an IP:Port is not appropriate.
|
||||||
|
* Added new `ping` field (in milliseconds) to the response object. As icmp packets are often blocked by NATs, and node has poor support
|
||||||
|
for raw sockets, this time is derived from the rtt of one of the UDP requests, or the time required to open a TCP socket
|
||||||
|
during the query.
|
||||||
|
* Improved debug logging across all parts of GameDig
|
||||||
|
* Removed global `Gamedig.debug`. `debug` is now an option on each query.
|
||||||
|
|
||||||
|
##### Protocol Changes
|
||||||
|
* Added support for games using older versions of battlefield protocol.
|
||||||
|
* Simplified detection of BC2 when using battlefield protocol.
|
||||||
|
* Fixed buildandshoot not reading player list
|
||||||
|
* Standardized all doom3 games into a single protocol, which can discover protocol discrepancies automatically.
|
||||||
|
* Standardized all gamespy2 games into a single protocol, which can discover protocol discrepancies automatically.
|
||||||
|
* Standardized all gamespy3 games into a single protocol, which can discover protocol discrepancies automatically.
|
||||||
|
* Improved valve protocol challenge key retry process
|
||||||
|
|
||||||
|
### 1.0.0
|
||||||
|
* First official release
|
||||||
|
* Node.js 6 is now required
|
||||||
309
README.md
309
README.md
|
|
@ -43,6 +43,7 @@ this query port may work instead. (defaults to protocol default port)
|
||||||
will cause many queries to take longer even if the server is online. (default 2000)
|
will cause many queries to take longer even if the server is online. (default 2000)
|
||||||
* **attemptTimeout**: number - Milliseconds allowed for an entire query attempt. This timeout is not commonly hit,
|
* **attemptTimeout**: number - Milliseconds allowed for an entire query attempt. This timeout is not commonly hit,
|
||||||
as the socketTimeout typically fires first. (default 10000)
|
as the socketTimeout typically fires first. (default 10000)
|
||||||
|
* **givenPortOnly**: boolean - Only attempt to query server on given port. (default false)
|
||||||
* **debug**: boolean - Enables massive amounts of debug logging to stdout. (default false)
|
* **debug**: boolean - Enables massive amounts of debug logging to stdout. (default false)
|
||||||
|
|
||||||
### Return Value
|
### Return Value
|
||||||
|
|
@ -54,10 +55,9 @@ The returned state object will contain the following keys:
|
||||||
* **password**: boolean - If a password is required
|
* **password**: boolean - If a password is required
|
||||||
* **maxplayers**: number
|
* **maxplayers**: number
|
||||||
* **players**: array of objects
|
* **players**: array of objects
|
||||||
* Each object **may or may not** contain name, ping, score, team, address.
|
* **name**: string - If the player's name is unknown, the string will be empty.
|
||||||
* The number of players online can be determined by `players.length`.
|
* **raw**: object - Additional information about the player if available (unstable)
|
||||||
* For servers which do not provide player names, this may be an array
|
* The content of this field MAY change on a per-protocol basis between GameDig patch releases (although not typical).
|
||||||
of empty objects (ex. `[{},{},{}]`), one for each player without a name.
|
|
||||||
* **bots**: array of objects - Same schema as `players`
|
* **bots**: array of objects - Same schema as `players`
|
||||||
* **connect**: string
|
* **connect**: string
|
||||||
* This will typically include the game's `ip:port`
|
* This will typically include the game's `ip:port`
|
||||||
|
|
@ -78,31 +78,32 @@ Games List
|
||||||
### Supported
|
### Supported
|
||||||
<!--- BEGIN GENERATED GAMES -->
|
<!--- BEGIN GENERATED GAMES -->
|
||||||
|
|
||||||
| GameDig Type ID | Name | Notes
|
| GameDig Type ID | Name | See Also
|
||||||
|---|---|---
|
|---|---|---
|
||||||
| `7d2d` | 7 Days to Die (2013)
|
| `7d2d` | 7 Days to Die (2013) | [Valve Protocol](#valve)
|
||||||
| `ageofchivalry` | Age of Chivalry (2007)
|
| `ageofchivalry` | Age of Chivalry (2007) | [Valve Protocol](#valve)
|
||||||
| `aoe2` | Age of Empires 2 (1999)
|
| `aoe2` | Age of Empires 2 (1999)
|
||||||
| `alienarena` | Alien Arena (2004)
|
| `alienarena` | Alien Arena (2004)
|
||||||
| `alienswarm` | Alien Swarm (2010)
|
| `alienswarm` | Alien Swarm (2010) | [Valve Protocol](#valve)
|
||||||
| `avp2` | Aliens versus Predator 2 (2001)
|
| `avp2` | Aliens versus Predator 2 (2001)
|
||||||
| `avp2010` | Aliens vs. Predator (2010)
|
| `avp2010` | Aliens vs. Predator (2010) | [Valve Protocol](#valve)
|
||||||
| `americasarmy` | America's Army (2002)
|
| `americasarmy` | America's Army (2002)
|
||||||
| `americasarmy2` | America's Army 2 (2003)
|
| `americasarmy2` | America's Army 2 (2003)
|
||||||
| `americasarmy3` | America's Army 3 (2009)
|
| `americasarmy3` | America's Army 3 (2009) | [Valve Protocol](#valve)
|
||||||
| `americasarmypg` | America's Army: Proving Grounds (2015)
|
| `americasarmypg` | America's Army: Proving Grounds (2015) | [Valve Protocol](#valve)
|
||||||
| `arcasimracing` | Arca Sim Racing (2008)
|
| `arcasimracing` | Arca Sim Racing (2008)
|
||||||
| `arkse` | Ark: Survival Evolved (2017)
|
| `arkse` | Ark: Survival Evolved (2017) | [Valve Protocol](#valve)
|
||||||
| `arma2` | ARMA 2 (2009)
|
| `arma2` | ARMA 2 (2009) | [Valve Protocol](#valve)
|
||||||
| `arma2oa` | ARMA 2: Operation Arrowhead (2010)
|
| `arma2oa` | ARMA 2: Operation Arrowhead (2010) | [Valve Protocol](#valve)
|
||||||
| `arma3` | ARMA 3 (2013)
|
| `arma3` | ARMA 3 (2013) | [Valve Protocol](#valve)
|
||||||
| `arma` | ARMA: Armed Assault (2007)
|
| `arma` | ARMA: Armed Assault (2007)
|
||||||
| `armacwa` | ARMA: Cold War Assault (2011)
|
| `armacwa` | ARMA: Cold War Assault (2011)
|
||||||
| `armar` | ARMA: Resistance (2011)
|
| `armar` | ARMA: Resistance (2011)
|
||||||
| `armagetron` | Armagetron Advanced (2001)
|
| `armagetron` | Armagetron Advanced (2001)
|
||||||
| `atlas` | Atlas (2018)
|
| `assettocorsa` | Assetto Corsa (2014)
|
||||||
|
| `atlas` | Atlas (2018) | [Valve Protocol](#valve)
|
||||||
| `baldursgate` | Baldur's Gate (1998)
|
| `baldursgate` | Baldur's Gate (1998)
|
||||||
| `bat1944` | Battalion 1944 (2018)
|
| `bat1944` | Battalion 1944 (2018) | [Valve Protocol](#valve)
|
||||||
| `bf1942` | Battlefield 1942 (2002)
|
| `bf1942` | Battlefield 1942 (2002)
|
||||||
| `bf2` | Battlefield 2 (2005)
|
| `bf2` | Battlefield 2 (2005)
|
||||||
| `bf2142` | Battlefield 2142 (2006)
|
| `bf2142` | Battlefield 2142 (2006)
|
||||||
|
|
@ -111,16 +112,16 @@ Games List
|
||||||
| `bfh` | Battlefield Hardline (2015)
|
| `bfh` | Battlefield Hardline (2015)
|
||||||
| `bfv` | Battlefield Vietnam (2004)
|
| `bfv` | Battlefield Vietnam (2004)
|
||||||
| `bfbc2` | Battlefield: Bad Company 2 (2010)
|
| `bfbc2` | Battlefield: Bad Company 2 (2010)
|
||||||
| `breach` | Breach (2011)
|
| `breach` | Breach (2011) | [Valve Protocol](#valve)
|
||||||
| `breed` | Breed (2004)
|
| `breed` | Breed (2004)
|
||||||
| `brink` | Brink (2011)
|
| `brink` | Brink (2011) | [Valve Protocol](#valve)
|
||||||
| `buildandshoot` | Build and Shoot / Ace of Spades Classic (2012)
|
| `buildandshoot` | Build and Shoot / Ace of Spades Classic (2012)
|
||||||
| `cod` | Call of Duty (2003)
|
| `cod` | Call of Duty (2003)
|
||||||
| `cod2` | Call of Duty 2 (2005)
|
| `cod2` | Call of Duty 2 (2005)
|
||||||
| `cod3` | Call of Duty 3 (2006)
|
| `cod3` | Call of Duty 3 (2006)
|
||||||
| `cod4` | Call of Duty 4: Modern Warfare (2007)
|
| `cod4` | Call of Duty 4: Modern Warfare (2007)
|
||||||
| `codmw2` | Call of Duty: Modern Warfare 2 (2009)
|
| `codmw2` | Call of Duty: Modern Warfare 2 (2009)
|
||||||
| `codmw3` | Call of Duty: Modern Warfare 3 (2011)
|
| `codmw3` | Call of Duty: Modern Warfare 3 (2011) | [Valve Protocol](#valve)
|
||||||
| `coduo` | Call of Duty: United Offensive (2004)
|
| `coduo` | Call of Duty: United Offensive (2004)
|
||||||
| `codwaw` | Call of Duty: World at War (2008)
|
| `codwaw` | Call of Duty: World at War (2008)
|
||||||
| `callofjuarez` | Call of Juarez (2006)
|
| `callofjuarez` | Call of Juarez (2006)
|
||||||
|
|
@ -129,87 +130,86 @@ Games List
|
||||||
| `codenameeagle` | Codename Eagle (2000)
|
| `codenameeagle` | Codename Eagle (2000)
|
||||||
| `cacrenegade` | Command and Conquer: Renegade (2002)
|
| `cacrenegade` | Command and Conquer: Renegade (2002)
|
||||||
| `commandos3` | Commandos 3: Destination Berlin (2003)
|
| `commandos3` | Commandos 3: Destination Berlin (2003)
|
||||||
| `conanexiles` | Conan Exiles (2018)
|
| `conanexiles` | Conan Exiles (2018) | [Valve Protocol](#valve)
|
||||||
| `contagion` | Contagion (2011)
|
| `contagion` | Contagion (2011) | [Valve Protocol](#valve)
|
||||||
| `contactjack` | Contract J.A.C.K. (2003)
|
| `contactjack` | Contract J.A.C.K. (2003)
|
||||||
| `cs15` | Counter-Strike 1.5 (2002)
|
| `cs15` | Counter-Strike 1.5 (2002) | [Valve Protocol](#valve)
|
||||||
| `cs16` | Counter-Strike 1.6 (2003)
|
| `cs16` | Counter-Strike 1.6 (2003) | [Valve Protocol](#valve)
|
||||||
| `cs2d` | Counter-Strike: 2D (2004)
|
| `cs2d` | Counter-Strike: 2D (2004)
|
||||||
| `cscz` | Counter-Strike: Condition Zero (2004)
|
| `cscz` | Counter-Strike: Condition Zero (2004) | [Valve Protocol](#valve)
|
||||||
| `csgo` | Counter-Strike: Global Offensive (2012) | [Notes](#csgo)
|
| `csgo` | Counter-Strike: Global Offensive (2012) | [Notes](#csgo), [Valve Protocol](#valve)
|
||||||
| `css` | Counter-Strike: Source (2004)
|
| `css` | Counter-Strike: Source (2004) | [Valve Protocol](#valve)
|
||||||
| `crossracing` | Cross Racing Championship Extreme 2005 (2005)
|
| `crossracing` | Cross Racing Championship Extreme 2005 (2005)
|
||||||
| `crysis` | Crysis (2007)
|
| `crysis` | Crysis (2007)
|
||||||
| `crysis2` | Crysis 2 (2011)
|
| `crysis2` | Crysis 2 (2011)
|
||||||
| `crysiswars` | Crysis Wars (2008)
|
| `crysiswars` | Crysis Wars (2008)
|
||||||
| `daikatana` | Daikatana (2000)
|
| `daikatana` | Daikatana (2000)
|
||||||
| `dnl` | Dark and Light (2017)
|
| `dnl` | Dark and Light (2017) | [Valve Protocol](#valve)
|
||||||
| `dmomam` | Dark Messiah of Might and Magic (2006)
|
| `dmomam` | Dark Messiah of Might and Magic (2006) | [Valve Protocol](#valve)
|
||||||
| `darkesthour` | Darkest Hour: Europe '44-'45 (2008)
|
| `darkesthour` | Darkest Hour: Europe '44-'45 (2008)
|
||||||
| `dod` | Day of Defeat (2003)
|
| `dod` | Day of Defeat (2003) | [Valve Protocol](#valve)
|
||||||
| `dods` | Day of Defeat: Source (2005)
|
| `dods` | Day of Defeat: Source (2005) | [Valve Protocol](#valve)
|
||||||
| `doi` | Day of Infamy (2017)
|
| `doi` | Day of Infamy (2017) | [Valve Protocol](#valve)
|
||||||
| `daysofwar` | Days of War (2017)
|
| `daysofwar` | Days of War (2017) | [Valve Protocol](#valve)
|
||||||
| `dayz` | DayZ (2018)
|
| `dayz` | DayZ (2018) | [Valve Protocol](#valve)
|
||||||
| `dayzmod` | DayZ Mod (2013)
|
| `dayzmod` | DayZ Mod (2013) | [Valve Protocol](#valve)
|
||||||
| `deadlydozenpt` | Deadly Dozen: Pacific Theater (2002)
|
| `deadlydozenpt` | Deadly Dozen: Pacific Theater (2002)
|
||||||
| `dh2005` | Deer Hunter 2005 (2004)
|
| `dh2005` | Deer Hunter 2005 (2004)
|
||||||
| `descent3` | Descent 3 (1999)
|
| `descent3` | Descent 3 (1999)
|
||||||
| `deusex` | Deus Ex (2000)
|
| `deusex` | Deus Ex (2000)
|
||||||
| `devastation` | Devastation (2003)
|
| `devastation` | Devastation (2003)
|
||||||
| `dinodday` | Dino D-Day (2011)
|
| `dinodday` | Dino D-Day (2011) | [Valve Protocol](#valve)
|
||||||
| `dirttrackracing2` | Dirt Track Racing 2 (2002)
|
| `dirttrackracing2` | Dirt Track Racing 2 (2002)
|
||||||
| `discord` | Discord | [Notes](#discord)
|
|
||||||
| `doom3` | Doom 3 (2004)
|
| `doom3` | Doom 3 (2004)
|
||||||
| `dota2` | Dota 2 (2013)
|
| `dota2` | Dota 2 (2013) | [Valve Protocol](#valve)
|
||||||
| `drakan` | Drakan: Order of the Flame (1999)
|
| `drakan` | Drakan: Order of the Flame (1999)
|
||||||
| `empyrion` | Empyrion - Galactic Survival (2015)
|
| `empyrion` | Empyrion - Galactic Survival (2015) | [Valve Protocol](#valve)
|
||||||
| `etqw` | Enemy Territory: Quake Wars (2007)
|
| `etqw` | Enemy Territory: Quake Wars (2007)
|
||||||
| `fear` | F.E.A.R. (2005)
|
| `fear` | F.E.A.R. (2005)
|
||||||
| `f1c9902` | F1 Challenge '99-'02 (2002)
|
| `f1c9902` | F1 Challenge '99-'02 (2002)
|
||||||
| `farcry` | Far Cry (2004)
|
| `farcry` | Far Cry (2004)
|
||||||
| `farcry2` | Far Cry 2 (2008)
|
| `farcry2` | Far Cry 2 (2008)
|
||||||
| `f12002` | Formula One 2002 (2002)
|
| `f12002` | Formula One 2002 (2002)
|
||||||
| `fortressforever` | Fortress Forever (2007)
|
| `fortressforever` | Fortress Forever (2007) | [Valve Protocol](#valve)
|
||||||
| `ffow` | Frontlines: Fuel of War (2008)
|
| `ffow` | Frontlines: Fuel of War (2008)
|
||||||
| `garrysmod` | Garry's Mod (2004)
|
| `garrysmod` | Garry's Mod (2004) | [Valve Protocol](#valve)
|
||||||
| `geneshift`<br>`mutantfactions` | Geneshift (2017)
|
| `geneshift`<br>`mutantfactions` | Geneshift (2017)
|
||||||
| `giantscitizenkabuto` | Giants: Citizen Kabuto (2000)
|
| `giantscitizenkabuto` | Giants: Citizen Kabuto (2000)
|
||||||
| `globaloperations` | Global Operations (2002)
|
| `globaloperations` | Global Operations (2002)
|
||||||
| `ges` | GoldenEye: Source (2010)
|
| `ges` | GoldenEye: Source (2010) | [Valve Protocol](#valve)
|
||||||
| `gore` | Gore: Ultimate Soldier (2002)
|
| `gore` | Gore: Ultimate Soldier (2002)
|
||||||
| `fivem` | Grand Theft Auto V - FiveM (2013)
|
| `fivem` | Grand Theft Auto V - FiveM (2013)
|
||||||
| `mtasa` | Grand Theft Auto: San Andreas - Multi Theft Auto (2004)
|
| `mtasa` | Grand Theft Auto: San Andreas - Multi Theft Auto (2004)
|
||||||
| `mtavc` | Grand Theft Auto: Vice City - Multi Theft Auto (2002)
|
| `mtavc` | Grand Theft Auto: Vice City - Multi Theft Auto (2002)
|
||||||
| `gunmanchronicles` | Gunman Chronicles (2000)
|
| `gunmanchronicles` | Gunman Chronicles (2000) | [Valve Protocol](#valve)
|
||||||
| `hl2dm` | Half-Life 2: Deathmatch (2004)
|
| `hl2dm` | Half-Life 2: Deathmatch (2004) | [Valve Protocol](#valve)
|
||||||
| `hldm` | Half-Life Deathmatch (1998)
|
| `hldm` | Half-Life Deathmatch (1998) | [Valve Protocol](#valve)
|
||||||
| `hldms` | Half-Life Deathmatch: Source (2005)
|
| `hldms` | Half-Life Deathmatch: Source (2005) | [Valve Protocol](#valve)
|
||||||
| `halo` | Halo (2003)
|
| `halo` | Halo (2003)
|
||||||
| `halo2` | Halo 2 (2007)
|
| `halo2` | Halo 2 (2007)
|
||||||
| `hll` | Hell Let Loose
|
| `hll` | Hell Let Loose | [Valve Protocol](#valve)
|
||||||
| `heretic2` | Heretic II (1998)
|
| `heretic2` | Heretic II (1998)
|
||||||
| `hexen2` | Hexen II (1997)
|
| `hexen2` | Hexen II (1997)
|
||||||
| `had2` | Hidden & Dangerous 2 (2003)
|
| `had2` | Hidden & Dangerous 2 (2003)
|
||||||
| `homefront` | Homefront (2011)
|
| `homefront` | Homefront (2011) | [Valve Protocol](#valve)
|
||||||
| `homeworld2` | Homeworld 2 (2003)
|
| `homeworld2` | Homeworld 2 (2003)
|
||||||
| `hurtworld` | Hurtworld (2015)
|
| `hurtworld` | Hurtworld (2015) | [Valve Protocol](#valve)
|
||||||
| `igi2` | I.G.I.-2: Covert Strike (2003)
|
| `igi2` | I.G.I.-2: Covert Strike (2003)
|
||||||
| `il2` | IL-2 Sturmovik (2001)
|
| `il2` | IL-2 Sturmovik (2001)
|
||||||
| `insurgency` | Insurgency (2014)
|
| `insurgency` | Insurgency (2014) | [Valve Protocol](#valve)
|
||||||
| `insurgencysandstorm` | Insurgency: Sandstorm (2018)
|
| `insurgencysandstorm` | Insurgency: Sandstorm (2018) | [Valve Protocol](#valve)
|
||||||
| `ironstorm` | Iron Storm (2002)
|
| `ironstorm` | Iron Storm (2002)
|
||||||
| `jamesbondnightfire` | James Bond 007: Nightfire (2002)
|
| `jamesbondnightfire` | James Bond 007: Nightfire (2002)
|
||||||
| `jc2mp` | Just Cause 2 - Multiplayer (2010)
|
| `jc2mp` | Just Cause 2 - Multiplayer (2010)
|
||||||
| `jc3mp` | Just Cause 3 - Multiplayer (2017)
|
| `jc3mp` | Just Cause 3 - Multiplayer (2017) | [Valve Protocol](#valve)
|
||||||
| `kspdmp` | Kerbal Space Program - DMP Multiplayer (2015)
|
| `kspdmp` | Kerbal Space Program - DMP Multiplayer (2015)
|
||||||
| `killingfloor` | Killing Floor (2009)
|
| `killingfloor` | Killing Floor (2009)
|
||||||
| `killingfloor2` | Killing Floor 2 (2016)
|
| `killingfloor2` | Killing Floor 2 (2016) | [Valve Protocol](#valve)
|
||||||
| `kingpin` | Kingpin: Life of Crime (1999)
|
| `kingpin` | Kingpin: Life of Crime (1999)
|
||||||
| `kisspc` | Kiss: Psycho Circus: The Nightmare Child (2000)
|
| `kisspc` | Kiss: Psycho Circus: The Nightmare Child (2000)
|
||||||
| `kzmod` | Kreedz Climbing (2017)
|
| `kzmod` | Kreedz Climbing (2017) | [Valve Protocol](#valve)
|
||||||
| `left4dead` | Left 4 Dead (2008)
|
| `left4dead` | Left 4 Dead (2008) | [Valve Protocol](#valve)
|
||||||
| `left4dead2` | Left 4 Dead 2 (2009)
|
| `left4dead2` | Left 4 Dead 2 (2009) | [Valve Protocol](#valve)
|
||||||
| `m2mp` | Mafia II - Multiplayer (2010)
|
| `m2mp` | Mafia II - Multiplayer (2010)
|
||||||
| `m2o` | Mafia II - Online (2010)
|
| `m2o` | Mafia II - Online (2010)
|
||||||
| `moh2010` | Medal of Honor (2010)
|
| `moh2010` | Medal of Honor (2010)
|
||||||
|
|
@ -219,15 +219,16 @@ Games List
|
||||||
| `mohsh` | Medal of Honor: Allied Assault Spearhead (2002)
|
| `mohsh` | Medal of Honor: Allied Assault Spearhead (2002)
|
||||||
| `mohpa` | Medal of Honor: Pacific Assault (2004)
|
| `mohpa` | Medal of Honor: Pacific Assault (2004)
|
||||||
| `mohwf` | Medal of Honor: Warfighter (2012)
|
| `mohwf` | Medal of Honor: Warfighter (2012)
|
||||||
| `medievalengineers` | Medieval Engineers (2015)
|
| `medievalengineers` | Medieval Engineers (2015) | [Valve Protocol](#valve)
|
||||||
| `minecraft`<br>`minecraftping` | Minecraft (2009)
|
| `minecraft`<br>`minecraftping` | Minecraft (2009)
|
||||||
| `minecraftpe`<br>`minecraftbe` | Minecraft: Bedrock Edition (2011)
|
| `minecraftpe`<br>`minecraftbe` | Minecraft: Bedrock Edition (2011)
|
||||||
| `mnc` | Monday Night Combat (2011)
|
| `mnc` | Monday Night Combat (2011) | [Valve Protocol](#valve)
|
||||||
|
| `mordhau` | Mordhau (2019) | [Valve Protocol](#valve)
|
||||||
| `mumble` | Mumble - GTmurmur Plugin (2005) | [Notes](#mumble)
|
| `mumble` | Mumble - GTmurmur Plugin (2005) | [Notes](#mumble)
|
||||||
| `mumbleping` | Mumble - Lightweight (2005) | [Notes](#mumble)
|
| `mumbleping` | Mumble - Lightweight (2005) | [Notes](#mumble)
|
||||||
| `nascarthunder2004` | NASCAR Thunder 2004 (2003)
|
| `nascarthunder2004` | NASCAR Thunder 2004 (2003)
|
||||||
| `ns` | Natural Selection (2002)
|
| `ns` | Natural Selection (2002) | [Valve Protocol](#valve)
|
||||||
| `ns2` | Natural Selection 2 (2012)
|
| `ns2` | Natural Selection 2 (2012) | [Valve Protocol](#valve)
|
||||||
| `nfshp2` | Need for Speed: Hot Pursuit 2 (2002)
|
| `nfshp2` | Need for Speed: Hot Pursuit 2 (2002)
|
||||||
| `nab` | Nerf Arena Blast (1999)
|
| `nab` | Nerf Arena Blast (1999)
|
||||||
| `netpanzer` | netPanzer (2002)
|
| `netpanzer` | netPanzer (2002)
|
||||||
|
|
@ -235,55 +236,56 @@ Games List
|
||||||
| `nwn2` | Neverwinter Nights 2 (2006)
|
| `nwn2` | Neverwinter Nights 2 (2006)
|
||||||
| `nexuiz` | Nexuiz (2005)
|
| `nexuiz` | Nexuiz (2005)
|
||||||
| `nitrofamily` | Nitro Family (2004)
|
| `nitrofamily` | Nitro Family (2004)
|
||||||
| `nmrih` | No More Room in Hell (2011)
|
| `nmrih` | No More Room in Hell (2011) | [Valve Protocol](#valve)
|
||||||
| `nolf2` | No One Lives Forever 2: A Spy in H.A.R.M.'s Way (2002)
|
| `nolf2` | No One Lives Forever 2: A Spy in H.A.R.M.'s Way (2002)
|
||||||
| `nucleardawn` | Nuclear Dawn (2011)
|
| `nucleardawn` | Nuclear Dawn (2011) | [Valve Protocol](#valve)
|
||||||
| `openarena` | OpenArena (2005)
|
| `openarena` | OpenArena (2005)
|
||||||
| `openttd` | OpenTTD (2004)
|
| `openttd` | OpenTTD (2004)
|
||||||
| `operationflashpoint`<br>`flashpoint` | Operation Flashpoint: Cold War Crisis (2001)
|
| `operationflashpoint`<br>`flashpoint` | Operation Flashpoint: Cold War Crisis (2001)
|
||||||
| `flashpointresistance` | Operation Flashpoint: Resistance (2002)
|
| `flashpointresistance` | Operation Flashpoint: Resistance (2002)
|
||||||
| `painkiller` | Painkiller
|
| `painkiller` | Painkiller
|
||||||
| `pixark` | PixARK (2018)
|
| `pixark` | PixARK (2018) | [Valve Protocol](#valve)
|
||||||
| `postal2` | Postal 2
|
| `postal2` | Postal 2
|
||||||
| `prey` | Prey
|
| `prey` | Prey
|
||||||
| `primalcarnage` | Primal Carnage: Extinction
|
| `primalcarnage` | Primal Carnage: Extinction | [Valve Protocol](#valve)
|
||||||
| `prbf2` | Project Reality: Battlefield 2 (2005)
|
| `prbf2` | Project Reality: Battlefield 2 (2005)
|
||||||
| `quake1` | Quake 1: QuakeWorld (1996)
|
| `quake1` | Quake 1: QuakeWorld (1996)
|
||||||
| `quake2` | Quake 2 (1997)
|
| `quake2` | Quake 2 (1997)
|
||||||
| `quake3` | Quake 3: Arena (1999)
|
| `quake3` | Quake 3: Arena (1999)
|
||||||
| `quake4` | Quake 4 (2005)
|
| `quake4` | Quake 4 (2005)
|
||||||
| `quakelive` | Quake Live (2010)
|
| `quakelive` | Quake Live (2010) | [Valve Protocol](#valve)
|
||||||
| `ragdollkungfu` | Rag Doll Kung Fu
|
| `ragdollkungfu` | Rag Doll Kung Fu | [Valve Protocol](#valve)
|
||||||
| `r6` | Rainbow Six
|
| `r6` | Rainbow Six
|
||||||
| `r6roguespear` | Rainbow Six 2: Rogue Spear
|
| `r6roguespear` | Rainbow Six 2: Rogue Spear
|
||||||
| `r6ravenshield` | Rainbow Six 3: Raven Shield
|
| `r6ravenshield` | Rainbow Six 3: Raven Shield
|
||||||
| `rallisportchallenge` | RalliSport Challenge
|
| `rallisportchallenge` | RalliSport Challenge
|
||||||
| `rallymasters` | Rally Masters
|
| `rallymasters` | Rally Masters
|
||||||
| `redorchestra` | Red Orchestra
|
| `redorchestra` | Red Orchestra
|
||||||
| `redorchestra2` | Red Orchestra 2
|
| `redorchestra2` | Red Orchestra 2 | [Valve Protocol](#valve)
|
||||||
| `redorchestraost` | Red Orchestra: Ostfront 41-45
|
| `redorchestraost` | Red Orchestra: Ostfront 41-45
|
||||||
| `redline` | Redline
|
| `redline` | Redline
|
||||||
| `rtcw` | Return to Castle Wolfenstein
|
| `rtcw` | Return to Castle Wolfenstein
|
||||||
| `rfactor` | rFactor
|
| `rfactor` | rFactor
|
||||||
| `ricochet` | Ricochet
|
| `ricochet` | Ricochet | [Valve Protocol](#valve)
|
||||||
| `riseofnations` | Rise of Nations
|
| `riseofnations` | Rise of Nations
|
||||||
| `rs2` | Rising Storm 2: Vietnam
|
| `rs2` | Rising Storm 2: Vietnam | [Valve Protocol](#valve)
|
||||||
| `rune` | Rune
|
| `rune` | Rune
|
||||||
| `rust` | Rust
|
| `rust` | Rust | [Valve Protocol](#valve)
|
||||||
| `stalker` | S.T.A.L.K.E.R.
|
| `stalker` | S.T.A.L.K.E.R.
|
||||||
| `samp` | San Andreas Multiplayer
|
| `samp` | San Andreas Multiplayer
|
||||||
|
| `savage2` | Savage 2: A Tortured Soul (2008)
|
||||||
| `ss` | Serious Sam
|
| `ss` | Serious Sam
|
||||||
| `ss2` | Serious Sam 2
|
| `ss2` | Serious Sam 2
|
||||||
| `shatteredhorizon` | Shattered Horizon
|
| `shatteredhorizon` | Shattered Horizon | [Valve Protocol](#valve)
|
||||||
| `shogo` | Shogo
|
| `shogo` | Shogo
|
||||||
| `shootmania` | Shootmania | [Notes](#nadeo-shootmania--trackmania--etc)
|
| `shootmania` | Shootmania | [Notes](#nadeo-shootmania--trackmania--etc)
|
||||||
| `sin` | SiN
|
| `sin` | SiN
|
||||||
| `sinep` | SiN Episodes
|
| `sinep` | SiN Episodes | [Valve Protocol](#valve)
|
||||||
| `soldat` | Soldat
|
| `soldat` | Soldat
|
||||||
| `sof` | Soldier of Fortune
|
| `sof` | Soldier of Fortune
|
||||||
| `sof2` | Soldier of Fortune 2
|
| `sof2` | Soldier of Fortune 2
|
||||||
| `spaceengineers` | Space Engineers
|
| `spaceengineers` | Space Engineers | [Valve Protocol](#valve)
|
||||||
| `squad` | Squad
|
| `squad` | Squad | [Valve Protocol](#valve)
|
||||||
| `stbc` | Star Trek: Bridge Commander
|
| `stbc` | Star Trek: Bridge Commander
|
||||||
| `stvef` | Star Trek: Voyager - Elite Force
|
| `stvef` | Star Trek: Voyager - Elite Force
|
||||||
| `stvef2` | Star Trek: Voyager - Elite Force 2
|
| `stvef2` | Star Trek: Voyager - Elite Force 2
|
||||||
|
|
@ -292,32 +294,32 @@ Games List
|
||||||
| `swbf` | Star Wars: Battlefront
|
| `swbf` | Star Wars: Battlefront
|
||||||
| `swbf2` | Star Wars: Battlefront 2
|
| `swbf2` | Star Wars: Battlefront 2
|
||||||
| `swrc` | Star Wars: Republic Commando
|
| `swrc` | Star Wars: Republic Commando
|
||||||
| `starbound` | Starbound
|
| `starbound` | Starbound | [Valve Protocol](#valve)
|
||||||
| `starmade` | StarMade
|
| `starmade` | StarMade
|
||||||
| `starsiege` | Starsiege (2009)
|
| `starsiege` | Starsiege (2009)
|
||||||
| `suicidesurvival` | Suicide Survival
|
| `suicidesurvival` | Suicide Survival | [Valve Protocol](#valve)
|
||||||
| `svencoop` | Sven Coop
|
| `svencoop` | Sven Coop | [Valve Protocol](#valve)
|
||||||
| `swat4` | SWAT 4
|
| `swat4` | SWAT 4
|
||||||
| `synergy` | Synergy
|
| `synergy` | Synergy | [Valve Protocol](#valve)
|
||||||
| `tacticalops` | Tactical Ops
|
| `tacticalops` | Tactical Ops
|
||||||
| `takeonhelicopters` | Take On Helicopters (2011)
|
| `takeonhelicopters` | Take On Helicopters (2011)
|
||||||
| `teamfactor` | Team Factor
|
| `teamfactor` | Team Factor
|
||||||
| `tf2` | Team Fortress 2
|
| `tf2` | Team Fortress 2 | [Valve Protocol](#valve)
|
||||||
| `tfc` | Team Fortress Classic
|
| `tfc` | Team Fortress Classic | [Valve Protocol](#valve)
|
||||||
| `teamspeak2` | Teamspeak 2
|
| `teamspeak2` | Teamspeak 2
|
||||||
| `teamspeak3` | Teamspeak 3 | [Notes](#teamspeak3)
|
| `teamspeak3` | Teamspeak 3 | [Notes](#teamspeak3)
|
||||||
| `terminus` | Terminus
|
| `terminus` | Terminus
|
||||||
| `terraria`<br>`tshock` | Terraria - TShock (2011) | [Notes](#terraria)
|
| `terraria`<br>`tshock` | Terraria - TShock (2011) | [Notes](#terraria)
|
||||||
| `forrest` | The Forrest (2014)
|
| `forrest` | The Forrest (2014) | [Valve Protocol](#valve)
|
||||||
| `hidden` | The Hidden (2005)
|
| `hidden` | The Hidden (2005) | [Valve Protocol](#valve)
|
||||||
| `nolf` | The Operative: No One Lives Forever (2000)
|
| `nolf` | The Operative: No One Lives Forever (2000)
|
||||||
| `ship` | The Ship
|
| `ship` | The Ship | [Valve Protocol](#valve)
|
||||||
| `graw` | Tom Clancy's Ghost Recon Advanced Warfighter (2006)
|
| `graw` | Tom Clancy's Ghost Recon Advanced Warfighter (2006)
|
||||||
| `graw2` | Tom Clancy's Ghost Recon Advanced Warfighter 2 (2007)
|
| `graw2` | Tom Clancy's Ghost Recon Advanced Warfighter 2 (2007)
|
||||||
| `thps3` | Tony Hawk's Pro Skater 3
|
| `thps3` | Tony Hawk's Pro Skater 3
|
||||||
| `thps4` | Tony Hawk's Pro Skater 4
|
| `thps4` | Tony Hawk's Pro Skater 4
|
||||||
| `thu2` | Tony Hawk's Underground 2
|
| `thu2` | Tony Hawk's Underground 2
|
||||||
| `towerunite` | Tower Unite
|
| `towerunite` | Tower Unite | [Valve Protocol](#valve)
|
||||||
| `trackmania2` | Trackmania 2 | [Notes](#nadeo-shootmania--trackmania--etc)
|
| `trackmania2` | Trackmania 2 | [Notes](#nadeo-shootmania--trackmania--etc)
|
||||||
| `trackmaniaforever` | Trackmania Forever | [Notes](#nadeo-shootmania--trackmania--etc)
|
| `trackmaniaforever` | Trackmania Forever | [Notes](#nadeo-shootmania--trackmania--etc)
|
||||||
| `tremulous` | Tremulous
|
| `tremulous` | Tremulous
|
||||||
|
|
@ -331,9 +333,10 @@ Games List
|
||||||
| `ut2003` | Unreal Tournament 2003
|
| `ut2003` | Unreal Tournament 2003
|
||||||
| `ut2004` | Unreal Tournament 2004
|
| `ut2004` | Unreal Tournament 2004
|
||||||
| `ut3` | Unreal Tournament 3
|
| `ut3` | Unreal Tournament 3
|
||||||
| `unturned` | unturned
|
| `unturned` | unturned | [Valve Protocol](#valve)
|
||||||
| `urbanterror` | Urban Terror
|
| `urbanterror` | Urban Terror
|
||||||
| `v8supercar` | V8 Supercar Challenge
|
| `v8supercar` | V8 Supercar Challenge
|
||||||
|
| `valheim` | Valheim (2021) | [Notes](#valheim), [Valve Protocol](#valve)
|
||||||
| `ventrilo` | Ventrilo
|
| `ventrilo` | Ventrilo
|
||||||
| `vcmp` | Vice City Multiplayer
|
| `vcmp` | Vice City Multiplayer
|
||||||
| `vietcong` | Vietcong
|
| `vietcong` | Vietcong
|
||||||
|
|
@ -343,8 +346,8 @@ Games List
|
||||||
| `wolfenstein2009` | Wolfenstein 2009
|
| `wolfenstein2009` | Wolfenstein 2009
|
||||||
| `wolfensteinet` | Wolfenstein: Enemy Territory
|
| `wolfensteinet` | Wolfenstein: Enemy Territory
|
||||||
| `xpandrally` | Xpand Rally
|
| `xpandrally` | Xpand Rally
|
||||||
| `zombiemaster` | Zombie Master
|
| `zombiemaster` | Zombie Master | [Valve Protocol](#valve)
|
||||||
| `zps` | Zombie Panic: Source
|
| `zps` | Zombie Panic: Source | [Valve Protocol](#valve)
|
||||||
|
|
||||||
<!--- END GENERATED GAMES -->
|
<!--- END GENERATED GAMES -->
|
||||||
|
|
||||||
|
|
@ -383,7 +386,6 @@ Games List
|
||||||
* Red Faction
|
* Red Faction
|
||||||
* S.T.A.L.K.E.R. Clear Sky
|
* S.T.A.L.K.E.R. Clear Sky
|
||||||
* Savage: The Battle For Newerth
|
* Savage: The Battle For Newerth
|
||||||
* Savage 2: A Tortured Soul
|
|
||||||
* SiN 1 Multiplayer
|
* SiN 1 Multiplayer
|
||||||
* South Park
|
* South Park
|
||||||
* Star Wars Jedi Knight: Dark Forces II
|
* Star Wars Jedi Knight: Dark Forces II
|
||||||
|
|
@ -400,7 +402,7 @@ Games List
|
||||||
|
|
||||||
> Want support for one of these games? Please open an issue to show your interest!
|
> 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
|
> __Know how to code?__ Protocol details for many of the games above are documented
|
||||||
> at https://github.com/sonicsnes/legacy-query-library-archive
|
> at https://github.com/gamedig/legacy-query-library-archive
|
||||||
> , ready for you to develop into GameDig!
|
> , ready for you to develop into GameDig!
|
||||||
|
|
||||||
> Don't see your game listed here?
|
> Don't see your game listed here?
|
||||||
|
|
@ -450,11 +452,14 @@ For teamspeak 3 queries to work correctly, the following permissions must be ava
|
||||||
|
|
||||||
### Terraria
|
### Terraria
|
||||||
Requires tshock server mod, and a REST user token, which can be passed to GameDig with the
|
Requires tshock server mod, and a REST user token, which can be passed to GameDig with the
|
||||||
additional option: token
|
additional option: `token`
|
||||||
|
|
||||||
### Discord
|
### Valheim
|
||||||
You must set host to the server's guild ID instead of IP, this can be found in server widget settings (Server ID) or by enabling developer mode in client settings and right-clicking the server's icon.
|
Valheim servers will only respond to queries if they are started in public mode (`-public 1`).
|
||||||
In order to retrieve information from discord server's they must have the Enable server widget option enabled.
|
|
||||||
|
### <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.
|
||||||
|
|
||||||
Usage from Command Line
|
Usage from Command Line
|
||||||
---
|
---
|
||||||
|
|
@ -472,121 +477,3 @@ gamedig --type minecraft mc.example.com:11234
|
||||||
|
|
||||||
The output of the command will be in JSON format. Additional advanced parameters can be passed in
|
The output of the command will be in JSON format. Additional advanced parameters can be passed in
|
||||||
as well: `--debug`, `--pretty`, `--socketTimeout 5000`, etc.
|
as well: `--debug`, `--pretty`, `--socketTimeout 5000`, etc.
|
||||||
|
|
||||||
Changelog
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2.0.20
|
|
||||||
* Fixed minecraft protocol never throwing exceptions
|
|
||||||
|
|
||||||
### 2.0.19
|
|
||||||
* Added Days of War (2017)
|
|
||||||
* Added The Forrest (2014)
|
|
||||||
* Added Just Cause 3 Multiplayer (2017)
|
|
||||||
* Added Project Reality: Battlefield 2 (2005)
|
|
||||||
* Added Quake Live (2010)
|
|
||||||
* Added Contagion (2011)
|
|
||||||
* Added Empyrion: Galactic Survival (2015)
|
|
||||||
* Added PixARK (2018)
|
|
||||||
|
|
||||||
### 2.0.16, 2.0.17, 2.0.18
|
|
||||||
* Various improvements to killing floor / unreal2 protocol
|
|
||||||
|
|
||||||
### 2.0.15
|
|
||||||
* Added Hell Let Loose
|
|
||||||
* Added Rising Storm 2: Vietnam
|
|
||||||
* Added Squad
|
|
||||||
* Fixed DNS lookup not working in some situations when dns.lookup unexpectedly returns a string
|
|
||||||
* Improved minecraft protocol for non-vanilla server implementations (bedrock, waterfall, bungeecord)
|
|
||||||
* Updated dependencies
|
|
||||||
|
|
||||||
### 2.0.14
|
|
||||||
* Node 8 compatibility fixes
|
|
||||||
|
|
||||||
### 2.0.13
|
|
||||||
* Improved logging
|
|
||||||
|
|
||||||
### 2.0.12
|
|
||||||
* Servers are now limited to 10000 players to prevent OOM
|
|
||||||
* Improvements to Starmade (2012)
|
|
||||||
* Added Atlas (2018)
|
|
||||||
|
|
||||||
### 2.0.11
|
|
||||||
* Added Acra Sim Racing
|
|
||||||
* Added Mafia 2: Online
|
|
||||||
|
|
||||||
### 2.0.10
|
|
||||||
* Added rFactor
|
|
||||||
|
|
||||||
### 2.0.9
|
|
||||||
* Added Vice City: Multiplayer
|
|
||||||
|
|
||||||
### 2.0.8
|
|
||||||
* Improve out-of-order packet handling for gamespy1 protocol
|
|
||||||
* Work-around for buggy duplicate player reporting from bf1942 servers
|
|
||||||
* Report team names rather than IDs when possible for gamespy1 protocol
|
|
||||||
|
|
||||||
### 2.0.7
|
|
||||||
* Prevent tcp socket errors from dumping straight to console
|
|
||||||
|
|
||||||
### 2.0.6
|
|
||||||
* Added support for host domains requiring Punycode encoding (special characters)
|
|
||||||
|
|
||||||
### 2.0.5
|
|
||||||
* Added support for Counter-Strike: 2D
|
|
||||||
|
|
||||||
### 2.0.4
|
|
||||||
* Added details about new 2.0 reponse fields to the README.
|
|
||||||
|
|
||||||
### 2.0.3
|
|
||||||
* Added support for Insurgency: Sandstorm
|
|
||||||
|
|
||||||
### 2.0.2
|
|
||||||
* Added support for Starsiege 2009 (starsiege)
|
|
||||||
|
|
||||||
### 2.0.1
|
|
||||||
* Updated readme games list for 2.0
|
|
||||||
* Fixed csgo default port
|
|
||||||
|
|
||||||
### 2.0.0
|
|
||||||
|
|
||||||
##### Breaking API changes
|
|
||||||
* **Node 8 is now required**
|
|
||||||
* Removed the `port_query` option. You can now pass either the server's game port **or** query port in the `port` option, and
|
|
||||||
GameDig will automatically discover the proper port to query. Passing the query port is more likely be successful in
|
|
||||||
unusual cases, as otherwise it must be automatically derived from the game port.
|
|
||||||
* Removed `callback` parameter from Gamedig.query. Only promises are now supported. If you would like to continue
|
|
||||||
using callbacks, you can use node's `util.callbackify` function to convert the method to callback format.
|
|
||||||
* Removed `query` field from response object, as it was poorly documented and unstable.
|
|
||||||
* Removed `notes` field from options / response object. Data can be passed through a standard javascript context if needed.
|
|
||||||
|
|
||||||
##### Minor Changes
|
|
||||||
* Rewrote core to use promises extensively for better error-handling. Async chains have been dramatically simplified
|
|
||||||
by using async/await across the codebase, eliminating callback chains and the 'async' dependency.
|
|
||||||
* Replaced `--output pretty` cli parameter with `--pretty`.
|
|
||||||
* You can now query from CLI using shorthand syntax: `gamedig --type <gameid> <ip>[:<port>]`
|
|
||||||
* UDP socket is only opened if needed by a query.
|
|
||||||
* Automatic query port detection -- If provided with a non-standard port, gamedig will attempt to discover if it is a
|
|
||||||
game port or query port by querying twice: once to the port provided, and once to the port including the game's query
|
|
||||||
port offset (if available).
|
|
||||||
* Added new `connect` field to the response object. This will typically include the game's `ip:port` (the port will reflect the server's
|
|
||||||
game port, even if you passed in a query port in your request). For some games, this may be a server ID or connection url
|
|
||||||
if an IP:Port is not appropriate.
|
|
||||||
* Added new `ping` field (in milliseconds) to the response object. As icmp packets are often blocked by NATs, and node has poor support
|
|
||||||
for raw sockets, this time is derived from the rtt of one of the UDP requests, or the time required to open a TCP socket
|
|
||||||
during the query.
|
|
||||||
* Improved debug logging across all parts of GameDig
|
|
||||||
* Removed global `Gamedig.debug`. `debug` is now an option on each query.
|
|
||||||
|
|
||||||
##### Protocol Changes
|
|
||||||
* Added support for games using older versions of battlefield protocol.
|
|
||||||
* Simplified detection of BC2 when using battlefield protocol.
|
|
||||||
* Fixed buildandshoot not reading player list
|
|
||||||
* Standardized all doom3 games into a single protocol, which can discover protocol discrepancies automatically.
|
|
||||||
* Standardized all gamespy2 games into a single protocol, which can discover protocol discrepancies automatically.
|
|
||||||
* Standardized all gamespy3 games into a single protocol, which can discover protocol discrepancies automatically.
|
|
||||||
* Improved valve protocol challenge key retry process
|
|
||||||
|
|
||||||
### 1.0.0
|
|
||||||
* First official release
|
|
||||||
* Node.js 6 is now required
|
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,15 @@ const Minimist = require('minimist'),
|
||||||
Gamedig = require('..');
|
Gamedig = require('..');
|
||||||
|
|
||||||
const argv = Minimist(process.argv.slice(2), {
|
const argv = Minimist(process.argv.slice(2), {
|
||||||
boolean: ['pretty','debug'],
|
boolean: ['pretty','debug','givenPortOnly']
|
||||||
string: ['_']
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const debug = argv.debug;
|
const debug = argv.debug;
|
||||||
delete argv.debug;
|
delete argv.debug;
|
||||||
const pretty = !!argv.pretty || debug;
|
const pretty = !!argv.pretty || debug;
|
||||||
delete argv.pretty;
|
delete argv.pretty;
|
||||||
|
const givenPortOnly = argv.givenPortOnly;
|
||||||
|
delete argv.givenPortOnly;
|
||||||
|
|
||||||
const options = {};
|
const options = {};
|
||||||
for(const key of Object.keys(argv)) {
|
for(const key of Object.keys(argv)) {
|
||||||
|
|
@ -35,6 +36,9 @@ if (argv._.length >= 1) {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
options.debug = true;
|
options.debug = true;
|
||||||
}
|
}
|
||||||
|
if (givenPortOnly) {
|
||||||
|
options.givenPortOnly = true;
|
||||||
|
}
|
||||||
|
|
||||||
Gamedig.query(options)
|
Gamedig.query(options)
|
||||||
.then((state) => {
|
.then((state) => {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ aoe2|Age of Empires 2 (1999)|ase|port_query=27224
|
||||||
alienarena|Alien Arena (2004)|quake2|port_query=27910
|
alienarena|Alien Arena (2004)|quake2|port_query=27910
|
||||||
alienswarm|Alien Swarm (2010)|valve|port=27015
|
alienswarm|Alien Swarm (2010)|valve|port=27015
|
||||||
arkse|Ark: Survival Evolved (2017)|valve|port=7777,port_query=27015
|
arkse|Ark: Survival Evolved (2017)|valve|port=7777,port_query=27015
|
||||||
|
assettocorsa|Assetto Corsa (2014)|assettocorsa|port=9610
|
||||||
atlas|Atlas (2018)|valve|port=5761,port_query_offset=51800
|
atlas|Atlas (2018)|valve|port=5761,port_query_offset=51800
|
||||||
avp2|Aliens versus Predator 2 (2001)|gamespy1|port=27888
|
avp2|Aliens versus Predator 2 (2001)|gamespy1|port=27888
|
||||||
avp2010|Aliens vs. Predator (2010)|valve|port=27015
|
avp2010|Aliens vs. Predator (2010)|valve|port=27015
|
||||||
|
|
@ -162,6 +163,7 @@ minecraft,minecraftping|Minecraft (2009)|minecraft|port=25565
|
||||||
minecraftpe,minecraftbe|Minecraft: Bedrock Edition (2011)|minecraft|port=19132
|
minecraftpe,minecraftbe|Minecraft: Bedrock Edition (2011)|minecraft|port=19132
|
||||||
|
|
||||||
mnc|Monday Night Combat (2011)|valve|port=7777,port_query=27016
|
mnc|Monday Night Combat (2011)|valve|port=7777,port_query=27016
|
||||||
|
mordhau|Mordhau (2019)|valve|port=7777,port_query=27015
|
||||||
mtavc|Grand Theft Auto: Vice City - Multi Theft Auto (2002)|ase|port=22003,port_query_offset=123
|
mtavc|Grand Theft Auto: Vice City - Multi Theft Auto (2002)|ase|port=22003,port_query_offset=123
|
||||||
mtasa|Grand Theft Auto: San Andreas - Multi Theft Auto (2004)|ase|port=22003,port_query_offset=123
|
mtasa|Grand Theft Auto: San Andreas - Multi Theft Auto (2004)|ase|port=22003,port_query_offset=123
|
||||||
mumble|Mumble - GTmurmur Plugin (2005)|mumble|port=64738,port_query=27800|doc_notes=mumble
|
mumble|Mumble - GTmurmur Plugin (2005)|mumble|port=64738,port_query=27800|doc_notes=mumble
|
||||||
|
|
@ -215,6 +217,7 @@ rs2|Rising Storm 2: Vietnam|valve|port=27015
|
||||||
rune|Rune|gamespy1|port=7777,port_query_offset=1
|
rune|Rune|gamespy1|port=7777,port_query_offset=1
|
||||||
rust|Rust|valve|port=28015
|
rust|Rust|valve|port=28015
|
||||||
samp|San Andreas Multiplayer|samp|port=7777
|
samp|San Andreas Multiplayer|samp|port=7777
|
||||||
|
savage2|Savage 2: A Tortured Soul (2008)|savage2|port_query=11235
|
||||||
spaceengineers|Space Engineers|valve|port=27015
|
spaceengineers|Space Engineers|valve|port=27015
|
||||||
ss|Serious Sam|gamespy1|port=25600,port_query_offset=1
|
ss|Serious Sam|gamespy1|port=25600,port_query_offset=1
|
||||||
ss2|Serious Sam 2|gamespy2|port=25600
|
ss2|Serious Sam 2|gamespy2|port=25600
|
||||||
|
|
@ -277,6 +280,7 @@ ut3|Unreal Tournament 3|ut3|port=7777,port_query_offset=-1277
|
||||||
|
|
||||||
urbanterror|Urban Terror|quake3|port_query=27960
|
urbanterror|Urban Terror|quake3|port_query=27960
|
||||||
v8supercar|V8 Supercar Challenge|gamespy1|port_query=16700
|
v8supercar|V8 Supercar Challenge|gamespy1|port_query=16700
|
||||||
|
valheim|Valheim (2021)|valve|port=2456,port_query_offset=1|doc_notes=valheim
|
||||||
vcmp|Vice City Multiplayer|vcmp|port=8192
|
vcmp|Vice City Multiplayer|vcmp|port=8192
|
||||||
ventrilo|Ventrilo|ventrilo|port=3784
|
ventrilo|Ventrilo|ventrilo|port=3784
|
||||||
vietcong|Vietcong|gamespy1|port=5425,port_query=15425
|
vietcong|Vietcong|gamespy1|port=5425,port_query=15425
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class GameResolver {
|
||||||
|
|
||||||
printReadme() {
|
printReadme() {
|
||||||
let out = '';
|
let out = '';
|
||||||
out += '| GameDig Type ID | Name | Notes\n';
|
out += '| GameDig Type ID | Name | See Also\n';
|
||||||
out += '|---|---|---\n';
|
out += '|---|---|---\n';
|
||||||
|
|
||||||
const sorted = this.games
|
const sorted = this.games
|
||||||
|
|
@ -36,8 +36,16 @@ class GameResolver {
|
||||||
let keysOut = game.keys.map(key => '`'+key+'`').join('<br>');
|
let keysOut = game.keys.map(key => '`'+key+'`').join('<br>');
|
||||||
out += "| " + keysOut.padEnd(10, " ") + " "
|
out += "| " + keysOut.padEnd(10, " ") + " "
|
||||||
+ "| " + game.pretty;
|
+ "| " + game.pretty;
|
||||||
if(game.extra.doc_notes)
|
let notes = [];
|
||||||
out += " | [Notes](#"+game.extra.doc_notes+")";
|
if(game.extra.doc_notes) {
|
||||||
|
notes.push("[Notes](#" + game.extra.doc_notes + ")");
|
||||||
|
}
|
||||||
|
if(game.options.protocol === 'valve') {
|
||||||
|
notes.push('[Valve Protocol](#valve)');
|
||||||
|
}
|
||||||
|
if(notes.length) {
|
||||||
|
out += " | " + notes.join(', ');
|
||||||
|
}
|
||||||
out += "\n";
|
out += "\n";
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ class QueryRunner {
|
||||||
const attempts = [];
|
const attempts = [];
|
||||||
|
|
||||||
if (userOptions.port) {
|
if (userOptions.port) {
|
||||||
if (gameQueryPortOffset) {
|
if (gameQueryPortOffset && !userOptions.givenPortOnly) {
|
||||||
attempts.push({
|
attempts.push({
|
||||||
...defaultOptions,
|
...defaultOptions,
|
||||||
...gameOptions,
|
...gameOptions,
|
||||||
|
|
@ -38,7 +38,7 @@ class QueryRunner {
|
||||||
port: userOptions.port + gameQueryPortOffset
|
port: userOptions.port + gameQueryPortOffset
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (userOptions.port === gameOptions.port && gameQueryPort) {
|
if (userOptions.port === gameOptions.port && gameQueryPort && !userOptions.givenPortOnly) {
|
||||||
attempts.push({
|
attempts.push({
|
||||||
...defaultOptions,
|
...defaultOptions,
|
||||||
...gameOptions,
|
...gameOptions,
|
||||||
|
|
|
||||||
51
lib/Results.js
Normal file
51
lib/Results.js
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
class Player {
|
||||||
|
name = '';
|
||||||
|
raw = {};
|
||||||
|
|
||||||
|
constructor(data) {
|
||||||
|
if (typeof data === 'string') {
|
||||||
|
this.name = data;
|
||||||
|
} else {
|
||||||
|
const {name, ...raw} = data;
|
||||||
|
if (name) this.name = name;
|
||||||
|
if (raw) this.raw = raw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Players extends Array {
|
||||||
|
setNum(num) {
|
||||||
|
// If the server specified some ridiculous number of players (billions), we don't want to
|
||||||
|
// run out of ram allocating these objects.
|
||||||
|
num = Math.min(num, 10000);
|
||||||
|
|
||||||
|
while(this.players.length < num) {
|
||||||
|
this.push({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
push(data) {
|
||||||
|
super.push(new Player(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Results {
|
||||||
|
name = '';
|
||||||
|
map = '';
|
||||||
|
password = false;
|
||||||
|
|
||||||
|
raw = {};
|
||||||
|
|
||||||
|
maxplayers = 0;
|
||||||
|
players = new Players();
|
||||||
|
bots = new Players();
|
||||||
|
|
||||||
|
set players(num) {
|
||||||
|
this.players.setNum(num);
|
||||||
|
}
|
||||||
|
set bots(num) {
|
||||||
|
this.bots.setNum(num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Results;
|
||||||
|
|
@ -115,12 +115,12 @@ class Reader {
|
||||||
if(bytes === 1) r = this.buffer.readUInt8(this.i);
|
if(bytes === 1) r = this.buffer.readUInt8(this.i);
|
||||||
else if(bytes === 2) r = this.buffer.readUInt16BE(this.i);
|
else if(bytes === 2) r = this.buffer.readUInt16BE(this.i);
|
||||||
else if(bytes === 4) r = this.buffer.readUInt32BE(this.i);
|
else if(bytes === 4) r = this.buffer.readUInt32BE(this.i);
|
||||||
else if(bytes === 8) r = readUInt64BE(this.buffer,this.i).toString();
|
else if(bytes === 8) r = readUInt64BE(this.buffer,this.i);
|
||||||
} else {
|
} else {
|
||||||
if(bytes === 1) r = this.buffer.readUInt8(this.i);
|
if(bytes === 1) r = this.buffer.readUInt8(this.i);
|
||||||
else if(bytes === 2) r = this.buffer.readUInt16LE(this.i);
|
else if(bytes === 2) r = this.buffer.readUInt16LE(this.i);
|
||||||
else if(bytes === 4) r = this.buffer.readUInt32LE(this.i);
|
else if(bytes === 4) r = this.buffer.readUInt32LE(this.i);
|
||||||
else if(bytes === 8) r = readUInt64LE(this.buffer,this.i).toString();
|
else if(bytes === 8) r = readUInt64LE(this.buffer,this.i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.i += bytes;
|
this.i += bytes;
|
||||||
|
|
|
||||||
552
package-lock.json
generated
552
package-lock.json
generated
|
|
@ -1,32 +1,66 @@
|
||||||
{
|
{
|
||||||
"name": "gamedig",
|
"name": "gamedig",
|
||||||
"version": "2.0.14",
|
"version": "3.0.1",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@sindresorhus/is": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-n4J+zu52VdY43kdi/XdI9DzuMr1Mur8zFL5ZRG2opCans9aiFwkPxHYFEb5Xgy7n1Z4K6WfI4FpqUqsh3E8BPQ=="
|
||||||
|
},
|
||||||
|
"@szmarczak/http-timer": {
|
||||||
|
"version": "4.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz",
|
||||||
|
"integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==",
|
||||||
|
"requires": {
|
||||||
|
"defer-to-connect": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/cacheable-request": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==",
|
||||||
|
"requires": {
|
||||||
|
"@types/http-cache-semantics": "*",
|
||||||
|
"@types/keyv": "*",
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/responselike": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/cheerio": {
|
"@types/cheerio": {
|
||||||
"version": "0.22.13",
|
"version": "0.22.21",
|
||||||
"resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.21.tgz",
|
||||||
"integrity": "sha512-OZd7dCUOUkiTorf97vJKwZnSja/DmHfuBAroe1kREZZTCf/tlFecwHhsOos3uVHxeKGZDwzolIrCUApClkdLuA==",
|
"integrity": "sha512-aGI3DfswwqgKPiEOTaiHV2ZPC9KEhprpgEbJnv0fZl3SGX0cGgEva1126dGrMC6AJM6v/aihlUgJn9M5DbDZ/Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/http-cache-semantics": {
|
||||||
"version": "8.10.54",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.54.tgz",
|
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz",
|
||||||
"integrity": "sha512-kaYyLYf6ICn6/isAyD4K1MyWWd5Q3JgH6bnMN089LUx88+s4W8GvK9Q6JMBVu5vsFFp7pMdSxdKmlBXwH/VFRg=="
|
"integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A=="
|
||||||
},
|
},
|
||||||
"ajv": {
|
"@types/keyv": {
|
||||||
"version": "6.6.2",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz",
|
||||||
"integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==",
|
"integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"fast-deep-equal": "^2.0.1",
|
"@types/node": "*"
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
}
|
||||||
"json-schema-traverse": "^0.4.1",
|
},
|
||||||
"uri-js": "^4.2.2"
|
"@types/node": {
|
||||||
|
"version": "12.20.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.7.tgz",
|
||||||
|
"integrity": "sha512-gWL8VUkg8VRaCAUgG9WmhefMqHmMblxe2rVpMF86nZY/+ZysU+BkAp+3cz03AixWDSSz0ks5WX59yAhv/cDwFA=="
|
||||||
|
},
|
||||||
|
"@types/responselike": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==",
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"amdefine": {
|
"amdefine": {
|
||||||
|
|
@ -39,34 +73,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
||||||
"integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8="
|
"integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8="
|
||||||
},
|
},
|
||||||
"asn1": {
|
|
||||||
"version": "0.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
|
|
||||||
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
|
|
||||||
"requires": {
|
|
||||||
"safer-buffer": "~2.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"assert-plus": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
|
||||||
},
|
|
||||||
"asynckit": {
|
|
||||||
"version": "0.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
|
||||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
|
||||||
},
|
|
||||||
"aws-sign2": {
|
|
||||||
"version": "0.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
|
||||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
|
||||||
},
|
|
||||||
"aws4": {
|
|
||||||
"version": "1.8.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
|
|
||||||
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
|
|
||||||
},
|
|
||||||
"barse": {
|
"barse": {
|
||||||
"version": "0.4.3",
|
"version": "0.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/barse/-/barse-0.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/barse/-/barse-0.4.3.tgz",
|
||||||
|
|
@ -75,28 +81,29 @@
|
||||||
"readable-stream": "~1.0.2"
|
"readable-stream": "~1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bcrypt-pbkdf": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
|
||||||
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
|
|
||||||
"requires": {
|
|
||||||
"tweetnacl": "^0.14.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"bluebird": {
|
|
||||||
"version": "3.7.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz",
|
|
||||||
"integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg=="
|
|
||||||
},
|
|
||||||
"boolbase": {
|
"boolbase": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||||
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
|
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
|
||||||
},
|
},
|
||||||
"caseless": {
|
"cacheable-lookup": {
|
||||||
"version": "0.12.0",
|
"version": "5.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz",
|
||||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
"integrity": "sha512-W+JBqF9SWe18A72XFzN/V/CULFzPm7sBXzzR6ekkE+3tLG72wFZrBiBZhrZuDoYexop4PHJVdFAKb/Nj9+tm9w=="
|
||||||
|
},
|
||||||
|
"cacheable-request": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==",
|
||||||
|
"requires": {
|
||||||
|
"clone-response": "^1.0.2",
|
||||||
|
"get-stream": "^5.1.0",
|
||||||
|
"http-cache-semantics": "^4.0.0",
|
||||||
|
"keyv": "^4.0.0",
|
||||||
|
"lowercase-keys": "^2.0.0",
|
||||||
|
"normalize-url": "^4.1.0",
|
||||||
|
"responselike": "^2.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"cheerio": {
|
"cheerio": {
|
||||||
"version": "1.0.0-rc.3",
|
"version": "1.0.0-rc.3",
|
||||||
|
|
@ -111,12 +118,12 @@
|
||||||
"parse5": "^3.0.1"
|
"parse5": "^3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"combined-stream": {
|
"clone-response": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
|
||||||
"integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
|
"integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"delayed-stream": "~1.0.0"
|
"mimic-response": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commander": {
|
"commander": {
|
||||||
|
|
@ -157,18 +164,25 @@
|
||||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
|
||||||
"integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg=="
|
"integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg=="
|
||||||
},
|
},
|
||||||
"dashdash": {
|
"decompress-response": {
|
||||||
"version": "1.14.1",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||||
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
|
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"assert-plus": "^1.0.0"
|
"mimic-response": "^3.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"mimic-response": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"delayed-stream": {
|
"defer-to-connect": {
|
||||||
"version": "1.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz",
|
||||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
"integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg=="
|
||||||
},
|
},
|
||||||
"dom-serializer": {
|
"dom-serializer": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
|
|
@ -201,13 +215,12 @@
|
||||||
"domelementtype": "1"
|
"domelementtype": "1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ecc-jsbn": {
|
"end-of-stream": {
|
||||||
"version": "0.1.2",
|
"version": "1.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||||
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
|
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"jsbn": "~0.1.0",
|
"once": "^1.4.0"
|
||||||
"safer-buffer": "^2.1.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"entities": {
|
"entities": {
|
||||||
|
|
@ -220,41 +233,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/event-to-promise/-/event-to-promise-0.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/event-to-promise/-/event-to-promise-0.7.0.tgz",
|
||||||
"integrity": "sha1-ywffzUGNoiIdkPd+q3E7wjXiCQ8="
|
"integrity": "sha1-ywffzUGNoiIdkPd+q3E7wjXiCQ8="
|
||||||
},
|
},
|
||||||
"extend": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
|
||||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
|
||||||
},
|
|
||||||
"extsprintf": {
|
|
||||||
"version": "1.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
|
|
||||||
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
|
|
||||||
},
|
|
||||||
"fast-deep-equal": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
|
||||||
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
|
|
||||||
},
|
|
||||||
"fast-json-stable-stringify": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
|
|
||||||
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
|
|
||||||
},
|
|
||||||
"forever-agent": {
|
|
||||||
"version": "0.6.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
|
||||||
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
|
|
||||||
},
|
|
||||||
"form-data": {
|
|
||||||
"version": "2.3.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
|
||||||
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
|
|
||||||
"requires": {
|
|
||||||
"asynckit": "^0.4.0",
|
|
||||||
"combined-stream": "^1.0.6",
|
|
||||||
"mime-types": "^2.1.12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"gbxremote": {
|
"gbxremote": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/gbxremote/-/gbxremote-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/gbxremote/-/gbxremote-0.2.1.tgz",
|
||||||
|
|
@ -267,12 +245,30 @@
|
||||||
"xmlrpc": "^1.3.1"
|
"xmlrpc": "^1.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"getpass": {
|
"get-stream": {
|
||||||
"version": "0.1.7",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz",
|
||||||
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
|
"integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"assert-plus": "^1.0.0"
|
"pump": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"got": {
|
||||||
|
"version": "11.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/got/-/got-11.5.1.tgz",
|
||||||
|
"integrity": "sha512-reQEZcEBMTGnujmQ+Wm97mJs/OK6INtO6HmLI+xt3+9CvnRwWjXutUvb2mqr+Ao4Lu05Rx6+udx9sOQAmExMxA==",
|
||||||
|
"requires": {
|
||||||
|
"@sindresorhus/is": "^3.0.0",
|
||||||
|
"@szmarczak/http-timer": "^4.0.5",
|
||||||
|
"@types/cacheable-request": "^6.0.1",
|
||||||
|
"@types/responselike": "^1.0.0",
|
||||||
|
"cacheable-lookup": "^5.0.3",
|
||||||
|
"cacheable-request": "^7.0.1",
|
||||||
|
"decompress-response": "^6.0.0",
|
||||||
|
"http2-wrapper": "^1.0.0-beta.5.0",
|
||||||
|
"lowercase-keys": "^2.0.0",
|
||||||
|
"p-cancelable": "^2.0.0",
|
||||||
|
"responselike": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"graceful-readlink": {
|
"graceful-readlink": {
|
||||||
|
|
@ -280,20 +276,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
|
||||||
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU="
|
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU="
|
||||||
},
|
},
|
||||||
"har-schema": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
|
||||||
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
|
|
||||||
},
|
|
||||||
"har-validator": {
|
|
||||||
"version": "5.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
|
|
||||||
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
|
|
||||||
"requires": {
|
|
||||||
"ajv": "^6.5.5",
|
|
||||||
"har-schema": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"htmlparser2": {
|
"htmlparser2": {
|
||||||
"version": "3.10.1",
|
"version": "3.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
|
||||||
|
|
@ -332,22 +314,26 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"http-signature": {
|
"http-cache-semantics": {
|
||||||
"version": "1.2.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
|
||||||
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
|
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ=="
|
||||||
|
},
|
||||||
|
"http2-wrapper": {
|
||||||
|
"version": "1.0.0-beta.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz",
|
||||||
|
"integrity": "sha512-xYz9goEyBnC8XwXDTuC/MZ6t+MrKVQZOk4s7+PaDkwIsQd8IwqvM+0M6bA/2lvG8GHXcPdf+MejTUeO2LCPCeQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"assert-plus": "^1.0.0",
|
"quick-lru": "^5.1.1",
|
||||||
"jsprim": "^1.2.2",
|
"resolve-alpn": "^1.0.0"
|
||||||
"sshpk": "^1.7.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"iconv-lite": {
|
"iconv-lite": {
|
||||||
"version": "0.5.0",
|
"version": "0.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
|
||||||
"integrity": "sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw==",
|
"integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"safer-buffer": ">= 2.1.2 < 3"
|
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"inherits": {
|
"inherits": {
|
||||||
|
|
@ -355,84 +341,58 @@
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||||
},
|
},
|
||||||
"is-typedarray": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
|
|
||||||
},
|
|
||||||
"isarray": {
|
"isarray": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||||
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||||
},
|
},
|
||||||
"isstream": {
|
"json-buffer": {
|
||||||
"version": "0.1.2",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
|
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
|
||||||
},
|
},
|
||||||
"jsbn": {
|
"keyv": {
|
||||||
"version": "0.1.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.1.tgz",
|
||||||
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
|
"integrity": "sha512-xz6Jv6oNkbhrFCvCP7HQa8AaII8y8LRpoSm661NOKLr4uHuBwhX4epXrPQgF3+xdJnN4Esm5X0xwY4bOlALOtw==",
|
||||||
},
|
|
||||||
"json-schema": {
|
|
||||||
"version": "0.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
|
||||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
|
|
||||||
},
|
|
||||||
"json-schema-traverse": {
|
|
||||||
"version": "0.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
|
||||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
|
||||||
},
|
|
||||||
"json-stringify-safe": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
|
||||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
|
|
||||||
},
|
|
||||||
"jsprim": {
|
|
||||||
"version": "1.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
|
|
||||||
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"assert-plus": "1.0.0",
|
"json-buffer": "3.0.1"
|
||||||
"extsprintf": "1.3.0",
|
|
||||||
"json-schema": "0.2.3",
|
|
||||||
"verror": "1.10.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.15",
|
"version": "4.17.19",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
|
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
|
||||||
},
|
},
|
||||||
"long": {
|
"long": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
|
||||||
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
|
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
|
||||||
},
|
},
|
||||||
"mime-db": {
|
"lowercase-keys": {
|
||||||
"version": "1.37.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz",
|
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
|
||||||
"integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg=="
|
"integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="
|
||||||
},
|
},
|
||||||
"mime-types": {
|
"mimic-response": {
|
||||||
"version": "2.1.21",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz",
|
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
|
||||||
"integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==",
|
"integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="
|
||||||
"requires": {
|
|
||||||
"mime-db": "~1.37.0"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||||
},
|
},
|
||||||
"moment": {
|
"moment": {
|
||||||
"version": "2.24.0",
|
"version": "2.27.0",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz",
|
||||||
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
|
"integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ=="
|
||||||
|
},
|
||||||
|
"normalize-url": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ=="
|
||||||
},
|
},
|
||||||
"nth-check": {
|
"nth-check": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
|
|
@ -442,10 +402,18 @@
|
||||||
"boolbase": "~1.0.0"
|
"boolbase": "~1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"oauth-sign": {
|
"once": {
|
||||||
"version": "0.9.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
|
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||||
|
"requires": {
|
||||||
|
"wrappy": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p-cancelable": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg=="
|
||||||
},
|
},
|
||||||
"parse5": {
|
"parse5": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
|
|
@ -455,30 +423,29 @@
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"performance-now": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
|
||||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
|
||||||
},
|
|
||||||
"process-nextick-args": {
|
"process-nextick-args": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||||
},
|
},
|
||||||
"psl": {
|
"pump": {
|
||||||
"version": "1.1.31",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz",
|
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
|
||||||
"integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw=="
|
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
|
||||||
|
"requires": {
|
||||||
|
"end-of-stream": "^1.1.0",
|
||||||
|
"once": "^1.3.1"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"punycode": {
|
"punycode": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||||
},
|
},
|
||||||
"qs": {
|
"quick-lru": {
|
||||||
"version": "6.5.2",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
|
||||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="
|
||||||
},
|
},
|
||||||
"readable-stream": {
|
"readable-stream": {
|
||||||
"version": "1.0.34",
|
"version": "1.0.34",
|
||||||
|
|
@ -491,68 +458,17 @@
|
||||||
"string_decoder": "~0.10.x"
|
"string_decoder": "~0.10.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"request": {
|
"resolve-alpn": {
|
||||||
"version": "2.88.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.0.0.tgz",
|
||||||
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
|
"integrity": "sha512-rTuiIEqFmGxne4IovivKSDzld2lWW9QCjqv80SYjPgf+gS35eaCAjaP54CCwGAwBtnCsvNLYtqxe1Nw+i6JEmA=="
|
||||||
"requires": {
|
|
||||||
"aws-sign2": "~0.7.0",
|
|
||||||
"aws4": "^1.8.0",
|
|
||||||
"caseless": "~0.12.0",
|
|
||||||
"combined-stream": "~1.0.6",
|
|
||||||
"extend": "~3.0.2",
|
|
||||||
"forever-agent": "~0.6.1",
|
|
||||||
"form-data": "~2.3.2",
|
|
||||||
"har-validator": "~5.1.0",
|
|
||||||
"http-signature": "~1.2.0",
|
|
||||||
"is-typedarray": "~1.0.0",
|
|
||||||
"isstream": "~0.1.2",
|
|
||||||
"json-stringify-safe": "~5.0.1",
|
|
||||||
"mime-types": "~2.1.19",
|
|
||||||
"oauth-sign": "~0.9.0",
|
|
||||||
"performance-now": "^2.1.0",
|
|
||||||
"qs": "~6.5.2",
|
|
||||||
"safe-buffer": "^5.1.2",
|
|
||||||
"tough-cookie": "~2.4.3",
|
|
||||||
"tunnel-agent": "^0.6.0",
|
|
||||||
"uuid": "^3.3.2"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"tough-cookie": {
|
|
||||||
"version": "2.4.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
|
|
||||||
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
|
|
||||||
"requires": {
|
|
||||||
"psl": "^1.1.24",
|
|
||||||
"punycode": "^1.4.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"punycode": {
|
|
||||||
"version": "1.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
|
||||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"request-promise": {
|
"responselike": {
|
||||||
"version": "4.2.4",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz",
|
||||||
"integrity": "sha512-8wgMrvE546PzbR5WbYxUQogUnUDfM0S7QIFZMID+J73vdFARkFy+HElj4T+MWYhpXwlLp0EQ8Zoj8xUA0he4Vg==",
|
"integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bluebird": "^3.5.0",
|
"lowercase-keys": "^2.0.0"
|
||||||
"request-promise-core": "1.1.2",
|
|
||||||
"stealthy-require": "^1.1.1",
|
|
||||||
"tough-cookie": "^2.3.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"request-promise-core": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==",
|
|
||||||
"requires": {
|
|
||||||
"lodash": "^4.17.11"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
|
|
@ -570,27 +486,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||||
},
|
},
|
||||||
"sshpk": {
|
|
||||||
"version": "1.16.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.0.tgz",
|
|
||||||
"integrity": "sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ==",
|
|
||||||
"requires": {
|
|
||||||
"asn1": "~0.2.3",
|
|
||||||
"assert-plus": "^1.0.0",
|
|
||||||
"bcrypt-pbkdf": "^1.0.0",
|
|
||||||
"dashdash": "^1.12.0",
|
|
||||||
"ecc-jsbn": "~0.1.1",
|
|
||||||
"getpass": "^0.1.1",
|
|
||||||
"jsbn": "~0.1.0",
|
|
||||||
"safer-buffer": "^2.0.2",
|
|
||||||
"tweetnacl": "~0.14.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"stealthy-require": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
|
|
||||||
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
|
|
||||||
},
|
|
||||||
"string-to-stream": {
|
"string-to-stream": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/string-to-stream/-/string-to-stream-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/string-to-stream/-/string-to-stream-1.1.1.tgz",
|
||||||
|
|
@ -634,67 +529,20 @@
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||||
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
|
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
|
||||||
},
|
},
|
||||||
"tough-cookie": {
|
|
||||||
"version": "2.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
|
|
||||||
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
|
|
||||||
"requires": {
|
|
||||||
"psl": "^1.1.28",
|
|
||||||
"punycode": "^2.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tunnel-agent": {
|
|
||||||
"version": "0.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
|
||||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
|
||||||
"requires": {
|
|
||||||
"safe-buffer": "^5.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tweetnacl": {
|
|
||||||
"version": "0.14.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
|
||||||
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
|
|
||||||
},
|
|
||||||
"uri-js": {
|
|
||||||
"version": "4.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
|
||||||
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
|
|
||||||
"requires": {
|
|
||||||
"punycode": "^2.1.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"punycode": {
|
|
||||||
"version": "2.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
|
||||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"util-deprecate": {
|
"util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||||
},
|
},
|
||||||
"uuid": {
|
|
||||||
"version": "3.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
|
|
||||||
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
|
|
||||||
},
|
|
||||||
"varint": {
|
"varint": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz",
|
||||||
"integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8="
|
"integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8="
|
||||||
},
|
},
|
||||||
"verror": {
|
"wrappy": {
|
||||||
"version": "1.10.0",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||||
"requires": {
|
|
||||||
"assert-plus": "^1.0.0",
|
|
||||||
"core-util-is": "1.0.2",
|
|
||||||
"extsprintf": "^1.2.0"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"xmlbuilder": {
|
"xmlbuilder": {
|
||||||
"version": "8.2.2",
|
"version": "8.2.2",
|
||||||
|
|
|
||||||
38
package.json
38
package.json
|
|
@ -7,33 +7,45 @@
|
||||||
"game",
|
"game",
|
||||||
"utility",
|
"utility",
|
||||||
"util",
|
"util",
|
||||||
"server"
|
"server",
|
||||||
|
"gameserver",
|
||||||
|
"node",
|
||||||
|
"nodejs",
|
||||||
|
"game-server-query",
|
||||||
|
"game server query",
|
||||||
|
"server query",
|
||||||
|
"game server",
|
||||||
|
"gameserverquery",
|
||||||
|
"serverquery",
|
||||||
|
"terraria",
|
||||||
|
"counter strike",
|
||||||
|
"csgo",
|
||||||
|
"minecraft"
|
||||||
],
|
],
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"author": "Michael Morrison",
|
"author": "GameDig Contributors",
|
||||||
"version": "2.0.20",
|
"version": "3.0.3",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sonicsnes/node-gamedig.git"
|
"url": "https://github.com/gamedig/node-gamedig.git"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/sonicsnes/node-gamedig/issues"
|
"url": "https://github.com/gamedig/node-gamedig/issues"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.0.0"
|
"node": ">=12.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cheerio": "^1.0.0-rc.3",
|
"cheerio": "^1.0.0-rc.3",
|
||||||
"compressjs": "^1.0.2",
|
"compressjs": "^1.0.2",
|
||||||
"gbxremote": "^0.2.1",
|
"gbxremote": "^0.2.1",
|
||||||
"iconv-lite": "^0.5.0",
|
"got": "^11.5.1",
|
||||||
|
"iconv-lite": "^0.6.2",
|
||||||
"long": "^4.0.0",
|
"long": "^4.0.0",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.5",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.27.0",
|
||||||
"punycode": "^2.1.1",
|
"punycode": "^2.1.1",
|
||||||
"request": "^2.88.0",
|
|
||||||
"request-promise": "^4.2.4",
|
|
||||||
"varint": "^5.0.0"
|
"varint": "^5.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -48,7 +60,7 @@
|
||||||
"README.md"
|
"README.md"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/cheerio": "^0.22.13",
|
"@types/cheerio": "^0.22.21",
|
||||||
"@types/node": "^8.10.54"
|
"@types/node": "^12.20.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
40
protocols/assettocorsa.js
Normal file
40
protocols/assettocorsa.js
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
const Core = require('./core');
|
||||||
|
|
||||||
|
class AssettoCorsa extends Core {
|
||||||
|
async run(state) {
|
||||||
|
const serverInfo = await this.request({
|
||||||
|
url: `http://${this.options.address}:${this.options.port}/INFO`,
|
||||||
|
responseType: 'json'
|
||||||
|
});
|
||||||
|
const carInfo = await this.request({
|
||||||
|
url: `http://${this.options.address}:${this.options.port}/JSON|${parseInt(Math.random() * 999999999999999, 10)}`,
|
||||||
|
responseType: 'json'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!serverInfo || !carInfo || !carInfo.Cars) {
|
||||||
|
throw new Error('Query not successful');
|
||||||
|
}
|
||||||
|
|
||||||
|
state.maxplayers = serverInfo.maxclients;
|
||||||
|
state.name = serverInfo.name;
|
||||||
|
state.map = serverInfo.track;
|
||||||
|
state.password = serverInfo.pass;
|
||||||
|
state.gamePort = serverInfo.port;
|
||||||
|
state.raw.carInfo = carInfo.Cars;
|
||||||
|
state.raw.serverInfo = serverInfo;
|
||||||
|
|
||||||
|
for (const car of carInfo.Cars) {
|
||||||
|
if (car.IsConnected) {
|
||||||
|
state.players.push({
|
||||||
|
name: car.DriverName,
|
||||||
|
car: car.Model,
|
||||||
|
skin: car.Skin,
|
||||||
|
nation: car.DriverNation,
|
||||||
|
team: car.DriverTeam
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AssettoCorsa;
|
||||||
|
|
@ -4,7 +4,7 @@ const Core = require('./core'),
|
||||||
class BuildAndShoot extends Core {
|
class BuildAndShoot extends Core {
|
||||||
async run(state) {
|
async run(state) {
|
||||||
const body = await this.request({
|
const body = await this.request({
|
||||||
uri: 'http://'+this.options.address+':'+this.options.port+'/',
|
url: 'http://'+this.options.address+':'+this.options.port+'/',
|
||||||
});
|
});
|
||||||
|
|
||||||
let m;
|
let m;
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@ const EventEmitter = require('events').EventEmitter,
|
||||||
net = require('net'),
|
net = require('net'),
|
||||||
Reader = require('../lib/reader'),
|
Reader = require('../lib/reader'),
|
||||||
HexUtil = require('../lib/HexUtil'),
|
HexUtil = require('../lib/HexUtil'),
|
||||||
requestAsync = require('request-promise'),
|
got = require('got'),
|
||||||
Promises = require('../lib/Promises'),
|
Promises = require('../lib/Promises'),
|
||||||
Logger = require('../lib/Logger'),
|
Logger = require('../lib/Logger'),
|
||||||
DnsResolver = require('../lib/DnsResolver');
|
DnsResolver = require('../lib/DnsResolver'),
|
||||||
|
Results = require('../lib/Results');
|
||||||
|
|
||||||
let uid = 0;
|
let uid = 0;
|
||||||
|
|
||||||
|
|
@ -35,16 +36,17 @@ class Core extends EventEmitter {
|
||||||
}
|
}
|
||||||
this.logger.prefix = 'Q#' + (uid++);
|
this.logger.prefix = 'Q#' + (uid++);
|
||||||
|
|
||||||
this.logger.debug("Query is running with options:", this.options);
|
this.logger.debug("Starting");
|
||||||
|
this.logger.debug("Protocol: " + this.constructor.name);
|
||||||
|
this.logger.debug("Options:", this.options);
|
||||||
|
|
||||||
let abortCall = null;
|
let abortCall = null;
|
||||||
this.abortedPromise = new Promise((resolve,reject) => {
|
this.abortedPromise = new Promise((resolve,reject) => {
|
||||||
abortCall = () => reject(new Error("Query is finished -- cancelling outstanding promises"));
|
abortCall = () => reject(new Error("Query is finished -- cancelling outstanding promises"));
|
||||||
|
}).catch(() => {
|
||||||
|
// Make sure that if this promise isn't attached to, it doesn't throw a unhandled promise rejection
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make sure that if this promise isn't attached to, it doesn't throw a unhandled promise rejection
|
|
||||||
this.abortedPromise.catch(() => {});
|
|
||||||
|
|
||||||
let timeout;
|
let timeout;
|
||||||
try {
|
try {
|
||||||
const promise = this.runOnce();
|
const promise = this.runOnce();
|
||||||
|
|
@ -73,44 +75,13 @@ class Core extends EventEmitter {
|
||||||
if (resolved.port) options.port = resolved.port;
|
if (resolved.port) options.port = resolved.port;
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = {
|
const state = new Results();
|
||||||
name: '',
|
|
||||||
map: '',
|
|
||||||
password: false,
|
|
||||||
|
|
||||||
raw: {},
|
|
||||||
|
|
||||||
maxplayers: 0,
|
|
||||||
players: [],
|
|
||||||
bots: []
|
|
||||||
};
|
|
||||||
|
|
||||||
await this.run(state);
|
await this.run(state);
|
||||||
|
|
||||||
// because lots of servers prefix with spaces to try to appear first
|
// because lots of servers prefix with spaces to try to appear first
|
||||||
state.name = (state.name || '').trim();
|
state.name = (state.name || '').trim();
|
||||||
|
|
||||||
if (typeof state.players === 'number') {
|
|
||||||
const num = state.players;
|
|
||||||
state.players = [];
|
|
||||||
state.raw.rcvNumPlayers = num;
|
|
||||||
if (num < 10000) {
|
|
||||||
for (let i = 0; i < num; i++) {
|
|
||||||
state.players.push({});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (typeof state.bots === 'number') {
|
|
||||||
const num = state.bots;
|
|
||||||
state.bots = [];
|
|
||||||
state.raw.rcvNumBots = num;
|
|
||||||
if (num < 10000) {
|
|
||||||
for (let i = 0; i < num; i++) {
|
|
||||||
state.bots.push({});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!('connect' in state)) {
|
if (!('connect' in state)) {
|
||||||
state.connect = ''
|
state.connect = ''
|
||||||
+ (state.gameHost || this.options.host || this.options.address)
|
+ (state.gameHost || this.options.host || this.options.address)
|
||||||
|
|
@ -129,7 +100,7 @@ class Core extends EventEmitter {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(state) {}
|
async run(/** Results */ state) {}
|
||||||
|
|
||||||
/** Param can be a time in ms, or a promise (which will be timed) */
|
/** Param can be a time in ms, or a promise (which will be timed) */
|
||||||
registerRtt(param) {
|
registerRtt(param) {
|
||||||
|
|
@ -342,24 +313,26 @@ class Core extends EventEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async request(params) {
|
async tcpPing() {
|
||||||
// If we haven't opened a raw tcp socket yet during this query, just open one and then immediately close it.
|
// This will give a much more accurate RTT than using the rtt of an http request.
|
||||||
// This will give us a much more accurate RTT than using the rtt of the http request.
|
|
||||||
if (!this.usedTcp) {
|
if (!this.usedTcp) {
|
||||||
await this.withTcp(() => {});
|
await this.withTcp(() => {});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async request(params) {
|
||||||
|
await this.tcpPing();
|
||||||
|
|
||||||
let requestPromise;
|
let requestPromise;
|
||||||
try {
|
try {
|
||||||
requestPromise = requestAsync({
|
requestPromise = got({
|
||||||
...params,
|
...params,
|
||||||
timeout: this.options.socketTimeout,
|
timeout: this.options.socketTimeout
|
||||||
resolveWithFullResponse: true
|
|
||||||
});
|
});
|
||||||
this.debugLog(log => {
|
this.debugLog(log => {
|
||||||
log(() => params.uri + " HTTP-->");
|
log(() => params.url + " HTTP-->");
|
||||||
requestPromise
|
requestPromise
|
||||||
.then((response) => log(params.uri + " <--HTTP " + response.statusCode))
|
.then((response) => log(params.url + " <--HTTP " + response.statusCode))
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
});
|
});
|
||||||
const wrappedPromise = requestPromise.then(response => {
|
const wrappedPromise = requestPromise.then(response => {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ class Ffow extends Valve {
|
||||||
this.debugLog("Requesting ffow info ...");
|
this.debugLog("Requesting ffow info ...");
|
||||||
const b = await this.sendPacket(
|
const b = await this.sendPacket(
|
||||||
0x46,
|
0x46,
|
||||||
false,
|
|
||||||
'LSQ',
|
'LSQ',
|
||||||
0x49
|
0x49
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -12,20 +12,19 @@ class FiveM extends Quake2 {
|
||||||
await super.run(state);
|
await super.run(state);
|
||||||
|
|
||||||
{
|
{
|
||||||
const raw = await this.request({
|
const json = await this.request({
|
||||||
uri: 'http://' + this.options.address + ':' + this.options.port + '/info.json'
|
url: 'http://' + this.options.address + ':' + this.options.port + '/info.json',
|
||||||
|
responseType: 'json'
|
||||||
});
|
});
|
||||||
const json = JSON.parse(raw);
|
|
||||||
state.raw.info = json;
|
state.raw.info = json;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const raw = await this.request({
|
const json = await this.request({
|
||||||
uri: 'http://' + this.options.address + ':' + this.options.port + '/players.json'
|
url: 'http://' + this.options.address + ':' + this.options.port + '/players.json',
|
||||||
|
responseType: 'json'
|
||||||
});
|
});
|
||||||
const json = JSON.parse(raw);
|
|
||||||
state.raw.players = json;
|
state.raw.players = json;
|
||||||
state.players = [];
|
|
||||||
for (const player of json) {
|
for (const player of json) {
|
||||||
state.players.push({name: player.name, ping: player.ping});
|
state.players.push({name: player.name, ping: player.ping});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,33 @@
|
||||||
const Core = require('./core');
|
const Core = require('./core');
|
||||||
|
|
||||||
|
const stringKeys = new Set([
|
||||||
|
'website',
|
||||||
|
'gametype',
|
||||||
|
'gamemode',
|
||||||
|
'player'
|
||||||
|
]);
|
||||||
|
|
||||||
|
function normalizeEntry([key,value]) {
|
||||||
|
key = key.toLowerCase();
|
||||||
|
const split = key.split('_');
|
||||||
|
let keyType;
|
||||||
|
if (split.length === 2 && !isNaN(parseInt(split[1]))) {
|
||||||
|
keyType = split[0];
|
||||||
|
} else {
|
||||||
|
keyType = key;
|
||||||
|
}
|
||||||
|
if (!stringKeys.has(keyType) && !keyType.includes('name')) {
|
||||||
|
if (value.toLowerCase() === 'true') {
|
||||||
|
value = true;
|
||||||
|
} else if (value.toLowerCase() === 'false') {
|
||||||
|
value = false;
|
||||||
|
} else if (!isNaN(parseInt(value))) {
|
||||||
|
value = parseInt(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [key,value];
|
||||||
|
}
|
||||||
|
|
||||||
class Gamespy1 extends Core {
|
class Gamespy1 extends Core {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
@ -8,89 +36,80 @@ class Gamespy1 extends Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(state) {
|
async run(state) {
|
||||||
{
|
const raw = await this.sendPacket('\\status\\xserverquery');
|
||||||
const data = await this.sendPacket('info');
|
// Convert all keys to lowercase and normalize value types
|
||||||
state.raw = data;
|
const data = Object.fromEntries(Object.entries(raw).map(entry => normalizeEntry(entry)));
|
||||||
if ('hostname' in state.raw) state.name = state.raw.hostname;
|
state.raw = data;
|
||||||
if ('mapname' in state.raw) state.map = state.raw.mapname;
|
if ('hostname' in data) state.name = data.hostname;
|
||||||
if (this.trueTest(state.raw.password)) state.password = true;
|
if ('mapname' in data) state.map = data.mapname;
|
||||||
if ('maxplayers' in state.raw) state.maxplayers = parseInt(state.raw.maxplayers);
|
if (this.trueTest(data.password)) state.password = true;
|
||||||
if ('hostport' in state.raw) state.gamePort = parseInt(state.raw.hostport);
|
if ('maxplayers' in data) state.maxplayers = parseInt(data.maxplayers);
|
||||||
}
|
if ('hostport' in data) state.gamePort = parseInt(data.hostport);
|
||||||
{
|
|
||||||
const data = await this.sendPacket('rules');
|
|
||||||
state.raw.rules = data;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const data = await this.sendPacket('players');
|
|
||||||
const playersById = {};
|
|
||||||
const teamNamesById = {};
|
|
||||||
for (const ident of Object.keys(data)) {
|
|
||||||
const split = ident.split('_');
|
|
||||||
let key = split[0];
|
|
||||||
const id = split[1];
|
|
||||||
let value = data[ident];
|
|
||||||
|
|
||||||
|
const teamOffByOne = data.gameid === 'bf1942';
|
||||||
|
const playersById = {};
|
||||||
|
const teamNamesById = {};
|
||||||
|
for (const ident of Object.keys(data)) {
|
||||||
|
const split = ident.split('_');
|
||||||
|
if (split.length !== 2) continue;
|
||||||
|
let key = split[0].toLowerCase();
|
||||||
|
const id = parseInt(split[1]);
|
||||||
|
if (isNaN(id)) continue;
|
||||||
|
let value = data[ident];
|
||||||
|
|
||||||
|
delete data[ident];
|
||||||
|
|
||||||
|
if (key !== 'team' && key.startsWith('team')) {
|
||||||
|
// Info about a team
|
||||||
if (key === 'teamname') {
|
if (key === 'teamname') {
|
||||||
teamNamesById[id] = value;
|
teamNamesById[id] = value;
|
||||||
} else {
|
} else {
|
||||||
if (!(id in playersById)) playersById[id] = {};
|
// other team info which we don't track
|
||||||
if (key === 'playername') key = 'name';
|
|
||||||
else if (key === 'team') value = parseInt(value);
|
|
||||||
else if (key === 'score' || key === 'ping' || key === 'deaths' || key === 'kills') value = parseInt(value);
|
|
||||||
playersById[id][key] = value;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Info about a player
|
||||||
|
if (!(id in playersById)) playersById[id] = {};
|
||||||
|
if (key === 'playername' || key === 'player') {
|
||||||
|
key = 'name';
|
||||||
|
}
|
||||||
|
if (key === 'team' && !isNaN(parseInt(value))) {
|
||||||
|
key = 'teamId';
|
||||||
|
value = parseInt(value) + (teamOffByOne ? -1 : 0);
|
||||||
|
}
|
||||||
|
if (key !== 'name' && !isNaN(parseInt(value))) {
|
||||||
|
value = parseInt(value);
|
||||||
|
}
|
||||||
|
playersById[id][key] = value;
|
||||||
}
|
}
|
||||||
state.raw.teams = teamNamesById;
|
}
|
||||||
|
state.raw.teams = teamNamesById;
|
||||||
|
|
||||||
const players = Object.values(playersById);
|
const players = Object.values(playersById);
|
||||||
|
|
||||||
// Determine which team id might be for spectators
|
const seenHashes = new Set();
|
||||||
let specTeamId = null;
|
for (const player of players) {
|
||||||
for (const player of players) {
|
// Some servers (bf1942) report the same player multiple times (bug?)
|
||||||
if (!player.team) {
|
// Ignore these duplicates
|
||||||
|
if (player.keyhash) {
|
||||||
|
if (seenHashes.has(player.keyhash)) {
|
||||||
|
this.logger.debug("Rejected player with hash " + player.keyhash + " (Duplicate keyhash)");
|
||||||
continue;
|
continue;
|
||||||
} else if (teamNamesById[player.team]) {
|
|
||||||
continue;
|
|
||||||
} else if (teamNamesById[player.team-1] && (specTeamId === null || specTeamId === player.team)) {
|
|
||||||
specTeamId = player.team;
|
|
||||||
} else {
|
} else {
|
||||||
specTeamId = null;
|
seenHashes.add(player.keyhash);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.logger.debug(log => {
|
|
||||||
if (specTeamId === null) {
|
// Convert player's team ID to team name if possible
|
||||||
log("Could not detect a team ID for spectators");
|
if (player.hasOwnProperty('teamId')) {
|
||||||
|
if (Object.keys(teamNamesById).length) {
|
||||||
|
player.team = teamNamesById[player.teamId] || '';
|
||||||
} else {
|
} else {
|
||||||
log("Detected that team ID " + specTeamId + " is probably for spectators");
|
player.team = player.teamId;
|
||||||
|
delete player.teamId;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
const seenHashes = new Set();
|
|
||||||
for (const player of players) {
|
|
||||||
// Some servers (bf1942) report the same player multiple times (bug?)
|
|
||||||
// Ignore these duplicates
|
|
||||||
if (player.keyhash) {
|
|
||||||
if (seenHashes.has(player.keyhash)) {
|
|
||||||
this.logger.debug("Rejected player with hash " + player.keyhash + " (Duplicate keyhash)");
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
seenHashes.add(player.keyhash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert player's team ID to team name if possible
|
|
||||||
if (player.team) {
|
|
||||||
if (teamNamesById[player.team]) {
|
|
||||||
player.team = teamNamesById[player.team];
|
|
||||||
} else if (player.team === specTeamId) {
|
|
||||||
player.team = "spec";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
state.players.push(player);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.players.push(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,7 +119,7 @@ class Gamespy1 extends Core {
|
||||||
const parts = new Set();
|
const parts = new Set();
|
||||||
let maxPartNum = 0;
|
let maxPartNum = 0;
|
||||||
|
|
||||||
return await this.udpSend('\\'+type+'\\', buffer => {
|
return await this.udpSend(type, buffer => {
|
||||||
const reader = this.reader(buffer);
|
const reader = this.reader(buffer);
|
||||||
const str = reader.string(buffer.length);
|
const str = reader.string(buffer.length);
|
||||||
const split = str.split('\\');
|
const split = str.split('\\');
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,9 @@ class Gamespy2 extends Core {
|
||||||
{
|
{
|
||||||
const body = await this.sendPacket([0, 0xff, 0]);
|
const body = await this.sendPacket([0, 0xff, 0]);
|
||||||
const reader = this.reader(body);
|
const reader = this.reader(body);
|
||||||
state.players = this.readFieldData(reader);
|
for (const rawPlayer of this.readFieldData(reader)) {
|
||||||
|
state.players.push(rawPlayer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse teams
|
// Parse teams
|
||||||
|
|
|
||||||
|
|
@ -148,9 +148,15 @@ class Gamespy3 extends Core {
|
||||||
return await this.udpSend(b,(buffer) => {
|
return await this.udpSend(b,(buffer) => {
|
||||||
const reader = this.reader(buffer);
|
const reader = this.reader(buffer);
|
||||||
const iType = reader.uint(1);
|
const iType = reader.uint(1);
|
||||||
if(iType !== type) return;
|
if(iType !== type) {
|
||||||
|
this.logger.debug('Skipping packet, type mismatch');
|
||||||
|
return;
|
||||||
|
}
|
||||||
const iSessionId = reader.uint(4);
|
const iSessionId = reader.uint(4);
|
||||||
if(iSessionId !== this.sessionId) return;
|
if(iSessionId !== this.sessionId) {
|
||||||
|
this.logger.debug('Skipping packet, session id mismatch');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(!assemble) {
|
if(!assemble) {
|
||||||
return reader.rest();
|
return reader.rest();
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@ const Core = require('./core');
|
||||||
|
|
||||||
class GeneShift extends Core {
|
class GeneShift extends Core {
|
||||||
async run(state) {
|
async run(state) {
|
||||||
|
await this.tcpPing();
|
||||||
|
|
||||||
const body = await this.request({
|
const body = await this.request({
|
||||||
uri: 'http://geneshift.net/game/receiveLobby.php'
|
url: 'http://geneshift.net/game/receiveLobby.php'
|
||||||
});
|
});
|
||||||
|
|
||||||
const split = body.split('<br/>');
|
const split = body.split('<br/>');
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@ const Core = require('./core');
|
||||||
|
|
||||||
class Kspdmp extends Core {
|
class Kspdmp extends Core {
|
||||||
async run(state) {
|
async run(state) {
|
||||||
const body = await this.request({
|
const json = await this.request({
|
||||||
uri: 'http://'+this.options.address+':'+this.options.port
|
url: 'http://'+this.options.address+':'+this.options.port,
|
||||||
|
responseType: 'json'
|
||||||
});
|
});
|
||||||
|
|
||||||
const json = JSON.parse(body);
|
|
||||||
for (const one of json.players) {
|
for (const one of json.players) {
|
||||||
state.players.push({name:one.nickname,team:one.team});
|
state.players.push({name:one.nickname,team:one.team});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,16 @@
|
||||||
const Core = require('./core'),
|
const Core = require('./core'),
|
||||||
MinecraftVanilla = require('./minecraftvanilla'),
|
MinecraftVanilla = require('./minecraftvanilla'),
|
||||||
|
MinecraftBedrock = require('./minecraftbedrock'),
|
||||||
Gamespy3 = require('./gamespy3');
|
Gamespy3 = require('./gamespy3');
|
||||||
|
|
||||||
|
/*
|
||||||
|
Vanilla servers respond to minecraftvanilla only
|
||||||
|
Some modded vanilla servers respond to minecraftvanilla and gamespy3, or gamespy3 only
|
||||||
|
Some bedrock servers respond to gamespy3 only
|
||||||
|
Some bedrock servers respond to minecraftbedrock only
|
||||||
|
Unsure if any bedrock servers respond to gamespy3 and minecraftbedrock
|
||||||
|
*/
|
||||||
|
|
||||||
class Minecraft extends Core {
|
class Minecraft extends Core {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
@ -17,25 +26,40 @@ class Minecraft extends Core {
|
||||||
try { return await vanillaResolver.runOnceSafe(); } catch(e) {}
|
try { return await vanillaResolver.runOnceSafe(); } catch(e) {}
|
||||||
})());
|
})());
|
||||||
|
|
||||||
const bedrockResolver = new Gamespy3();
|
const gamespyResolver = new Gamespy3();
|
||||||
bedrockResolver.options = {
|
gamespyResolver.options = {
|
||||||
...this.options,
|
...this.options,
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
};
|
};
|
||||||
|
gamespyResolver.udpSocket = this.udpSocket;
|
||||||
|
promises.push((async () => {
|
||||||
|
try { return await gamespyResolver.runOnceSafe(); } catch(e) {}
|
||||||
|
})());
|
||||||
|
|
||||||
|
const bedrockResolver = new MinecraftBedrock();
|
||||||
|
bedrockResolver.options = this.options;
|
||||||
bedrockResolver.udpSocket = this.udpSocket;
|
bedrockResolver.udpSocket = this.udpSocket;
|
||||||
promises.push((async () => {
|
promises.push((async () => {
|
||||||
try { return await bedrockResolver.runOnceSafe(); } catch(e) {}
|
try { return await bedrockResolver.runOnceSafe(); } catch(e) {}
|
||||||
})());
|
})());
|
||||||
|
|
||||||
const [ vanillaState, bedrockState ] = await Promise.all(promises);
|
const [ vanillaState, gamespyState, bedrockState ] = await Promise.all(promises);
|
||||||
|
|
||||||
state.raw.vanilla = vanillaState;
|
state.raw.vanilla = vanillaState;
|
||||||
|
state.raw.gamespy = gamespyState;
|
||||||
state.raw.bedrock = bedrockState;
|
state.raw.bedrock = bedrockState;
|
||||||
|
|
||||||
if (!vanillaState && !bedrockState) {
|
if (!vanillaState && !gamespyState && !bedrockState) {
|
||||||
throw new Error('No protocols succeeded');
|
throw new Error('No protocols succeeded');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ordered from least worth to most worth (player names / etc)
|
||||||
|
if (bedrockState) {
|
||||||
|
if (bedrockState.name) state.name = bedrockState.name;
|
||||||
|
if (bedrockState.maxplayers) state.maxplayers = bedrockState.maxplayers;
|
||||||
|
if (bedrockState.players) state.players = bedrockState.players;
|
||||||
|
if (bedrockState.map) state.map = bedrockState.map;
|
||||||
|
}
|
||||||
if (vanillaState) {
|
if (vanillaState) {
|
||||||
try {
|
try {
|
||||||
let name = '';
|
let name = '';
|
||||||
|
|
@ -54,10 +78,11 @@ class Minecraft extends Core {
|
||||||
if (vanillaState.maxplayers) state.maxplayers = vanillaState.maxplayers;
|
if (vanillaState.maxplayers) state.maxplayers = vanillaState.maxplayers;
|
||||||
if (vanillaState.players) state.players = vanillaState.players;
|
if (vanillaState.players) state.players = vanillaState.players;
|
||||||
}
|
}
|
||||||
if (bedrockState) {
|
if (gamespyState) {
|
||||||
if (bedrockState.name) state.name = bedrockState.name;
|
if (gamespyState.name) state.name = gamespyState.name;
|
||||||
if (bedrockState.maxplayers) state.maxplayers = bedrockState.maxplayers;
|
if (gamespyState.maxplayers) state.maxplayers = gamespyState.maxplayers;
|
||||||
if (bedrockState.players) state.players = bedrockState.players;
|
if (gamespyState.players.length) state.players = gamespyState.players;
|
||||||
|
else if (gamespyState.raw.numplayers) state.players = parseInt(gamespyState.raw.numplayers);
|
||||||
}
|
}
|
||||||
// remove dupe spaces from name
|
// remove dupe spaces from name
|
||||||
state.name = state.name.replace(/\s+/g, ' ');
|
state.name = state.name.replace(/\s+/g, ' ');
|
||||||
|
|
|
||||||
76
protocols/minecraftbedrock.js
Normal file
76
protocols/minecraftbedrock.js
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
const Core = require('./core');
|
||||||
|
|
||||||
|
class MinecraftBedrock extends Core {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.byteorder = 'be';
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(state) {
|
||||||
|
const bufs = [
|
||||||
|
Buffer.from([0x01]), // Message ID, ID_UNCONNECTED_PING
|
||||||
|
Buffer.from('1122334455667788', 'hex'), // Nonce / timestamp
|
||||||
|
Buffer.from('00ffff00fefefefefdfdfdfd12345678', 'hex'), // Magic
|
||||||
|
Buffer.from('0000000000000000', 'hex') // Cliend GUID
|
||||||
|
];
|
||||||
|
|
||||||
|
return await this.udpSend(Buffer.concat(bufs), buffer => {
|
||||||
|
const reader = this.reader(buffer);
|
||||||
|
|
||||||
|
const messageId = reader.uint(1);
|
||||||
|
if (messageId !== 0x1c) {
|
||||||
|
this.logger.debug('Skipping packet, invalid message id');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nonce = reader.part(8).toString('hex'); // should match the nonce we sent
|
||||||
|
this.logger.debug('Nonce: ' + nonce);
|
||||||
|
if (nonce !== '1122334455667788') {
|
||||||
|
this.logger.debug('Skipping packet, invalid nonce');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These 8 bytes are identical to the serverId string we receive in decimal below
|
||||||
|
reader.skip(8);
|
||||||
|
|
||||||
|
const magic = reader.part(16).toString('hex');
|
||||||
|
this.logger.debug('Magic value: ' + magic);
|
||||||
|
if (magic !== '00ffff00fefefefefdfdfdfd12345678') {
|
||||||
|
this.logger.debug('Skipping packet, invalid magic');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusLen = reader.uint(2);
|
||||||
|
if (reader.remaining() !== statusLen) {
|
||||||
|
throw new Error('Invalid status length: ' + reader.remaining() + ' vs ' + statusLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusStr = reader.rest().toString('utf8');
|
||||||
|
this.logger.debug('Raw status str: ' + statusStr);
|
||||||
|
|
||||||
|
const split = statusStr.split(';');
|
||||||
|
if (split.length < 6) {
|
||||||
|
throw new Error('Missing enough chunks in status str');
|
||||||
|
}
|
||||||
|
|
||||||
|
state.raw.edition = split.shift();
|
||||||
|
state.name = split.shift();
|
||||||
|
state.raw.protocolVersion = split.shift();
|
||||||
|
state.raw.mcVersion = split.shift();
|
||||||
|
state.players = parseInt(split.shift());
|
||||||
|
state.maxplayers = parseInt(split.shift());
|
||||||
|
if (split.length) state.raw.serverId = split.shift();
|
||||||
|
if (split.length) state.map = split.shift();
|
||||||
|
if (split.length) state.raw.gameMode = split.shift();
|
||||||
|
if (split.length) state.raw.nintendoOnly = !!parseInt(split.shift());
|
||||||
|
if (split.length) state.raw.ipv4Port = split.shift();
|
||||||
|
if (split.length) state.raw.ipv6Port = split.shift();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = MinecraftBedrock;
|
||||||
|
|
@ -47,6 +47,7 @@ class MinecraftVanilla extends Core {
|
||||||
|
|
||||||
state.raw = json;
|
state.raw = json;
|
||||||
state.maxplayers = json.players.max;
|
state.maxplayers = json.players.max;
|
||||||
|
|
||||||
if(json.players.sample) {
|
if(json.players.sample) {
|
||||||
for(const player of json.players.sample) {
|
for(const player of json.players.sample) {
|
||||||
state.players.push({
|
state.players.push({
|
||||||
|
|
@ -55,7 +56,11 @@ class MinecraftVanilla extends Core {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let i = 0; i < Math.min(json.players.online, 10000); i++) {
|
|
||||||
|
// players.sample may not contain all players or no players at all, depending on how many players are online.
|
||||||
|
// Insert a dummy player object for every online player that is not listed in players.sample.
|
||||||
|
// Limit player amount to 10.000 players for performance reasons.
|
||||||
|
for (let i = state.players.length; i < Math.min(json.players.online, 10000); i++) {
|
||||||
state.players.push({});
|
state.players.push({});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,9 +60,9 @@ class OpenTtd extends Core {
|
||||||
company.id = reader.uint(1);
|
company.id = reader.uint(1);
|
||||||
company.name = reader.string();
|
company.name = reader.string();
|
||||||
company.year_start = reader.uint(4);
|
company.year_start = reader.uint(4);
|
||||||
company.value = reader.uint(8);
|
company.value = reader.uint(8).toString();
|
||||||
company.money = reader.uint(8);
|
company.money = reader.uint(8).toString();
|
||||||
company.income = reader.uint(8);
|
company.income = reader.uint(8).toString();
|
||||||
company.performance = reader.uint(2);
|
company.performance = reader.uint(2);
|
||||||
company.password = !!reader.uint(1);
|
company.password = !!reader.uint(1);
|
||||||
|
|
||||||
|
|
|
||||||
31
protocols/savage2.js
Normal file
31
protocols/savage2.js
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
const Core = require('./core');
|
||||||
|
|
||||||
|
class Savage2 extends Core {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(state) {
|
||||||
|
const buffer = await this.udpSend('\x01',b => b);
|
||||||
|
const reader = this.reader(buffer);
|
||||||
|
|
||||||
|
reader.skip(12);
|
||||||
|
state.name = this.stripColorCodes(reader.string());
|
||||||
|
state.players = reader.uint(1);
|
||||||
|
state.maxplayers = reader.uint(1);
|
||||||
|
state.raw.time = reader.string();
|
||||||
|
state.map = reader.string();
|
||||||
|
state.raw.nextmap = reader.string();
|
||||||
|
state.raw.location = reader.string();
|
||||||
|
state.raw.minplayers = reader.uint(1);
|
||||||
|
state.raw.gametype = reader.string();
|
||||||
|
state.raw.version = reader.string();
|
||||||
|
state.raw.minlevel = reader.uint(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
stripColorCodes(str) {
|
||||||
|
return str.replace(/\^./g,'');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Savage2;
|
||||||
|
|
@ -16,7 +16,7 @@ class Starmade extends Core {
|
||||||
const reader = this.reader(buffer);
|
const reader = this.reader(buffer);
|
||||||
const packetLength = reader.uint(4);
|
const packetLength = reader.uint(4);
|
||||||
this.logger.debug("Received packet length: " + packetLength);
|
this.logger.debug("Received packet length: " + packetLength);
|
||||||
const timestamp = reader.uint(8);
|
const timestamp = reader.uint(8).toString();
|
||||||
this.logger.debug("Received timestamp: " + timestamp);
|
this.logger.debug("Received timestamp: " + timestamp);
|
||||||
if (reader.remaining() < packetLength || reader.remaining() < 5) return;
|
if (reader.remaining() < packetLength || reader.remaining() < 5) return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,15 @@ const Core = require('./core');
|
||||||
|
|
||||||
class Terraria extends Core {
|
class Terraria extends Core {
|
||||||
async run(state) {
|
async run(state) {
|
||||||
const body = await this.request({
|
const json = await this.request({
|
||||||
uri: 'http://'+this.options.address+':'+this.options.port+'/v2/server/status',
|
url: 'http://'+this.options.address+':'+this.options.port+'/v2/server/status',
|
||||||
qs: {
|
searchParams: {
|
||||||
players: 'true',
|
players: 'true',
|
||||||
token: this.options.token
|
token: this.options.token
|
||||||
}
|
},
|
||||||
|
responseType: 'json'
|
||||||
});
|
});
|
||||||
|
|
||||||
const json = JSON.parse(body);
|
|
||||||
if(json.status !== '200') throw new Error('Invalid status');
|
if(json.status !== '200') throw new Error('Invalid status');
|
||||||
|
|
||||||
for (const one of json.players) {
|
for (const one of json.players) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
const Bzip2 = require('compressjs').Bzip2,
|
const Bzip2 = require('compressjs').Bzip2,
|
||||||
Core = require('./core');
|
Core = require('./core'),
|
||||||
|
Results = require('../lib/Results');
|
||||||
|
|
||||||
|
const AppId = {
|
||||||
|
Squad: 393380,
|
||||||
|
Bat1944: 489940,
|
||||||
|
Ship: 2400
|
||||||
|
};
|
||||||
|
|
||||||
class Valve extends Core {
|
class Valve extends Core {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
@ -34,11 +41,10 @@ class Valve extends Core {
|
||||||
await this.cleanup(state);
|
await this.cleanup(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
async queryInfo(state) {
|
async queryInfo(/** Results */ state) {
|
||||||
this.debugLog("Requesting info ...");
|
this.debugLog("Requesting info ...");
|
||||||
const b = await this.sendPacket(
|
const b = await this.sendPacket(
|
||||||
0x54,
|
0x54,
|
||||||
false,
|
|
||||||
'Source Engine Query\0',
|
'Source Engine Query\0',
|
||||||
this.goldsrcInfo ? 0x6D : 0x49,
|
this.goldsrcInfo ? 0x6D : 0x49,
|
||||||
false
|
false
|
||||||
|
|
@ -53,7 +59,7 @@ class Valve extends Core {
|
||||||
state.map = reader.string();
|
state.map = reader.string();
|
||||||
state.raw.folder = reader.string();
|
state.raw.folder = reader.string();
|
||||||
state.raw.game = reader.string();
|
state.raw.game = reader.string();
|
||||||
state.raw.steamappid = reader.uint(2);
|
state.raw.appId = reader.uint(2);
|
||||||
state.raw.numplayers = reader.uint(1);
|
state.raw.numplayers = reader.uint(1);
|
||||||
state.maxplayers = reader.uint(1);
|
state.maxplayers = reader.uint(1);
|
||||||
|
|
||||||
|
|
@ -85,7 +91,7 @@ class Valve extends Core {
|
||||||
if(this.goldsrcInfo) {
|
if(this.goldsrcInfo) {
|
||||||
state.raw.numbots = reader.uint(1);
|
state.raw.numbots = reader.uint(1);
|
||||||
} else {
|
} else {
|
||||||
if(state.raw.folder === 'ship') {
|
if(state.raw.appId === AppId.Ship) {
|
||||||
state.raw.shipmode = reader.uint(1);
|
state.raw.shipmode = reader.uint(1);
|
||||||
state.raw.shipwitnesses = reader.uint(1);
|
state.raw.shipwitnesses = reader.uint(1);
|
||||||
state.raw.shipduration = reader.uint(1);
|
state.raw.shipduration = reader.uint(1);
|
||||||
|
|
@ -93,30 +99,35 @@ class Valve extends Core {
|
||||||
state.raw.version = reader.string();
|
state.raw.version = reader.string();
|
||||||
const extraFlag = reader.uint(1);
|
const extraFlag = reader.uint(1);
|
||||||
if(extraFlag & 0x80) state.gamePort = reader.uint(2);
|
if(extraFlag & 0x80) state.gamePort = reader.uint(2);
|
||||||
if(extraFlag & 0x10) state.raw.steamid = reader.uint(8);
|
if(extraFlag & 0x10) state.raw.steamid = reader.uint(8).toString();
|
||||||
if(extraFlag & 0x40) {
|
if(extraFlag & 0x40) {
|
||||||
state.raw.sourcetvport = reader.uint(2);
|
state.raw.sourcetvport = reader.uint(2);
|
||||||
state.raw.sourcetvname = reader.string();
|
state.raw.sourcetvname = reader.string();
|
||||||
}
|
}
|
||||||
if(extraFlag & 0x20) state.raw.tags = reader.string();
|
if(extraFlag & 0x20) state.raw.tags = reader.string();
|
||||||
if(extraFlag & 0x01) state.raw.gameid = reader.uint(8);
|
if(extraFlag & 0x01) {
|
||||||
|
const gameId = reader.uint(8);
|
||||||
|
const betterAppId = gameId.getLowBitsUnsigned() & 0xffffff;
|
||||||
|
if (betterAppId) {
|
||||||
|
state.raw.appId = betterAppId;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// from https://developer.valvesoftware.com/wiki/Server_queries
|
// from https://developer.valvesoftware.com/wiki/Server_queries
|
||||||
if(
|
if(
|
||||||
state.raw.protocol === 7 && (
|
state.raw.protocol === 7 && (
|
||||||
state.raw.steamappid === 215
|
state.raw.appId === 215
|
||||||
|| state.raw.steamappid === 17550
|
|| state.raw.appId === 17550
|
||||||
|| state.raw.steamappid === 17700
|
|| state.raw.appId === 17700
|
||||||
|| state.raw.steamappid === 240
|
|| state.raw.appId === 240
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
this._skipSizeInSplitHeader = true;
|
this._skipSizeInSplitHeader = true;
|
||||||
}
|
}
|
||||||
this.debugLog("STEAM APPID: "+state.raw.steamappid);
|
this.logger.debug("INFO: ", state.raw);
|
||||||
this.debugLog("PROTOCOL: "+state.raw.protocol);
|
|
||||||
if(state.raw.protocol === 48) {
|
if(state.raw.protocol === 48) {
|
||||||
this.debugLog("GOLDSRC DETECTED - USING MODIFIED SPLIT FORMAT");
|
this.logger.debug("GOLDSRC DETECTED - USING MODIFIED SPLIT FORMAT");
|
||||||
this.goldsrcSplits = true;
|
this.goldsrcSplits = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +139,6 @@ class Valve extends Core {
|
||||||
this.debugLog("Requesting legacy challenge key ...");
|
this.debugLog("Requesting legacy challenge key ...");
|
||||||
await this.sendPacket(
|
await this.sendPacket(
|
||||||
0x57,
|
0x57,
|
||||||
false,
|
|
||||||
null,
|
null,
|
||||||
0x41,
|
0x41,
|
||||||
false
|
false
|
||||||
|
|
@ -136,22 +146,24 @@ class Valve extends Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async queryPlayers(state) {
|
async queryPlayers(/** Results */ state) {
|
||||||
state.raw.players = [];
|
state.raw.players = [];
|
||||||
|
|
||||||
// CSGO doesn't even respond sometimes if host_players_show is not 2
|
|
||||||
// Ignore timeouts in only this case
|
|
||||||
const allowTimeout = state.raw.steamappid === 730;
|
|
||||||
|
|
||||||
this.debugLog("Requesting player list ...");
|
this.debugLog("Requesting player list ...");
|
||||||
const b = await this.sendPacket(
|
const b = await this.sendPacket(
|
||||||
0x55,
|
0x55,
|
||||||
true,
|
|
||||||
null,
|
null,
|
||||||
0x44,
|
0x44,
|
||||||
allowTimeout
|
true
|
||||||
);
|
);
|
||||||
if (b === null) return; // timed out
|
|
||||||
|
if (b === null) {
|
||||||
|
// Player query timed out
|
||||||
|
// CSGO doesn't respond to player query if host_players_show is not 2
|
||||||
|
// Conan Exiles never responds to player query
|
||||||
|
// Just skip it, and we'll fill with dummy objects in cleanup()
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const reader = this.reader(b);
|
const reader = this.reader(b);
|
||||||
const num = reader.uint(1);
|
const num = reader.uint(1);
|
||||||
|
|
@ -175,42 +187,61 @@ class Valve extends Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async queryRules(state) {
|
async queryRules(/** Results */ state) {
|
||||||
state.raw.rules = {};
|
const appId = state.raw.appId;
|
||||||
|
if (appId === AppId.Squad
|
||||||
|
|| appId === AppId.Bat1944
|
||||||
|
|| this.options.requestRules) {
|
||||||
|
// let's get 'em
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rules = {};
|
||||||
|
state.raw.rules = rules;
|
||||||
this.debugLog("Requesting rules ...");
|
this.debugLog("Requesting rules ...");
|
||||||
const b = await this.sendPacket(0x56,true,null,0x45,true);
|
const b = await this.sendPacket(0x56,null,0x45,true);
|
||||||
if (b === null) return; // timed out - the server probably just has rules disabled
|
if (b === null) return; // timed out - the server probably has rules disabled
|
||||||
|
|
||||||
const reader = this.reader(b);
|
const reader = this.reader(b);
|
||||||
const num = reader.uint(2);
|
const num = reader.uint(2);
|
||||||
for(let i = 0; i < num; i++) {
|
for(let i = 0; i < num; i++) {
|
||||||
const key = reader.string();
|
const key = reader.string();
|
||||||
const value = reader.string();
|
const value = reader.string();
|
||||||
state.raw.rules[key] = value;
|
rules[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Battalion 1944 puts its info into rules fields for some reason
|
||||||
|
if (appId === AppId.Bat1944) {
|
||||||
|
if ('bat_name_s' in rules) {
|
||||||
|
state.name = rules.bat_name_s;
|
||||||
|
delete rules.bat_name_s;
|
||||||
|
if ('bat_player_count_s' in rules) {
|
||||||
|
state.raw.numplayers = parseInt(rules.bat_player_count_s);
|
||||||
|
delete rules.bat_player_count_s;
|
||||||
|
}
|
||||||
|
if ('bat_max_players_i' in rules) {
|
||||||
|
state.maxplayers = parseInt(rules.bat_max_players_i);
|
||||||
|
delete rules.bat_max_players_i;
|
||||||
|
}
|
||||||
|
if ('bat_has_password_s' in rules) {
|
||||||
|
state.password = rules.bat_has_password_s === 'Y';
|
||||||
|
delete rules.bat_has_password_s;
|
||||||
|
}
|
||||||
|
// apparently map is already right, and this var is often wrong
|
||||||
|
delete rules.bat_map_s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Squad keeps its password in a separate field
|
||||||
|
if (appId === AppId.Squad) {
|
||||||
|
if (rules.Password_b === "true") {
|
||||||
|
state.password = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async cleanup(state) {
|
async cleanup(/** Results */ state) {
|
||||||
// Battalion 1944 puts its info into rules fields for some reason
|
|
||||||
if ('bat_name_s' in state.raw.rules) {
|
|
||||||
state.name = state.raw.rules.bat_name_s;
|
|
||||||
delete state.raw.rules.bat_name_s;
|
|
||||||
if ('bat_player_count_s' in state.raw.rules) {
|
|
||||||
state.raw.numplayers = parseInt(state.raw.rules.bat_player_count_s);
|
|
||||||
delete state.raw.rules.bat_player_count_s;
|
|
||||||
}
|
|
||||||
if ('bat_max_players_i' in state.raw.rules) {
|
|
||||||
state.maxplayers = parseInt(state.raw.rules.bat_max_players_i);
|
|
||||||
delete state.raw.rules.bat_max_players_i;
|
|
||||||
}
|
|
||||||
if ('bat_has_password_s' in state.raw.rules) {
|
|
||||||
state.password = state.raw.rules.bat_has_password_s === 'Y';
|
|
||||||
delete state.raw.rules.bat_has_password_s;
|
|
||||||
}
|
|
||||||
// apparently map is already right, and this var is often wrong
|
|
||||||
delete state.raw.rules.bat_map_s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Organize players / hidden players into player / bot arrays
|
// Organize players / hidden players into player / bot arrays
|
||||||
const botProbability = (p) => {
|
const botProbability = (p) => {
|
||||||
if (p.time === -1) return Number.MAX_VALUE;
|
if (p.time === -1) return Number.MAX_VALUE;
|
||||||
|
|
@ -243,33 +274,29 @@ class Valve extends Core {
|
||||||
**/
|
**/
|
||||||
async sendPacket(
|
async sendPacket(
|
||||||
type,
|
type,
|
||||||
sendChallenge,
|
|
||||||
payload,
|
payload,
|
||||||
expect,
|
expect,
|
||||||
allowTimeout
|
allowTimeout
|
||||||
) {
|
) {
|
||||||
for (let keyRetry = 0; keyRetry < 3; keyRetry++) {
|
for (let keyRetry = 0; keyRetry < 3; keyRetry++) {
|
||||||
let requestKeyChanged = false;
|
let receivedNewChallengeKey = false;
|
||||||
const response = await this.sendPacketRaw(
|
const response = await this.sendPacketRaw(
|
||||||
type, sendChallenge, payload,
|
type, payload,
|
||||||
(payload) => {
|
(payload) => {
|
||||||
const reader = this.reader(payload);
|
const reader = this.reader(payload);
|
||||||
const type = reader.uint(1);
|
const type = reader.uint(1);
|
||||||
this.debugLog(() => "Received " + type.toString(16) + " expected " + expect.toString(16));
|
this.debugLog(() => "Received 0x" + type.toString(16) + " expected 0x" + expect.toString(16));
|
||||||
if (type === 0x41) {
|
if (type === 0x41) {
|
||||||
const key = reader.uint(4);
|
const key = reader.uint(4);
|
||||||
if (this._challenge !== key) {
|
if (this._challenge !== key) {
|
||||||
this.debugLog('Received new challenge key: ' + key);
|
this.debugLog('Received new challenge key: 0x' + key.toString(16));
|
||||||
this._challenge = key;
|
this._challenge = key;
|
||||||
if (sendChallenge) {
|
receivedNewChallengeKey = true;
|
||||||
this.debugLog('Challenge key changed -- allowing query retry if needed');
|
|
||||||
requestKeyChanged = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type === expect) {
|
if (type === expect) {
|
||||||
return reader.rest();
|
return reader.rest();
|
||||||
} else if (requestKeyChanged) {
|
} else if (receivedNewChallengeKey) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -277,7 +304,7 @@ class Valve extends Core {
|
||||||
if (allowTimeout) return null;
|
if (allowTimeout) return null;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (!requestKeyChanged) {
|
if (!receivedNewChallengeKey) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -294,26 +321,47 @@ class Valve extends Core {
|
||||||
**/
|
**/
|
||||||
async sendPacketRaw(
|
async sendPacketRaw(
|
||||||
type,
|
type,
|
||||||
sendChallenge,
|
|
||||||
payload,
|
payload,
|
||||||
onResponse,
|
onResponse,
|
||||||
onTimeout
|
onTimeout
|
||||||
) {
|
) {
|
||||||
|
const challengeAtBeginning = type === 0x55 || type === 0x56;
|
||||||
|
const challengeAtEnd = type === 0x54 && !!this._challenge;
|
||||||
|
|
||||||
if (typeof payload === 'string') payload = Buffer.from(payload, 'binary');
|
if (typeof payload === 'string') payload = Buffer.from(payload, 'binary');
|
||||||
const challengeLength = sendChallenge ? 4 : 0;
|
|
||||||
const payloadLength = payload ? payload.length : 0;
|
|
||||||
|
|
||||||
const b = Buffer.alloc(5 + challengeLength + payloadLength);
|
const b = Buffer.alloc(5
|
||||||
b.writeInt32LE(-1, 0);
|
+ (challengeAtBeginning ? 4 : 0)
|
||||||
b.writeUInt8(type, 4);
|
+ (challengeAtEnd ? 4 : 0)
|
||||||
|
+ (payload ? payload.length : 0)
|
||||||
|
);
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
if (sendChallenge) {
|
let challenge = this._challenge;
|
||||||
let challenge = this._challenge;
|
if (!challenge) challenge = 0xffffffff;
|
||||||
if (!challenge) challenge = 0xffffffff;
|
|
||||||
if (this.byteorder === 'le') b.writeUInt32LE(challenge, 5);
|
b.writeInt32LE(-1, offset);
|
||||||
else b.writeUInt32BE(challenge, 5);
|
offset += 4;
|
||||||
|
|
||||||
|
b.writeUInt8(type, offset);
|
||||||
|
offset += 1;
|
||||||
|
|
||||||
|
if (challengeAtBeginning) {
|
||||||
|
if (this.byteorder === 'le') b.writeUInt32LE(challenge, offset);
|
||||||
|
else b.writeUInt32BE(challenge, offset);
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload) {
|
||||||
|
payload.copy(b, offset);
|
||||||
|
offset += payload.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (challengeAtEnd) {
|
||||||
|
if (this.byteorder === 'le') b.writeUInt32LE(challenge, offset);
|
||||||
|
else b.writeUInt32BE(challenge, offset);
|
||||||
|
offset += 4;
|
||||||
}
|
}
|
||||||
if (payloadLength) payload.copy(b, 5 + challengeLength);
|
|
||||||
|
|
||||||
const packetStorage = {};
|
const packetStorage = {};
|
||||||
return await this.udpSend(
|
return await this.udpSend(
|
||||||
|
|
@ -351,7 +399,7 @@ class Valve extends Core {
|
||||||
|
|
||||||
packets[packetNum] = payload;
|
packets[packetNum] = payload;
|
||||||
|
|
||||||
this.debugLog(() => "Received partial packet uid:"+uid+" num:"+packetNum);
|
this.debugLog(() => "Received partial packet uid: 0x"+uid.toString(16)+" num: "+packetNum);
|
||||||
this.debugLog(() => "Received "+Object.keys(packets).length+'/'+numPackets+" packets for this UID");
|
this.debugLog(() => "Received "+Object.keys(packets).length+'/'+numPackets+" packets for this UID");
|
||||||
|
|
||||||
if(Object.keys(packets).length !== numPackets) return;
|
if(Object.keys(packets).length !== numPackets) return;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue