chore(launcher): Electron-only distro, CI sync with Windows pack
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
'use strict';
|
||||
|
||||
const { app, BrowserWindow, ipcMain, dialog, Menu } = require('electron');
|
||||
const path = require('path');
|
||||
const { spawn } = require('child_process');
|
||||
const { loadConfig, saveGameDir, resolveGameDir } = require('./lib/config-store');
|
||||
const { applyPatches, wowExePath, wowInstallValid, doAuth } = require('./lib/patch');
|
||||
const { setupAutoUpdater } = require('./lib/auto-update');
|
||||
|
||||
let mainWindow;
|
||||
let autoUpdateApi = {
|
||||
checkNow: async () => ({ skipped: true, reason: 'not initialized' }),
|
||||
};
|
||||
|
||||
function createWindow() {
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 720,
|
||||
height: 640,
|
||||
show: false,
|
||||
autoHideMenuBar: true,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.cjs'),
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false,
|
||||
sandbox: false,
|
||||
},
|
||||
});
|
||||
Menu.setApplicationMenu(null);
|
||||
mainWindow.loadFile(path.join(__dirname, 'index.html'));
|
||||
mainWindow.once('ready-to-show', () => mainWindow.show());
|
||||
}
|
||||
|
||||
function sendProgress(msg) {
|
||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||
mainWindow.webContents.send('launcher:progress', msg);
|
||||
}
|
||||
}
|
||||
|
||||
async function readMergedConfig() {
|
||||
const { configPath, config } = await loadConfig(app);
|
||||
const gameDir = resolveGameDir(config, configPath);
|
||||
const merged = { ...config, game_dir: gameDir };
|
||||
return { configPath, config: merged };
|
||||
}
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
createWindow();
|
||||
const { config } = await loadConfig(app);
|
||||
const tokenEnv = config.github && config.github.token_env;
|
||||
const token =
|
||||
(tokenEnv && String(process.env[tokenEnv] || '').trim()) ||
|
||||
String(process.env.GH_TOKEN || process.env.GITHUB_TOKEN || '').trim();
|
||||
const updateFeedUrl = String(process.env.LAUNCHER_UPDATE_URL || config.update_feed_url || '').trim();
|
||||
autoUpdateApi = setupAutoUpdater(app, () => mainWindow, {
|
||||
updateFeedUrl,
|
||||
githubOwner: config.github && config.github.owner,
|
||||
githubRepo: config.github && config.github.repo,
|
||||
token,
|
||||
});
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
||||
});
|
||||
});
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') app.quit();
|
||||
});
|
||||
|
||||
ipcMain.handle('launcher:load', async () => {
|
||||
const { configPath, config } = await readMergedConfig();
|
||||
return {
|
||||
configPath,
|
||||
gameDir: config.game_dir || '',
|
||||
authEnabled: !!(config.auth && config.auth.enabled),
|
||||
wowExe: (config.launch && config.launch.exe) || 'Wow.exe',
|
||||
wowOk: wowInstallValid(config),
|
||||
};
|
||||
});
|
||||
|
||||
ipcMain.handle('launcher:saveGameDir', async (_e, dir) => {
|
||||
const trimmed = String(dir || '').trim();
|
||||
if (!trimmed) throw new Error('folder path is empty');
|
||||
const { configPath } = await loadConfig(app);
|
||||
const norm = path.normalize(trimmed);
|
||||
const probe = { ...(await readMergedConfig()).config, game_dir: norm };
|
||||
if (!wowInstallValid(probe)) {
|
||||
throw new Error(`That folder does not contain ${(probe.launch && probe.launch.exe) || 'Wow.exe'}`);
|
||||
}
|
||||
const c = await saveGameDir(configPath, norm);
|
||||
const merged = { ...c, game_dir: resolveGameDir(c, configPath) };
|
||||
return { ok: true, gameDir: merged.game_dir, wowOk: wowInstallValid(merged) };
|
||||
});
|
||||
|
||||
ipcMain.handle('launcher:pickFolder', async (_e, startDir) => {
|
||||
const win = BrowserWindow.getFocusedWindow() || mainWindow;
|
||||
const r = await dialog.showOpenDialog(win, {
|
||||
title: 'Select World of Warcraft 3.3.5a folder',
|
||||
properties: ['openDirectory', 'createDirectory'],
|
||||
defaultPath: startDir && String(startDir).trim() ? String(startDir).trim() : undefined,
|
||||
});
|
||||
if (r.canceled || !r.filePaths || !r.filePaths[0]) return { canceled: true, path: '' };
|
||||
return { canceled: false, path: r.filePaths[0] };
|
||||
});
|
||||
|
||||
ipcMain.handle('launcher:auth', async (_e, { user, pass }) => {
|
||||
const { config } = await readMergedConfig();
|
||||
await doAuth(config, user, pass);
|
||||
return { ok: true };
|
||||
});
|
||||
|
||||
ipcMain.handle('launcher:sync', async () => {
|
||||
const { config } = await readMergedConfig();
|
||||
if (!wowInstallValid(config)) {
|
||||
throw new Error('Set a valid WoW folder (must contain Wow.exe) first.');
|
||||
}
|
||||
await applyPatches(config, sendProgress);
|
||||
return { ok: true };
|
||||
});
|
||||
|
||||
ipcMain.handle('launcher:checkUpdates', async () => {
|
||||
try {
|
||||
return await autoUpdateApi.checkNow();
|
||||
} catch (e) {
|
||||
const msg = e && (e.message || String(e));
|
||||
return { ok: false, error: msg };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('launcher:play', async () => {
|
||||
const { config } = await readMergedConfig();
|
||||
const exe = wowExePath(config);
|
||||
const args = (config.launch && config.launch.args) || [];
|
||||
const child = spawn(exe, args, {
|
||||
cwd: config.game_dir,
|
||||
detached: true,
|
||||
stdio: 'ignore',
|
||||
windowsHide: true,
|
||||
shell: false,
|
||||
});
|
||||
child.unref();
|
||||
return { ok: true };
|
||||
});
|
||||
Reference in New Issue
Block a user