From e8c721dc9372a74bdd9990870dd24b9273793ff2 Mon Sep 17 00:00:00 2001 From: Observer KRypt0n_ Date: Sun, 26 Dec 2021 23:38:04 +0200 Subject: [PATCH] API improvements - added `Runners.getWinetricks()` method to get the `winetricks.sh` script - added `Runners.createPrefix()` to create wine prefix using the currently selected wine version - added game installation and updating action scripts - added `Process.addSlashes()` method to easily isolate some strings --- neutralino.config.json | 2 +- src/ts/Launcher.ts | 6 +- src/ts/core/Runners.ts | 93 +++++++++++++++++++++++++++++++ src/ts/launcher/State.ts | 5 +- src/ts/launcher/states/Install.ts | 39 +++++++++++++ src/ts/neutralino/Process.ts | 18 ++++-- 6 files changed, 151 insertions(+), 12 deletions(-) create mode 100644 src/ts/launcher/states/Install.ts diff --git a/neutralino.config.json b/neutralino.config.json index 5284b6d..d630b22 100644 --- a/neutralino.config.json +++ b/neutralino.config.json @@ -22,7 +22,7 @@ "fullScreen": false, "alwaysOnTop": false, "icon": "/public/icons/64x64.png", - "enableInspector": false, + "enableInspector": true, "borderless": false, "maximize": false, "hidden": true, diff --git a/src/ts/Launcher.ts b/src/ts/Launcher.ts index 8246cea..855f8c4 100644 --- a/src/ts/Launcher.ts +++ b/src/ts/Launcher.ts @@ -7,8 +7,6 @@ import Configs from './Configs'; import ProgressBar from './launcher/ProgressBar'; import State from './launcher/State'; -declare const Neutralino; - export default class Launcher { public state?: State; @@ -51,7 +49,7 @@ export default class Launcher public showSettings(): Promise { return new Promise(async (resolve) => { - if (this.settingsMenu && await this.settingsMenu.running()) + if (this.settingsMenu) resolve(false); else @@ -67,7 +65,7 @@ export default class Launcher if (window.status) { - this.settingsMenu = new Process(window.data!.pid, 500); + this.settingsMenu = new Process(window.data!.pid, null); /*this.settingsMenu.finish(() => { Window.current.show(); diff --git a/src/ts/core/Runners.ts b/src/ts/core/Runners.ts index 554e058..4a99e35 100644 --- a/src/ts/core/Runners.ts +++ b/src/ts/core/Runners.ts @@ -6,6 +6,8 @@ import type { import constants from '../Constants'; import Configs from '../Configs'; import AbstractInstaller from './AbstractInstaller'; +import Downloader from './Downloader'; +import Process from '../neutralino/Process'; declare const Neutralino; @@ -119,6 +121,97 @@ class Runners else resolve(new Stream(runner)); }); } + + /** + * Get path to the winetricks.sh file + * + * If this file is not downloaded - then this method will download it + * and return the path after it + */ + public static getWinetricks(): Promise + { + return new Promise(async (resolve) => { + const winetricksPath = `${await constants.paths.launcherDir}/winetricks.sh`; + + Neutralino.filesystem.getStats(winetricksPath) + .then(() => resolve(winetricksPath)) + .catch(() => { + Downloader.download(constants.uri.winetricks, winetricksPath).then((stream) => { + stream.finish(() => resolve(winetricksPath)); + }); + }); + }); + } + + /** + * Create wine prefix using the current selected wine + * + * @param path folder to create prefix in + * @param progress function that will be called with every creation step + * + * @returns false if there's no selected wine version. Otherwise true + */ + public static createPrefix(path: string, progress?: (output: string, current: number, total: number) => void): Promise + { + const installationSteps = [ + // corefonts + 'Executing w_do_call corefonts', + 'Executing load_corefonts', + 'Executing load_andale', + 'Executing load_arial', + 'Executing load_comicsans', + 'Executing load_courier', + 'Executing load_georgia', + 'Executing load_impact', + 'Executing load_times', + 'Executing load_trebuchet', + 'Executing load_verdana', + 'Executing load_webdings', + + // usetakefocus=n (fullscreen input issues fix) + 'Executing load_usetakefocus n' + ]; + + return new Promise((resolve) => { + this.current.then((runner) => { + if (runner === null) + resolve(false); + + else + { + this.getWinetricks().then(async (winetricks) => { + // let installationProgress = 0; + + const process = await Process.run(`bash '${Process.addSlashes(winetricks)}' corefonts usetakefocus=n`, { + env: { + WINE: `${await constants.paths.runnersDir}/${runner.name}/${runner.files.wine}`, + WINESERVER: `${await constants.paths.runnersDir}/${runner.name}/${runner.files.wineserver}`, + WINEPREFIX: path + } + }); + + // todo: add process output reading + + process.finish(() => resolve(true)); + + /*installerProcess.stdout.on('data', (data: string) => { + let str = data.toString(); + + for (let i = 0; i < installationSteps.length; ++i) + if (str.includes(installationSteps[i])) + { + installationProgress = i + 1; + + break; + } + + progress(str, installationProgress, installationSteps.length); + });*/ + }); + } + }); + }); + } } export default Runners; diff --git a/src/ts/launcher/State.ts b/src/ts/launcher/State.ts index 935080f..8d4b1a4 100644 --- a/src/ts/launcher/State.ts +++ b/src/ts/launcher/State.ts @@ -11,7 +11,10 @@ export default class State protected _state: LauncherState = 'game-launch-available'; protected events = { - 'game-launch-available': import('./states/Launch') + 'game-launch-available': import('./states/Launch'), + + 'game-install-available': import('./states/Install'), + 'game-update-available': import('./states/Install') }; public constructor(launcher: Launcher) diff --git a/src/ts/launcher/states/Install.ts b/src/ts/launcher/states/Install.ts new file mode 100644 index 0000000..3b422aa --- /dev/null +++ b/src/ts/launcher/states/Install.ts @@ -0,0 +1,39 @@ +import type Launcher from '../../Launcher'; + +import Game from '../../Game'; + +export default (launcher: Launcher): Promise => { + return new Promise(async (resolve) => { + Game.update(await Game.current).then((stream) => { + launcher.progressBar?.init({ + label: 'Downloading game...', + showSpeed: true, + showEta: true, + showPercents: true, + showTotals: true + }); + + stream?.downloadStart(() => launcher.progressBar?.show()); + + stream?.downloadProgress((current: number, total: number, difference: number) => { + launcher.progressBar?.update(current, total, difference); + }); + + stream?.unpackStart(() => { + launcher.progressBar?.init({ + label: 'Unpacking game...', + showSpeed: true, + showEta: true, + showPercents: true, + showTotals: true + }); + }); + + stream?.unpackProgress((current: number, total: number, difference: number) => { + launcher.progressBar?.update(current, total, difference); + }); + + stream?.unpackFinish(() => resolve()); + }); + }); +}; diff --git a/src/ts/neutralino/Process.ts b/src/ts/neutralino/Process.ts index 4200b7d..1284486 100644 --- a/src/ts/neutralino/Process.ts +++ b/src/ts/neutralino/Process.ts @@ -117,22 +117,19 @@ class Process */ public static run(command: string, options: ProcessOptions = {}): Promise { - // Replace '\a\b' to '\\a\\b' - // And replace ''' to '\'' - const addSlashes = (str: string) => str.replaceAll('\\', '\\\\').replaceAll('\'', '\\\''); - + return new Promise(async (resolve) => { // Set env variables if (options.env) { Object.keys(options.env).forEach((key) => { - command = `${key}='${addSlashes(options.env![key])}' ${command}`; + command = `${key}='${this.addSlashes(options.env![key])}' ${command}`; }); } // Set current working directory if (options.cwd) - command = `cd '${addSlashes(options.cwd)}' && ${command} && cd -`; + command = `cd '${this.addSlashes(options.cwd)}' && ${command} && cd -`; // And run the command const process = await Neutralino.os.execCommand(command, { @@ -143,6 +140,15 @@ class Process resolve(new Process(process.pid)); }); } + + /** + * Replace '\a\b' to '\\a\\b' + * And replace ''' to '\'' + */ + public static addSlashes(str: string): string + { + return str.replaceAll('\\', '\\\\').replaceAll('\'', '\\\''); + } } export type { ProcessOptions };