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;