Added debugger

- disabled already selected dxvk/runner re-selection
- fixed `Voice.current` output
- made `Debug` and `DebugThread` classes
- fixed `winecfg` usage during DXVK installation
- `bash` usage was changed to the `./`
- added voice update state identification
- fixed shaders usage in game launching script
- added debugging to the `[launchder]/logs` folder
This commit is contained in:
Observer KRypt0n_ 2021-12-28 21:22:45 +02:00
parent fca10371b8
commit cec860e69c
No known key found for this signature in database
GPG key ID: DC5D4EC1303465DA
22 changed files with 449 additions and 43 deletions

View file

@ -164,12 +164,12 @@ This is our current roadmap goals. You can find older ones [here](ROADMAP.md)
* Rewrite sass code, provide more flexible theming ability
* <s>Add `svelte-i18n`</s>
* <s>Telemetry checking</s>
* <s>Tooltips for some options</s>
* <s>Debugger</s>
* Game pre-installation
* Launcher auto-updates
* Statistics window
* Debugger
* Loading screen
* Tooltips for some options
* Splash screen
* Theming system
* Chengelog window
* Default runner auto-installation
@ -180,7 +180,6 @@ This is our current roadmap goals. You can find older ones [here](ROADMAP.md)
* <s>Use `LauncherLib.getGameVersion` function instead of the `config.json`'s `version` property</s> *(deprecated due to the new core functions)*
* Add downloading pause button
* Fix button flickering at start when the launcher's state updates
* Game's update pre-installation
* Screenshots explorer
* Add Patch category in settings menu with
- Always participate in patches testing

View file

@ -98,7 +98,7 @@
class:list-item-disabled={disabledDxvks[dxvk.version]}
on:click|self={() => {
if (installedDxvks[dxvk.version])
if (installedDxvks[dxvk.version] && selectedVersion !== dxvk.version)
selectDxvk(dxvk);
}}
>

View file

@ -78,7 +78,7 @@
class:list-item-disabled={disabledRunners[runner.name]}
on:click|self={() => {
if (installedRunners[runner.name])
if (installedRunners[runner.name] && selectedVersion !== runner.name)
{
selectedVersion = runner.name;

View file

@ -1,6 +1,8 @@
import '../i18n';
import App from '../index.svelte';
import constants from '../ts/Constants';
import Archive from '../ts/core/Archive';
import Debug from '../ts/core/Debug';
import Downloader from '../ts/core/Downloader';
declare const Neutralino;
@ -13,7 +15,26 @@ Neutralino.events.on('windowClose', () => {
Downloader.closeStreams(true);
Archive.closeStreams(true);
Neutralino.app.exit();
constants.paths.launcherDir.then(async (path) => {
const time = new Date;
Neutralino.filesystem.getStats(`${path}/logs`)
.then(() => saveLog())
.catch(async () => {
await Neutralino.filesystem.createDirectory(`${path}/logs`);
saveLog();
});
const saveLog = async () => {
const log = Debug.get().join("\r\n");
if (log != '')
await Neutralino.filesystem.writeFile(`${path}/logs/${time.getDay()}-${time.getMonth()}-${time.getFullYear()}-${time.getHours()}-${time.getMinutes()}-${time.getSeconds()}.log`, log);
Neutralino.app.exit();
};
});
});
const app = new App({

View file

@ -1,10 +1,18 @@
import '../i18n';
import Debug from '../ts/core/Debug';
import App from '../settings.svelte';
declare const Neutralino;
Neutralino.init();
Neutralino.events.on('windowClose', async () => {
await Neutralino.storage.setData('log', JSON.stringify(Debug.getRecords()));
Neutralino.app.exit();
});
const app = new App({
target: document.getElementById('app')!
});

View file

@ -10,6 +10,7 @@ import fetch from './core/Fetch';
import AbstractInstaller from './core/AbstractInstaller';
import Domain from './core/Domain';
import promisify from './core/promisify';
import Debug, { DebugThread } from './core/Debug';
declare const Neutralino;
@ -42,6 +43,11 @@ export default class Game
const buffer = new TextDecoder('ascii').decode(new Uint8Array(config));
const version = /([1-9]+\.[0-9]+\.[0-9]+)_[\d]+_[\d]+/.exec(buffer);
Debug.log({
function: 'Game.current',
message: `Current game version: ${version !== null ? version[1] : '<unknown>'}`
});
resolve(version !== null ? version[1] : null);
})
.catch(() => resolve(null));
@ -140,6 +146,12 @@ export default class Game
*/
public static update(version: string|null = null): Promise<Stream|null>
{
Debug.log(
version !== null ?
`Updating the game from the ${version} version` :
'Installing the game'
);
return new Promise((resolve, reject) => {
(version === null ? this.latest : this.getDiff(version))
.then((data: Latest|Diff|null) => resolve(data === null ? null : new Stream(data.path)))
@ -152,6 +164,8 @@ export default class Game
*/
public static isTelemetryDisabled(): Promise<boolean>
{
const debugThread = new DebugThread('Game.isTelemetryDisabled', 'Checking if the telemetry servers are disabled');
return new Promise(async (resolve) => {
const pipeline = promisify({
callbacks: await constants.uri.telemetry.map((domain) => {
@ -168,6 +182,8 @@ export default class Game
Object.values(result).forEach((value) => disabled ||= value as boolean);
debugThread.log(`Telemetry is ${disabled ? 'not ' : ''}disabled`);
resolve(disabled === false);
});
});

View file

@ -6,6 +6,9 @@ import Configs from './Configs';
import ProgressBar from './launcher/ProgressBar';
import State from './launcher/State';
import Debug from './core/Debug';
declare const Neutralino;
export default class Launcher
{
@ -36,7 +39,8 @@ export default class Launcher
title: 'Settings',
width: 900,
height: 600,
enableInspector: true
enableInspector: true,
exitProcessOnClose: false
});
if (window.status)
@ -45,6 +49,14 @@ export default class Launcher
this.settingsMenu.finish(() => {
this.settingsMenu = undefined;
Neutralino.storage.getData('log')
.then((data) => {
Debug.merge(JSON.parse(data));
Neutralino.storage.setData('log', undefined);
})
.catch(() => {});
Window.current.show();
})

View file

@ -8,6 +8,7 @@ import fetch from './core/Fetch';
import AbstractInstaller from './core/AbstractInstaller';
import promisify from './core/promisify';
import Process from './neutralino/Process';
import Debug, { DebugThread } from './core/Debug';
declare const Neutralino;
@ -132,6 +133,8 @@ export default class Patch
*/
public static get latest(): Promise<PatchInfo>
{
const debugThread = new DebugThread('Patch.latest', 'Getting the latest patch information');
return new Promise(async (resolve, reject) => {
const getLatestPatchInfo = (versions: string[], source: 'origin' | 'additional'): Promise<PatchInfo> => {
return new Promise(async (resolve) => {
@ -145,7 +148,12 @@ export default class Patch
resolve(await getLatestPatchInfo(versions.slice(1), 'origin'));
// Otherwise - return found info
else resolve(patchInfo);
else
{
debugThread.log({ message: patchInfo });
resolve(patchInfo);
}
})
.catch(async (error) => {
// If we couldn't connect to the origin repo
@ -271,6 +279,11 @@ export default class Patch
*/
public static install(): Promise<Stream|null>
{
Debug.log({
function: 'Patch.install',
message: 'Installing the patch...'
});
return new Promise((resolve, reject) => {
this.latest
.then((patch) => {

View file

@ -5,6 +5,7 @@ import constants from './Constants';
import Game from './Game';
import AbstractInstaller from './core/AbstractInstaller';
import Configs from './Configs';
import Debug from './core/Debug';
declare const Neutralino;
@ -41,23 +42,36 @@ export default class Voice
// Parse installed voice packages
Neutralino.filesystem.readDirectory(await constants.paths.voiceDir)
.then((files) => {
files = files
.filter((file) => file.type == 'DIRECTORY')
files = files.filter((file) => file.type == 'DIRECTORY')
.map((file) => file.entry);
Object.keys(langs).forEach((folder) => {
if (files.includes(folder) && langs[folder] !== undefined)
if (files.includes(folder))
installedVoice.installed.push(langs[folder]);
});
parseActiveVoice();
})
.catch(() => {});
.catch(() => parseActiveVoice());
// Parse active voice package
Neutralino.filesystem.readFile(persistentPath)
.then((lang) => installedVoice.active = langs[lang] ?? null)
.catch(() => {});
const parseActiveVoice = () => {
Neutralino.filesystem.readFile(persistentPath)
.then((lang) => {
installedVoice.active = langs[lang] ?? null;
resolve(installedVoice);
Debug.log({
function: 'Voice.current',
message: {
'active voice': installedVoice.active,
'installed voices': installedVoice.installed.join(', ')
}
});
resolve(installedVoice);
})
.catch(() => resolve(installedVoice));
};
});
}
@ -106,6 +120,12 @@ export default class Voice
*/
public static update(lang: string|null = null, version: string|null = null): Promise<Stream|null>
{
Debug.log(
version !== null ?
`Updating the voice package from the ${version} version` :
'Installing the voice package'
);
return new Promise((resolve, reject) => {
(version === null ? this.latest : this.getDiff(version))
.then((data: VoicePack[]|null) => {

View file

@ -1,6 +1,7 @@
import constants from '../Constants';
import Downloader from './Downloader';
import Archive from './Archive';
import { DebugThread } from './Debug';
declare const Neutralino;
@ -33,6 +34,13 @@ export default abstract class Installer
public constructor(uri: string, unpackDir: string|Promise<string>)
{
const debugThread = new DebugThread('AbstractInstaller', {
message: {
'uri': uri,
'unpack dir': typeof unpackDir === 'string' ? unpackDir : '<promise>'
}
});
constants.paths.launcherDir.then((launcherDir) => {
const archivePath = `${launcherDir}/${Downloader.fileFromUri(uri)}`;
@ -79,6 +87,8 @@ export default abstract class Installer
this.unpackFinished = true;
Neutralino.filesystem.removeFile(archivePath);
debugThread.log('Installation finished');
if (this.onUnpackFinish)
this.onUnpackFinish();
@ -86,8 +96,15 @@ export default abstract class Installer
});
};
const shouldResolve = typeof unpackDir !== 'string';
Promise.resolve(unpackDir)
.then((unpackDir) => unpackArchive(unpackDir));
.then((unpackDir) => {
if (shouldResolve)
debugThread.log(`Resolved unpack dir: ${unpackDir}`);
unpackArchive(unpackDir);
});
});
});
});
@ -164,4 +181,4 @@ export default abstract class Installer
if (this.unpackFinished)
callback();
}
}
};

View file

@ -5,6 +5,7 @@ import type {
ArchiveInfo
} from '../types/Archive';
import { DebugThread } from './Debug';
import promisify from './promisify';
declare const Neutralino;
@ -52,6 +53,13 @@ class Stream
this.unpackDir = unpackDir;
this.started = true;
const debugThread = new DebugThread('Archive/Stream', {
message: {
'path': path,
'unpack dir': unpackDir
}
});
if (this.onStart)
this.onStart();
@ -83,6 +91,8 @@ class Stream
this._id = result.pid;
});
debugThread.log(`Unpacking started with command: ${command}`);
const updateProgress = async () => {
let difference: number = 0;
let pool: any[] = [];
@ -122,6 +132,8 @@ class Stream
{
this.finished = true;
debugThread.log('Unpacking finished');
if (this.onFinish)
this.onFinish();
}
@ -222,6 +234,8 @@ export default class Archive
*/
public static getInfo(path: string): Promise<ArchiveInfo|null>
{
const debugThread = new DebugThread('Archive.getInfo', `Getting info about archive: ${path}`);
return new Promise(async (resolve) => {
let archive: ArchiveInfo = {
size: {
@ -252,6 +266,15 @@ export default class Archive
});
}
debugThread.log({
message: {
'type': archive.type,
'compressed size': archive.size.compressed,
'uncompressed size': archive.size.uncompressed,
'files amount': archive.files.length
}
});
resolve(archive);
break;
@ -276,11 +299,22 @@ export default class Archive
});
}
debugThread.log({
message: {
'type': archive.type,
'compressed size': archive.size.compressed,
'uncompressed size': archive.size.uncompressed,
'files amount': archive.files.length
}
});
resolve(archive);
break;
default:
debugThread.log(`Unsupported archive type: ${archive.type}`);
resolve(null);
break;
@ -314,7 +348,7 @@ export default class Archive
stream.close(forced);
});
}
}
};
export { Stream };

View file

@ -6,6 +6,7 @@ import AbstractInstaller from './AbstractInstaller';
import Process from '../neutralino/Process';
import promisify from './promisify';
import Runners from './Runners';
import { DebugThread } from './Debug';
declare const Neutralino;
@ -133,13 +134,19 @@ export default class DXVK
*/
public static delete(dxvk: TDXVK|TDXVK['version']): Promise<void>
{
const debugThread = new DebugThread('DXVK.delete', `Deleting dxvk ${typeof dxvk === 'string' ? dxvk : dxvk.version}`);
return new Promise(async (resolve) => {
const version = typeof dxvk !== 'string' ?
dxvk.version : dxvk;
Process.run(`rm -rf '${Process.addSlashes(await constants.paths.dxvksDir + '/dxvk-' + version)}'`)
.then((process) => {
process.finish(() => resolve());
process.finish(() => {
debugThread.log('Deletion completed');
resolve();
});
});
});
}
@ -152,6 +159,8 @@ export default class DXVK
return new Promise(async (resolve) => {
const version = typeof dxvk !== 'string' ?
dxvk.version : dxvk;
const debugThread = new DebugThread('DXVK.apply', `Applying dxvk ${version}`);
const dxvkDir = `${await constants.paths.dxvksDir}/dxvk-${version}`;
const runner = await Runners.current();
@ -168,22 +177,40 @@ export default class DXVK
* And then run it
*/
(): Promise<void> => new Promise(async (resolve) => {
Process.run(`bash '${dxvkDir}/setup_dxvk.sh' install`, {
const alias = runner ? `alias winecfg=\\'${runnerDir}/${runner.files.winecfg}\\'\\n` : '';
Process.run(`eval $'${alias ? alias : ''}./setup_dxvk.sh install'`, {
cwd: dxvkDir,
env: {
WINE: runner ? `${runnerDir}/${runner.files.wine}` : 'wine',
WINECFG: runner ? `${runnerDir}/${runner.files.winecfg}` : 'winecfg',
WINESERVER: runner ? `${runnerDir}/${runner.files.wineserver}` : 'wineserver',
WINEPREFIX: prefix
}
}).then((process) => {
process.finish(() => resolve());
let processOutput = '';
process.output((output) => processOutput += output);
process.finish(() => {
debugThread.log({
message: [
'Setup script output:',
...processOutput.split(/\r\n|\r|\n/)
]
});
resolve();
});
});
})
]
});
pipeline.then(() => resolve());
pipeline.then(() => {
debugThread.log('Applying completed');
resolve();
});
});
}
}

119
src/ts/core/Debug.ts Normal file
View file

@ -0,0 +1,119 @@
import type { DebugOptions, LogRecord } from '../types/Debug';
class DebugThread
{
protected thread: number;
protected funcName: string|null;
public constructor(funcName: string|null = null, options: DebugOptions|string|null = null)
{
// Generate some random thread id
this.thread = 1000 + Math.round(Math.random() * 8999);
this.funcName = funcName;
if (options !== null)
this.log(options);
}
public log(options: DebugOptions|string)
{
Debug.log({
thread: this.thread,
function: this.funcName ?? '',
...(typeof options === 'string' ? { message: options } : options)
});
}
}
class Debug
{
protected static logOutput: LogRecord[] = [];
protected static formatTime(time: number): string
{
const prefixTime = (time: number): string => {
return time < 10 ? `0${time}` : time.toString();
};
const date = new Date(time);
return `${prefixTime(date.getHours())}:${prefixTime(date.getMinutes())}:${prefixTime(date.getSeconds())}.${date.getMilliseconds()}`;
}
public static log(options: DebugOptions|string)
{
const time = Date.now();
let output: LogRecord = {
time: time,
log: [
`[${this.formatTime(time)}]`
]
};
if (typeof options === 'string')
output.log[0] += ` ${options}`;
else
{
// Add thread id
if (options.thread)
output.log[0] += `[thread: ${options.thread}]`;
// Add function name
if (options.function)
output.log[0] += `[${options.function}]`;
// Add log message if it is a single line
if (typeof options.message === 'string')
output.log[0] += ` ${options.message}`;
// message: [a, b, c, d]
else if (Array.isArray(options.message))
options.message.forEach((line) => {
if (line !== '')
output.log.push(` - ${line}`);
});
// message: { a: b, c: d }
else Object.keys(options.message).forEach((key) => {
output.log.push(` - [${key}] ${options.message[key]}`);
});
}
this.logOutput.push(output);
}
public static merge(records: LogRecord[])
{
this.logOutput.unshift(...records);
this.logOutput.sort((a, b) => a.time - b.time);
}
public static getRecords(): LogRecord[]
{
return this.logOutput;
}
public static get(): string[]
{
let output: string[] = [];
this.logOutput.forEach((record) => {
record.log.forEach((line) => output.push(line));
});
return output;
}
}
export default Debug;
export { DebugThread };
export type {
DebugOptions,
LogRecord
};

View file

@ -1,11 +1,14 @@
import type { DomainInfo } from '../types/Domain';
import Process from '../neutralino/Process';
import { DebugThread } from './Debug';
export default class Domain
{
public static getInfo(uri: string): Promise<DomainInfo>
{
const debugThread = new DebugThread('Domain.getInfo', `Getting info about uri: ${uri}`);
return new Promise(async (resolve) => {
const process = await Process.run(`ping -n 1 -w 1 -B ${uri}`);
@ -23,12 +26,19 @@ export default class Domain
if (regex !== null)
{
resolve({
process.outputInterval = null;
process.runningInterval = null;
const info: DomainInfo = {
uri: regex[1],
remoteIp: regex[2],
localIp: regex[3],
available: regex[2] !== regex[3]
});
};
debugThread.log({ message: info });
resolve(info);
}
});
});

View file

@ -1,3 +1,4 @@
import { DebugThread } from './Debug';
import fetch from './Fetch';
declare const Neutralino;
@ -36,15 +37,27 @@ class Stream
this.total = total;
this.started = true;
const debugThread = new DebugThread('Downloader/Stream', {
message: {
'uri': uri,
'output file': output,
'total size': total
}
});
if (this.onStart)
this.onStart();
Neutralino.os.execCommand(`curl -s -L -N -o "${output}" "${uri}"`, {
const command = `curl -s -L -N -o "${output}" "${uri}"`;
Neutralino.os.execCommand(command, {
background: true
}).then((result) => {
this._id = result.pid;
});
debugThread.log(`Downloading started with command: ${command}`);
const updateProgress = () => {
Neutralino.filesystem.getStats(output).then((stats) => {
if (this.onProgress)
@ -56,6 +69,8 @@ class Stream
{
this.finished = true;
debugThread.log('Downloading finished');
if (this.onFinish)
this.onFinish();
}
@ -166,6 +181,6 @@ export default class Downloader
else return 'index.html';
}
}
};
export { Stream };

View file

@ -1,5 +1,6 @@
import constants from '../Constants';
import Process from '../neutralino/Process';
import Debug, { DebugThread } from './Debug';
import Downloader from './Downloader';
import Runners from './Runners';
@ -16,8 +17,22 @@ export default class Prefix
path ??= await constants.paths.prefix.current;
Neutralino.filesystem.getStats(`${path}/drive_c`)
.then(() => resolve(true))
.catch(() => resolve(false));
.then(() => {
Debug.log({
function: 'Prefix.exists',
message: `Prefix exists here: ${path}`
});
resolve(true);
})
.catch(() => {
Debug.log({
function: 'Prefix.exists',
message: `Prefix doesn't exist here: ${path}`
});
resolve(false);
});
});
}
@ -52,6 +67,8 @@ export default class Prefix
*/
public static create(path: string, progress?: (output: string, current: number, total: number) => void): Promise<boolean>
{
const debugThread = new DebugThread('Prefix.create', 'Creating wine prefix');
const installationSteps = [
// corefonts
'Executing w_do_call corefonts',
@ -74,14 +91,20 @@ export default class Prefix
return new Promise((resolve) => {
Runners.current().then((runner) => {
if (runner === null)
{
debugThread.log('Runner doesn\'t selected');
resolve(false);
}
else
{
debugThread.log(`Using runner: ${runner.title} (${runner.name})`);
this.getWinetricks().then(async (winetricks) => {
let installationProgress = 0;
const process = await Process.run(`bash '${Process.addSlashes(winetricks)}' corefonts usetakefocus=n`, {
const process = await Process.run(`./'${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}`,
@ -91,6 +114,7 @@ export default class Prefix
process.outputInterval = null;
// If progress specified
if (progress)
{
process.outputInterval = 1500;
@ -116,7 +140,11 @@ export default class Prefix
});
}
process.finish(() => resolve(true));
process.finish(() => {
debugThread.log('Prefix creation completed');
resolve(true);
});
});
}
});

View file

@ -6,8 +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';
import { DebugThread } from './Debug';
declare const Neutralino;
@ -140,13 +140,19 @@ class Runners
*/
public static delete(runner: Runner|Runner['name']): Promise<void>
{
const debugThread = new DebugThread('Runners.delete', `Deleting runner ${typeof runner === 'string' ? runner : runner.name}`);
return new Promise(async (resolve) => {
const name = typeof runner !== 'string' ?
runner.name : runner;
Process.run(`rm -rf '${Process.addSlashes(await constants.paths.runnersDir + '/' + name)}'`)
.then((process) => {
process.finish(() => resolve());
process.finish(() => {
debugThread.log('Runner deleted');
resolve();
});
});
});
}

View file

@ -5,6 +5,7 @@ import Window from '../neutralino/Window';
import Game from '../Game';
import Patch from '../Patch';
import Voice from '../Voice';
export default class State
{
@ -35,8 +36,12 @@ export default class State
this.launchButton.onclick = () => {
if (this.events[this._state])
{
this.launchButton.style['display'] = 'none';
this.events[this._state].then((event) => {
event.default(this.launcher).then(() => {
this.launchButton.style['display'] = 'block';
this.update();
});
});
@ -118,6 +123,7 @@ export default class State
const gameCurrent = await Game.current;
const gameLatest = (await Game.latest).version;
const patch = await Patch.latest;
const voiceData = await Voice.current;
if (gameCurrent === null)
state = 'game-installation-available';
@ -125,6 +131,10 @@ export default class State
else if (gameCurrent != gameLatest)
state = 'game-update-available';
// TODO: update this thing if the user selected another voice language
else if (voiceData.installed.length === 0)
state = 'game-voice-update-required';
else if (!patch.applied)
{
state = patch.state == 'preparation' ?

View file

@ -5,8 +5,6 @@ import Prefix from '../../core/Prefix';
export default (launcher: Launcher): Promise<void> => {
return new Promise(async (resolve) => {
launcher.state!.launchButton!.style['display'] = 'none';
Prefix.exists().then((exists) => {
if (!exists)
{

View file

@ -1,5 +1,6 @@
import Configs from '../../Configs';
import constants from '../../Constants';
import { DebugThread } from '../../core/Debug';
import Notifications from '../../core/Notifications';
import Runners from '../../core/Runners';
import Game from '../../Game';
@ -9,6 +10,8 @@ declare const Neutralino;
export default (): Promise<void> => {
return new Promise(async (resolve) => {
const debugThread = new DebugThread('State/Launch', 'Starting the game');
const telemetry = await Game.isTelemetryDisabled();
// If telemetry servers are not disabled
@ -22,6 +25,8 @@ export default (): Promise<void> => {
icon: icon,
importance: 'critical'
});
debugThread.log('Telemetry is not disabled!');
}
// Otherwise run the game
@ -51,7 +56,7 @@ export default (): Promise<void> => {
}
}
console.log(`Wine executable: ${wineExeutable}`);
debugThread.log(`Wine executable path: ${wineExeutable}`);
// Some special variables
let env: any = {};
@ -77,9 +82,9 @@ export default (): Promise<void> => {
*/
const shaders = await Configs.get('shaders');
if (shaders !== null)
if (shaders !== 'none')
{
const userShadersFile = `${constants.paths.shadersDir}/${shaders}/vkBasalt.conf`;
const userShadersFile = `${constants.paths.shadersDir}/public/${shaders}/vkBasalt.conf`;
const launcherShadersFile = `${await constants.paths.launcherDir}/vkBasalt.conf`;
env['ENABLE_VKBASALT'] = 1;
@ -114,9 +119,7 @@ export default (): Promise<void> => {
/*if (LauncherLib.getConfig('gamemode'))
command = `gamemoderun ${command}`;*/
const command = `${wineExeutable} launcher.bat`;
console.log(`Execution command: ${command}`);
const command = `'${Process.addSlashes(wineExeutable)}' launcher.bat`;
/**
* Starting the game

View file

@ -1,3 +1,5 @@
import Debug, { DebugThread } from "../core/Debug";
declare const Neutralino;
declare const NL_CWD;
@ -49,6 +51,8 @@ class Process
public constructor(pid: number, outputFile: string|null = null)
{
const debugThread = new DebugThread('Process/Stream', 'Opened process stream');
this.id = pid;
this.outputFile = outputFile;
@ -66,6 +70,8 @@ class Process
{
this._finished = true;
debugThread.log('Process stopped');
if (this.onFinish)
this.onFinish(this);
}
@ -86,7 +92,19 @@ class Process
this.outputOffset = output.length;
if (this._finished)
{
if (output !== '')
{
debugThread.log({
message: [
'Process output:',
...output.split(/\r\n|\r|\n/)
]
});
}
Neutralino.filesystem.removeFile(this.outputFile);
}
else if (this.outputInterval)
setTimeout(updateOutput, this.outputInterval);
@ -184,6 +202,15 @@ class Process
background: true
});
Debug.log({
function: 'Process.run',
message: {
'running command': command,
'cwd': options.cwd,
...options.env
}
});
resolve(new Process(process.pid, tmpFile));
});
}

23
src/ts/types/Debug.d.ts vendored Normal file
View file

@ -0,0 +1,23 @@
type DebugOptions = {
/**
* Some random-generated thread id
*/
thread?: number;
/**
* Some function name
*/
function?: string;
/**
* Some log message
*/
message: string|string[]|object;
};
type LogRecord = {
time: number;
log: string[];
};
export type { DebugOptions, LogRecord };