diff --git a/games/protocols/gamespy1.js b/games/protocols/gamespy1.js new file mode 100644 index 0000000..bd4fd65 --- /dev/null +++ b/games/protocols/gamespy1.js @@ -0,0 +1,85 @@ +var async = require('async'); + +module.exports = require('./core').extend({ + init: function() { + this._super(); + this.sessionId = 1; + this.encoding = 'latin1'; + this.byteorder = 'be'; + }, + run: function(state) { + var self = this; + + async.series([ + function(c) { + self.sendPacket('info', function(data) { + state.raw = data; + if('hostname' in state.raw) state.name = state.raw.hostname; + if('mapname' in state.raw) state.map = state.raw.mapname; + if(state.raw.password == '1') state.password = true; + if('maxplayers' in state.raw) state.maxplayers = parseInt(state.raw.maxplayers); + c(); + }); + }, + function(c) { + self.sendPacket('rules', function(data) { + state.raw.rules = data; + c(); + }); + }, + function(c) { + self.sendPacket('players', function(data) { + var players = {}; + var teams = {}; + for(var ident in data) { + var split = ident.split('_'); + var key = split[0]; + var id = split[1]; + var value = data[ident]; + + if(key == 'teamname') { + teams[id] = value; + } else { + if(!(id in players)) players[id] = {}; + if(key == 'playername') key = 'name'; + else if(key == 'team') value = parseInt(value)-1; + else if(key == 'score' || key == 'ping' || key == 'deaths') value = parseInt(value); + players[id][key] = value; + } + } + + state.raw.teams = teams; + for(var i in players) state.players.push(players[i]); + self.finish(state); + }); + } + ]); + + }, + sendPacket: function(type,callback) { + var self = this; + var queryId = ''; + var output = {}; + this.udpSend('\\'+type+'\\',function(buffer) { + var reader = self.reader(buffer); + var str = reader.string({length:buffer.length}); + var split = str.split('\\'); + split.shift(); + var data = {}; + while(split.length) { + var key = split.shift(); + var value = split.shift() || ''; + data[key] = value; + } + if(!('queryid' in data)) return; + if(queryId && data.queryid != queryId) return; + for(var i in data) output[i] = data[i]; + if('final' in output) { + delete output.final; + delete output.queryid; + callback(output); + return true; + } + }); + } +}); diff --git a/games/protocols/gamespy2.js b/games/protocols/gamespy2.js new file mode 100644 index 0000000..c85724b --- /dev/null +++ b/games/protocols/gamespy2.js @@ -0,0 +1,78 @@ +module.exports = require('./core').extend({ + init: function() { + this._super(); + this.sessionId = 1; + this.encoding = 'latin1'; + this.byteorder = 'be'; + }, + run: function(state) { + var self = this; + + var request = new Buffer([0xfe,0xfd,0x00,0x00,0x00,0x00,0x01,0xff,0xff,0xff]); + this.udpSend(request,function(buffer) { + var reader = self.reader(buffer); + var header = reader.uint(1); + if(header != 0) return; + var pingId = reader.uint(4); + if(pingId != 1) return; + + while(!reader.done()) { + var key = reader.string(); + var value = reader.string(); + if(!key) break; + state.raw[key] = value; + } + + if('hostname' in state.raw) state.name = state.raw.hostname; + if('mapname' in state.raw) state.map = state.raw.mapname; + if(state.raw.password == '1') state.password = true; + if('maxplayers' in state.raw) state.maxplayers = parseInt(state.raw.maxplayers); + + state.players = self.readFieldData(reader); + state.raw.teams = self.readFieldData(reader); + + self.finish(state); + return true; + }); + }, + readFieldData: function(reader) { + var count = reader.uint(1); + // count is unreliable (often it's wrong), so we don't use it. + // read until we hit an empty first field string + + if(this.debug) + console.log("Reading fields, starting at: "+reader.rest()); + + var fields = []; + while(!reader.done()) { + var field = reader.string(); + if(!field) break; + if(field.charCodeAt(0) <= 2) field = field.substring(1); + fields.push(field); + if(this.debug) console.log("field:"+field); + } + + var units = []; + outer: while(!reader.done()) { + var unit = {}; + for(var iField = 0; iField < fields.length; iField++) { + var key = fields[iField]; + var value = reader.string(); + if(!value && iField == 0) break outer; + if(this.debug) console.log("value:"+value); + if(key == 'player_') key = 'name'; + else if(key == 'score_') key = 'score'; + else if(key == 'deaths_') key = 'deaths'; + else if(key == 'ping_') key = 'ping'; + else if(key == 'team_') key = 'team'; + else if(key == 'kills_') key = 'kills'; + else if(key == 'team_t') key = 'name'; + else if(key == 'tickets_t') key = 'tickets'; + unit[key] = value; + } + units.push(unit); + } + + return units; + } +});