mirror of
https://github.com/gamedig/node-gamedig.git
synced 2024-11-17 17:25:19 +01:00
Add Gamespy 1 and 2 protocol support
This commit is contained in:
parent
d5b4310cef
commit
6680c2dfa2
2 changed files with 163 additions and 0 deletions
85
games/protocols/gamespy1.js
Normal file
85
games/protocols/gamespy1.js
Normal file
|
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
78
games/protocols/gamespy2.js
Normal file
78
games/protocols/gamespy2.js
Normal file
|
@ -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;
|
||||
}
|
||||
});
|
Loading…
Reference in a new issue