diff --git a/README.md b/README.md index d083ff9..6149ed5 100644 --- a/README.md +++ b/README.md @@ -250,6 +250,7 @@ Games List * Red Orchestra 2 (redorchestra2) * Redline (redline) * Return to Castle Wolfenstein (rtcw) +* rFactor (rfactor) * Ricochet (ricochet) * Rise of Nations (riseofnations) * Rune (rune) @@ -430,6 +431,9 @@ as well: `--debug`, `--pretty`, `--socketTimeout 5000`, etc. Changelog --- +### 2.0.10 +Added support for rFactor + ### 2.0.9 Added support for Vice City: Multiplayer diff --git a/games.txt b/games.txt index e065e62..95b8971 100644 --- a/games.txt +++ b/games.txt @@ -1,29 +1,5 @@ # id | pretty name for readme | protocol | options | extra -#### TODO: -# cube1|Cube 1|cube|port=28786,port_query_offset=1 -# assaultcube|Assault Cube|cube|port_query=28764 -# cube2|Cube 2: Sauerbraten|cube|port=28785,port_query_offset=1 -# bloodfrontier|Blood Frontier|cube - -# arcasimracing|Arca Sim Racing|rfactor|port=34397,port_query_offset=-100 -# rfactor|rFactor|rfactor|port=34397,port_query_offset=-100 - -# bfris|BFRIS|bfris|port=44001 -# freelancer|Freelancer|freelancer|port_query=2302 -# gr|Ghost Recon|ghostrecon|port=2346,port_query_offset=2 -# gtr2|GTR2|gtr2|port=34297,port_query_offset=1 -# haze|Haze|haze -# plainsight|Plain Sight|plainsight -# redfaction|Red Faction|redfaction|port_query=7755 -# savage|Savage|savage|port_query=11235 -# savage2|Savage 2|savage2|port_query=11235 -# teeworlds|Teeworlds|teeworlds|port=8303 -# tribes|Tribes 1: Starsiege|tribes|port_query=28001 -# tribes2|Tribes 2|tribes2|port_query=28000 -# worldinconflict|World in Conflict|worldinconflict - - 7d2d|7 Days to Die|valve|port=26900,port_query_offset=1 ageofchivalry|Age of Chivalry|valve|port=27015 aoe2|Age of Empires 2|ase|port_query=27224 @@ -218,6 +194,7 @@ redorchestraost|Red Orchestra: Ostfront 41-45|gamespy1|port=7757,port_query_offs redorchestra2|Red Orchestra 2|valve|port=7777,port_query=27015 redline|Redline|gamespy1|port_query=25252 rtcw|Return to Castle Wolfenstein|quake3|port_query=27960 +rfactor|rFactor|rfactor|port=34397,port_query_offset=-100 ricochet|Ricochet|valve|port=27015 riseofnations|Rise of Nations|gamespy1|port_query=6501 rune|Rune|gamespy1|port=7777,port_query_offset=1 diff --git a/package.json b/package.json index eb8f008..e2967f2 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ ], "main": "lib/index.js", "author": "Michael Morrison", - "version": "2.0.9", + "version": "2.0.10", "repository": { "type": "git", "url": "https://github.com/sonicsnes/node-gamedig.git" diff --git a/protocols/core.js b/protocols/core.js index 94e6bf1..92a9cc2 100644 --- a/protocols/core.js +++ b/protocols/core.js @@ -99,6 +99,21 @@ class Core extends EventEmitter { // because lots of servers prefix with spaces to try to appear first state.name = (state.name || '').trim(); + if (typeof state.players === 'number') { + const num = state.players; + state.players = []; + for (let i = 0; i < num; i++) { + state.players.push({}); + } + } + if (typeof state.bots === 'number') { + const num = state.bots; + state.bots = []; + for (let i = 0; i < num; i++) { + state.bots.push({}); + } + } + if (!('connect' in state)) { state.connect = '' + (state.gameHost || this.options.host || this.options.address) diff --git a/protocols/geneshift.js b/protocols/geneshift.js index b9559c6..891db5e 100644 --- a/protocols/geneshift.js +++ b/protocols/geneshift.js @@ -26,7 +26,7 @@ class GeneShift extends Core { state.raw.country = found[1]; state.name = found[4]; state.map = found[5]; - state.raw.numplayers = parseInt(found[6]); + state.players = parseInt(found[6]); state.maxplayers = parseInt(found[7]); // fields[8] is unknown? state.raw.rules = found[9]; @@ -40,10 +40,6 @@ class GeneShift extends Core { state.raw.mercs = !!parseInt(found[17]); // fields[18] is unknown? listen server? state.raw.version = found[19]; - - for(let i = 0; i < state.raw.numplayers; i++) { - state.players.push({}); - } } } diff --git a/protocols/jc2mp.js b/protocols/jc2mp.js index 77d2bf6..996809c 100644 --- a/protocols/jc2mp.js +++ b/protocols/jc2mp.js @@ -12,9 +12,7 @@ class Jc2mp extends Gamespy3 { async run(state) { await super.run(state); if(!state.players.length && parseInt(state.raw.numplayers)) { - for(let i = 0; i < parseInt(state.raw.numplayers); i++) { - state.players.push({}); - } + state.players = parseInt(state.raw.numplayers); } } } diff --git a/protocols/minecraft.js b/protocols/minecraft.js index 260751a..536b87b 100644 --- a/protocols/minecraft.js +++ b/protocols/minecraft.js @@ -59,9 +59,7 @@ class Minecraft extends Core { }); } } - while(state.players.length < json.players.online) { - state.players.push({}); - } + state.players = json.players.online; } varIntBuffer(num) { diff --git a/protocols/mumbleping.js b/protocols/mumbleping.js index 7737dee..eca4a4c 100644 --- a/protocols/mumbleping.js +++ b/protocols/mumbleping.js @@ -17,12 +17,9 @@ class MumblePing extends Core { state.raw.versionMinor = reader.uint(1); state.raw.versionPatch = reader.uint(1); reader.skip(8); - state.raw.numplayers = reader.uint(4); + state.players = reader.uint(4); state.maxplayers = reader.uint(4); state.raw.allowedbandwidth = reader.uint(4); - for(let i = 0; i < state.raw.numplayers; i++) { - state.players.push({}); - } } } diff --git a/protocols/openttd.js b/protocols/openttd.js index 09c0959..9bf336f 100644 --- a/protocols/openttd.js +++ b/protocols/openttd.js @@ -35,10 +35,7 @@ class OpenTtd extends Core { 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.players = reader.uint(1); state.raw.numspectators = reader.uint(1); state.map = reader.string(); state.raw.map_width = reader.uint(2); diff --git a/protocols/rfactor.js b/protocols/rfactor.js new file mode 100644 index 0000000..7d4b58c --- /dev/null +++ b/protocols/rfactor.js @@ -0,0 +1,75 @@ +const Core = require('./core'); + +class Rfactor extends Core { + constructor() { + super(); + //this.byteorder = 'be'; + } + + async run(state) { + const buffer = await this.udpSend('rF_S',b => b); + const reader = this.reader(buffer); + + state.raw.gamename = this.readString(reader, 8); + state.raw.fullUpdate = reader.uint(1); + state.raw.region = reader.uint(2); + state.raw.ip = reader.part(4); + state.raw.size = reader.uint(2); + state.raw.version = reader.uint(2); + state.raw.versionRaceCast = reader.uint(2); + state.gamePort = reader.uint(2); + state.raw.queryPort = reader.uint(2); + state.raw.game = this.readString(reader, 20); + state.name = this.readString(reader, 28); + state.map = this.readString(reader, 32); + state.raw.motd = this.readString(reader, 96); + state.raw.packedAids = reader.uint(2); + state.raw.ping = reader.uint(2); + state.raw.packedFlags = reader.uint(1); + state.raw.rate = reader.uint(1); + state.players = reader.uint(1); + state.maxplayers = reader.uint(1); + state.raw.bots = reader.uint(1); + state.raw.packedSpecial = reader.uint(1); + state.raw.damage = reader.uint(1); + state.raw.packedRules = reader.uint(2); + state.raw.credits1 = reader.uint(1); + state.raw.credits2 = reader.uint(2); + this.logger.debug(reader.offset()); + state.raw.time = reader.uint(2); + state.raw.laps = reader.uint(2) / 16; + reader.skip(3); + state.raw.vehicles = reader.string(); + + state.password = !!(state.raw.packedSpecial & 2); + state.raw.raceCast = !!(state.raw.packedSpecial & 4); + state.raw.fixedSetups = !!(state.raw.packedSpecial & 16); + + const aids = [ + 'TractionControl', + 'AntiLockBraking', + 'StabilityControl', + 'AutoShifting', + 'AutoClutch', + 'Invulnerability', + 'OppositeLock', + 'SteeringHelp', + 'BrakingHelp', + 'SpinRecovery', + 'AutoPitstop' + ]; + state.raw.aids = []; + for (let offset = 0; offset < aids.length; offset++) { + if (state.packedAids && (1 << offset)) { + state.raw.aids.push(aids[offset]); + } + } + } + + // Consumes bytesToConsume, but only returns string up to the first null + readString(reader, bytesToConsume) { + return reader.string(bytesToConsume).replace(/\0.*$/g,''); + } +} + +module.exports = Rfactor; diff --git a/protocols/samp.js b/protocols/samp.js index 4b3b70f..8af3c99 100644 --- a/protocols/samp.js +++ b/protocols/samp.js @@ -70,9 +70,7 @@ class Samp extends Core { } } if (!gotPlayerData) { - for(let i = 0; i < state.raw.numplayers; i++) { - state.players.push({}); - } + state.players = state.raw.numplayers; } } readString(reader,lenBytes) { diff --git a/protocols/starmade.js b/protocols/starmade.js index 18d063b..2aac31f 100644 --- a/protocols/starmade.js +++ b/protocols/starmade.js @@ -51,14 +51,8 @@ class Starmade extends Core { if(typeof data[3] === 'number') state.raw.version = data[3].toFixed(7).replace(/0+$/, ''); if(typeof data[4] === 'string') state.name = data[4]; if(typeof data[5] === 'string') state.raw.description = data[5]; - if(typeof data[7] === 'number') state.raw.numplayers = data[7]; + if(typeof data[7] === 'number') state.players = data[7]; if(typeof data[8] === 'number') state.maxplayers = data[8]; - - if('numplayers' in state.raw) { - for(let i = 0; i < state.raw.numplayers; i++) { - state.players.push({}); - } - } } }