2017-08-09 11:05:55 +02:00
|
|
|
const async = require('async'),
|
2017-08-09 12:32:09 +02:00
|
|
|
moment = require('moment');
|
2014-11-18 07:43:33 +01:00
|
|
|
|
2017-08-09 11:05:55 +02:00
|
|
|
class OpenTtd extends require('./core') {
|
2017-08-09 12:32:09 +02:00
|
|
|
run(state) {
|
|
|
|
async.series([
|
|
|
|
(c) => {
|
|
|
|
this.query(0,1,1,4,(reader, version) => {
|
|
|
|
if(version >= 4) {
|
|
|
|
const numGrf = reader.uint(1);
|
|
|
|
state.raw.grfs = [];
|
|
|
|
for(let i = 0; i < numGrf; i++) {
|
2017-08-09 11:05:55 +02:00
|
|
|
const grf = {};
|
2017-08-09 12:32:09 +02:00
|
|
|
grf.id = reader.part(4).toString('hex');
|
|
|
|
grf.md5 = reader.part(16).toString('hex');
|
|
|
|
state.raw.grfs.push(grf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(version >= 3) {
|
|
|
|
state.raw.date_current = this.readDate(reader);
|
|
|
|
state.raw.date_start = this.readDate(reader);
|
|
|
|
}
|
|
|
|
if(version >= 2) {
|
|
|
|
state.raw.maxcompanies = reader.uint(1);
|
|
|
|
state.raw.numcompanies = reader.uint(1);
|
|
|
|
state.raw.maxspectators = reader.uint(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
state.name = reader.string();
|
|
|
|
state.raw.version = reader.string();
|
|
|
|
|
|
|
|
state.raw.language = this.decode(
|
|
|
|
reader.uint(1),
|
|
|
|
['any','en','de','fr']
|
|
|
|
);
|
|
|
|
|
|
|
|
state.password = !!reader.uint(1);
|
|
|
|
state.maxplayers = reader.uint(1);
|
|
|
|
state.raw.numplayers = reader.uint(1);
|
|
|
|
for(let i = 0; i < state.raw.numplayers; i++) {
|
|
|
|
state.players.push({});
|
|
|
|
}
|
|
|
|
state.raw.numspectators = reader.uint(1);
|
|
|
|
state.map = reader.string();
|
|
|
|
state.raw.map_width = reader.uint(2);
|
|
|
|
state.raw.map_height = reader.uint(2);
|
|
|
|
|
|
|
|
state.raw.landscape = this.decode(
|
|
|
|
reader.uint(1),
|
|
|
|
['temperate','arctic','desert','toyland']
|
|
|
|
);
|
|
|
|
|
|
|
|
state.raw.dedicated = !!reader.uint(1);
|
|
|
|
|
|
|
|
c();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
(c) => {
|
2017-08-09 11:05:55 +02:00
|
|
|
const vehicle_types = ['train','truck','bus','aircraft','ship'];
|
|
|
|
const station_types = ['station','truckbay','busstation','airport','dock'];
|
2014-11-18 07:43:33 +01:00
|
|
|
|
2017-08-09 12:32:09 +02:00
|
|
|
this.query(2,3,-1,-1, (reader,version) => {
|
|
|
|
// we don't know how to deal with companies outside version 6
|
|
|
|
if(version !== 6) return c();
|
2014-11-18 07:43:33 +01:00
|
|
|
|
2017-08-09 12:32:09 +02:00
|
|
|
state.raw.companies = [];
|
2017-08-09 11:05:55 +02:00
|
|
|
const numCompanies = reader.uint(1);
|
2017-08-09 12:32:09 +02:00
|
|
|
for(let iCompany = 0; iCompany < numCompanies; iCompany++) {
|
2017-08-09 11:05:55 +02:00
|
|
|
const company = {};
|
2017-08-09 12:32:09 +02:00
|
|
|
company.id = reader.uint(1);
|
|
|
|
company.name = reader.string();
|
|
|
|
company.year_start = reader.uint(4);
|
|
|
|
company.value = reader.uint(8);
|
|
|
|
company.money = reader.uint(8);
|
|
|
|
company.income = reader.uint(8);
|
|
|
|
company.performance = reader.uint(2);
|
|
|
|
company.password = !!reader.uint(1);
|
|
|
|
|
|
|
|
company.vehicles = {};
|
|
|
|
for(const type of vehicle_types) {
|
|
|
|
company.vehicles[type] = reader.uint(2);
|
|
|
|
}
|
|
|
|
company.stations = {};
|
|
|
|
for(const type of station_types) {
|
|
|
|
company.stations[type] = reader.uint(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
company.clients = reader.string();
|
|
|
|
state.raw.companies.push(company);
|
|
|
|
}
|
|
|
|
|
|
|
|
c();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
(c) => {
|
|
|
|
this.finish(state);
|
|
|
|
}
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
query(type,expected,minver,maxver,done) {
|
2017-08-09 11:05:55 +02:00
|
|
|
const b = Buffer.from([0x03,0x00,type]);
|
2017-08-09 12:32:09 +02:00
|
|
|
this.udpSend(b,(buffer) => {
|
2017-08-09 11:05:55 +02:00
|
|
|
const reader = this.reader(buffer);
|
2014-11-18 07:43:33 +01:00
|
|
|
|
2017-08-09 11:05:55 +02:00
|
|
|
const packetLen = reader.uint(2);
|
2017-08-09 12:32:09 +02:00
|
|
|
if(packetLen !== buffer.length) {
|
|
|
|
this.fatal('Invalid reported packet length: '+packetLen+' '+buffer.length);
|
|
|
|
return true;
|
|
|
|
}
|
2014-11-18 07:43:33 +01:00
|
|
|
|
2017-08-09 11:05:55 +02:00
|
|
|
const packetType = reader.uint(1);
|
2017-08-09 12:32:09 +02:00
|
|
|
if(packetType !== expected) {
|
|
|
|
this.fatal('Unexpected response packet type: '+packetType);
|
|
|
|
return true;
|
|
|
|
}
|
2014-11-18 07:43:33 +01:00
|
|
|
|
2017-08-09 11:05:55 +02:00
|
|
|
const protocolVersion = reader.uint(1);
|
2017-08-09 12:32:09 +02:00
|
|
|
if((minver !== -1 && protocolVersion < minver) || (maxver !== -1 && protocolVersion > maxver)) {
|
|
|
|
this.fatal('Unknown protocol version: '+protocolVersion+' Expected: '+minver+'-'+maxver);
|
|
|
|
return true;
|
|
|
|
}
|
2014-11-18 07:43:33 +01:00
|
|
|
|
2017-08-09 12:32:09 +02:00
|
|
|
done(reader,protocolVersion);
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
}
|
2014-11-18 07:43:33 +01:00
|
|
|
|
2017-08-09 12:32:09 +02:00
|
|
|
readDate(reader) {
|
2017-08-09 11:05:55 +02:00
|
|
|
const daysSinceZero = reader.uint(4);
|
|
|
|
const temp = new Date(0,0,1);
|
2017-08-09 12:32:09 +02:00
|
|
|
temp.setFullYear(0);
|
|
|
|
temp.setDate(daysSinceZero+1);
|
|
|
|
return moment(temp).format('YYYY-MM-DD');
|
|
|
|
}
|
|
|
|
|
|
|
|
decode(num,arr) {
|
|
|
|
if(num < 0 || num >= arr.length) {
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
return arr[num];
|
|
|
|
}
|
2017-08-09 11:05:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = OpenTtd;
|