Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Linux launch support #116

Closed
wants to merge 12 commits into from
Binary file added src/app/icons/linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions src/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,32 @@ <h2>%%gui.settings.title.ns%%</h2>
<input>
</div>
</div>
<div class="title">
<img src="icons/linux.png">
<h2>%%gui.settings.title.linux%%</h2>
</div>
<div class="option linuxopt" name="wineprefix">
<div class="text">
%%gui.settings.wineprefix.title%%
<div class="desc">
%%gui.settings.wineprefix.desc%%
</div>
</div>
<div class="actions">
<input>
</div>
</div>
<div class="option linuxopt" name="winebin">
<div class="text">
%%gui.settings.winebin.title%%
<div class="desc">
%%gui.settings.winebin.desc%%
</div>
</div>
<div class="actions">
<input>
</div>
</div>
<div class="title">
<img src="icons/language.png">
<h2>%%gui.settings.title.language%%</h2>
Expand Down
7 changes: 7 additions & 0 deletions src/app/js/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@ var Settings = {
}
}

if (process.platform == "win32") {
let linuxopts = document.querySelectorAll(".options .linuxopt");
for (let i = 0; i < linuxopts.length; i++) {
linuxopts[i].style.display = "none";
}
}

ipcRenderer.send("can-autoupdate");
ipcRenderer.on("cant-autoupdate", () => {
document.querySelector(".option[name=autoupdate]").style.display = "none";
Expand Down
15 changes: 15 additions & 0 deletions src/app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ let shouldInstallNorthstar = false;
var settings = {
nsargs: "",
gamepath: "",
wineprefix: "",
nsupdate: true,
autolang: true,
forcedlang: "en",
autoupdate: true,
originkill: false,
zip: "/northstar.zip",
lang: navigator.language,
winebin: "/usr/bin/wine64",
excludes: [
"ns_startup_args.txt",
"ns_startup_args_dedi.txt"
Expand Down Expand Up @@ -112,6 +114,19 @@ function setButtons(state) {
disablearray(document.querySelectorAll("#browser #browserEntries .text button"));
}

ipcRenderer.on("gamestate", (event, state) => {
setButtons(! state);

let string = lang("gui.launch");
if (state) {
string = lang("gui.running");
}

let btns = document.querySelectorAll(".playBtnContainer .playBtn");
btns[0].innerHTML = string;
btns[1].innerHTML = string;
})

ipcRenderer.on("set-buttons", (event, state) => {
setButtons(state);
})
Expand Down
4 changes: 4 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ function start() {
process.exit(0)
}
});

ipcMain.on("gamestarted", (event) => {win.webContents.send("gamestate", true)});
ipcMain.on("gamestopped", (event) => {win.webContents.send("gamestate", false)});

ipcMain.on("minimize", () => {win.minimize()});
ipcMain.on("relaunch", () => {app.relaunch(); app.exit()});

Expand Down
10 changes: 10 additions & 0 deletions src/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,17 @@

"gui.settings.save": "Save",
"gui.settings.discard": "Discard",
"gui.settings.title.linux": "Linux",
"gui.settings.title.ns": "Northstar",
"gui.settings.title.language": "Language",
"gui.settings.title.updates": "Updates",
"gui.settings.title.misc": "Miscellaneous",
"gui.settings.nsargs.title": "Launch options",
"gui.settings.nsargs.desc": "Here you can add launch options for Northstar/Titanfall.",
"gui.settings.wineprefix.title": "Wine Prefix",
"gui.settings.wineprefix.desc": "The prefix which Wine/Proton will use, if left empty, it'll try to find your Steam prefix automatically.",
"gui.settings.winebin.title": "Wine Executable",
"gui.settings.winebin.desc": "The version of Wine/Proton to use to run the game, if set to \"/usr/bin/wine64\", Viper will try to find the latest installed version of Proton automatically, if it can't find anything it'll fallback to wine64",
"gui.settings.autolang.title": "Auto-Detect Language",
"gui.settings.autolang.desc": "When enabled, Viper tries to automatically detect your system language, when disabled you can manually change the language below.",
"gui.settings.forcedlang.title": "Language",
Expand Down Expand Up @@ -121,6 +126,7 @@
"gui.server.offline": "Masterserver is Offline",

"gui.launch": "Launch",
"gui.running": "Running",
"gui.launchvanilla": "Vanilla",
"gui.launchnorthstar": "Northstar",
"gui.installnorthstar": "Install",
Expand All @@ -141,6 +147,10 @@
"gui.toast.desc.duped": "has multiple mod folders in it, with the same name, causing duplicate folders, if you're the developer, you should fix this.",
"gui.toast.desc.unknown_error": "An unknown error occurred, click for more details. You may want to take a screenshot of the detailed error when filing a bug report.",

"wine.invalidprefix": "The selected Wine prefix doesn't exist, and is therefore invalid.",
"wine.originnotfound": "Origin can't be found in the selected Wine prefix.",
"wine.cantfindprefix": "Viper was unable to automatically find and set your Wine prefix.",

"gui.toast.noInternet.title": "No Internet",
"gui.toast.noInternet.desc": "Viper may not work properly.",

Expand Down
14 changes: 13 additions & 1 deletion src/lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
"gui.settings.save": "Guardar",
"gui.settings.discard": "Descartar",
"gui.settings.title.ns": "Northstar",
"gui.settings.title.linux": "Linux",
"gui.settings.title.updates": "Actualizaciones",
"gui.settings.title.misc": "Misceláneos",
"gui.settings.nsargs.title": "Opciones de lanzamiento",
Expand All @@ -105,6 +106,10 @@
"gui.settings.autolang.desc": "Cuando está habilitado, Viper intenta detectar automáticamente el idioma de su sistema, cuando está deshabilitado, puede cambiar manualmente el idioma a continuación.",
"gui.settings.forcedlang.title": "Idioma",
"gui.settings.forcedlang.desc": "Cuando \"Detectar automáticamente el idioma\" está deshabilitado, ésta opción decidirá el lenguaje. Se necesita reiniciar para que surja efecto.",
"gui.settings.wineprefix.title": "Prefijo de Wine",
"gui.settings.wineprefix.desc": "El prefijo el cual usará Wine/Proton. Si se deja vacío, se tratará de encontrar su prefijo de Steam automáticamente.",
"gui.settings.winebin.title": "Ejecutable de Wine ",
"gui.settings.winebin.desc": "La versión de Wine/Proton que se usará para ejecutar el juego. Si se elige \"/usr/bin/wine64\", Viper tratará de encontrar la ultima versión instalada de Proton automáticamente, si no se encuentra, se usará wine64",

"gui.update.downloading": "Descargando...",
"gui.update.extracting": "Extrayendo actualización...",
Expand Down Expand Up @@ -136,6 +141,7 @@
"gui.toast.desc.duped": "¡Nombres de las carpetas duplicados!",
"gui.toast.desc.unknown_error": "Ha ocurrido un error desconocido, presiona para más detalles. Recomendamos que tomes una captura de pantalla del error con sus detalles cuando reportes un error.",

"gui.running": "Ejecutándose",
"gui.server.player": "jugador",
"gui.server.players": "jugadores",
"gui.server.servers": "servidores",
Expand All @@ -160,8 +166,14 @@
"general.mods.enabled": "Modificaciones habilitadas:",
"general.mods.disabled": "Modificaciones deshabilitadas:",
"general.mods.installed": "Modificiaciones intaladas:",
"general.missingpath": "¡La ruta del jueno no se ha podido encontrar automaticamente! ¡Por favor, elige la ruta manualmente!",
"general.missingpath": "¡La ruta del jueno no se ha podido encontrar automáticamente! ¡Por favor, elige la ruta manualmente!",
"general.notinstalled": "¡Northstar no se ha instalado!",
"general.launching": "Ejecutando",

"wine.invalidprefix": "El prefijo seleccionado de Wine no existe, y por ende es inválido.",
"wine.originnotfound": "Origin no pudo ser encontrado en el prefijo de Wine seleccionado.",
"wine.cantfindprefix": "Viper no logró encontrar y establecer automáticamente el prefijo de Wine",

"general.launching": "Ejecutando",
"general.invalidconfig": "Su archivo de configuración está formateado de forma incorrecta, si ha sido editado manualmente, por favor valide que ha sido escrito correctamente. \n\nSi no ha editado manualmente el archivo de configuración, es recomendado que simplemente restaure la configuración. \n\nPara restaurar tu configuración simplemente de click en \"OK\" a continuación. \n\nMas detalles:\n",

Expand Down
10 changes: 10 additions & 0 deletions src/lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,16 @@
"gui.settings.save": "Sauvegarder",
"gui.settings.discard": "Annuler",
"gui.settings.title.ns": "Northstar",
"gui.settings.title.linux": "Linux",
"gui.settings.title.language": "Langue",
"gui.settings.title.updates": "Mises à jour",
"gui.settings.title.misc": "Divers",
"gui.settings.nsargs.title": "Options de lancement",
"gui.settings.nsargs.desc": "Vous pouvez ajouter ici des options de démarrage pour Northstar/Titanfall.",
"gui.settings.wineprefix.title": "Préfixe Wine",
"gui.settings.wineprefix.desc": "Le préfixe utilisé par Wine/Proton ; si laissé vide, il essaiera de trouver automatiquement votre préfixe Steam.",
"gui.settings.winebin.title": "Exécutable Wine",
"gui.settings.winebin.desc": "La version de Wine/Proton à utiliser pour lancer le jeu, s'il vaut \"/usr/bin/wine64\", Viper essaiera de déterminer automatiquement la dernière version installée de Proton (et utilisera wine64 s'il ne trouve rien).",
"gui.settings.autolang.title": "Auto-détection de la langue",
"gui.settings.autolang.desc": "Lorsque activée, Viper essaie de déterminer automatiquement la langue de votre système ; désactiver cette option vous permet de sélectionner manuellement la langue utilisée.",
"gui.settings.forcedlang.title": "Langue",
Expand Down Expand Up @@ -121,6 +126,7 @@
"gui.server.offline": "Le serveur maître est hors-ligne",

"gui.launch": "Jouer",
"gui.running": "En cours d'exécution",
"gui.launchvanilla": "Vanilla",
"gui.launchnorthstar": "Northstar",
"gui.installnorthstar": "Installer",
Expand All @@ -141,6 +147,10 @@
"gui.toast.desc.duped": "contient plusieurs dossiers ayant le même nom ; si vous êtes le développer, vous devriez réparer ceci.",
"gui.toast.desc.unknown_error": "Une erreur inconnue est survenue, cliquez pour plus de détails. Vous devriez prendre une capture d'écran de l'erreur si vous comptez créer un ticket.",

"wine.invalidprefix": "Le préfixe Wine sélectionné n'existe pas, et n'est donc pas valide.",
"wine.originnotfound": "Origin ne peut être trouvé dans le préfixe Wine sélectionné.",
"wine.cantfindprefix": "Viper n'a pas pu trouver et configurer votre préfixe Wine.",

"gui.toast.noInternet.title": "Pas de connexion Internet",
"gui.toast.noInternet.desc": "Viper ne fonctionnera pas correctement tant que la connexion n'est pas rétablie.",

Expand Down
153 changes: 153 additions & 0 deletions src/modules/find.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
const fs = require("fs");
const path = require("path");
const vdf = require("simple-vdf");
const { app } = require("electron");

const util = require("util");
const exec = util.promisify(require("child_process").exec);

let libraries = [];
let home = app.getPath("home");

let symdir = ".steam/steam";
let localdir = ".local/share/Steam";
let flatpakdir = ".var/app/com.valvesoftware.Steam/";

module.exports = {
prefix: () => {
if (process.platform == "win32") {return false}
let compatdir = "/steamapps/compatdata/1237970/pfx";
let folders = [
path.join(home, symdir, compatdir),
path.join(home, localdir, compatdir),
path.join(home, flatpakdir, symdir, compatdir),
path.join(home, flatpakdir, localdir, compatdir),
]

for (let i = 0; i < folders.length; i++) {
let origin = path.join(folders[i], "drive_c/Program Files (x86)/Origin/Origin.exe");
if (fs.existsSync(folders[i])) {
if (fs.existsSync(origin)) {
return {
origin: origin,
path: folders[i],
}

}
}
}

return false;
},
proton: () => {
module.exports.game(true);

let proton = "0.0";
let protonpath = false;

for (let i = 0; i < libraries.length; i++) {
if (! fs.existsSync(libraries[i])
|| fs.statSync(libraries[i]).isDirectory()) {

continue;
}

let files = fs.readdirSync(libraries[i]);
for (let ii = 0; ii < files.length; ii++) {
if (files[ii].match(/^Proton [0-9]+\.[0-9]+/)) {
if (fs.existsSync(path.join(libraries[i], files[ii], "/dist/bin/wine64"))) {
let version = files[ii].replace(/^Proton /, "");
if (version > proton) {
proton = version;
protonpath = path.join(libraries[i], files[ii], "/dist/bin/wine64");
}
}
}
}
}

return protonpath;
},
game: async (quiet) => {
let gamepath = "";

// Autodetect path
// Windows only using powershell and windows registery
// Get-Item -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Respawn\Titanfall2\
if (process.platform == "win32") {
try {
const {stdout} = await exec("Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\Respawn\\Titanfall2\\ -Name \"Install Dir\"", {"shell":"powershell.exe"});

const gamepath = stdout.split('\n')
.filter(r => r.indexOf("Install Dir") !== -1)[0]
.replace(/\s+/g,' ')
.trim()
.replace("Install Dir : ","");

if (gamepath) {return gamepath}
} catch (err) {}
}

// Detect using Steam VDF
function readvdf(data) {
// Parse read_data
data = vdf.parse(data);

let values = Object.values(data["libraryfolders"]);
if (typeof values[values.length - 1] != "object") {
values.pop(1);
}

libraries = [];

// `.length - 1` This is because the last value is `contentstatsid`
for (let i = 0; i < values.length; i++) {
libraries.push(values[i].path + "/steamapps/common");

let data_array = Object.values(values[i])

if (fs.existsSync(data_array[0] + "/steamapps/common/Titanfall2/Titanfall2.exe")) {
if (! quiet ) {console.log("Found game in:", data_array[0])}
return data_array[0] + "/steamapps/common/Titanfall2";
} else {
if (! quiet ) {console.log("Game not in:", data_array[0])}
}
}
}

let folders = [];
switch (process.platform) {
case "win32":
folders = ["C:\\Program Files (x86)\\Steam\\steamapps\\libraryfolders.vdf"];
break
case "linux":
case "openbsd":
case "freebsd":
let vdfdir = "/steamapps/libraryfolders.vdf";
folders = [
path.join(home, symdir, vdfdir),
path.join(home, localdir, vdfdir),
path.join(home, flatpakdir, symdir, vdfdir),
path.join(home, flatpakdir, localdir, vdfdir)
]
break
}

if (folders.length > 0) {
for (let i = 0; i < folders.length; i++) {
if (! fs.existsSync(folders[i])) {continue}
if (! quiet ) {console.log("Searching VDF file at:", folders[i])}

let data = fs.readFileSync(folders[i])
let read_vdf = readvdf(data.toString())
if (read_vdf) {return read_vdf}
}
}

if (gamepath) {
return gamepath;
} else {
return false;
}
}
}
Loading