From c5abf7aa07770cfc9d19be31692d6c40c9536f98 Mon Sep 17 00:00:00 2001 From: Michael Morrison Date: Sun, 2 Feb 2014 07:20:36 -0600 Subject: [PATCH] Add mumble support --- README.md | 7 +++++++ games/mumble.js | 46 +++++++++++++++++++++++++++++++++++++++++ games/mumbleping.js | 31 +++++++++++++++++++++++++++ games/protocols/core.js | 11 ++++++---- games/teamspeak3.js | 2 +- 5 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 games/mumble.js create mode 100644 games/mumbleping.js diff --git a/README.md b/README.md index de24391..9d489fd 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,7 @@ Supported Games * Minecraft (minecraft) [[Additional Notes](#minecraft)] * Monday Night Combat (mnc) * Multi Theft Auto [[Separate Query Port - Usually port+123](#separate-query-port)] +* Mumble [[Additional Notes](#mumble)] * Mutant Factions (mutantfactions) * Natural Selection (ns) * Natural Selection 2 (ns2) [[Separate Query Port - Usually port+1](#separate-query-port)] @@ -198,6 +199,12 @@ Don't see your game listed here? Some minecraft servers may not respond to a typical status query. If this is the case, try using the 'minecraftping' server type instead, which uses a less accurate but more reliable solution. +#### Mumble +For full query results from Mumble, you must be running the +[GTmurmur plugin](http://www.gametracker.com/downloads/gtmurmurplugin.php). +If you do not wish to run the plugin, or do not require details such as channel and user lists, +you can use the 'mumbleping' server type instead, which uses a less accurate but more reliable solution + #### Nadeo (ShootMania / TrackMania / etc) The server must have xmlrpc enabled, and you must pass the xmlrpc port to GameDig, not the connection port. You must have a user account on the server with access level User or higher. diff --git a/games/mumble.js b/games/mumble.js new file mode 100644 index 0000000..d283e18 --- /dev/null +++ b/games/mumble.js @@ -0,0 +1,46 @@ +var async = require('async'); + +module.exports = require('./protocols/core').extend({ + init: function() { + this._super(); + this.pretty = 'Mumble'; + this.options.port = 27800; + this.options.tcpTimeout = 5000; + }, + run: function(state) { + var self = this; + + this.tcpSend('\x6A\x73\x6F\x6E', function(buffer) { + if(buffer.length < 10) return; + var str = buffer.toString(); + var json; + try { + json = JSON.parse(str); + } catch(e) { + // probably not all here yet + return; + } + + state.raw = json; + state.name = json.name; + + var channelStack = [state.raw.root]; + while(channelStack.length) { + var channel = channelStack.shift(); + channel.description = self.cleanComment(channel.description); + channelStack = channelStack.concat(channel.channels); + for(var i = 0; i < channel.users.length; i++) { + var user = channel.users[i]; + user.comment = self.cleanComment(user.comment); + state.players.push(user); + } + } + + self.finish(state); + return true; + }); + }, + cleanComment: function(str) { + return str.replace(/<.*>/g,''); + } +}); diff --git a/games/mumbleping.js b/games/mumbleping.js new file mode 100644 index 0000000..abbe7c0 --- /dev/null +++ b/games/mumbleping.js @@ -0,0 +1,31 @@ +var async = require('async'); + +module.exports = require('./protocols/core').extend({ + init: function() { + this._super(); + this.pretty = 'Mumble'; + this.options.port = 64738; + this.byteorder = 'be'; + }, + run: function(state) { + var self = this; + + this.udpSend('\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08', function(buffer) { + if(buffer.length < 24) return; + var reader = self.reader(buffer); + reader.skip(1); + state.raw.versionMajor = reader.uint(1); + state.raw.versionMinor = reader.uint(1); + state.raw.versionPatch = reader.uint(1); + reader.skip(8); + state.raw.numplayers = reader.uint(4); + state.maxplayers = reader.uint(4); + state.raw.allowedbandwidth = reader.uint(4); + for(var i = 0; i < state.raw.numplayers; i++) { + state.players.push({}); + } + self.finish(state); + return true; + }); + } +}); diff --git a/games/protocols/core.js b/games/protocols/core.js index 9fda13b..e1a7cf5 100644 --- a/games/protocols/core.js +++ b/games/protocols/core.js @@ -8,7 +8,10 @@ var EventEmitter = require('events').EventEmitter, module.exports = Class.extend(EventEmitter,{ init: function() { this._super(); - this.options = {}; + this.options = { + tcpTimeout: 1000, + udpTimeout: 1000 + }; this.maxAttempts = 1; this.attempt = 1; this.finished = false; @@ -207,6 +210,7 @@ module.exports = Class.extend(EventEmitter,{ var socket = this.tcpSocket = net.connect(port,address,function() { if(self.debug) console.log(address+':'+port+" TCPCONNECTED"); + connected = true; c(socket); }); socket.setTimeout(10000); @@ -242,14 +246,13 @@ module.exports = Class.extend(EventEmitter,{ if(self.tcpCallback) return self.fatal('Attempted to send TCP packet while still waiting on a managed response'); self._tcpConnect(function(socket) { socket.write(buffer); - if(self.debug) console.log(socket.remoteAddress+':'+socket.remotePort+" TCP--> "+buffer.toString('hex')); }); if(!ondata) return; self.tcpTimeoutTimer = self.setTimeout(function() { self.tcpCallback = false; self.fatal('TCP Watchdog Timeout'); - },1000); + },self.options.tcpTimeout); self.tcpCallback = ondata; }); }, @@ -268,7 +271,7 @@ module.exports = Class.extend(EventEmitter,{ var timeout = false; if(!ontimeout || ontimeout() !== true) timeout = true; if(timeout) self.fatal('UDP Watchdog Timeout'); - },1000); + },self.options.udpTimeout); self.udpCallback = onpacket; }); }, diff --git a/games/teamspeak3.js b/games/teamspeak3.js index 7de23dd..9309342 100644 --- a/games/teamspeak3.js +++ b/games/teamspeak3.js @@ -3,7 +3,7 @@ var async = require('async'); module.exports = require('./protocols/core').extend({ init: function() { this._super(); - this.pretty = 'Teamspeak 2'; + this.pretty = 'Teamspeak 3'; this.options.port = 9987; this.options.master_port = 10011; },