2019-01-07 01:52:03 +01:00
|
|
|
const Core = require('./core');
|
|
|
|
|
2018-03-18 10:46:14 +01:00
|
|
|
/** Unsupported -- use at your own risk!! */
|
|
|
|
|
2019-01-07 01:52:03 +01:00
|
|
|
class Tribes1Master extends Core {
|
2018-03-18 10:46:14 +01:00
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
this.encoding = 'latin1';
|
|
|
|
}
|
2019-01-10 13:03:07 +01:00
|
|
|
|
|
|
|
async run(state) {
|
2018-03-18 10:46:14 +01:00
|
|
|
const queryBuffer = Buffer.from([
|
|
|
|
0x10, // standard header
|
|
|
|
0x03, // dump servers
|
|
|
|
0xff, // ask for all packets
|
|
|
|
0x00, // junk
|
|
|
|
0x01, 0x02, // challenge
|
|
|
|
]);
|
|
|
|
|
|
|
|
let parts = new Map();
|
|
|
|
let total = 0;
|
2019-01-10 13:03:07 +01:00
|
|
|
const full = await this.udpSend(queryBuffer,(buffer) => {
|
2018-03-18 10:46:14 +01:00
|
|
|
const reader = this.reader(buffer);
|
|
|
|
const header = reader.uint(2);
|
|
|
|
if (header !== 0x0610) {
|
2019-01-10 13:03:07 +01:00
|
|
|
this.debugLog('Header response does not match: ' + header.toString(16));
|
|
|
|
return;
|
2018-03-18 10:46:14 +01:00
|
|
|
}
|
|
|
|
const num = reader.uint(1);
|
|
|
|
const t = reader.uint(1);
|
|
|
|
if (t <= 0 || (total > 0 && t !== total)) {
|
2019-01-10 13:03:07 +01:00
|
|
|
throw new Error('Conflicting packet total: ' + t);
|
2018-03-18 10:46:14 +01:00
|
|
|
}
|
|
|
|
total = t;
|
|
|
|
|
|
|
|
if (num < 1 || num > total) {
|
2019-01-10 13:03:07 +01:00
|
|
|
this.debugLog('Invalid packet number: ' + num + ' ' + total);
|
|
|
|
return;
|
2018-03-18 10:46:14 +01:00
|
|
|
}
|
|
|
|
if (parts.has(num)) {
|
2019-01-10 13:03:07 +01:00
|
|
|
this.debugLog('Duplicate part: ' + num);
|
|
|
|
return;
|
2018-03-18 10:46:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
reader.skip(2); // challenge (0x0201)
|
|
|
|
reader.skip(2); // always 0x6600
|
|
|
|
parts.set(num, reader.rest());
|
|
|
|
|
|
|
|
if (parts.size === total) {
|
|
|
|
const ordered = [];
|
|
|
|
for (let i = 1; i <= total; i++) ordered.push(parts.get(i));
|
2019-01-10 13:03:07 +01:00
|
|
|
return Buffer.concat(ordered);
|
|
|
|
}
|
|
|
|
});
|
2018-03-18 10:46:14 +01:00
|
|
|
|
2019-01-10 13:03:07 +01:00
|
|
|
const fullReader = this.reader(full);
|
|
|
|
state.raw.name = this.readString(fullReader);
|
|
|
|
state.raw.motd = this.readString(fullReader);
|
2018-03-18 10:46:14 +01:00
|
|
|
|
2019-01-10 13:03:07 +01:00
|
|
|
state.raw.servers = [];
|
|
|
|
while (!fullReader.done()) {
|
|
|
|
fullReader.skip(1); // junk ?
|
|
|
|
const count = fullReader.uint(1);
|
|
|
|
for (let i = 0; i < count; i++) {
|
|
|
|
const six = fullReader.uint(1);
|
|
|
|
if (six !== 6) {
|
|
|
|
throw new Error('Expecting 6');
|
2018-03-18 10:46:14 +01:00
|
|
|
}
|
2019-01-10 13:03:07 +01:00
|
|
|
const ip = fullReader.uint(4);
|
|
|
|
const port = fullReader.uint(2);
|
|
|
|
const ipStr = (ip & 255) + '.' + (ip >> 8 & 255) + '.' + (ip >> 16 & 255) + '.' + (ip >>> 24);
|
|
|
|
state.raw.servers.push(ipStr+":"+port);
|
2018-03-18 10:46:14 +01:00
|
|
|
}
|
2019-01-10 13:03:07 +01:00
|
|
|
}
|
2018-03-18 10:46:14 +01:00
|
|
|
}
|
|
|
|
readString(reader) {
|
2019-02-05 02:58:28 +01:00
|
|
|
return reader.pascalString(1);
|
2018-03-18 10:46:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = Tribes1Master;
|