node-gamedig/protocols/satisfactory.js
CosminPerRam 5b1da1ad71
feat: Satisfactory add lightweight query (#652)
* feat: add lightweight query

* docs: update CHANGELOG
2024-10-14 00:28:19 +03:00

98 lines
2.8 KiB
JavaScript

import Core from './core.js'
export default class satisfactory extends Core {
constructor () {
super()
// Don't use the tcp ping probing
this.usedTcp = true
}
async run (state) {
const packet = Buffer.from([0xD5, 0xF6, 0, 1, 5, 5, 5, 5, 5, 5, 5, 5, 1])
const response = await this.udpSend(packet, packet => {
const reader = this.reader(packet)
const header = reader.part(4)
if (header.equals(Buffer.from([0xD5, 0xF6, 1, 2]))) return
reader.skip(8) // skip the cookie
return reader
})
state.raw.serverState = response.int(1)
state.version = response.int(4).toString()
state.raw.serverFlags = response.int(8)
const subStatesCount = response.int(1)
response.skip(subStatesCount * 3)
const nameLength = response.int(2)
state.name = response.part(nameLength).toString('utf-8')
/**
* To get information about the Satisfactory game server, you need to first obtain a client authenticationToken.
* https://satisfactory.wiki.gg/wiki/Dedicated_servers/HTTPS_API
*/
const tokenRequestJson = {
function: 'PasswordlessLogin',
data: {
MinimumPrivilegeLevel: 'Client'
}
}
const queryJson = {
function: 'QueryServerState'
}
const headers = {
'Content-Type': 'application/json'
}
/**
* Satisfactory servers unless specified use self-signed certificates for the HTTPS API.
* Because of this we default the `rejectUnauthorized` flag to `false` unless set.
* For more information see GAMES_LIST.md
*/
if (!this.options.rejectUnauthorized) this.options.rejectUnauthorized = false
const tokenRequestResponse = await this.queryInfo(tokenRequestJson, headers)
const { data: queryResponse } = await this.queryInfo(queryJson, {
...headers,
Authorization: `Bearer ${tokenRequestResponse.data.authenticationToken}`
})
/**
* Satisfactory API cannot pull Server Name at the moment, see QA and vote for fix here
* https://questions.satisfactorygame.com/post/66ebebad772a987f4a8b9ef8
*/
state.numplayers = queryResponse.serverGameState.numConnectedPlayers
state.maxplayers = queryResponse.serverGameState.playerLimit
state.raw.http = queryResponse
}
async queryInfo (json, headers) {
const url = `https://${this.options.host}:${this.options.port}/api/v1/`
this.logger.debug(`POST: ${url}`)
const response = await this.request({
url,
json,
headers,
method: 'POST',
responseType: 'json',
https: {
minVersion: 'TLSv1.2',
rejectUnauthorized: this.options.rejectUnauthorized
}
})
if (response.data == null) {
throw new Error('Unable to retrieve data from server')
} else {
return response
}
}
}