diff --git a/package.json b/package.json
index a40faf6..6f9fde7 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
"check": "svelte-check --tsconfig ./tsconfig.json"
},
"dependencies": {
- "@empathize/framework": "^1.3.5",
+ "@empathize/framework": "^1.4.0",
"js-md5": "^0.7.3",
"semver": "^7.3.5",
"svelte-i18n": "^3.3.13",
diff --git a/src/components/ShadersSelection.svelte b/src/components/ShadersSelection.svelte
index 88e440c..289b9d8 100644
--- a/src/components/ShadersSelection.svelte
+++ b/src/components/ShadersSelection.svelte
@@ -1,10 +1,11 @@
diff --git a/src/empathize.ts b/src/empathize.ts
index 237b973..1512f39 100644
--- a/src/empathize.ts
+++ b/src/empathize.ts
@@ -9,7 +9,7 @@ import {
Windows,
// OS API
- Process, Tray, IPC, Notification, Archive,
+ Process, Tray, IPC, Notification, Archive, Package,
// Network API
fetch, Domain, Downloader,
@@ -42,7 +42,7 @@ export {
Windows,
// OS API
- Process, Tray, IPC, Notification, Archive,
+ Process, Tray, IPC, Notification, Archive, Package,
// Network API
fetch, Domain, Downloader,
diff --git a/src/settings.svelte b/src/settings.svelte
index 52a2c96..1a514b6 100644
--- a/src/settings.svelte
+++ b/src/settings.svelte
@@ -6,7 +6,7 @@
import { onMount } from 'svelte';
import { _, locale, locales } from 'svelte-i18n';
- import { Windows, Configs, Debug, IPC, Process, path } from './empathize';
+ import { Windows, Configs, Debug, IPC, Process, path, Package } from './empathize';
import constants from './ts/Constants';
import Launcher from './ts/Launcher';
@@ -86,7 +86,7 @@
tooltip: 'settings.enhancements.items.gamemode.tooltip.enabled'
};
- Launcher.isPackageAvailable('gamemoderun').then((available) => {
+ Package.exists('gamemoderun').then((available) => {
gamemode.disabled = !available;
if (gamemode.disabled)
diff --git a/src/ts/Game.ts b/src/ts/Game.ts
index 0554cdb..18c8578 100644
--- a/src/ts/Game.ts
+++ b/src/ts/Game.ts
@@ -7,7 +7,7 @@ import type {
import type { Stream as DownloadingStream } from '@empathize/framework/dist/network/Downloader';
-import { fetch, Domain, promisify, Downloader, Cache, Debug } from '../empathize';
+import { fetch, Domain, promisify, Downloader, Cache, Debug, Package } from '../empathize';
import { DebugThread } from '@empathize/framework/dist/meta/Debug';
import constants from './Constants';
@@ -246,31 +246,45 @@ export default class Game
/**
* Check if the telemetry servers are disabled
+ *
+ * @returns throws Error object when iputils package (ping command) is not available
*/
public static isTelemetryDisabled(): Promise
{
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) => {
- return new Promise((resolve) => {
- Domain.getInfo(domain).then((info) => resolve(info.available));
- });
- }),
- callAtOnce: true,
- interval: 500
- });
+ return new Promise(async (resolve, reject) => {
+ // If ping command is not available - throw an error
+ if (!await Package.exists('ping'))
+ {
+ debugThread.log('iputils package is not installed');
- pipeline.then((result) => {
- let disabled = false;
+ reject(new Error('iputils package is not installed'));
+ }
- Object.values(result).forEach((value) => disabled ||= value as boolean);
+ // Otherwise - check if telemetry is disabled
+ else
+ {
+ const pipeline = promisify({
+ callbacks: await constants.uri.telemetry.map((domain) => {
+ return new Promise((resolve) => {
+ Domain.getInfo(domain).then((info) => resolve(info.available));
+ });
+ }),
+ callAtOnce: true,
+ interval: 500
+ });
- debugThread.log(`Telemetry is ${disabled ? 'not ' : ''}disabled`);
+ pipeline.then((result) => {
+ let disabled = false;
- resolve(disabled === false);
- });
+ Object.values(result).forEach((value) => disabled ||= value as boolean);
+
+ debugThread.log(`Telemetry is ${disabled ? 'not ' : ''}disabled`);
+
+ resolve(disabled === false);
+ });
+ }
});
}
}
diff --git a/src/ts/Launcher.ts b/src/ts/Launcher.ts
index 953ad2e..13288ec 100644
--- a/src/ts/Launcher.ts
+++ b/src/ts/Launcher.ts
@@ -154,45 +154,4 @@ export default class Launcher
});
});
}
-
- /**
- * Check if some binary file or package downloaded
- */
- public static isPackageAvailable(name: string): Promise
- {
- return new Promise(async (resolve) => {
- let available = false;
-
- let paths: string[] = (await Neutralino.os.getEnv('PATH')).split(':');
-
- // Add "/usr/share" if it is not included
- // because we use these paths to check if some library exists in system
- if (!paths.includes('/usr/share'))
- paths.push('/usr/share');
-
- // Sort them by length because obviously
- // "/usr/bin" more important than some randomly generated
- // yaml or npm folder for its globally downloaded packages
- paths = paths.sort((a, b) => a.length - b.length);
-
- for (const path of paths)
- {
- // Becasue await Neutralino.filesystem.getStats will throw an erro
- // if the specified path doesn't exist
- try
- {
- if (await Neutralino.filesystem.getStats(`${path}/${name}`))
- {
- available = true;
-
- break;
- }
- }
-
- catch {}
- }
-
- resolve(available);
- });
- }
};
diff --git a/src/ts/launcher/states/ApplyPatch.ts b/src/ts/launcher/states/ApplyPatch.ts
index 04aaee8..92a3a4d 100644
--- a/src/ts/launcher/states/ApplyPatch.ts
+++ b/src/ts/launcher/states/ApplyPatch.ts
@@ -1,6 +1,7 @@
-import { Notification } from '../../../empathize';
+import { Notification, Package } from '../../../empathize';
+
+import type Launcher from '../../Launcher';
-import Launcher from '../../Launcher';
import Patch from '../../Patch';
import constants from '../../Constants';
import Locales from '../Locales';
@@ -8,7 +9,7 @@ import Locales from '../Locales';
export default (launcher: Launcher): Promise => {
return new Promise(async (resolve) => {
// Show an error notification if xdelta3 package is not installed
- if (!await Launcher.isPackageAvailable('xdelta3'))
+ if (!await Package.exists('xdelta3'))
{
Notification.show({
...(Locales.translate('notifications.xdelta3_package_required') as { title: string, body: string }),
diff --git a/src/ts/launcher/states/Launch.ts b/src/ts/launcher/states/Launch.ts
index 6ad22e0..9e663b9 100644
--- a/src/ts/launcher/states/Launch.ts
+++ b/src/ts/launcher/states/Launch.ts
@@ -1,7 +1,8 @@
-import { Process, Windows, Configs, Notification, path } from '../../../empathize';
+import { Process, Windows, Configs, Notification, path, Package } from '../../../empathize';
import { DebugThread } from '@empathize/framework/dist/meta/Debug';
-import Launcher from '../../Launcher';
+import type Launcher from '../../Launcher';
+
import constants from '../../Constants';
import Runners from '../../core/Runners';
import Game from '../../Game';
@@ -13,240 +14,235 @@ export default (launcher: Launcher): Promise => {
return new Promise(async (resolve) => {
const debugThread = new DebugThread('State/Launch', 'Starting the game');
- // Show an error notification if ping is not available
- if (!await Launcher.isPackageAvailable('ping'))
- {
- Notification.show({
- ...(Locales.translate('notifications.iputils_package_required') as { title: string, body: string }),
- icon: `${constants.paths.appDir}/public/images/baal64-transparent.png`,
- importance: 'critical'
- });
-
- debugThread.log('iputils package is not installed!');
-
- resolve();
- }
-
- const telemetry = await Game.isTelemetryDisabled();
-
- // If telemetry servers are not disabled
- if (!telemetry)
- {
- Notification.show({
- ...(Locales.translate('notifications.telemetry_not_disabled') as { title: string, body: string }),
- icon: `${constants.paths.appDir}/public/images/baal64-transparent.png`,
- importance: 'critical'
- });
-
- debugThread.log('Telemetry is not disabled!');
- }
-
- // Otherwise run the game
- else
- {
- Windows.current.hide();
-
- launcher.updateDiscordRPC('in-game');
-
- launcher.tray.update([
- { text: 'Starting the game...', disabled: true }
- ]);
-
- /**
- * Selecting wine executable
- */
- let wineExeutable = 'wine';
-
- const runner = await Runners.current();
-
- if (runner !== null)
- wineExeutable = `${await constants.paths.runnersDir}/${runner.name}/${runner.files.wine}`;
-
- debugThread.log(`Wine executable path: ${wineExeutable}`);
-
- // Some special variables
- let env: any = {};
-
- /**
- * HUD
- */
- switch (await Configs.get('hud'))
- {
- case 'dxvk':
- env['DXVK_HUD'] = 'fps,frametimes,version,gpuload';
-
- break;
-
- case 'mangohud':
- env['MANGOHUD'] = 1;
-
- break;
- }
-
- /**
- * Wine synchronizations
- *
- * @link https://github.com/AdelKS/LinuxGamingGuide#wine-tkg
- */
- switch (await Configs.get('winesync'))
- {
- case 'esync':
- env['WINEESYNC'] = 1;
-
- break;
-
- case 'fsync':
- env['WINEESYNC'] = 1;
- env['WINEFSYNC'] = 1;
-
- break;
- }
-
- /**
- * AMD FSR
- */
- if (await Configs.get('fsr'))
- {
- env['WINE_FULLSCREEN_FSR'] = 1;
- env['WINE_FULLSCREEN_FSR_STRENGTH'] = 3;
- }
-
- /**
- * Shaders
- */
- const shaders = await Configs.get('shaders');
-
- if (shaders !== 'none' && await Launcher.isPackageAvailable('reshade'))
- {
- const launcherShadersFile = `${await constants.paths.launcherDir}/vkBasalt.conf`;
-
- env['ENABLE_VKBASALT'] = 1;
- env['VKBASALT_CONFIG_FILE'] = launcherShadersFile;
-
- if (shaders !== 'custom')
+ // Check if telemetry servers are disabled
+ Game.isTelemetryDisabled()
+ .then(async (telemetryDisabled) => {
+ // If telemetry servers are not disabled
+ if (!telemetryDisabled)
{
- const userShadersFile = `${constants.paths.shadersDir}/${shaders}/vkBasalt.conf`;
-
- await Neutralino.filesystem.writeFile(launcherShadersFile, await Neutralino.filesystem.readFile(userShadersFile));
- }
- }
+ Notification.show({
+ ...(Locales.translate('notifications.telemetry_not_disabled') as { title: string, body: string }),
+ icon: `${constants.paths.appDir}/public/images/baal64-transparent.png`,
+ importance: 'critical'
+ });
- /**
- * GPU selection
- */
- // TODO
- /*if (LauncherLib.getConfig('gpu') != 'default')
- {
- const gpu = await SwitcherooControl.getGpuByName(LauncherLib.getConfig('gpu'));
-
- if (gpu)
- {
- env = {
- ...env,
- ...SwitcherooControl.getEnvAsObject(gpu)
- };
+ debugThread.log('Telemetry is not disabled!');
}
- else console.warn(`GPU ${LauncherLib.getConfig('gpu')} not found. Launching on the default GPU`);
- }*/
+ // Otherwise run the game
+ else
+ {
+ Windows.current.hide();
- let command = `"${path.addSlashes(wineExeutable)}" ${await Configs.get('fps_unlocker') ? 'unlockfps.bat' : 'launcher.bat'}`;
+ launcher.updateDiscordRPC('in-game');
- /**
- * Gamemode integration
- */
- if (await Configs.get('gamemode') && await Launcher.isPackageAvailable('gamemoderun'))
- command = `gamemoderun ${command}`;
+ launcher.tray.update([
+ { text: 'Starting the game...', disabled: true }
+ ]);
- /**
- * Starting the game
- */
- const startTime = Date.now();
+ /**
+ * Selecting wine executable
+ */
+ let wineExeutable = 'wine';
- const process = await Process.run(command, {
- env: {
- WINEPREFIX: await constants.paths.prefix.current,
- ...env,
- ...((await Configs.get('env') as object|null) ?? {})
- },
- cwd: await constants.paths.gameDir
- });
+ const runner = await Runners.current();
- // Game was started by the launcher.bat file
- // so we just need to wait until AnimeGame.e process
- // will be closed
- process.finish(() => {
- const processName = `${constants.placeholders.uppercase.first + constants.placeholders.uppercase.second}.e`;
+ if (runner !== null)
+ wineExeutable = `${await constants.paths.runnersDir}/${runner.name}/${runner.files.wine}`;
- let closeGameCounter = 0;
+ debugThread.log(`Wine executable path: ${wineExeutable}`);
- const waiter = async () => {
- const processes: string = (await Neutralino.os.execCommand('ps -A')).stdOut;
+ // Some special variables
+ let env: any = {};
- // Game is still running
- if (processes.includes(processName))
+ /**
+ * HUD
+ */
+ switch (await Configs.get('hud'))
{
- const playtime = Math.round((Date.now() - startTime) / 1000);
+ case 'dxvk':
+ env['DXVK_HUD'] = 'fps,frametimes,version,gpuload';
- let hours: string|number = Math.floor(playtime / 3600);
- let minutes: string|number = Math.floor((playtime - hours * 3600) / 60);
- let seconds: string|number = playtime - hours * 3600 - minutes * 60;
+ break;
- if (hours < 10)
- hours = `0${hours}`;
+ case 'mangohud':
+ env['MANGOHUD'] = 1;
- if (minutes < 10)
- minutes = `0${minutes}`;
-
- if (seconds < 10)
- seconds = `0${seconds}`;
-
- // FIXME: tray doesn't work in AppImage
- launcher.tray.update([
- { text: `Playing for ${hours}:${minutes}:${seconds}`, disabled: true },
- {
- text: `Close game${closeGameCounter > 0 ? ` (${closeGameCounter})` : ''}`,
-
- click: () => Neutralino.os.execCommand(`kill ${++closeGameCounter < 3 ? '-15' : '-9'} $(pidof ${processName})`)
- }
- ]);
-
- setTimeout(waiter, 3000);
+ break;
}
- // Game was closed
- else
+ /**
+ * Wine synchronizations
+ *
+ * @link https://github.com/AdelKS/LinuxGamingGuide#wine-tkg
+ */
+ switch (await Configs.get('winesync'))
{
- const stopTime = Date.now();
+ case 'esync':
+ env['WINEESYNC'] = 1;
- Windows.current.show();
- // FIXME: Windows.current.center(1280, 700);
+ break;
- launcher.updateDiscordRPC('in-launcher');
- launcher.tray.hide();
+ case 'fsync':
+ env['WINEESYNC'] = 1;
+ env['WINEFSYNC'] = 1;
- // Purge game logs
- Configs.get('purge_logs.game').then(async (purge_logs) => {
- if (purge_logs)
- {
- const gameDir = path.addSlashes(await constants.paths.gameDir);
-
- // Delete .log files (e.g. "ZFGameBrowser_xxxx.log")
- Neutralino.os.execCommand(`find "${gameDir}" -maxdepth 1 -type f -name "*.log" -delete`);
-
- // Delete .dmp files (e.g. "DumpFile-zfbrowser-xxxxxx.dmp")
- Neutralino.os.execCommand(`find "${gameDir}" -maxdepth 1 -type f -name "*.dmp" -delete`);
- }
- });
-
- // TODO
-
- resolve();
+ break;
}
- };
- setTimeout(waiter, 5000);
+ /**
+ * AMD FSR
+ */
+ if (await Configs.get('fsr'))
+ {
+ env['WINE_FULLSCREEN_FSR'] = 1;
+ env['WINE_FULLSCREEN_FSR_STRENGTH'] = 3;
+ }
+
+ /**
+ * Shaders
+ */
+ const shaders = await Configs.get('shaders');
+
+ if (shaders !== 'none' && await Package.exists('reshade'))
+ {
+ const launcherShadersFile = `${await constants.paths.launcherDir}/vkBasalt.conf`;
+
+ env['ENABLE_VKBASALT'] = 1;
+ env['VKBASALT_CONFIG_FILE'] = launcherShadersFile;
+
+ if (shaders !== 'custom')
+ {
+ const userShadersFile = `${constants.paths.shadersDir}/${shaders}/vkBasalt.conf`;
+
+ await Neutralino.filesystem.writeFile(launcherShadersFile, await Neutralino.filesystem.readFile(userShadersFile));
+ }
+ }
+
+ /**
+ * GPU selection
+ */
+ // TODO
+ /*if (LauncherLib.getConfig('gpu') != 'default')
+ {
+ const gpu = await SwitcherooControl.getGpuByName(LauncherLib.getConfig('gpu'));
+
+ if (gpu)
+ {
+ env = {
+ ...env,
+ ...SwitcherooControl.getEnvAsObject(gpu)
+ };
+ }
+
+ else console.warn(`GPU ${LauncherLib.getConfig('gpu')} not found. Launching on the default GPU`);
+ }*/
+
+ let command = `"${path.addSlashes(wineExeutable)}" ${await Configs.get('fps_unlocker') ? 'unlockfps.bat' : 'launcher.bat'}`;
+
+ /**
+ * Gamemode integration
+ */
+ if (await Configs.get('gamemode') && await Package.exists('gamemoderun'))
+ command = `gamemoderun ${command}`;
+
+ /**
+ * Starting the game
+ */
+ const startTime = Date.now();
+
+ const process = await Process.run(command, {
+ env: {
+ WINEPREFIX: await constants.paths.prefix.current,
+ ...env,
+ ...((await Configs.get('env') as object|null) ?? {})
+ },
+ cwd: await constants.paths.gameDir
+ });
+
+ // Game was started by the launcher.bat file
+ // so we just need to wait until AnimeGame.e process
+ // will be closed
+ process.finish(() => {
+ const processName = `${constants.placeholders.uppercase.first + constants.placeholders.uppercase.second}.e`;
+
+ let closeGameCounter = 0;
+
+ const waiter = async () => {
+ const processes: string = (await Neutralino.os.execCommand('ps -A')).stdOut;
+
+ // Game is still running
+ if (processes.includes(processName))
+ {
+ const playtime = Math.round((Date.now() - startTime) / 1000);
+
+ let hours: string|number = Math.floor(playtime / 3600);
+ let minutes: string|number = Math.floor((playtime - hours * 3600) / 60);
+ let seconds: string|number = playtime - hours * 3600 - minutes * 60;
+
+ if (hours < 10)
+ hours = `0${hours}`;
+
+ if (minutes < 10)
+ minutes = `0${minutes}`;
+
+ if (seconds < 10)
+ seconds = `0${seconds}`;
+
+ // FIXME: tray doesn't work in AppImage
+ launcher.tray.update([
+ { text: `Playing for ${hours}:${minutes}:${seconds}`, disabled: true },
+ {
+ text: `Close game${closeGameCounter > 0 ? ` (${closeGameCounter})` : ''}`,
+
+ click: () => Neutralino.os.execCommand(`kill ${++closeGameCounter < 3 ? '-15' : '-9'} $(pidof ${processName})`)
+ }
+ ]);
+
+ setTimeout(waiter, 3000);
+ }
+
+ // Game was closed
+ else
+ {
+ const stopTime = Date.now();
+
+ Windows.current.show();
+ // FIXME: Windows.current.center(1280, 700);
+
+ launcher.updateDiscordRPC('in-launcher');
+ launcher.tray.hide();
+
+ // Purge game logs
+ Configs.get('purge_logs.game').then(async (purge_logs) => {
+ if (purge_logs)
+ {
+ const gameDir = path.addSlashes(await constants.paths.gameDir);
+
+ // Delete .log files (e.g. "ZFGameBrowser_xxxx.log")
+ Neutralino.os.execCommand(`find "${gameDir}" -maxdepth 1 -type f -name "*.log" -delete`);
+
+ // Delete .dmp files (e.g. "DumpFile-zfbrowser-xxxxxx.dmp")
+ Neutralino.os.execCommand(`find "${gameDir}" -maxdepth 1 -type f -name "*.dmp" -delete`);
+ }
+ });
+
+ // TODO
+
+ resolve();
+ }
+ };
+
+ setTimeout(waiter, 5000);
+ });
+ }
+ })
+ .catch(() => {
+ Notification.show({
+ ...(Locales.translate('notifications.iputils_package_required') as { title: string, body: string }),
+ icon: `${constants.paths.appDir}/public/images/baal64-transparent.png`,
+ importance: 'critical'
+ });
});
- }
});
};