mirror of
https://github.com/gamedig/node-gamedig.git
synced 2024-11-17 17:25:19 +01:00
feat: Add version
as a top level field (#532)
* add top level version on existing entries * start adding version on new protocols WIP * add version to more games * more games with version * add more games * more version * even more games with version * add 'delete state.raw.version' * fix delete version * Update CHANGELOG.md * add version in Results.js * more games * add new game * more games * add version on README * add new game * other game * new game * add unreal2 version * add ventrilo version * add eldewrito eldewrito * add beammp version * fix starmade version * add new version in samp protocol * docs: tweak the changelog line a bit --------- Co-authored-by: CosminPerRam <cosmin.p@live.com>
This commit is contained in:
parent
fb6a5a1c7a
commit
a7c3b5474c
40 changed files with 52 additions and 13 deletions
|
@ -1,6 +1,7 @@
|
|||
|
||||
## To Be Released...
|
||||
## 5.0.0-beta.3
|
||||
* Added a new stabilized field `version` in the query response (By @podrivo #532)
|
||||
* Euro Truck Simulator 2 (2012) - Added support (By @podrivo #523)
|
||||
* Eco - Fixed querying servers using reverse queries and player names (By @Vito0912 #526)
|
||||
* Factorio (2016) - Added support (By @Vito0912 #527)
|
||||
|
|
|
@ -78,6 +78,7 @@ The returned state object will contain the following keys:
|
|||
| **connect** | string | This will typically include the game's `IP:PORT`. The port will reflect the server's game port, even if your request specified the game's query port in the request. For some games, this may be a server ID or connection URL if an IP:PORT is not appropriate for end-users. |
|
||||
| **ping** | number | Round trip time to the server (in milliseconds). Note that this is not the RTT of an ICMP echo, as ICMP packets are often blocked by NATs and node has poor support for raw sockets. This value is derived from the RTT of one of the query packets, which is usually quite accurate, but may add a bit due to server lag. |
|
||||
| **queryPort** | number | Indicates on which port the query was done on, 0 if this is not applicable. |
|
||||
| **version** | string | Game version that is running on the server. Empty if not present. |
|
||||
| **raw** | object | Contains all information received from the server in a disorganized format. |
|
||||
|
||||
Note that `raw` (or **unstable**) objects contents MAY change on a per-protocol basis between GameDig patch releases (although not typical).
|
||||
|
|
|
@ -25,6 +25,7 @@ export class Results {
|
|||
password = false
|
||||
|
||||
raw = {}
|
||||
version = ''
|
||||
|
||||
maxplayers = 0
|
||||
numplayers = 0
|
||||
|
|
|
@ -21,7 +21,7 @@ export default class armagetron extends Core {
|
|||
state.numplayers = this.readUInt(reader)
|
||||
state.raw.versionmin = this.readUInt(reader)
|
||||
state.raw.versionmax = this.readUInt(reader)
|
||||
state.raw.version = this.readString(reader)
|
||||
state.version = this.readString(reader)
|
||||
state.maxplayers = this.readUInt(reader)
|
||||
|
||||
const players = this.readString(reader)
|
||||
|
|
|
@ -9,4 +9,9 @@ export default class asa extends Epic {
|
|||
this.clientSecret = 'PP5UGxysEieNfSrEicaD1N2Bb3TdXuD7xHYcsdUHZ7s'
|
||||
this.deploymentId = 'ad9a8feffb3b4b2ca315546f038c3ae2'
|
||||
}
|
||||
|
||||
async run(state) {
|
||||
await super.run(state)
|
||||
state.version = state.raw.attributes.BUILDID_s + '.' + state.raw.attributes.MINORBUILDID_s
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ export default class ase extends Core {
|
|||
state.name = this.readString(reader)
|
||||
state.raw.gametype = this.readString(reader)
|
||||
state.map = this.readString(reader)
|
||||
state.raw.version = this.readString(reader)
|
||||
state.version = this.readString(reader)
|
||||
state.password = this.readString(reader) === '1'
|
||||
state.numplayers = parseInt(this.readString(reader))
|
||||
state.maxplayers = parseInt(this.readString(reader))
|
||||
|
|
|
@ -22,6 +22,7 @@ export default class assettocorsa extends Core {
|
|||
state.gamePort = serverInfo.port
|
||||
state.raw.carInfo = carInfo.Cars
|
||||
state.raw.serverInfo = serverInfo
|
||||
state.version = state.raw.serverInfo.poweredBy
|
||||
|
||||
for (const car of carInfo.Cars) {
|
||||
if (car.IsConnected) {
|
||||
|
|
|
@ -66,7 +66,7 @@ export default class battlefield extends Core {
|
|||
{
|
||||
const data = await this.query(socket, ['version'])
|
||||
data.shift()
|
||||
state.raw.version = data.shift()
|
||||
state.version = data.shift()
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -28,5 +28,6 @@ export default class beammp extends Core {
|
|||
})
|
||||
|
||||
state.raw = server
|
||||
if ('version' in state.raw) state.version = state.raw.version
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ export default class doom3 extends Core {
|
|||
let reader = this.reader(body)
|
||||
const protoVersion = reader.uint(4)
|
||||
state.raw.protocolVersion = (protoVersion >> 16) + '.' + (protoVersion & 0xffff)
|
||||
state.version = state.raw.protocolVersion
|
||||
|
||||
// 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)
|
||||
|
|
|
@ -17,5 +17,6 @@ export default class eco extends Core {
|
|||
state.gamePort = serverInfo.GamePort
|
||||
state.players = serverInfo.OnlinePlayersNames?.map(name => ({ name, raw: {} })) || []
|
||||
state.raw = serverInfo
|
||||
state.version = state.raw.Version
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,5 +17,6 @@ export default class eldewrito extends Core {
|
|||
state.connect = this.options.address + ':' + json.port
|
||||
|
||||
state.raw = json
|
||||
if ('eldewritoVersion' in state.raw) state.version = state.raw.eldewritoVersion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@ export default class factorio extends Core {
|
|||
state.players = players.map(player => ({ name: player, raw: {} }))
|
||||
|
||||
state.raw = serverInfo
|
||||
state.version = state.raw.application_version.game_version + '.' + state.raw.application_version.build_version
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ export default class farmingsimulator extends Core {
|
|||
}
|
||||
})
|
||||
|
||||
state.raw.version = serverInfo.attr('version')
|
||||
state.version = serverInfo.attr('version')
|
||||
|
||||
// TODO: Add state.raw
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ export default class ffow extends valve {
|
|||
state.raw.mod = reader.string()
|
||||
state.raw.gamemode = reader.string()
|
||||
state.raw.description = reader.string()
|
||||
state.raw.version = reader.string()
|
||||
state.version = reader.string()
|
||||
state.gamePort = reader.uint(2)
|
||||
state.numplayers = reader.uint(1)
|
||||
state.maxplayers = reader.uint(1)
|
||||
|
|
|
@ -17,6 +17,7 @@ export default class fivem extends quake2 {
|
|||
responseType: 'json'
|
||||
})
|
||||
state.raw.info = json
|
||||
if ('version' in state.raw.info) state.version = state.raw.info.version
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -113,6 +113,7 @@ export default class gamespy1 extends Core {
|
|||
}
|
||||
|
||||
state.numplayers = state.players.length
|
||||
state.version = state.raw.gamever
|
||||
}
|
||||
|
||||
async sendPacket (type) {
|
||||
|
|
|
@ -23,6 +23,7 @@ export default class gamespy2 extends Core {
|
|||
if (this.trueTest(state.raw.password)) state.password = true
|
||||
if ('maxplayers' in state.raw) state.maxplayers = parseInt(state.raw.maxplayers)
|
||||
if ('hostport' in state.raw) state.gamePort = parseInt(state.raw.hostport)
|
||||
if ('gamever' in state.raw) state.version = state.raw.gamever
|
||||
}
|
||||
|
||||
// Parse players
|
||||
|
|
|
@ -112,6 +112,7 @@ export default class gamespy3 extends Core {
|
|||
if (state.raw.password === '1') state.password = true
|
||||
if ('maxplayers' in state.raw) state.maxplayers = parseInt(state.raw.maxplayers)
|
||||
if ('hostport' in state.raw) state.gamePort = parseInt(state.raw.hostport)
|
||||
if ('gamever' in state.raw) state.version = state.raw.gamever
|
||||
|
||||
if ('' in state.raw.playerTeamInfo) {
|
||||
for (const playerInfo of state.raw.playerTeamInfo['']) {
|
||||
|
|
|
@ -41,6 +41,6 @@ export default class geneshift extends Core {
|
|||
state.raw.friendlyfire = !!parseInt(found[16])
|
||||
state.raw.mercs = !!parseInt(found[17])
|
||||
// fields[18] is unknown? listen server?
|
||||
state.raw.version = found[19]
|
||||
state.version = found[19]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,5 +12,7 @@ export default class jc2mp extends gamespy3 {
|
|||
|
||||
async run (state) {
|
||||
await super.run(state)
|
||||
|
||||
state.version = state.raw.version
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ export default class mafia2mp extends Core {
|
|||
state.numplayers = parseInt(this.readString(reader))
|
||||
state.maxplayers = parseInt(this.readString(reader))
|
||||
state.raw.gamemode = this.readString(reader)
|
||||
state.version = state.raw.gamemode
|
||||
state.password = !!reader.uint(1)
|
||||
state.gamePort = this.options.port - 1
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ export default class minecraft extends Core {
|
|||
if (vanillaState.maxplayers) state.maxplayers = vanillaState.maxplayers
|
||||
if (vanillaState.players.length) state.players = vanillaState.players
|
||||
if (vanillaState.ping) this.registerRtt(vanillaState.ping)
|
||||
if (vanillaState.raw.version) state.version = vanillaState.raw.version.name
|
||||
}
|
||||
if (gamespyState) {
|
||||
if (gamespyState.name) state.name = gamespyState.name
|
||||
|
@ -93,6 +94,7 @@ export default class minecraft extends Core {
|
|||
if (bedrockState.maxplayers) state.maxplayers = bedrockState.maxplayers
|
||||
if (bedrockState.map) state.map = bedrockState.map
|
||||
if (bedrockState.ping) this.registerRtt(bedrockState.ping)
|
||||
if (bedrockState.raw.mcVersion) state.version = bedrockState.raw.mcVersion
|
||||
}
|
||||
// remove dupe spaces from name
|
||||
state.name = state.name.replace(/\s+/g, ' ')
|
||||
|
|
|
@ -57,6 +57,7 @@ export default class minecraftbedrock extends Core {
|
|||
state.name = split.shift()
|
||||
state.raw.protocolVersion = split.shift()
|
||||
state.raw.mcVersion = split.shift()
|
||||
state.version = state.raw.mcVersion
|
||||
state.numplayers = parseInt(split.shift())
|
||||
state.maxplayers = parseInt(split.shift())
|
||||
if (split.length) state.raw.serverId = split.shift()
|
||||
|
|
|
@ -16,6 +16,7 @@ export default class mumbleping extends Core {
|
|||
state.raw.versionMajor = reader.uint(1)
|
||||
state.raw.versionMinor = reader.uint(1)
|
||||
state.raw.versionPatch = reader.uint(1)
|
||||
state.version = state.raw.versionMajor + '.' + state.raw.versionMinor + '.' + state.raw.versionPatch
|
||||
reader.skip(8)
|
||||
state.numplayers = reader.uint(4)
|
||||
state.maxplayers = reader.uint(4)
|
||||
|
|
|
@ -25,7 +25,7 @@ export default class openttd extends Core {
|
|||
}
|
||||
|
||||
state.name = reader.string()
|
||||
state.raw.version = reader.string()
|
||||
state.version = reader.string()
|
||||
|
||||
state.raw.language = this.decode(
|
||||
reader.uint(1),
|
||||
|
|
|
@ -15,5 +15,6 @@ export default class palworld extends Epic {
|
|||
await super.run(state)
|
||||
state.name = state.raw.attributes.NAME_s
|
||||
state.numplayers = state.raw.attributes.PLAYERS_l
|
||||
state.version = state.raw.attributes.VERSION_S
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,9 @@ export default class quake1 extends quake2 {
|
|||
this.responseHeader = 'n'
|
||||
this.isQuake1 = true
|
||||
}
|
||||
|
||||
async run(state) {
|
||||
await super.run(state)
|
||||
if ('*version' in state.raw) state.version = state.raw['*version']
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ export default class quake2 extends Core {
|
|||
if ('sv_hostname' in state.raw) state.name = state.raw.sv_hostname
|
||||
if ('hostname' in state.raw) state.name = state.raw.hostname
|
||||
if ('clients' in state.raw) state.numplayers = state.raw.clients
|
||||
if ('iv' in state.raw) state.version = state.raw.iv
|
||||
else state.numplayers = state.players.length + state.bots.length
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ export default class quake3 extends quake2 {
|
|||
state.name = this.stripColors(state.name)
|
||||
for (const key of Object.keys(state.raw)) {
|
||||
state.raw[key] = this.stripColors(state.raw[key])
|
||||
if ('version' in state.raw) state.version = state.raw.version
|
||||
}
|
||||
for (const player of state.players) {
|
||||
player.name = this.stripColors(player.name)
|
||||
|
|
|
@ -10,7 +10,7 @@ export default class rfactor extends Core {
|
|||
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.version = reader.uint(2)
|
||||
state.raw.versionRaceCast = reader.uint(2)
|
||||
state.gamePort = reader.uint(2)
|
||||
state.raw.queryPort = reader.uint(2)
|
||||
|
|
|
@ -16,7 +16,7 @@ export default class samp extends Core {
|
|||
const reader = await this.sendPacket('i')
|
||||
if (this.isVcmp) {
|
||||
const consumed = reader.part(12)
|
||||
state.raw.version = this.reader(consumed).string()
|
||||
state.version = this.reader(consumed).string()
|
||||
}
|
||||
state.password = !!reader.uint(1)
|
||||
state.numplayers = reader.uint(2)
|
||||
|
@ -35,6 +35,7 @@ export default class samp extends Core {
|
|||
const key = reader.pascalString(1)
|
||||
const value = reader.pascalString(1)
|
||||
state.raw.rules[key] = value
|
||||
if ('version' in state.raw.rules) state.version = state.raw.rules.version
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ export default class savage2 extends Core {
|
|||
state.raw.location = reader.string()
|
||||
state.raw.minplayers = reader.uint(1)
|
||||
state.raw.gametype = reader.string()
|
||||
state.raw.version = reader.string()
|
||||
state.version = reader.string()
|
||||
state.raw.minlevel = reader.uint(1)
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ export default class starmade extends Core {
|
|||
this.logger.debug('Received raw data array', data)
|
||||
|
||||
if (typeof data[0] === 'number') state.raw.infoVersion = data[0]
|
||||
if (typeof data[1] === 'number') state.raw.version = data[1]
|
||||
if (typeof data[1] === 'string') state.version = data[1]
|
||||
if (typeof data[2] === 'string') state.name = data[2]
|
||||
if (typeof data[3] === 'string') state.raw.description = data[3]
|
||||
if (typeof data[4] === 'number') state.raw.startTime = data[4]
|
||||
|
|
|
@ -17,6 +17,7 @@ export default class teamspeak3 extends Core {
|
|||
if ('virtualserver_name' in state.raw) state.name = state.raw.virtualserver_name
|
||||
if ('virtualserver_maxclients' in state.raw) state.maxplayers = state.raw.virtualserver_maxclients
|
||||
if ('virtualserver_clientsonline' in state.raw) state.numplayers = state.raw.virtualserver_clientsonline
|
||||
if ('virtualserver_version' in state.raw) state.version = state.raw.virtualserver_version
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -14,5 +14,6 @@ export default class theisleevrima extends Epic {
|
|||
await super.run(state)
|
||||
state.name = state.raw.attributes.SERVERNAME_s
|
||||
state.map = state.raw.attributes.MAP_NAME_s
|
||||
state.version = state.raw.attributes.SERVER_VERSION_s
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ export default class tribes1 extends Core {
|
|||
|
||||
state.raw.gametype = this.readString(reader)
|
||||
const isStarsiege2009 = state.raw.gametype === 'Starsiege'
|
||||
state.raw.version = this.readString(reader)
|
||||
state.version = this.readString(reader)
|
||||
state.name = this.readString(reader)
|
||||
|
||||
if (isStarsiege2009) {
|
||||
|
|
|
@ -46,6 +46,7 @@ export default class unreal2 extends Core {
|
|||
}
|
||||
}
|
||||
if ('GamePassword' in state.raw.rules) { state.password = state.raw.rules.GamePassword !== 'True' }
|
||||
if ('UTComp_Version' in state.raw.rules) { state.version = state.raw.rules.UTComp_Version }
|
||||
}
|
||||
|
||||
if (state.raw.mutators.includes('KillingFloorMut') ||
|
||||
|
|
|
@ -94,7 +94,8 @@ export default class valve extends Core {
|
|||
state.raw.shipwitnesses = reader.uint(1)
|
||||
state.raw.shipduration = reader.uint(1)
|
||||
}
|
||||
state.raw.version = reader.string()
|
||||
state.version = reader.string()
|
||||
|
||||
const extraFlag = reader.uint(1)
|
||||
if (extraFlag & 0x80) state.gamePort = reader.uint(2)
|
||||
if (extraFlag & 0x10) state.raw.steamid = reader.uint(8).toString()
|
||||
|
|
|
@ -21,6 +21,7 @@ export default class ventrilo extends Core {
|
|||
|
||||
if ('NAME' in state.raw) state.name = state.raw.NAME
|
||||
if ('MAXCLIENTS' in state.raw) state.maxplayers = state.raw.MAXCLIENTS
|
||||
if ('VERSION' in state.raw) state.version = state.raw.VERSION
|
||||
if (this.trueTest(state.raw.AUTH)) state.password = true
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue