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
This commit is contained in:
Observer KRypt0n_ 2021-12-26 23:38:04 +02:00
parent 342eeadbfd
commit e8c721dc93
No known key found for this signature in database
GPG key ID: DC5D4EC1303465DA
6 changed files with 151 additions and 12 deletions

View file

@ -22,7 +22,7 @@
"fullScreen": false,
"alwaysOnTop": false,
"icon": "/public/icons/64x64.png",
"enableInspector": false,
"enableInspector": true,
"borderless": false,
"maximize": false,
"hidden": true,

View file

@ -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<boolean>
{
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();

View file

@ -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<string>
{
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<boolean>
{
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;

View file

@ -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)

View file

@ -0,0 +1,39 @@
import type Launcher from '../../Launcher';
import Game from '../../Game';
export default (launcher: Launcher): Promise<void> => {
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());
});
});
};

View file

@ -117,22 +117,19 @@ class Process
*/
public static run(command: string, options: ProcessOptions = {}): Promise<Process>
{
// 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 };