Additional async rewrite

This commit is contained in:
mmorrison 2019-01-12 04:43:36 -06:00
parent efe12a00aa
commit 29ce0b82d0
24 changed files with 654 additions and 470 deletions

View file

@ -3,7 +3,6 @@ const Core = require('./core');
class Doom3 extends Core {
constructor() {
super();
this.pretty = 'Doom 3';
this.encoding = 'latin1';
this.isEtqw = false;
this.hasSpaceBeforeClanTag = false;
@ -11,26 +10,33 @@ class Doom3 extends Core {
this.hasTypeFlag = false;
}
async run(state) {
const body = await this.udpSend('\xff\xffgetInfo\x00PiNGPoNG\x00', packet => {
const body = await this.udpSend('\xff\xffgetInfo\x00PiNGPoNg\x00', packet => {
const reader = this.reader(packet);
const header = reader.uint(2);
if(header !== 0xffff) return;
const header2 = reader.string();
if(header2 !== 'infoResponse') return;
const challengePart1 = reader.string({length:4});
if (challengePart1 !== "PiNG") return;
// some doom3 implementations only return the first 4 bytes of the challenge
const challengePart2 = reader.string({length:4});
if (challengePart2 !== 'PoNg') reader.skip(-4);
return reader.rest();
});
const reader = this.reader(body);
if(this.isEtqw) {
const taskId = reader.uint(4);
}
const challenge = reader.uint(4);
let reader = this.reader(body);
const protoVersion = reader.uint(4);
state.raw.protocolVersion = (protoVersion>>16)+'.'+(protoVersion&0xffff);
if(this.isEtqw) {
// some doom implementations send us a packet size here, some don't (etqw does this)
// we can tell if this is a packet size, because the third and fourth byte will be 0 (no packets are that massive)
reader.skip(2);
const packetContainsSize = (reader.uint(2) === 0);
reader.skip(-4);
if (packetContainsSize) {
const size = reader.uint(4);
this.debugLog("Received packet size: " + size);
}
while(!reader.done()) {
@ -42,23 +48,22 @@ class Doom3 extends Core {
}
if(!key) break;
state.raw[key] = value;
this.debugLog(key + "=" + value);
}
let i = 0;
while(!reader.done()) {
i++;
const player = {};
player.id = reader.uint(1);
if(player.id === 32) break;
player.ping = reader.uint(2);
if(!this.isEtqw) player.rate = reader.uint(4);
player.name = this.stripColors(reader.string());
if(this.hasClanTag) {
if(this.hasSpaceBeforeClanTag) reader.uint(1);
player.clantag = this.stripColors(reader.string());
}
if(this.hasTypeFlag) player.typeflag = reader.uint(1);
const isEtqw = state.raw.gamename && state.raw.gamename.toLowerCase().includes('etqw');
const rest = reader.rest();
let playerResult = this.attemptPlayerParse(rest, isEtqw, false, false, false);
if (!playerResult) playerResult = this.attemptPlayerParse(rest, isEtqw, true, false, false);
if (!playerResult) playerResult = this.attemptPlayerParse(rest, isEtqw, true, true, true);
if (!playerResult) {
throw new Error("Unable to find a suitable parse strategy for player list");
}
let players;
[players,reader] = playerResult;
for (const player of players) {
if(!player.ping || player.typeflag)
state.bots.push(player);
else
@ -66,7 +71,7 @@ class Doom3 extends Core {
}
state.raw.osmask = reader.uint(4);
if(this.isEtqw) {
if(isEtqw) {
state.raw.ranked = reader.uint(1);
state.raw.timeleft = reader.uint(4);
state.raw.gamestate = reader.uint(1);
@ -84,6 +89,59 @@ class Doom3 extends Core {
if(state.raw.si_map) state.map = state.raw.si_map;
if(state.raw.si_maxplayers) state.maxplayers = parseInt(state.raw.si_maxplayers);
if(state.raw.si_usepass === '1') state.password = true;
if (this.options.port === 27733) state.gamePort = 3074; // etqw has a different query and game port
}
attemptPlayerParse(rest, isEtqw, hasClanTag, hasClanTagPos, hasTypeFlag) {
this.debugLog("starting player parse attempt:");
this.debugLog("isEtqw: " + isEtqw);
this.debugLog("hasClanTag: " + hasClanTag);
this.debugLog("hasClanTagPos: " + hasClanTagPos);
this.debugLog("hasTypeFlag: " + hasTypeFlag);
const reader = this.reader(rest);
let lastId = -1;
const players = [];
while(true) {
this.debugLog("---");
if (reader.done()) {
this.debugLog("* aborting attempt, overran buffer *");
return null;
}
const player = {};
player.id = reader.uint(1);
this.debugLog("id: " + player.id);
if (player.id <= lastId || player.id > 0x20) {
this.debugLog("* aborting attempt, invalid player id *");
return null;
}
lastId = player.id;
if(player.id === 0x20) {
this.debugLog("* player parse successful *");
break;
}
player.ping = reader.uint(2);
this.debugLog("ping: " + player.ping);
if(!isEtqw) {
player.rate = reader.uint(4);
this.debugLog("rate: " + player.rate);
}
player.name = this.stripColors(reader.string());
this.debugLog("name: " + player.name);
if(hasClanTag) {
if(hasClanTagPos) {
const clanTagPos = reader.uint(1);
this.debugLog("clanTagPos: " + clanTagPos);
}
player.clantag = this.stripColors(reader.string());
this.debugLog("clan tag: " + player.clantag);
}
if(hasTypeFlag) {
player.typeflag = reader.uint(1);
this.debugLog("type flag: " + player.typeflag);
}
players.push(player);
}
return [players,reader];
}
stripColors(str) {