From 8ad0fbc87b1ca779918a1244f4ea5a09a1140a83 Mon Sep 17 00:00:00 2001 From: Tom <25043847+Douile@users.noreply.github.com> Date: Sat, 4 Jan 2020 01:03:02 +0000 Subject: [PATCH 1/7] Add discord protocol --- README.md | 7 ++++++- games.txt | 1 + protocols/discord.js | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 protocols/discord.js diff --git a/README.md b/README.md index 8f961db..5348f93 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,7 @@ Games List | `devastation` | Devastation (2003) | `dinodday` | Dino D-Day (2011) | `dirttrackracing2` | Dirt Track Racing 2 (2002) +| `discord` | Discord | [Notes](#discord) | `doom3` | Doom 3 (2004) | `dota2` | Dota 2 (2013) | `drakan` | Drakan: Order of the Flame (1999) @@ -451,6 +452,10 @@ For teamspeak 3 queries to work correctly, the following permissions must be ava Requires tshock server mod, and a REST user token, which can be passed to GameDig with the additional option: token +### Discord +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. +In order to retrieve information from discord server's they must have the Enable server widget option enabled. + Usage from Command Line --- @@ -547,7 +552,7 @@ Changelog ##### 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 +* 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 diff --git a/games.txt b/games.txt index 9f31c25..7d19884 100644 --- a/games.txt +++ b/games.txt @@ -87,6 +87,7 @@ deusex|Deus Ex (2000)|gamespy2|port=7791,port_query_offset=1 devastation|Devastation (2003)|unreal2|port=7777,port_query_offset=1 dinodday|Dino D-Day (2011)|valve|port=27015 dirttrackracing2|Dirt Track Racing 2 (2002)|gamespy1|port=32240,port_query_offset=-100 +discord|Discord|discord|port=443 dnl|Dark and Light (2017)|valve|port=7777,port_query=27015 dod|Day of Defeat (2003)|valve|port=27015 dods|Day of Defeat: Source (2005)|valve|port=27015 diff --git a/protocols/discord.js b/protocols/discord.js new file mode 100644 index 0000000..d79c140 --- /dev/null +++ b/protocols/discord.js @@ -0,0 +1,35 @@ +const Core = require('./core'); + +class Discord extends Core { + constructor() { + super(); + this.dnsResolver = { resolve: function(address) {return {address: address} } }; + } + + async run(state) { + console.log('SENDING HTTP Request'); + this.usedTcp = true; + console.log(this.options); + const raw = await this.request({ + uri: 'https://discordapp.com/api/guilds/' + this.options.address + '/widget.json', + }); + const json = JSON.parse(raw); + state.name = json.name; + if (json.instant_invite) { + state.connect = json.instant_invite; + } else { + state.connect = 'https://discordapp.com/channels/' + this.options.address + } + state.players = json.members.map(v => { + return { + name: v.username + '#' + v.discriminator, + username: v.username, + discriminator: v.discriminator, + team: v.status + } + }); + state.raw = json; + } +} + +module.exports = Discord; From 5dd7446eaeb8416f97f66185a638ff728bb7942f Mon Sep 17 00:00:00 2001 From: Tom <25043847+Douile@users.noreply.github.com> Date: Sat, 4 Jan 2020 01:03:48 +0000 Subject: [PATCH 2/7] Force host argument to be string (Int causes error) --- bin/gamedig.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/gamedig.js b/bin/gamedig.js index 720928e..f0e0126 100644 --- a/bin/gamedig.js +++ b/bin/gamedig.js @@ -4,7 +4,8 @@ const Minimist = require('minimist'), Gamedig = require('..'); const argv = Minimist(process.argv.slice(2), { - boolean: ['pretty','debug'] + boolean: ['pretty','debug'], + string: ['_'] }); const debug = argv.debug; From 0128e4d97226179b2696a3256b9e685fce4f35de Mon Sep 17 00:00:00 2001 From: Tom <25043847+Douile@users.noreply.github.com> Date: Sat, 4 Jan 2020 13:43:35 +0000 Subject: [PATCH 3/7] Remove extra logging Whoops --- protocols/discord.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/protocols/discord.js b/protocols/discord.js index d79c140..b428ab3 100644 --- a/protocols/discord.js +++ b/protocols/discord.js @@ -7,9 +7,7 @@ class Discord extends Core { } async run(state) { - console.log('SENDING HTTP Request'); this.usedTcp = true; - console.log(this.options); const raw = await this.request({ uri: 'https://discordapp.com/api/guilds/' + this.options.address + '/widget.json', }); From 3a8164cfbccaf05a95b0b2f953afaf7d69e68a93 Mon Sep 17 00:00:00 2001 From: Tom <25043847+Douile@users.noreply.github.com> Date: Sat, 4 Jan 2020 13:44:09 +0000 Subject: [PATCH 4/7] Set max players to total amount of members in server --- protocols/discord.js | 1 + 1 file changed, 1 insertion(+) diff --git a/protocols/discord.js b/protocols/discord.js index b428ab3..717f50b 100644 --- a/protocols/discord.js +++ b/protocols/discord.js @@ -26,6 +26,7 @@ class Discord extends Core { team: v.status } }); + state.maxplayers = json.presence_count; state.raw = json; } } From f337cf6f58d0b0da1435e49023a2e7cf5d9d33d9 Mon Sep 17 00:00:00 2001 From: Tom <25043847+Douile@users.noreply.github.com> Date: Sat, 4 Jan 2020 13:53:36 +0000 Subject: [PATCH 5/7] Remove discriminator's from player names The widget API seems to always set discriminator to 0000 --- protocols/discord.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/protocols/discord.js b/protocols/discord.js index 717f50b..c70b846 100644 --- a/protocols/discord.js +++ b/protocols/discord.js @@ -20,9 +20,7 @@ class Discord extends Core { } state.players = json.members.map(v => { return { - name: v.username + '#' + v.discriminator, - username: v.username, - discriminator: v.discriminator, + name: v.username, team: v.status } }); From d9310db38b392ffc1983117ea9a79a003511b897 Mon Sep 17 00:00:00 2001 From: Michael Morrison Date: Tue, 18 May 2021 22:11:58 -0500 Subject: [PATCH 6/7] Restore executable bit on gamedig.js --- bin/gamedig.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 bin/gamedig.js diff --git a/bin/gamedig.js b/bin/gamedig.js old mode 100644 new mode 100755 From fe124a44875f0fcc8b3f7302679eee5d2b04811f Mon Sep 17 00:00:00 2001 From: Michael Morrison Date: Tue, 18 May 2021 22:33:36 -0500 Subject: [PATCH 7/7] Bring discord protocol up to date with gamedig 3.0 --- README.md | 6 ++++++ bin/gamedig.js | 3 ++- games.txt | 2 +- lib/QueryRunner.js | 7 ++++++- protocols/core.js | 5 ++++- protocols/discord.js | 49 ++++++++++++++++++++++---------------------- 6 files changed, 43 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 28bf245..bd393af 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ Games List | `devastation` | Devastation (2003) | `dinodday` | Dino D-Day (2011) | [Valve Protocol](#valve) | `dirttrackracing2` | Dirt Track Racing 2 (2002) +| `discord` | Discord | [Notes](#discord) | `doom3` | Doom 3 (2004) | `dota2` | Dota 2 (2013) | [Valve Protocol](#valve) | `drakan` | Drakan: Order of the Flame (1999) @@ -428,6 +429,11 @@ Games with Additional Notes To receive a full player list response from CS:GO servers, the server must have set the cvar: host_players_show 2 +### Discord +You must set the `guildId` request field to the server's guild ID. Do not provide an IP. +The Guild ID can be found in server widget settings (Server ID) or by enabling developer mode in client settings and right-clicking the server's icon. +In order to retrieve information from discord server's they must have the `Enable server widget` option enabled. + ### Mumble For full query results from Mumble, you must be running the [GTmurmur plugin](http://www.gametracker.com/downloads/gtmurmurplugin.php). diff --git a/bin/gamedig.js b/bin/gamedig.js index 040af19..e4b53e9 100755 --- a/bin/gamedig.js +++ b/bin/gamedig.js @@ -4,7 +4,8 @@ const Minimist = require('minimist'), Gamedig = require('..'); const argv = Minimist(process.argv.slice(2), { - boolean: ['pretty','debug','givenPortOnly'] + boolean: ['pretty','debug','givenPortOnly'], + string: ['guildId'] }); const debug = argv.debug; diff --git a/games.txt b/games.txt index a912011..ee834cc 100644 --- a/games.txt +++ b/games.txt @@ -88,7 +88,7 @@ deusex|Deus Ex (2000)|gamespy2|port=7791,port_query_offset=1 devastation|Devastation (2003)|unreal2|port=7777,port_query_offset=1 dinodday|Dino D-Day (2011)|valve|port=27015 dirttrackracing2|Dirt Track Racing 2 (2002)|gamespy1|port=32240,port_query_offset=-100 -discord|Discord|discord|port=443 +discord|Discord|discord||doc_notes=discord dnl|Dark and Light (2017)|valve|port=7777,port_query=27015 dod|Day of Defeat (2003)|valve|port=27015 dods|Day of Defeat: Source (2005)|valve|port=27015 diff --git a/lib/QueryRunner.js b/lib/QueryRunner.js index 062496a..31eaac0 100644 --- a/lib/QueryRunner.js +++ b/lib/QueryRunner.js @@ -66,7 +66,12 @@ class QueryRunner { port: gameOptions.port + (gameQueryPortOffset || 0) }); } else { - throw new Error("Could not determine port to query. Did you provide a port or gameid?"); + // Hopefully the request doesn't need a port. If it does, it'll fail when making the request. + attempts.push({ + ...defaultOptions, + ...gameOptions, + ...userOptions + }); } const numRetries = userOptions.maxAttempts || gameOptions.maxAttempts || defaultOptions.maxAttempts; diff --git a/protocols/core.js b/protocols/core.js index d2535ff..3e7d1e1 100644 --- a/protocols/core.js +++ b/protocols/core.js @@ -146,7 +146,10 @@ class Core extends EventEmitter { } assertValidPort(port) { - if (!port || port < 1 || port > 65535) { + if (!port) { + throw new Error("Could not determine port to query. Did you provide a port?"); + } + if (port < 1 || port > 65535) { throw new Error("Invalid tcp/ip port: " + port); } } diff --git a/protocols/discord.js b/protocols/discord.js index c70b846..739086e 100644 --- a/protocols/discord.js +++ b/protocols/discord.js @@ -1,32 +1,31 @@ const Core = require('./core'); class Discord extends Core { - constructor() { - super(); - this.dnsResolver = { resolve: function(address) {return {address: address} } }; - } - - async run(state) { - this.usedTcp = true; - const raw = await this.request({ - uri: 'https://discordapp.com/api/guilds/' + this.options.address + '/widget.json', - }); - const json = JSON.parse(raw); - state.name = json.name; - if (json.instant_invite) { - state.connect = json.instant_invite; - } else { - state.connect = 'https://discordapp.com/channels/' + this.options.address + async run(state) { + const guildId = this.options.guildId; + if (typeof guildId !== 'string') { + throw new Error('guildId option must be set when querying discord. Ensure the guildId is a string and not a number.' + + " (It's too large of a number for javascript to store without losing precision)"); + } + this.usedTcp = true; + const raw = await this.request({ + url: 'https://discordapp.com/api/guilds/' + guildId + '/widget.json', + }); + const json = JSON.parse(raw); + state.name = json.name; + if (json.instant_invite) { + state.connect = json.instant_invite; + } else { + state.connect = 'https://discordapp.com/channels/' + guildId; + } + for (const member of json.members) { + const {username: name, ...rest} = member; + state.players.push({ name, ...rest }); + } + delete json.members; + state.maxplayers = 500000; + state.raw = json; } - state.players = json.members.map(v => { - return { - name: v.username, - team: v.status - } - }); - state.maxplayers = json.presence_count; - state.raw = json; - } } module.exports = Discord;