From 6a0ed624c15d16d5f22db221e738b0944ff11380 Mon Sep 17 00:00:00 2001 From: mmorrison Date: Sat, 26 Oct 2019 20:20:26 -0500 Subject: [PATCH] Automatically detect killing floor extended info, don't clobber re-used unreal 2 rule keys, add unreal 2 scoreboard info --- games.txt | 4 +-- protocols/killingfloor.js | 10 ------ protocols/unreal2.js | 74 +++++++++++++++++++++++---------------- protocols/ut2004.js | 11 ------ 4 files changed, 45 insertions(+), 54 deletions(-) delete mode 100644 protocols/killingfloor.js delete mode 100644 protocols/ut2004.js diff --git a/games.txt b/games.txt index 2bbf25b..7036219 100644 --- a/games.txt +++ b/games.txt @@ -132,7 +132,7 @@ insurgencysandstorm|Insurgency: Sandstorm (2018)|valve|port=27015,port_query_off ironstorm|Iron Storm (2002)|gamespy1|port_query=3505 jamesbondnightfire|James Bond 007: Nightfire (2002)|gamespy1|port_query=6550 jc2mp|Just Cause 2 - Multiplayer (2010)|jc2mp|port=7777 -killingfloor|Killing Floor (2009)|killingfloor|port=7707,port_query_offset=1 +killingfloor|Killing Floor (2009)|unreal2|port=7707,port_query_offset=1 killingfloor2|Killing Floor 2 (2016)|valve|port=7777,port_query=27015 kingpin|Kingpin: Life of Crime (1999)|gamespy1|port=31510,port_query_offset=-10 kisspc|Kiss: Psycho Circus: The Nightmare Child (2000)|gamespy1|port=7777,port_query_offset=1 @@ -263,7 +263,7 @@ unreal|Unreal|gamespy1|port=7777,port_query_offset=1 unturned|unturned|valve|port=27015,port_query_offset=1 ut|Unreal Tournament|gamespy1|port=7777,port_query_offset=1 ut2003|Unreal Tournament 2003|unreal2|port=7757,port_query_offset=1 -ut2004|Unreal Tournament 2004|ut2004|port=7777,port_query_offset=1 +ut2004|Unreal Tournament 2004|unreal2|port=7777,port_query_offset=1 ut3|Unreal Tournament 3|ut3|port=7777,port_query_offset=-1277 urbanterror|Urban Terror|quake3|port_query=27960 diff --git a/protocols/killingfloor.js b/protocols/killingfloor.js deleted file mode 100644 index ab50dda..0000000 --- a/protocols/killingfloor.js +++ /dev/null @@ -1,10 +0,0 @@ -const Unreal2 = require('./unreal2'); - -class KillingFloor extends Unreal2 { - readExtraInfo(reader,state) { - state.raw.wavecurrent = reader.uint(4); - state.raw.wavetotal = reader.uint(4); - } -} - -module.exports = KillingFloor; diff --git a/protocols/unreal2.js b/protocols/unreal2.js index 4d0a325..b08c147 100644 --- a/protocols/unreal2.js +++ b/protocols/unreal2.js @@ -6,6 +6,7 @@ class Unreal2 extends Core { this.encoding = 'latin1'; } async run(state) { + let extraInfoReader; { const b = await this.sendPacket(0, true); const reader = this.reader(b); @@ -18,7 +19,10 @@ class Unreal2 extends Core { state.raw.gametype = this.readUnrealString(reader, true); state.raw.numplayers = reader.uint(4); state.maxplayers = reader.uint(4); - this.readExtraInfo(reader, state); + this.logger.debug(log => { + log("UNREAL2 EXTRA INFO", reader.buffer.slice(reader.i)); + }); + extraInfoReader = reader; } { @@ -29,57 +33,65 @@ class Unreal2 extends Core { while(!reader.done()) { const key = this.readUnrealString(reader,true); const value = this.readUnrealString(reader,true); - if(key === 'Mutator') state.raw.mutators.push(value); - else if (key || value) state.raw.rules[key] = value; + this.logger.debug(key+'='+value); + if(key === 'Mutator' || key === 'mutator') { + state.raw.mutators.push(value); + } else if (key || value) { + if (state.raw.rules.hasOwnProperty(key)) { + state.raw.rules[key] += ',' + value; + } else { + state.raw.rules[key] = value; + } + } } if('GamePassword' in state.raw.rules) state.password = state.raw.rules.GamePassword !== 'True'; } + if (state.raw.mutators.includes('KillingFloorMut') + || state.raw.rules['Num trader weapons'] + || state.raw.rules['Server Version'] === '1065' + ) { + // Killing Floor + state.raw.wavecurrent = extraInfoReader.uint(4); + state.raw.wavetotal = extraInfoReader.uint(4); + state.raw.ping = extraInfoReader.uint(4); + state.raw.flags = extraInfoReader.uint(4); + state.raw.skillLevel = this.readUnrealString(extraInfoReader, true); + } else { + state.raw.ping = extraInfoReader.uint(4); + // These fields were added in later revisions of unreal engine + if (extraInfoReader.remaining() >= 8) { + state.raw.flags = extraInfoReader.uint(4); + state.raw.skill = this.readUnrealString(extraInfoReader, true); + } + } + { const b = await this.sendPacket(2,false); const reader = this.reader(b); + state.raw.scoreboard = {}; while(!reader.done()) { const player = {}; player.id = reader.uint(4); - if(!player.id) break; - if(player.id === 0) { - // Unreal2XMP Player (ID is always 0) - reader.skip(4); - } player.name = this.readUnrealString(reader,true); player.ping = reader.uint(4); player.score = reader.int(4); - reader.skip(4); // stats ID + player.statsId = reader.uint(4); + this.logger.debug(player); - // Extra data for Unreal2XMP players - if(player.id === 0) { - const count = reader.uint(1); - for(let iField = 0; iField < count; iField++) { - const key = this.readUnrealString(reader,true); - const value = this.readUnrealString(reader,true); - player[key] = value; - } + if (!player.id) { + state.raw.scoreboard[player.name] = player.score; + } else if (!player.ping) { + state.bots.push(player); + } else { + state.players.push(player); } - - if(player.id === 0 && player.name === 'Player') { - // these show up in ut2004 queries, but aren't real - // not even really sure why they're there - continue; - } - - (player.ping ? state.players : state.bots).push(player); } } } - readExtraInfo(reader,state) { - this.debugLog(log => { - log("UNREAL2 EXTRA INFO", reader.buffer.slice(reader.i)); - }); - } - readUnrealString(reader, stripColor) { let length = reader.uint(1), ucs2 = false; if(length >= 0x80) { diff --git a/protocols/ut2004.js b/protocols/ut2004.js deleted file mode 100644 index ab36ed1..0000000 --- a/protocols/ut2004.js +++ /dev/null @@ -1,11 +0,0 @@ -const Unreal2 = require('./unreal2'); - -class Ut2004 extends Unreal2 { - readExtraInfo(reader,state) { - state.raw.ping = reader.uint(4); - state.raw.flags = reader.uint(4); - state.raw.skill = reader.uint(2); - } -} - -module.exports = Ut2004;