diff --git a/CHANGELOG.md b/CHANGELOG.md index 721af3c..c84ab69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 5.X.Y * Feat: Replaced `punycode` package usage with `url.domainToASCII` (#630). * Feat: World of Padman (2007) - Added support (#636) +* Feat: Satisfactory - Added support (By @Smidy13 #645) * Feat: Update Soldat protocol (#642) * Feat: TOXIKK (2016) - Added support (#641) diff --git a/GAMES_LIST.md b/GAMES_LIST.md index ee78fb0..c9ec156 100644 --- a/GAMES_LIST.md +++ b/GAMES_LIST.md @@ -257,6 +257,7 @@ | rune | Rune | | | rust | Rust | [Valve Protocol](#valve) | | s2ats | Savage 2: A Tortured Soul | | +| satisfactory | Satisfactory | [Notes](#satisfactory) | | sdtd | 7 Days to Die | [Valve Protocol](#valve) | | serioussam | Serious Sam | | | serioussam2 | Serious Sam 2 | | @@ -492,5 +493,9 @@ EOS does not provide players data. Palworld support can be unstable, the devs mention the api is currently experimental. To query Palworld servers, the `RESTAPIEnabled` setting must be `True` in the configuration file, and you need to pass the `username` (currently always `admin`) and the `adminpassword` (from the server config) as the `password` parameter. +### Satisfactory +Satisfactory servers unless specified use self-signed certificates for the HTTPS API. If you are using a self-signed certificate you will need to set the `rejectUnauthorized` flag in options to `false` in order to connect. +For more information on setting a user certificate refer to the [Satisfactory Dedicated server/HTTPS API wiki documentation](https://satisfactory.wiki.gg/wiki/Dedicated_servers/HTTPS_API). + ### Soldat Requires `Allow_Download` and `Logging` to be `1` in the server config. diff --git a/lib/games.js b/lib/games.js index ddfe220..d45c4be 100644 --- a/lib/games.js +++ b/lib/games.js @@ -2546,6 +2546,17 @@ export const games = { old_id: '7d2d' } }, + satisfactory: { + name: 'Satisfactory', + release_year: 2019, + options: { + port: 7777, + protocol: 'satisfactory' + }, + extra: { + doc_notes: 'satisfactory' + } + }, spaceengineers: { name: 'Space Engineers', release_year: 2019, diff --git a/protocols/index.js b/protocols/index.js index cd54f12..d1ccd4b 100644 --- a/protocols/index.js +++ b/protocols/index.js @@ -39,7 +39,9 @@ import quake2 from './quake2.js' import quake3 from './quake3.js' import rfactor from './rfactor.js' import samp from './samp.js' +import satisfactory from './satisfactory.js' import savage2 from './savage2.js' +import soldat from './soldat.js' import starmade from './starmade.js' import starsiege from './starsiege.js' import teamspeak2 from './teamspeak2.js' @@ -63,13 +65,11 @@ import xonotic from './xonotic.js' import altvmp from './altvmp.js' import vintagestorymaster from './vintagestorymaster.js' import vintagestory from './vintagestory.js' -import soldat from './soldat.js' export { armagetron, ase, asa, assettocorsa, battlefield, buildandshoot, cs2d, discord, doom3, eco, epic, factorio, farmingsimulator, ffow, fivem, gamespy1, gamespy2, gamespy3, geneshift, goldsrc, gtasao, hexen2, jc2mp, kspdmp, mafia2mp, mafia2online, minecraft, minecraftbedrock, minecraftvanilla, minetest, mumble, mumbleping, nadeo, openttd, palworld, quake1, quake2, quake3, rfactor, ragemp, samp, - savage2, starmade, starsiege, teamspeak2, teamspeak3, terraria, toxikk, tribes1, tribes1master, unreal2, ut3, valve, - vcmp, ventrilo, warsow, eldewrito, beammpmaster, beammp, dayz, theisleevrima, xonotic, altvmp, vintagestorymaster, - vintagestory, soldat + satisfactory, soldat, savage2, starmade, starsiege, teamspeak2, teamspeak3, terraria, toxikk, tribes1, tribes1master, unreal2, ut3, valve, + vcmp, ventrilo, warsow, eldewrito, beammpmaster, beammp, dayz, theisleevrima, xonotic, altvmp, vintagestorymaster, vintagestory } diff --git a/protocols/satisfactory.js b/protocols/satisfactory.js new file mode 100644 index 0000000..56beace --- /dev/null +++ b/protocols/satisfactory.js @@ -0,0 +1,82 @@ +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) { + + /** + * 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' + } + + let 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 + + let tokenRequestResponse = await this.queryInfo(tokenRequestJson, headers) + + headers.Authorization = `Bearer ${tokenRequestResponse.data.authenticationToken}` + + let queryResponse = await this.queryInfo(queryJson, headers) + + /** + * 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.data.serverGameState.numConnectedPlayers + state.maxplayers = queryResponse.data.serverGameState.playerLimit + state.raw = 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 + } + } +}