Massive revamp for standardization of output
This commit is contained in:
parent
397d09d9d3
commit
007f1ffb8b
35
README.md
35
README.md
|
@ -22,25 +22,34 @@ Gamedig.query(
|
|||
);
|
||||
```
|
||||
|
||||
State Object
|
||||
Callback Function
|
||||
---
|
||||
The callback function is "guaranteed" to be called exactly once, indicating either a query error or timeout
|
||||
(in the state's error key), or with a state object containg the successful results.
|
||||
The callback function is "guaranteed" to be called exactly once.
|
||||
|
||||
The returned state object may contain some or all of the following keys:
|
||||
If an error occurs, the returned object will contain an "error" key, indicating the issue.
|
||||
If the error key exists, it should be assumed that the game server is offline or unreachable.
|
||||
|
||||
Otherwise, the returned object will contain the following keys:
|
||||
|
||||
Guaranteed:
|
||||
|
||||
* error
|
||||
* name
|
||||
* numplayers
|
||||
* maxplayers
|
||||
* players
|
||||
* name
|
||||
* ping
|
||||
* score
|
||||
* map
|
||||
* gametype
|
||||
* password (boolean)
|
||||
* maxplayers
|
||||
* players (may contain name, ping, score, team, address)
|
||||
* bots (same as players)
|
||||
* raw (contains special keys depending on the type of server queried - UNSTABLE)
|
||||
* notes (passed through from the input)
|
||||
* query (details about the query performed)
|
||||
* host
|
||||
* address
|
||||
* port
|
||||
* type
|
||||
* pretty (a "pretty" string describing the game)
|
||||
|
||||
Many other keys will also be available will be available on a game by game basis.
|
||||
It can usually be assumed that the number of players online is equal to the length of the players array.
|
||||
Some servers may return an additional player count number, which may be present in the unstable raw object.
|
||||
|
||||
Supported Games
|
||||
---
|
||||
|
|
|
@ -1,41 +1,40 @@
|
|||
module.exports = require('./core').extend({
|
||||
init: function() {
|
||||
this._super();
|
||||
this.pretty = 'Armagetron';
|
||||
this.encoding = 'latin1';
|
||||
this.byteorder = 'be';
|
||||
this.options.port = 4534;
|
||||
},
|
||||
run: function() {
|
||||
run: function(state) {
|
||||
var self = this;
|
||||
|
||||
var b = new Buffer([0,0x35,0,0,0,0,0,0x11]);
|
||||
|
||||
this.udpSend(b,function(buffer) {
|
||||
var state = {};
|
||||
var reader = self.reader(buffer);
|
||||
|
||||
reader.skip(6);
|
||||
|
||||
state.port = self.readUInt(reader);
|
||||
state.hostname = self.readString(reader,buffer);
|
||||
state.raw.port = self.readUInt(reader);
|
||||
state.raw.hostname = self.readString(reader,buffer);
|
||||
state.name = self.readString(reader,buffer);
|
||||
state.numplayers = self.readUInt(reader);
|
||||
state.versionmin = self.readUInt(reader);
|
||||
state.versionmax = self.readUInt(reader);
|
||||
state.version = self.readString(reader,buffer);
|
||||
state.raw.numplayers = self.readUInt(reader);
|
||||
state.raw.versionmin = self.readUInt(reader);
|
||||
state.raw.versionmax = self.readUInt(reader);
|
||||
state.raw.version = self.readString(reader,buffer);
|
||||
state.maxplayers = self.readUInt(reader);
|
||||
|
||||
var players = self.readString(reader,buffer);
|
||||
var list = players.split('\n');
|
||||
state.players = [];
|
||||
for(var i = 0; i < list.length; i++) {
|
||||
if(!list[i]) continue;
|
||||
state.players.push({name:list[i]});
|
||||
}
|
||||
|
||||
state.options = self.readString(reader,buffer);
|
||||
state.uri = self.readString(reader,buffer);
|
||||
state.globalids = self.readString(reader,buffer);
|
||||
state.raw.options = self.readString(reader,buffer);
|
||||
state.raw.uri = self.readString(reader,buffer);
|
||||
state.raw.globalids = self.readString(reader,buffer);
|
||||
self.finish(state);
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -33,21 +33,40 @@ module.exports = Class.extend(EventEmitter,{
|
|||
|
||||
this.done({error: err.toString()});
|
||||
},
|
||||
prepState: function(state) {
|
||||
initState: function() {
|
||||
return {
|
||||
name: '',
|
||||
map: '',
|
||||
password: false,
|
||||
|
||||
raw: {},
|
||||
|
||||
maxplayers: 0,
|
||||
players: [],
|
||||
bots: []
|
||||
};
|
||||
},
|
||||
finalizeState: function(state) {
|
||||
if(this.options.notes)
|
||||
state.notes = this.options.notes;
|
||||
if('host' in this.options) state.queryhost = this.options.host;
|
||||
if('port' in this.options) state.queryport = this.options.port;
|
||||
|
||||
state.query = {};
|
||||
if('host' in this.options) state.query.host = this.options.host;
|
||||
if('port' in this.options) state.query.port = this.options.port;
|
||||
state.query.type = this.type;
|
||||
if('pretty' in this) state.query.pretty = this.pretty;
|
||||
|
||||
if('players' in state) state.numplayers = state.players.length;
|
||||
if('bots' in state) state.numbots = state.bots.length;
|
||||
},
|
||||
finish: function(result) {
|
||||
this.finalizeState(result);
|
||||
this.done(result);
|
||||
},
|
||||
done: function(result) {
|
||||
if(this.finished) return;
|
||||
clearTimeout(this.globalTimeoutTimer);
|
||||
|
||||
this.prepState(result);
|
||||
|
||||
this.reset();
|
||||
this.finished = true;
|
||||
this.emit('finished',result);
|
||||
|
@ -80,7 +99,7 @@ module.exports = Class.extend(EventEmitter,{
|
|||
self.parseDns(self.options.host,c);
|
||||
}
|
||||
}, function(c) {
|
||||
self.run();
|
||||
self.run(self.initState());
|
||||
}
|
||||
|
||||
]);
|
||||
|
@ -98,12 +117,12 @@ module.exports = Class.extend(EventEmitter,{
|
|||
reader: function(buffer) {
|
||||
return new Reader(this,buffer);
|
||||
},
|
||||
translateState: function(state,trans) {
|
||||
translate: function(obj,trans) {
|
||||
for(var from in trans) {
|
||||
var to = trans[from];
|
||||
if(from in state) {
|
||||
if(to) state[to] = state[from];
|
||||
delete state[from];
|
||||
if(from in obj) {
|
||||
if(to) obj[to] = obj[from];
|
||||
delete obj[from];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@ module.exports = require('./core').extend({
|
|||
this.encoding = 'latin1';
|
||||
this.byteorder = 'be';
|
||||
},
|
||||
run: function() {
|
||||
run: function(state) {
|
||||
var self = this;
|
||||
|
||||
this.sendPacket(9,false,false,false,function(buffer) {
|
||||
|
@ -16,15 +16,12 @@ module.exports = require('./core').extend({
|
|||
self.sendPacket(0,challenge,new Buffer([0xff,0xff,0xff,0x01]),true,function(buffer) {
|
||||
|
||||
var reader = self.reader(buffer);
|
||||
var state = {
|
||||
players:[]
|
||||
};
|
||||
|
||||
while(!reader.done()) {
|
||||
var key = reader.string();
|
||||
if(!key) break;
|
||||
var value = reader.string();
|
||||
state[key] = value;
|
||||
state.raw[key] = value;
|
||||
}
|
||||
|
||||
var mode = '';
|
||||
|
@ -42,6 +39,9 @@ module.exports = require('./core').extend({
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if('hostname' in state.raw) state.name = state.raw.hostname;
|
||||
if('map' in state.raw) state.map = state.raw.map;
|
||||
|
||||
self.finish(state);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
module.exports = require('./unreal2').extend({
|
||||
init: function() {
|
||||
this._super();
|
||||
this.pretty = 'Killing Floor';
|
||||
this.options.port = 7708;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -3,6 +3,7 @@ var dns = require('dns');
|
|||
module.exports = require('./gamespy3').extend({
|
||||
init: function() {
|
||||
this._super();
|
||||
this.pretty = 'Minecraft';
|
||||
this.maxAttempts = 2;
|
||||
this.options.port = 25565;
|
||||
},
|
||||
|
|
|
@ -14,7 +14,7 @@ module.exports = require('./core').extend({
|
|||
this.gbxclient = false;
|
||||
}
|
||||
},
|
||||
run: function() {
|
||||
run: function(state) {
|
||||
var self = this;
|
||||
|
||||
var cmds = [
|
||||
|
@ -46,8 +46,6 @@ module.exports = require('./core').extend({
|
|||
});
|
||||
}
|
||||
}, function() {
|
||||
var state = {};
|
||||
|
||||
var gamemode = '';
|
||||
var igm = results[5].GameMode;
|
||||
if(igm == 0) gamemode="Rounds";
|
||||
|
@ -61,14 +59,13 @@ module.exports = require('./core').extend({
|
|||
state.password = (results[3].Password != 'No password');
|
||||
state.maxplayers = results[3].CurrentMaxPlayers;
|
||||
state.map = self.stripColors(results[4].Name);
|
||||
state.gametype = gamemode;
|
||||
state.raw.gametype = gamemode;
|
||||
|
||||
state.players = [];
|
||||
results[2].forEach(function(player) {
|
||||
state.players.push({name:self.stripColors(player.Name)});
|
||||
});
|
||||
|
||||
console.log(state);
|
||||
self.finish(state);
|
||||
});
|
||||
},
|
||||
stripColors: function(str) {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
module.exports = require('./core').extend({
|
||||
init: function() {
|
||||
this._super();
|
||||
this.pretty = 'Quake 2';
|
||||
this.options.port = 27910;
|
||||
this.encoding = 'latin1';
|
||||
this.delimiter = '\n';
|
||||
this.sendHeader = 'status';
|
||||
this.responseHeader = 'print';
|
||||
},
|
||||
run: function() {
|
||||
run: function(state) {
|
||||
var self = this;
|
||||
|
||||
this.udpSend('\xff\xff\xff\xff'+this.sendHeader+'\x00',function(buffer) {
|
||||
|
@ -15,18 +16,15 @@ module.exports = require('./core').extend({
|
|||
var header = reader.string();
|
||||
if(header != '\xff\xff\xff\xff'+this.responseHeader) return;
|
||||
|
||||
var state = {};
|
||||
|
||||
var info = reader.string().split('\\');
|
||||
if(info[0] == '') info.shift();
|
||||
while(true) {
|
||||
var key = info.shift();
|
||||
var value = info.shift();
|
||||
if(typeof value == 'undefined') break;
|
||||
state[key] = value;
|
||||
state.raw[key] = value;
|
||||
}
|
||||
|
||||
state.players = [];
|
||||
while(!reader.done()) {
|
||||
var player = reader.string();
|
||||
|
||||
|
@ -50,11 +48,16 @@ module.exports = require('./core').extend({
|
|||
var name = args[2] || '';
|
||||
var address = args[3] || '';
|
||||
|
||||
state.players.push({
|
||||
(ping == 0 ? state.bots : state.players).push({
|
||||
frags:frags, ping:ping, name:name, address:address
|
||||
});
|
||||
}
|
||||
|
||||
if('g_needpass' in state.raw) state.password = state.raw.g_needpass;
|
||||
if('mapname' in state.raw) state.map = state.raw.mapname;
|
||||
if('sv_maxclients' in state.raw) state.maxplayers = state.raw.sv_maxclients;
|
||||
if('sv_hostname' in state.raw) state.name = state.raw.sv_hostname;
|
||||
|
||||
self.finish(state);
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
module.exports = require('./quake2').extend({
|
||||
init: function() {
|
||||
this._super();
|
||||
this.pretty = 'Quake 3';
|
||||
this.options.port = 27960;
|
||||
this.sendHeader = 'getstatus';
|
||||
this.responseHeader = 'statusResponse';
|
||||
|
|
|
@ -7,11 +7,10 @@ module.exports = require('./core').extend({
|
|||
this.goldsrc = false;
|
||||
this.options.port = 27015;
|
||||
},
|
||||
run: function() {
|
||||
run: function(state) {
|
||||
|
||||
var self = this;
|
||||
var challenge;
|
||||
var state = {};
|
||||
|
||||
async.series([
|
||||
function(c) {
|
||||
|
@ -21,55 +20,55 @@ module.exports = require('./core').extend({
|
|||
function(b) {
|
||||
var reader = self.reader(b);
|
||||
|
||||
if(self.goldsrc) state.address = reader.string();
|
||||
else state.protocol = reader.uint(1);
|
||||
if(self.goldsrc) state.raw.address = reader.string();
|
||||
else state.raw.protocol = reader.uint(1);
|
||||
|
||||
state.name = reader.string();
|
||||
state.map = reader.string();
|
||||
state.folder = reader.string();
|
||||
state.game = reader.string();
|
||||
state.steamappid = reader.uint(2);
|
||||
state.numplayers = reader.uint(1);
|
||||
state.raw.folder = reader.string();
|
||||
state.raw.game = reader.string();
|
||||
state.raw.steamappid = reader.uint(2);
|
||||
state.raw.numplayers = reader.uint(1);
|
||||
state.maxplayers = reader.uint(1);
|
||||
|
||||
if(self.goldsrc) state.protocol = reader.uint(1);
|
||||
else state.numbots = reader.uint(1);
|
||||
if(self.goldsrc) state.raw.protocol = reader.uint(1);
|
||||
else state.raw.numbots = reader.uint(1);
|
||||
|
||||
state.listentype = String.fromCharCode(reader.uint(1));
|
||||
state.environment = String.fromCharCode(reader.uint(1));
|
||||
state.passworded = reader.uint(1);
|
||||
state.raw.listentype = String.fromCharCode(reader.uint(1));
|
||||
state.raw.environment = String.fromCharCode(reader.uint(1));
|
||||
state.password = reader.uint(1);
|
||||
if(self.goldsrc) {
|
||||
state.ismod = reader.uint(1);
|
||||
if(state.ismod) {
|
||||
state.modlink = reader.string();
|
||||
state.moddownload = reader.string();
|
||||
state.raw.ismod = reader.uint(1);
|
||||
if(state.raw.ismod) {
|
||||
state.raw.modlink = reader.string();
|
||||
state.raw.moddownload = reader.string();
|
||||
reader.skip(1);
|
||||
state.modversion = reader.uint(4);
|
||||
state.modsize = reader.uint(4);
|
||||
state.modtype = reader.uint(1);
|
||||
state.moddll = reader.uint(1);
|
||||
state.raw.modversion = reader.uint(4);
|
||||
state.raw.modsize = reader.uint(4);
|
||||
state.raw.modtype = reader.uint(1);
|
||||
state.raw.moddll = reader.uint(1);
|
||||
}
|
||||
}
|
||||
state.secure = reader.uint(1);
|
||||
state.raw.secure = reader.uint(1);
|
||||
|
||||
if(self.goldsrc) {
|
||||
state.numbots = reader.uint(1);
|
||||
state.raw.numbots = reader.uint(1);
|
||||
} else {
|
||||
if(state.folder == 'ship') {
|
||||
state.shipmode = reader.uint(1);
|
||||
state.shipwitnesses = reader.uint(1);
|
||||
state.shipduration = reader.uint(1);
|
||||
if(state.raw.folder == 'ship') {
|
||||
state.raw.shipmode = reader.uint(1);
|
||||
state.raw.shipwitnesses = reader.uint(1);
|
||||
state.raw.shipduration = reader.uint(1);
|
||||
}
|
||||
state.version = reader.string();
|
||||
state.raw.version = reader.string();
|
||||
var extraFlag = reader.uint(1);
|
||||
if(extraFlag & 0x80) state.port = reader.uint(2);
|
||||
if(extraFlag & 0x10) state.steamid = reader.uint(8);
|
||||
if(extraFlag & 0x80) state.raw.port = reader.uint(2);
|
||||
if(extraFlag & 0x10) state.raw.steamid = reader.uint(8);
|
||||
if(extraFlag & 0x40) {
|
||||
state.sourcetvport = reader.uint(2);
|
||||
state.sourcetvname = reader.string();
|
||||
state.raw.sourcetvport = reader.uint(2);
|
||||
state.raw.sourcetvname = reader.string();
|
||||
}
|
||||
if(extraFlag & 0x20) state.tags = reader.string();
|
||||
if(extraFlag & 0x01) state.gameid = reader.uint(8);
|
||||
if(extraFlag & 0x20) state.raw.tags = reader.string();
|
||||
if(extraFlag & 0x01) state.raw.gameid = reader.uint(8);
|
||||
}
|
||||
|
||||
c();
|
||||
|
@ -87,13 +86,12 @@ module.exports = require('./core').extend({
|
|||
self.sendPacket(0x55,challenge,false,0x44,function(b) {
|
||||
var reader = self.reader(b);
|
||||
var num = reader.uint(1);
|
||||
state.players = [];
|
||||
for(var i = 0; i < num; i++) {
|
||||
reader.skip(1);
|
||||
var name = reader.string();
|
||||
var score = reader.uint(4);
|
||||
var time = reader.float();
|
||||
state.players.push({
|
||||
(time == -1 ? state.bots : state.players).push({
|
||||
name:name, score:score, time:time
|
||||
});
|
||||
}
|
||||
|
@ -104,11 +102,11 @@ module.exports = require('./core').extend({
|
|||
self.sendPacket(0x56,challenge,false,0x45,function(b) {
|
||||
var reader = self.reader(b);
|
||||
var num = reader.uint(2);
|
||||
state.rules = [];
|
||||
state.raw.rules = [];
|
||||
for(var i = 0; i < num; i++) {
|
||||
var key = reader.string();
|
||||
var value = reader.string();
|
||||
state.rules[key] = value;
|
||||
state.raw.rules[key] = value;
|
||||
}
|
||||
c();
|
||||
});
|
||||
|
|
|
@ -3,9 +3,10 @@ var request = require('request');
|
|||
module.exports = require('./core').extend({
|
||||
init: function() {
|
||||
this._super();
|
||||
this.pretty = 'Terraria';
|
||||
this.options.port = 7878;
|
||||
},
|
||||
run: function() {
|
||||
run: function(state) {
|
||||
var self = this;
|
||||
request({
|
||||
uri: 'http://'+this.options.address+':'+this.options.port+'/status',
|
||||
|
@ -21,18 +22,16 @@ module.exports = require('./core').extend({
|
|||
|
||||
if(json.status != 200) return self.error('Invalid status');
|
||||
|
||||
var players = [];
|
||||
var split = json.players.split(',');
|
||||
split.forEach(function(one) {
|
||||
players.push({name:one});
|
||||
state.players.push({name:one});
|
||||
});
|
||||
|
||||
state.name = json.name;
|
||||
state.raw.port = json.port;
|
||||
state.raw.numplayers = json.playercount;
|
||||
|
||||
self.finish({
|
||||
'name': json.name,
|
||||
'port': json.port,
|
||||
'numplayers': json.playercount,
|
||||
'players': players
|
||||
});
|
||||
self.finish(state);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -5,54 +5,55 @@ module.exports = require('./core').extend({
|
|||
this._super();
|
||||
this.encoding = 'latin1';
|
||||
},
|
||||
run: function() {
|
||||
run: function(state) {
|
||||
|
||||
var self = this;
|
||||
var state = {};
|
||||
|
||||
async.series([
|
||||
function(c) {
|
||||
self.sendPacket(0,true,function(b) {
|
||||
var reader = self.reader(b);
|
||||
state.serverid = reader.uint(4);
|
||||
state.ip = reader.pascal();
|
||||
state.port = reader.uint(4);
|
||||
state.queryport = reader.uint(4);
|
||||
state.raw.serverid = reader.uint(4);
|
||||
state.raw.ip = reader.pascal();
|
||||
state.raw.port = reader.uint(4);
|
||||
state.raw.queryport = reader.uint(4);
|
||||
state.name = reader.pascal();
|
||||
state.map = reader.pascal();
|
||||
state.gametype = reader.pascal();
|
||||
state.numplayers = reader.uint(4);
|
||||
state.raw.gametype = reader.pascal();
|
||||
state.raw.numplayers = reader.uint(4);
|
||||
state.maxplayers = reader.uint(4);
|
||||
state.ping = reader.uint(4);
|
||||
state.raw.ping = reader.uint(4);
|
||||
c();
|
||||
});
|
||||
},
|
||||
function(c) {
|
||||
self.sendPacket(1,true,function(b) {
|
||||
var reader = self.reader(b);
|
||||
state.mutators = [];
|
||||
state.rules = {};
|
||||
state.raw.mutators = [];
|
||||
state.raw.rules = {};
|
||||
while(!reader.done()) {
|
||||
var key = reader.pascal();
|
||||
var value = reader.pascal();
|
||||
if(key == 'Mutator') state.mutators.push(value);
|
||||
else state.rules[key] = value;
|
||||
if(key == 'Mutator') state.raw.mutators.push(value);
|
||||
else state.raw.rules[key] = value;
|
||||
}
|
||||
|
||||
if('GamePassword' in state.raw.rules)
|
||||
state.password = state.raw.rules.GamePassword != 'True';
|
||||
|
||||
c();
|
||||
});
|
||||
},
|
||||
function(c) {
|
||||
self.sendPacket(2,false,function(b) {
|
||||
var reader = self.reader(b);
|
||||
state.players = [];
|
||||
while(!reader.done()) {
|
||||
var id = reader.uint(4);
|
||||
console.log(b.slice(reader.offset()));
|
||||
var name = reader.pascal();
|
||||
var ping = reader.uint(4);
|
||||
var score = reader.uint(4);
|
||||
reader.skip(4);
|
||||
state.players.push({
|
||||
(ping == 0 ? state.bots : state.players).push({
|
||||
id: id, name: name, ping: ping, score: score
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
module.exports = require('./unreal2').extend({
|
||||
init: function() {
|
||||
this._super();
|
||||
this.pretty = 'Unreal Tournament 2004';
|
||||
this.options.port = 7778;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
module.exports = require('./gamespy3').extend({
|
||||
init: function() {
|
||||
this._super();
|
||||
this.pretty = 'Unreal Tournament 3';
|
||||
this.options.port = 6500;
|
||||
},
|
||||
prepState: function(state) {
|
||||
finalizeState: function(state) {
|
||||
this._super(state);
|
||||
|
||||
this.translateState(state,{
|
||||
//'OwningPlayerName': 'hostname',
|
||||
this.translate(state.raw,{
|
||||
'mapname': false,
|
||||
'p1073741825': 'map',
|
||||
'p1073741826': 'gametype',
|
||||
|
@ -35,7 +35,7 @@ module.exports = require('./gamespy3').extend({
|
|||
'p268435968': false,
|
||||
'p268435969': false
|
||||
});
|
||||
|
||||
|
||||
function split(a) {
|
||||
var s = a.split('\x1c');
|
||||
s = s.filter(function(e) { return e });
|
||||
|
@ -43,5 +43,9 @@ module.exports = require('./gamespy3').extend({
|
|||
}
|
||||
if('custom_mutators' in state) state['custom_mutators'] = split(state['custom_mutators']);
|
||||
if('stock_mutators' in state) state['stock_mutators'] = split(state['stock_mutators']);
|
||||
|
||||
if('map' in state.raw) state.map = state.raw.map;
|
||||
if('password' in state.raw) state.password = state.raw.password;
|
||||
if('servername' in state.raw) state.name = state.raw.servername;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
module.exports = require('./quake3').extend({
|
||||
init: function() {
|
||||
this._super();
|
||||
this.pretty = 'Warsow';
|
||||
this.options.port = 44400;
|
||||
},
|
||||
prepState: function(state) {
|
||||
|
|
Loading…
Reference in New Issue