2023-09-14 22:28:31 +02:00
|
|
|
import Core from './core.js';
|
2019-01-07 01:52:03 +01:00
|
|
|
|
2023-09-14 22:28:31 +02:00
|
|
|
export default class quake2 extends Core {
|
2017-08-09 11:05:55 +02:00
|
|
|
constructor() {
|
2017-08-09 12:32:09 +02:00
|
|
|
super();
|
|
|
|
this.encoding = 'latin1';
|
|
|
|
this.delimiter = '\n';
|
|
|
|
this.sendHeader = 'status';
|
|
|
|
this.responseHeader = 'print';
|
|
|
|
this.isQuake1 = false;
|
|
|
|
}
|
2014-10-29 08:02:03 +01:00
|
|
|
|
2019-01-09 12:35:11 +01:00
|
|
|
async run(state) {
|
|
|
|
const body = await this.udpSend('\xff\xff\xff\xff'+this.sendHeader+'\x00', packet => {
|
|
|
|
const reader = this.reader(packet);
|
|
|
|
const header = reader.string({length: 4, encoding: 'latin1'});
|
|
|
|
if (header !== '\xff\xff\xff\xff') return;
|
|
|
|
let type;
|
|
|
|
if (this.isQuake1) {
|
2019-02-05 02:58:28 +01:00
|
|
|
type = reader.string(this.responseHeader.length);
|
2017-08-09 12:32:09 +02:00
|
|
|
} else {
|
2019-01-09 12:35:11 +01:00
|
|
|
type = reader.string({encoding: 'latin1'});
|
2017-08-09 12:32:09 +02:00
|
|
|
}
|
2019-01-09 12:35:11 +01:00
|
|
|
if (type !== this.responseHeader) return;
|
|
|
|
return reader.rest();
|
|
|
|
});
|
2014-10-29 08:02:03 +01:00
|
|
|
|
2019-01-09 12:35:11 +01:00
|
|
|
const reader = this.reader(body);
|
|
|
|
const info = reader.string().split('\\');
|
|
|
|
if(info[0] === '') info.shift();
|
2014-10-29 08:02:03 +01:00
|
|
|
|
2019-01-09 12:35:11 +01:00
|
|
|
while(true) {
|
|
|
|
const key = info.shift();
|
|
|
|
const value = info.shift();
|
|
|
|
if(typeof value === 'undefined') break;
|
|
|
|
state.raw[key] = value;
|
|
|
|
}
|
2014-10-29 08:02:03 +01:00
|
|
|
|
2019-01-09 12:35:11 +01:00
|
|
|
while(!reader.done()) {
|
|
|
|
const line = reader.string();
|
|
|
|
if(!line || line.charAt(0) === '\0') break;
|
2014-10-29 08:02:03 +01:00
|
|
|
|
2019-01-09 12:35:11 +01:00
|
|
|
const args = [];
|
|
|
|
const split = line.split('"');
|
|
|
|
split.forEach((part,i) => {
|
|
|
|
const inQuote = (i%2 === 1);
|
|
|
|
if(inQuote) {
|
|
|
|
args.push(part);
|
2017-08-09 12:32:09 +02:00
|
|
|
} else {
|
2019-01-09 12:35:11 +01:00
|
|
|
const splitSpace = part.split(' ');
|
|
|
|
for (const subpart of splitSpace) {
|
|
|
|
if(subpart) args.push(subpart);
|
|
|
|
}
|
2017-08-09 12:32:09 +02:00
|
|
|
}
|
2019-01-09 12:35:11 +01:00
|
|
|
});
|
2014-10-29 08:02:03 +01:00
|
|
|
|
2019-01-09 12:35:11 +01:00
|
|
|
const player = {};
|
|
|
|
if(this.isQuake1) {
|
|
|
|
player.id = parseInt(args.shift());
|
|
|
|
player.score = parseInt(args.shift());
|
|
|
|
player.time = parseInt(args.shift());
|
|
|
|
player.ping = parseInt(args.shift());
|
|
|
|
player.name = args.shift();
|
|
|
|
player.skin = args.shift();
|
|
|
|
player.color1 = parseInt(args.shift());
|
|
|
|
player.color2 = parseInt(args.shift());
|
|
|
|
} else {
|
|
|
|
player.frags = parseInt(args.shift());
|
|
|
|
player.ping = parseInt(args.shift());
|
|
|
|
player.name = args.shift() || '';
|
2019-01-10 13:03:07 +01:00
|
|
|
if (!player.name) delete player.name;
|
2019-01-09 12:35:11 +01:00
|
|
|
player.address = args.shift() || '';
|
2019-01-10 13:03:07 +01:00
|
|
|
if (!player.address) delete player.address;
|
2017-08-09 12:32:09 +02:00
|
|
|
}
|
2014-10-29 08:02:03 +01:00
|
|
|
|
2019-01-09 12:35:11 +01:00
|
|
|
(player.ping ? state.players : state.bots).push(player);
|
|
|
|
}
|
2014-10-29 08:02:03 +01:00
|
|
|
|
2019-01-09 12:35:11 +01:00
|
|
|
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('maxclients' in state.raw) state.maxplayers = state.raw.maxclients;
|
|
|
|
if('sv_hostname' in state.raw) state.name = state.raw.sv_hostname;
|
|
|
|
if('hostname' in state.raw) state.name = state.raw.hostname;
|
2017-08-09 12:32:09 +02:00
|
|
|
}
|
2017-08-09 11:05:55 +02:00
|
|
|
}
|