diff options
author | 0neGal <mail@0negal.com> | 2022-10-23 03:26:54 +0200 |
---|---|---|
committer | 0neGal <mail@0negal.com> | 2022-10-23 03:29:23 +0200 |
commit | 0862c82996f11822fa851eeebc247d12f88dcd7d (patch) | |
tree | 2084b900a35eeccce2d0a027df3b49dc8d1e29d1 /src/utils.js | |
parent | efb5761268d1ced56cc633347a5143343aa957c6 (diff) | |
parent | 096c54e746def93eb6ee1b2a8d91e1e62555d610 (diff) | |
download | Viper-0862c82996f11822fa851eeebc247d12f88dcd7d.tar.gz Viper-0862c82996f11822fa851eeebc247d12f88dcd7d.zip |
Merge branch 'main' into linux-launch
Diffstat (limited to 'src/utils.js')
-rw-r--r-- | src/utils.js | 438 |
1 files changed, 291 insertions, 147 deletions
diff --git a/src/utils.js b/src/utils.js index 2c1ed98..e6a3245 100644 --- a/src/utils.js +++ b/src/utils.js @@ -12,12 +12,14 @@ const find = require("./extras/find"); const requests = require("./extras/requests"); const unzip = require("unzipper"); -const run = require("child_process").spawn; +const repair = require("jsonrepair"); const exec = require("child_process").exec; const { https } = require("follow-redirects"); process.chdir(app.getPath("appData")); +var invalidsettings = false; + // Base settings var settings = { gamepath: "", @@ -27,6 +29,7 @@ var settings = { wineprefix: "", forcedlang: "en", autoupdate: true, + originkill: false, nsargs: "-multiple", zip: "/northstar.zip", winebin: "/usr/bin/wine64", @@ -39,9 +42,29 @@ var settings = { ] } +// Logs into the dev tools of the renderer +function winLog(msg) { + ipcMain.emit("win-log", msg, msg); +} + +// Sends an alert to the renderer +function winAlert(msg) { + ipcMain.emit("win-alert", msg, msg); +} + // Creates the settings file with the base settings if it doesn't exist. if (fs.existsSync("viper.json")) { - settings = {...settings, ...JSON.parse(fs.readFileSync("viper.json", "utf8"))}; + let conf = fs.readFileSync("viper.json", "utf8"); + let json = "{}"; + + // Validates viper.json + try { + json = JSON.parse(conf); + }catch (e) { + invalidsettings = true; + } + + settings = {...settings, ...json}; settings.zip = path.join(settings.gamepath + "/northstar.zip"); let args = path.join(settings.gamepath, "ns_startup_args.txt"); @@ -80,6 +103,47 @@ async function isGameRunning() { }); } +// checks if any origin processes are running +async function isOriginRunning() { + return new Promise(resolve => { + let procs = ["Origin.exe", "OriginClientService.exe"]; + let cmd = (() => { + switch (process.platform) { + case "linux": return "ps -A"; + case "win32": return "tasklist"; + } + })(); + + exec(cmd, (err, stdout) => { + procs.forEach(proc => { + if (stdout.includes(proc)) { + resolve(true); + return; + } + resolve(false); + }); + }); + }); +} + +// kill origin processes +async function killOrigin() { + return new Promise(resolve => { + let proc = "Origin.exe"; //I'm pretty sure we only have to kill this one + let cmd = (() => { + switch (process.platform) { + case "linux": return "killall " + proc; + case "win32": return "taskkill /IM " + proc + " /F"; + } + })(); + + exec(cmd, (err, stdout) => { + // just try and fail silently if we don't find it w/e + resolve(true); + }); + }); +} + // Handles auto updating Northstar. // // It uses isGameRunning() to ensure it doesn't run while the game is @@ -92,6 +156,7 @@ function handleNorthstarUpdating() { async function _checkForUpdates() { let localVersion = getNSVersion(); let distantVersion = await requests.getLatestNsVersion(); + if (distantVersion == false) { return; } console.log(lang("cli.autoupdates.checking")); // Checks if NS is outdated @@ -100,19 +165,19 @@ function handleNorthstarUpdating() { if (await isGameRunning()) { console.log(lang("cli.autoupdates.gamerunning")); new Notification({ - title: lang("gui.nsupdate.gaming.title"), + title: lang("gui.nsupdate.gaming.title"), body: lang("gui.nsupdate.gaming.body") }).show(); } else { console.log(lang("cli.autoupdates.updatingns")); - update(); + updateNorthstar(); } } else { - console.log(lang("cli.autoupdates.noupdate")) + console.log(lang("cli.autoupdates.noupdate")); } setTimeout( - _checkForUpdates, + _checkForUpdates, 15 * 60 * 1000 // interval in between each update check // by default 15 minutes. @@ -166,11 +231,11 @@ async function setpath(win, forcedialog) { return; } if (! fs.existsSync(path.join(res.filePaths[0], "Titanfall2.exe"))) { - ipcMain.emit("wrongpath"); + ipcMain.emit("wrong-path"); return; } - setGamepath(res.filePaths[0]) + setGamepath(res.filePaths[0]); cli.exit(); return; @@ -185,6 +250,8 @@ async function setpath(win, forcedialog) { // You can also pass a settings object to the function and it'll try and // merge it together with the already existing settings function saveSettings(obj = {}) { + if (invalidsettings) {return false} + settings = {...settings, ...obj}; if (fs.existsSync(settings.gamepath)) { @@ -197,17 +264,57 @@ function saveSettings(obj = {}) { // Returns the current Northstar version // If not installed it'll return "unknown" function getNSVersion() { - var versionFilePath = path.join(settings.gamepath, "ns_version.txt"); + // if NorthstarLauncher.exe doesn't exist, always return "unknown" + if (! fs.existsSync(path.join(settings.gamepath, "NorthstarLauncher.exe"))) { + return "unknown"; + } - if (fs.existsSync(versionFilePath)) { - return fs.readFileSync(versionFilePath, "utf8"); - } else { - if (gamepathExists()) { - fs.writeFileSync(versionFilePath, "unknown"); + // mods to check version of + var versionFiles = [ + "Northstar.Client", + "Northstar.Custom", + "Northstar.CustomServers" + ] + + var versions = []; + + + let add = (version) => { + versions.push(version) + } + + // checks version of mods + for (let i = 0; i < versionFiles.length; i++) { + var versionFile = path.join(settings.gamepath, "R2Northstar/mods/", versionFiles[i],"/mod.json"); + if (fs.existsSync(versionFile)) { + if (! fs.statSync(versionFile).isFile()) { + add("unknown"); + } + + try { + add("v" + JSON.parse(fs.readFileSync(versionFile, "utf8")).Version); + }catch(err) { + add("unknown"); + } + } else { + add("unknown"); } + } - return "unknown"; + if (versions.includes("unknown")) {return "unknown"} + + // verifies all mods have the same version number + let mismatch = false; + let baseVersion = versions[0]; + for (let i = 0; i < versions.length; i++) { + if (versions[i] != baseVersion) { + mismatch = true; + break + } } + + if (mismatch) {return "unknown"} + return baseVersion; } @@ -231,7 +338,7 @@ function restoreExcludedFiles() { for (let i = 0; i < settings.excludes.length; i++) { let exclude = path.join(settings.gamepath + "/" + settings.excludes[i]); if (fs.existsSync(exclude + ".excluded")) { - fs.renameSync(exclude + ".excluded", exclude) + fs.renameSync(exclude + ".excluded", exclude); } } } @@ -247,7 +354,7 @@ restoreExcludedFiles(); // As to handle not overwriting files we rename certain files to // <file>.excluded, then rename them back after the extraction. The // unzip module does not support excluding files directly. -async function update() { +async function updateNorthstar() { if (! gamepathExists()) {return} ipcMain.emit("ns-update-event", "cli.update.checking"); @@ -255,6 +362,11 @@ async function update() { var version = getNSVersion(); const latestAvailableVersion = await requests.getLatestNsVersion(); + console.log(latestAvailableVersion) + if (latestAvailableVersion == false) { + ipcMain.emit("ns-update-event", "cli.update.noInternet"); + return; + } // Makes sure it is not already the latest version if (version === latestAvailableVersion) { @@ -267,7 +379,7 @@ async function update() { } else { if (version != "unknown") { console.log(lang("cli.update.current"), version); - }; + }; console.log(lang("cli.update.downloading") + ":", latestAvailableVersion); ipcMain.emit("ns-update-event", "cli.update.downloading"); } @@ -276,7 +388,7 @@ async function update() { for (let i = 0; i < settings.excludes.length; i++) { let exclude = path.join(settings.gamepath + "/" + settings.excludes[i]); if (fs.existsSync(exclude)) { - fs.renameSync(exclude, exclude + ".excluded") + fs.renameSync(exclude, exclude + ".excluded"); } } @@ -295,19 +407,32 @@ async function update() { stream.on("finish", () => { stream.close(); + let extract = fs.createReadStream(settings.zip); + winLog(lang("gui.update.extracting")); ipcMain.emit("ns-update-event", "gui.update.extracting"); console.log(lang("cli.update.downloaddone")); // Extracts the zip, this is the part where we're actually // installing Northstar. - fs.createReadStream(settings.zip).pipe(unzip.Extract({path: settings.gamepath})) - .on("finish", () => { - fs.writeFileSync(path.join(settings.gamepath, "ns_version.txt"), latestAvailableVersion); + extract.pipe(unzip.Extract({path: settings.gamepath})) + + let max = received; + received = 0; + + extract.on("data", (chunk) => { + received += chunk.length; + let percent = Math.floor(received / max * 100); + ipcMain.emit("ns-update-event", lang("gui.update.extracting") + " " + percent + "%"); + }) + + extract.on("end", () => { + extract.close(); ipcMain.emit("getversion"); restoreExcludedFiles(); - ipcMain.emit("guigetmods"); + ipcMain.emit("gui-getmods"); + ipcMain.emit("get-version"); ipcMain.emit("ns-update-event", "cli.update.uptodate.short"); winLog(lang("gui.update.finished")); console.log(lang("cli.update.finished")); @@ -322,7 +447,7 @@ async function update() { // This uses electron updater to easily update and publish releases, it // simply fetches it from GitHub and updates if it's outdated, very // useful. Not much we have to do on our side. -function updatevp(autoinstall) { +function updateViper(autoinstall) { const { autoUpdater } = require("electron-updater"); if (! autoUpdater.isUpdaterActive()) { @@ -399,7 +524,7 @@ function launch(version) { if (process.platform != "win32") { run(winebin, [path.join(settings.gamepath + "/Titanfall2.exe")]) } else { - run(path.join(settings.gamepath + "/Titanfall2.exe")) + exec("Titanfall2.exe", {cwd: settings.gamepath}); } break; @@ -415,25 +540,14 @@ function launch(version) { run(winebin, [prefix.origin]) run(winebin, [path.join(settings.gamepath + "/NorthstarLauncher.exe")]) } else { - run(path.join(settings.gamepath + "/Titanfall2.exe"), ["-northstar"]) + exec("NorthstarLauncher.exe", {cwd: settings.gamepath}); } - break; } process.chdir(cwd); } -// Logs into the dev tools of the renderer -function winLog(msg) { - ipcMain.emit("winLog", msg, msg); -} - -// Sends an alert to the renderer -function winAlert(msg) { - ipcMain.emit("winAlert", msg, msg); -} - // Returns true/false depending on if the gamepath currently exists/is // mounted, used to avoid issues... function gamepathExists() { @@ -455,17 +569,17 @@ const mods = { let modpath = path.join(settings.gamepath, "R2Northstar/mods"); if (getNSVersion() == "unknown") { - winLog(lang("general.notinstalled")) - console.log("error: " + lang("general.notinstalled")) + winLog(lang("general.notinstalled")); + console.log("error: " + lang("general.notinstalled")); cli.exit(1); return false; } - let mods = []; + let enabled = []; let disabled = []; if (! fs.existsSync(modpath)) { - fs.mkdirSync(path.join(modpath, "disabled"), {recursive: true}) + fs.mkdirSync(path.join(modpath), {recursive: true}); return { enabled: [], disabled: [], @@ -473,53 +587,44 @@ const mods = { }; } - files = fs.readdirSync(modpath) + files = fs.readdirSync(modpath); files.forEach((file) => { if (fs.statSync(path.join(modpath, file)).isDirectory()) { - if (fs.existsSync(path.join(modpath, file, "mod.json"))) { - try { - mods.push({...require(path.join(modpath, file, "mod.json")), FolderName: file, Disabled: false}) - }catch(err) { - if (cli.hasArgs()) {console.log("error: " + lang("cli.mods.improperjson"), file)} - mods.push({Name: file, FolderName: file, Version: "unknown", Disabled: false}) - } + let modjson = path.join(modpath, file, "mod.json"); + if (fs.existsSync(modjson)) { + let mod = JSON.parse(repair(fs.readFileSync(modjson, "utf8"))); - let manifest = path.join(modpath, file, "manifest.json"); - if (fs.existsSync(manifest)) { - try {mods[mods.length - 1].ManifestName = require(manifest).name}catch(err){} - } - } - } - }) + let obj = { + Version: "unknown", + Name: "unknown", + FolderName: file, + ...mod} - let disabledPath = path.join(modpath, "disabled") - if (! fs.existsSync(disabledPath)) { - fs.mkdirSync(disabledPath) - } + obj.Disabled = ! mods.modfile().get(obj.Name); - files = fs.readdirSync(disabledPath) - files.forEach((file) => { - if (fs.statSync(path.join(disabledPath, file)).isDirectory()) { - if (fs.existsSync(path.join(disabledPath, file, "mod.json"))) { - try { - disabled.push({...require(path.join(disabledPath, file, "mod.json")), FolderName: file, Disabled: true}) - }catch(err) { - if (cli.hasArgs()) {console.log("error: " + lang("cli.mods.improperjson"), file)} - disabled.push({Name: file, FolderName: file, Version: "unknown", Disabled: true}) + let manifestfile = path.join(modpath, file, "manifest.json"); + if (fs.existsSync(manifestfile)) { + let manifest = JSON.parse(repair(fs.readFileSync(manifestfile, "utf8"))); + + obj.ManifestName = manifest.name; + if (obj.Version == "unknown") { + obj.Version = manifest.version_number; + } } - } - let manifest = path.join(modpath, file, "manifest.json"); - if (fs.existsSync(manifest)) { - try {mods[mods.length - 1].ManifestName = require(manifest).name}catch(err){} + if (obj.Disabled) { + disabled.push(obj); + } else { + enabled.push(obj); + } } } }) return { - enabled: mods, + enabled: enabled, disabled: disabled, - all: [...mods, ...disabled] + all: [...enabled, ...disabled] }; }, @@ -533,8 +638,8 @@ const mods = { let modpath = path.join(settings.gamepath, "R2Northstar/mods"); if (getNSVersion() == "unknown") { - winLog(lang("general.notinstalled")) - console.log("error: " + lang("general.notinstalled")) + winLog(lang("general.notinstalled")); + console.log("error: " + lang("general.notinstalled")); cli.exit(1); return false; } @@ -550,6 +655,67 @@ const mods = { return false; }, + // Manages the enabledmods.json file + // + // It can both return info about the file, but also toggle mods in + // it, generate the file itself, and so on. + modfile: () => { + let modpath = path.join(settings.gamepath, "R2Northstar/mods"); + let file = path.join(modpath, "..", "enabledmods.json"); + + if (! fs.existsSync(modpath)) { + fs.mkdirSync(path.join(modpath), {recursive: true}); + } + + if (! fs.existsSync(file)) { + fs.writeFileSync(file, "{}"); + } + + return { + gen: () => { + let names = {}; + let list = mods.list().all; + for (let i = 0; i < list.length; i++) { + names[list[i].Name] = true + } + + fs.writeFileSync(file, JSON.stringify(names)); + }, + disable: (mod) => { + let data = JSON.parse(repair(fs.readFileSync(file, "utf8"))); + data[mod] = false; + fs.writeFileSync(file, JSON.stringify(data)); + }, + enable: (mod) => { + let data = JSON.parse(repair(fs.readFileSync(file, "utf8"))); + data[mod] = true; + fs.writeFileSync(file, JSON.stringify(data)); + }, + toggle: (mod) => { + let data = JSON.parse(repair(fs.readFileSync(file, "utf8"))); + if (data[mod] != undefined) { + data[mod] = ! data[mod]; + } else { + data[mod] = false; + } + + fs.writeFileSync(file, JSON.stringify(data)); + }, + get: (mod) => { + let data = JSON.parse(repair(fs.readFileSync(file, "utf8"))); + let names = Object.keys(data); + + if (data[mod]) { + return true; + } else if (data[mod] === false) { + return false; + } else { + return true; + } + } + }; + }, + // Installs mods from a file path // // Either a zip or folder is supported, we'll also try to search @@ -559,15 +725,15 @@ const mods = { let modname = mod.replace(/^.*(\\|\/|\:)/, ""); if (getNSVersion() == "unknown") { - winLog(lang("general.notinstalled")) - console.log("error: " + lang("general.notinstalled")) + winLog(lang("general.notinstalled")); + console.log("error: " + lang("general.notinstalled")); cli.exit(1); return false; } let notamod = () => { - winLog(lang("gui.mods.notamod")) - console.log("error: " + lang("cli.mods.notamod")) + winLog(lang("gui.mods.notamod")); + console.log("error: " + lang("cli.mods.notamod")); cli.exit(1); return false; } @@ -576,30 +742,30 @@ const mods = { console.log(lang("cli.mods.installed")); cli.exit(); - winLog(lang("gui.mods.installedmod")) + winLog(lang("gui.mods.installedmod")); if (modname == "mods") { - let manifest = path.join(app.getPath("userData"), "Archives/manifest.json") + let manifest = path.join(app.getPath("userData"), "Archives/manifest.json"); if (fs.existsSync(manifest)) { modname = require(manifest).name; } } - ipcMain.emit("installedmod", "", { + ipcMain.emit("installed-mod", "", { name: modname, malformed: malformed, }); - ipcMain.emit("guigetmods"); + ipcMain.emit("gui-getmods"); return true; } if (! fs.existsSync(mod)) {return notamod()} if (fs.statSync(mod).isDirectory()) { - winLog(lang("gui.mods.installing")) + winLog(lang("gui.mods.installing")); files = fs.readdirSync(mod); - if (fs.existsSync(path.join(mod, "mod.json")) && + if (fs.existsSync(path.join(mod, "mod.json")) && fs.statSync(path.join(mod, "mod.json")).isFile()) { if (fs.existsSync(path.join(modpath, modname))) { @@ -607,8 +773,8 @@ const mods = { } let copydest = path.join(modpath, modname); if (typeof destname == "string") {copydest = path.join(modpath, destname)} - copy(mod, copydest) - copy(manifestfile, path.join(copydest, "manifest.json")) + copy(mod, copydest); + copy(manifestfile, path.join(copydest, "manifest.json")); return installed(); } else { @@ -619,7 +785,7 @@ const mods = { if (fs.existsSync(path.join(mod, files[i], "mod.json")) && fs.statSync(path.join(mod, files[i], "mod.json")).isFile()) { - mods.install(path.join(mod, files[i])) + mods.install(path.join(mod, files[i])); if (mods.install(path.join(mod, files[i]))) {return true}; } } @@ -630,7 +796,7 @@ const mods = { return notamod(); } else { - winLog(lang("gui.mods.extracting")) + winLog(lang("gui.mods.extracting")); let cache = path.join(app.getPath("userData"), "Archives"); if (fs.existsSync(cache)) { fs.rmSync(cache, {recursive: true}); @@ -662,7 +828,7 @@ const mods = { } if (files.length == 0) { - ipcMain.emit("failedmod"); + ipcMain.emit("failed-mod"); return notamod(); } } @@ -693,26 +859,18 @@ const mods = { if (fs.existsSync(tmp)) { if (! fs.statSync(tmp).isDirectory()) { - fs.rmSync(tmp) + fs.rmSync(tmp); } } else { - fs.mkdirSync(tmp) + fs.mkdirSync(tmp); if (fs.existsSync(modlocation)) { - fs.rmSync(modlocation) + fs.rmSync(modlocation); } } let stream = fs.createWriteStream(modlocation); res.pipe(stream); - // let received = 0; - // // Progress messages, we should probably switch this to - // // percentage instead of how much is downloaded. - // res.on("data", (chunk) => { - // received += chunk.length; - // ipcMain.emit("ns-update-event", lang("gui.update.downloading") + " " + (received / 1024 / 1024).toFixed(1) + "mb"); - // }) - stream.on("finish", () => { stream.close(); mods.install(modlocation); @@ -728,8 +886,8 @@ const mods = { let modpath = path.join(settings.gamepath, "R2Northstar/mods"); if (getNSVersion() == "unknown") { - winLog(lang("general.notinstalled")) - console.log("error: " + lang("general.notinstalled")) + winLog(lang("general.notinstalled")); + console.log("error: " + lang("general.notinstalled")); cli.exit(1); return false; } @@ -737,19 +895,19 @@ const mods = { if (mod == "allmods") { let modlist = mods.list().all; for (let i = 0; i < modlist.length; i++) { - mods.remove(modlist[i].Name) + mods.remove(modlist[i].Name); } return } let disabled = path.join(modpath, "disabled"); if (! fs.existsSync(disabled)) { - fs.mkdirSync(disabled) + fs.mkdirSync(disabled); } let modName = mods.get(mod).FolderName; if (! modName) { - console.log("error: " + lang("cli.mods.cantfind")) + console.log("error: " + lang("cli.mods.cantfind")); cli.exit(1); return; } @@ -769,8 +927,8 @@ const mods = { fs.rmSync(modPath, {recursive: true}); console.log(lang("cli.mods.removed")); cli.exit(); - ipcMain.emit("guigetmods"); - ipcMain.emit("removedmod", "", { + ipcMain.emit("gui-getmods"); + ipcMain.emit("removed-mod", "", { name: mod.replace(/^.*(\\|\/|\:)/, ""), manifestname: manifestname }); @@ -786,11 +944,9 @@ const mods = { // you checked for if a mod is already disable and if not run the // function. However we currently have no need for that. toggle: (mod, fork) => { - let modpath = path.join(settings.gamepath, "R2Northstar/mods"); - if (getNSVersion() == "unknown") { - winLog(lang("general.notinstalled")) - console.log("error: " + lang("general.notinstalled")) + winLog(lang("general.notinstalled")); + console.log("error: " + lang("general.notinstalled")); cli.exit(1); return false; } @@ -798,7 +954,7 @@ const mods = { if (mod == "allmods") { let modlist = mods.list().all; for (let i = 0; i < modlist.length; i++) { - mods.toggle(modlist[i].Name, true) + mods.toggle(modlist[i].Name, true); } console.log(lang("cli.mods.toggledall")); @@ -806,42 +962,22 @@ const mods = { return } - let disabled = path.join(modpath, "disabled"); - if (! fs.existsSync(disabled)) { - fs.mkdirSync(disabled) - } - - let modName = mods.get(mod).FolderName; - if (! modName) { - console.log("error: " + lang("cli.mods.cantfind")) - cli.exit(1); - return; - } - - let modPath = path.join(modpath, modName); - let dest = path.join(disabled, modName); - - if (mods.get(mod).Disabled) { - modPath = path.join(disabled, modName); - dest = path.join(modpath, modName); - } - - fs.moveSync(modPath, dest) + mods.modfile().toggle(mod); if (! fork) { console.log(lang("cli.mods.toggled")); cli.exit(); } - ipcMain.emit("guigetmods"); + ipcMain.emit("gui-getmods"); } }; setInterval(async () => { if (gamepathExists()) { - ipcMain.emit("guigetmods"); + ipcMain.emit("gui-getmods"); } else { if (fs.existsSync("viper.json")) { if (settings.gamepath != "") { - ipcMain.emit("gamepathlost"); + ipcMain.emit("gamepath-lost"); } } } @@ -855,19 +991,27 @@ setInterval(async () => { module.exports = { mods, - lang, winLog, - launch, - update, - setpath, - updatevp, - settings, - saveSettings, + + updateViper, getNSVersion, getTF2Version, + updateNorthstar, + handleNorthstarUpdating, + + launch, + killOrigin, isGameRunning, + isOriginRunning, + + + settings, + saveSettings, + + setpath, gamepathExists, - handleNorthstarUpdating, + + lang, setlang: (lang) => { settings.lang = lang; saveSettings(); |