diff --git a/.gitignore b/.gitignore index e578779..b533c73 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ pkg/ # Package files *.tar.zst +*.zst.DS_Store *.zst bun.lockb -.env \ No newline at end of file +.env diff --git a/GUI/index.html b/GUI/index.html index 843aaad..c1d0399 100644 --- a/GUI/index.html +++ b/GUI/index.html @@ -431,6 +431,27 @@ +
+

+ + Launcher Behavior +

+ +
+ +
+
+ +

diff --git a/GUI/js/settings.js b/GUI/js/settings.js index 0ec95e6..dd383be 100644 --- a/GUI/js/settings.js +++ b/GUI/js/settings.js @@ -3,9 +3,11 @@ let customJavaCheck; let customJavaOptions; let customJavaPath; let browseJavaBtn; -let settingsPlayerName; -let discordRPCCheck; -let gpuPreferenceRadios; +let settingsPlayerName; +let discordRPCCheck; +let closeLauncherCheck; +let gpuPreferenceRadios; + // UUID Management elements let currentUuidDisplay; @@ -159,9 +161,11 @@ function setupSettingsElements() { customJavaOptions = document.getElementById('customJavaOptions'); customJavaPath = document.getElementById('customJavaPath'); browseJavaBtn = document.getElementById('browseJavaBtn'); - settingsPlayerName = document.getElementById('settingsPlayerName'); - discordRPCCheck = document.getElementById('discordRPCCheck'); - gpuPreferenceRadios = document.querySelectorAll('input[name="gpuPreference"]'); + settingsPlayerName = document.getElementById('settingsPlayerName'); + discordRPCCheck = document.getElementById('discordRPCCheck'); + closeLauncherCheck = document.getElementById('closeLauncherCheck'); + gpuPreferenceRadios = document.querySelectorAll('input[name="gpuPreference"]'); + // UUID Management elements currentUuidDisplay = document.getElementById('currentUuid'); @@ -190,9 +194,14 @@ function setupSettingsElements() { settingsPlayerName.addEventListener('change', savePlayerName); } - if (discordRPCCheck) { - discordRPCCheck.addEventListener('change', saveDiscordRPC); - } + if (discordRPCCheck) { + discordRPCCheck.addEventListener('change', saveDiscordRPC); + } + + if (closeLauncherCheck) { + closeLauncherCheck.addEventListener('change', saveCloseLauncher); + } + // UUID event listeners if (copyUuidBtn) { @@ -335,18 +344,43 @@ async function saveDiscordRPC() { } } -async function loadDiscordRPC() { - try { - if (window.electronAPI && window.electronAPI.loadDiscordRPC) { - const enabled = await window.electronAPI.loadDiscordRPC(); - if (discordRPCCheck) { - discordRPCCheck.checked = enabled; - } - } - } catch (error) { - console.error('Error loading Discord RPC setting:', error); - } -} +async function loadDiscordRPC() { + try { + if (window.electronAPI && window.electronAPI.loadDiscordRPC) { + const enabled = await window.electronAPI.loadDiscordRPC(); + if (discordRPCCheck) { + discordRPCCheck.checked = enabled; + } + } + } catch (error) { + console.error('Error loading Discord RPC setting:', error); + } +} + +async function saveCloseLauncher() { + try { + if (window.electronAPI && window.electronAPI.saveCloseLauncher && closeLauncherCheck) { + const enabled = closeLauncherCheck.checked; + await window.electronAPI.saveCloseLauncher(enabled); + } + } catch (error) { + console.error('Error saving close launcher setting:', error); + } +} + +async function loadCloseLauncher() { + try { + if (window.electronAPI && window.electronAPI.loadCloseLauncher) { + const enabled = await window.electronAPI.loadCloseLauncher(); + if (closeLauncherCheck) { + closeLauncherCheck.checked = enabled; + } + } + } catch (error) { + console.error('Error loading close launcher setting:', error); + } +} + async function savePlayerName() { try { @@ -457,13 +491,15 @@ async function loadGpuPreference() { } } -async function loadAllSettings() { - await loadCustomJavaPath(); - await loadPlayerName(); - await loadCurrentUuid(); - await loadDiscordRPC(); - await loadGpuPreference(); -} +async function loadAllSettings() { + await loadCustomJavaPath(); + await loadPlayerName(); + await loadCurrentUuid(); + await loadDiscordRPC(); + await loadCloseLauncher(); + await loadGpuPreference(); +} + async function openGameLocation() { try { diff --git a/GUI/locales/en.json b/GUI/locales/en.json index b7981be..d142831 100644 --- a/GUI/locales/en.json +++ b/GUI/locales/en.json @@ -122,7 +122,10 @@ "logsCopy": "Copy", "logsRefresh": "Refresh", "logsFolder": "Open Folder", - "logsLoading": "Loading logs..." + "logsLoading": "Loading logs...", + "closeLauncher": "Launcher Behavior", + "closeOnStart": "Close Launcher on game start", + "closeOnStartDescription": "Automatically close the launcher after Hytale has launched" }, "uuid": { "modalTitle": "UUID Management", diff --git a/GUI/locales/es.json b/GUI/locales/es.json index 283108b..4bb89c8 100644 --- a/GUI/locales/es.json +++ b/GUI/locales/es.json @@ -122,7 +122,10 @@ "logsCopy": "Copiar", "logsRefresh": "Actualizar", "logsFolder": "Abrir Carpeta", - "logsLoading": "Cargando registros..." + "logsLoading": "Cargando registros...", + "closeLauncher": "Comportamiento del Launcher", + "closeOnStart": "Cerrar Launcher al iniciar el juego", + "closeOnStartDescription": "Cierra automáticamente el launcher después de que Hytale se haya iniciado" }, "uuid": { "modalTitle": "Gestión de UUID", diff --git a/GUI/locales/pt-BR.json b/GUI/locales/pt-BR.json index e48c1b0..492440b 100644 --- a/GUI/locales/pt-BR.json +++ b/GUI/locales/pt-BR.json @@ -122,7 +122,10 @@ "logsCopy": "Copiar", "logsRefresh": "Atualizar", "logsFolder": "Abrir Pasta", - "logsLoading": "Carregando registros..." + "logsLoading": "Carregando registros...", + "closeLauncher": "Comportamento do Lançador", + "closeOnStart": "Fechar Lançador ao iniciar o jogo", + "closeOnStartDescription": "Fechar automaticamente o lançador após o Hytale ter sido iniciado" }, "uuid": { "modalTitle": "Gerenciamento de UUID", diff --git a/backend/core/config.js b/backend/core/config.js index 23332a8..03cff49 100644 --- a/backend/core/config.js +++ b/backend/core/config.js @@ -156,6 +156,15 @@ function loadLanguage() { return config.language || 'en'; } +function saveCloseLauncherOnStart(enabled) { + saveConfig({ closeLauncherOnStart: !!enabled }); +} + +function loadCloseLauncherOnStart() { + const config = loadConfig(); + return config.closeLauncherOnStart !== undefined ? config.closeLauncherOnStart : false; +} + function saveModsToConfig(mods) { try { const config = loadConfig(); @@ -331,5 +340,8 @@ module.exports = { resetCurrentUserUuid, // GPU Preference exports saveGpuPreference, - loadGpuPreference + loadGpuPreference, + // Close Launcher export + saveCloseLauncherOnStart, + loadCloseLauncherOnStart }; diff --git a/backend/launcher.js b/backend/launcher.js index cadee5e..32a6c59 100644 --- a/backend/launcher.js +++ b/backend/launcher.js @@ -17,6 +17,8 @@ const { loadDiscordRPC, saveLanguage, loadLanguage, + saveCloseLauncherOnStart, + loadCloseLauncherOnStart, saveModsToConfig, loadModsFromConfig, getUuidForUser, @@ -124,6 +126,10 @@ module.exports = { saveLanguage, loadLanguage, + // Close Launcher functions + saveCloseLauncherOnStart, + loadCloseLauncherOnStart, + // GPU Preference functions saveGpuPreference, loadGpuPreference, diff --git a/main.js b/main.js index e0ab2d0..9fe72d6 100644 --- a/main.js +++ b/main.js @@ -2,7 +2,8 @@ const path = require('path'); require('dotenv').config({ path: path.join(__dirname, '.env') }); const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron'); const fs = require('fs'); -const { launchGame, launchGameWithVersionCheck, installGame, saveUsername, loadUsername, saveChatUsername, loadChatUsername, saveChatColor, loadChatColor, saveJavaPath, loadJavaPath, saveInstallPath, loadInstallPath, saveDiscordRPC, loadDiscordRPC, saveLanguage, loadLanguage, isGameInstalled, uninstallGame, repairGame, getHytaleNews, handleFirstLaunchCheck, proposeGameUpdate, markAsLaunched } = require('./backend/launcher'); +const { launchGame, launchGameWithVersionCheck, installGame, saveUsername, loadUsername, saveChatUsername, loadChatUsername, saveChatColor, loadChatColor, saveJavaPath, loadJavaPath, saveInstallPath, loadInstallPath, saveDiscordRPC, loadDiscordRPC, saveLanguage, loadLanguage, saveCloseLauncherOnStart, loadCloseLauncherOnStart, isGameInstalled, uninstallGame, repairGame, getHytaleNews, handleFirstLaunchCheck, proposeGameUpdate, markAsLaunched } = require('./backend/launcher'); + const UpdateManager = require('./backend/updateManager'); const logger = require('./backend/logger'); const profileManager = require('./backend/managers/profileManager'); @@ -186,10 +187,21 @@ function createWindow() { if (input.key === 'F12') { event.preventDefault(); } - if (input.key === 'F5') { - event.preventDefault(); - } - }); + if (input.key === 'F5') { + event.preventDefault(); + } + + // Close application shortcuts + const isMac = process.platform === 'darwin'; + const quitShortcut = (isMac && input.meta && input.key.toLowerCase() === 'q') || + (!isMac && input.control && input.key.toLowerCase() === 'q') || + (!isMac && input.alt && input.key === 'F4'); + + if (quitShortcut) { + app.quit(); + } + }); + mainWindow.webContents.on('context-menu', (e) => { @@ -333,15 +345,14 @@ app.on('before-quit', () => { cleanupDiscordRPC(); }); -app.on('window-all-closed', () => { - console.log('=== LAUNCHER CLOSING ==='); - - cleanupDiscordRPC(); - - if (process.platform !== 'darwin') { - app.quit(); - } -}); +app.on('window-all-closed', () => { + console.log('=== LAUNCHER CLOSING ==='); + + cleanupDiscordRPC(); + + app.quit(); +}); + ipcMain.handle('launch-game', async (event, playerName, javaPath, installPath, gpuPreference) => { try { @@ -358,9 +369,20 @@ ipcMain.handle('launch-game', async (event, playerName, javaPath, installPath, g } }; - const result = await launchGameWithVersionCheck(playerName, progressCallback, javaPath, installPath, gpuPreference); - - return result; + const result = await launchGameWithVersionCheck(playerName, progressCallback, javaPath, installPath, gpuPreference); + + if (result.success && result.launched) { + const closeOnStart = loadCloseLauncherOnStart(); + if (closeOnStart) { + console.log('Close Launcher on start enabled, quitting application...'); + setTimeout(() => { + app.quit(); + }, 1000); + } + } + + return result; + } catch (error) { console.error('Launch error:', error); const errorMessage = error.message || error.toString(); @@ -475,11 +497,21 @@ ipcMain.handle('save-language', (event, language) => { return { success: true }; }); -ipcMain.handle('load-language', () => { - return loadLanguage(); -}); - -ipcMain.handle('select-install-path', async () => { +ipcMain.handle('load-language', () => { + return loadLanguage(); +}); + +ipcMain.handle('save-close-launcher', (event, enabled) => { + saveCloseLauncherOnStart(enabled); + return { success: true }; +}); + +ipcMain.handle('load-close-launcher', () => { + return loadCloseLauncherOnStart(); +}); + +ipcMain.handle('select-install-path', async () => { + const result = await dialog.showOpenDialog(mainWindow, { properties: ['openDirectory'], title: 'Select Installation Folder' @@ -804,11 +836,10 @@ ipcMain.handle('open-download-page', async () => { try { await shell.openExternal(updateManager.getDownloadUrl()); - setTimeout(() => { - if (mainWindow && !mainWindow.isDestroyed()) { - mainWindow.close(); - } - }, 1000); + setTimeout(() => { + app.quit(); + }, 1000); + return { success: true }; } catch (error) { @@ -850,11 +881,10 @@ ipcMain.handle('get-detected-gpu', () => { return global.detectedGpu; }); -ipcMain.handle('window-close', () => { - if (mainWindow && !mainWindow.isDestroyed()) { - mainWindow.close(); - } -}); +ipcMain.handle('window-close', () => { + app.quit(); +}); + ipcMain.handle('window-minimize', () => { if (mainWindow && !mainWindow.isDestroyed()) { diff --git a/package-lock.json b/package-lock.json index 90d6855..bb1bcd6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "hytale-f2p-launcherv2", + "name": "hytale-f2p-launcher", "version": "2.0.2b", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "hytale-f2p-launcherv2", + "name": "hytale-f2p-launcher", "version": "2.0.2b", "license": "MIT", "dependencies": { diff --git a/preload.js b/preload.js index 759eb5e..b00d840 100644 --- a/preload.js +++ b/preload.js @@ -21,6 +21,8 @@ contextBridge.exposeInMainWorld('electronAPI', { loadDiscordRPC: () => ipcRenderer.invoke('load-discord-rpc'), saveLanguage: (language) => ipcRenderer.invoke('save-language', language), loadLanguage: () => ipcRenderer.invoke('load-language'), + saveCloseLauncher: (enabled) => ipcRenderer.invoke('save-close-launcher', enabled), + loadCloseLauncher: () => ipcRenderer.invoke('load-close-launcher'), selectInstallPath: () => ipcRenderer.invoke('select-install-path'), browseJavaPath: () => ipcRenderer.invoke('browse-java-path'), isGameInstalled: () => ipcRenderer.invoke('is-game-installed'),