Linux build with proton picker
Build check / build-windows (pull_request) Has been cancelled
Build check / build-linux (pull_request) Has been cancelled

This commit is contained in:
2026-07-29 22:33:23 -04:00
committed by Patrick Begley
parent 5812065b56
commit 275166559a
18 changed files with 862 additions and 54 deletions
+88 -18
View File
@@ -1,5 +1,5 @@
import path from 'path';
import { spawn } from 'child_process';
import os from 'os';
import fs from 'fs-extra';
import Logger from 'electron-log/main';
@@ -12,6 +12,12 @@ import { patchConfig } from '~main/modules/patcher';
import { applyLocalePatch } from '~main/modules/localePatch';
import { minimizeToTray, restoreFromTray } from '~main/modules/tray';
import { getMod } from '~common/mods';
import {
ensureWowDesktopEntry,
gameLaunchEnv,
spawnDetachedGame,
spawnWithProton
} from '~main/modules/proton';
import { createTRPCRouter, publicProcedure } from '../trpc';
@@ -33,7 +39,13 @@ type StartResult = { ok: boolean; error?: string };
export const launcherRouter = createTRPCRouter({
start: publicProcedure.mutation(async (): Promise<StartResult> => {
const { cleanWdb, minimizeToTrayOnPlay, clientDir } = Preferences.data;
const {
cleanWdb,
minimizeToTrayOnPlay,
clientDir,
useProton,
protonPath
} = Preferences.data;
if (!clientDir) return { ok: false, error: 'No game folder is set.' };
const exePath = path.join(clientDir, 'WoW.exe');
@@ -64,22 +76,49 @@ export const launcherRouter = createTRPCRouter({
const octoLocale = Preferences.data.locale || 'enUS';
const gameEnv = { ...process.env, OCTO_LOCALE: octoLocale };
const launchExe = useLoader ? loaderPath : exePath;
const launchArgs = useLoader ? ['WoW.exe'] : [];
const wantProton = os.platform() === 'linux' && !!useProton;
if (wantProton && !protonPath)
return {
ok: false,
error: 'Proton is enabled but no Proton version is selected.'
};
Logger.log(
useLoader
wantProton
? `Launching via Proton${useLoader ? ' + VanillaFixes' : ''} (OCTO_LOCALE=${octoLocale})...`
: useLoader
? `Launching via VanillaFixes (OCTO_LOCALE=${octoLocale})...`
: `Launching ${exePath} (OCTO_LOCALE=${octoLocale})...`
);
const child = useLoader
? spawn(loaderPath, ['WoW.exe'], {
env: gameEnv,
cwd: clientDir,
detached: !minimizeToTrayOnPlay
})
: spawn(exePath, {
env: gameEnv,
cwd: clientDir,
detached: !minimizeToTrayOnPlay
});
const launchEnv = gameLaunchEnv(gameEnv);
if (os.platform() === 'linux')
await ensureWowDesktopEntry(clientDir).catch(e =>
Logger.warn('Failed to write WoW desktop entry', e)
);
let child;
try {
child = wantProton
? await spawnWithProton({
protonDir: protonPath!,
exePath: launchExe,
args: launchArgs,
cwd: clientDir,
env: launchEnv
})
: spawnDetachedGame(launchExe, launchArgs, {
env: launchEnv,
cwd: clientDir
});
} catch (e) {
Logger.error('Failed to launch the game', e);
const message = e instanceof Error ? e.message : String(e);
return { ok: false, error: `Failed to launch the game: ${message}` };
}
try {
await new Promise<void>((resolve, reject) => {
@@ -93,6 +132,13 @@ export const launcherRouter = createTRPCRouter({
}
child.on('error', e => Logger.error('Game process error', e));
// VanillaFixes / Proton often exit right after spawning WoW — don't treat
// that as the game ending. Tray restore uses isGameRunning polling.
child.on('exit', code => {
Logger.log(
`Launch helper exited (code=${code}); tracking WoW.exe separately`
);
});
if (!minimizeToTrayOnPlay) {
mainWindow?.close();
@@ -100,10 +146,34 @@ export const launcherRouter = createTRPCRouter({
}
minimizeToTray();
child.on('exit', () => {
Logger.log('WoW stopped');
restoreFromTray();
});
void watchUntilGameExits(exePath);
return { ok: true };
})
});
const sleep = (ms: number) => new Promise<void>(r => setTimeout(r, ms));
/** Wait for WoW.exe to appear (chainloader/proton lag), then restore tray on exit. */
const watchUntilGameExits = async (exePath: string) => {
const appearDeadline = Date.now() + 45_000;
let seen = false;
while (Date.now() < appearDeadline) {
if (await isGameRunning(exePath)) {
seen = true;
break;
}
await sleep(500);
}
if (!seen) {
Logger.warn('WoW.exe never appeared after launch; restoring tray');
restoreFromTray();
return;
}
Logger.log('WoW.exe detected; waiting for it to exit...');
while (await isGameRunning(exePath)) {
await sleep(2000);
}
Logger.log('WoW stopped');
restoreFromTray();
};