diff --git a/GUI/js/launcher.js b/GUI/js/launcher.js
index d11f48a..b629a2f 100644
--- a/GUI/js/launcher.js
+++ b/GUI/js/launcher.js
@@ -193,7 +193,8 @@ window.switchProfile = async (id) => {
};
export async function launch() {
- if (isDownloading || (playBtn && playBtn.disabled)) return;
+ const btn = homePlayBtn || playBtn;
+ if (isDownloading || (btn && btn.disabled)) return;
// ==========================================================================
// STEP 1: Check launch readiness from backend (single source of truth)
@@ -271,11 +272,7 @@ export async function launch() {
// STEP 3: Start launch process
// ==========================================================================
if (window.LauncherUI) window.LauncherUI.showProgress();
- isDownloading = true;
- if (playBtn) {
- playBtn.disabled = true;
- playText.textContent = 'LAUNCHING...';
- }
+ lockPlayButton('LAUNCHING...');
try {
const startingMsg = window.i18n ? window.i18n.t('progress.startingGame') : 'Starting game...';
@@ -285,15 +282,11 @@ export async function launch() {
// Pass playerName from config - backend will validate again
const result = await window.electronAPI.launchGame(playerName, javaPath, '', gpuPreference);
- isDownloading = false;
-
- if (window.LauncherUI) {
- window.LauncherUI.hideProgress();
- }
- resetPlayButton();
-
if (result.usernameTaken) {
// Username reserved by another player
+ isDownloading = false;
+ if (window.LauncherUI) window.LauncherUI.hideProgress();
+ resetPlayButton();
if (window.LauncherUI && window.LauncherUI.showError) {
window.LauncherUI.showError('This username is reserved by another player. Please change your player name in Identity settings.');
} else {
@@ -302,9 +295,57 @@ export async function launch() {
return;
}
+ if (result.nameLocked) {
+ // UUID is password-protected and locked to a specific name
+ isDownloading = false;
+ if (window.LauncherUI) window.LauncherUI.hideProgress();
+ resetPlayButton();
+ const msg = result.registeredName
+ ? `This UUID is locked to username "${result.registeredName}". Change your identity name to "${result.registeredName}" in Settings.`
+ : 'This UUID is locked to a different username. Check your identity settings.';
+ if (window.LauncherUI && window.LauncherUI.showError) {
+ window.LauncherUI.showError(msg);
+ } else {
+ showNotification(msg, 'error');
+ }
+ return;
+ }
+
if (result.passwordRequired) {
- // UUID has a password — show interactive password dialog
- const launchResult = await promptForPasswordAndLaunch(playerName, javaPath, gpuPreference);
+ // Check for saved password first
+ let savedPw = null;
+ try {
+ const cfg = await window.electronAPI.loadConfig();
+ const uuid = result.uuid || '';
+ savedPw = cfg && cfg.savedPasswords && cfg.savedPasswords[uuid] ? cfg.savedPasswords[uuid] : null;
+ } catch (e) { /* ignore */ }
+
+ if (savedPw) {
+ // Try saved password silently
+ if (window.LauncherUI) window.LauncherUI.showProgress();
+ lockPlayButton('LAUNCHING...');
+ const autoResult = await window.electronAPI.launchGameWithPassword(playerName, javaPath, '', gpuPreference, savedPw);
+ if (autoResult.success) {
+ isDownloading = false;
+ if (window.LauncherUI) window.LauncherUI.hideProgress();
+ resetPlayButton();
+ if (window.electronAPI.minimizeWindow) setTimeout(() => { window.electronAPI.minimizeWindow(); }, 500);
+ return;
+ }
+ // Saved password failed — clear it and show popup
+ isDownloading = false;
+ if (window.LauncherUI) window.LauncherUI.hideProgress();
+ resetPlayButton();
+ try {
+ const cfg2 = await window.electronAPI.loadConfig();
+ const sp = cfg2.savedPasswords || {};
+ delete sp[result.uuid || ''];
+ await window.electronAPI.saveConfig({ savedPasswords: sp });
+ } catch (e) { /* ignore */ }
+ }
+
+ // Show interactive password dialog
+ const launchResult = await promptForPasswordAndLaunch(playerName, javaPath, gpuPreference, result.uuid);
if (launchResult && launchResult.success) {
if (window.electronAPI.minimizeWindow) setTimeout(() => { window.electronAPI.minimizeWindow(); }, 500);
}
@@ -312,12 +353,21 @@ export async function launch() {
}
if (result.success) {
+ // Keep button locked so user can't double-launch
+ if (window.LauncherUI) window.LauncherUI.hideProgress();
+ lockPlayButton('GAME RUNNING');
+ setTimeout(() => {
+ resetPlayButton();
+ }, 10000); // Reset after 10s (game should be visible by then)
if (window.electronAPI.minimizeWindow) {
setTimeout(() => {
window.electronAPI.minimizeWindow();
}, 500);
}
} else {
+ isDownloading = false;
+ if (window.LauncherUI) window.LauncherUI.hideProgress();
+ resetPlayButton();
console.error('[Launcher] Launch failed:', result.error);
// Handle specific error cases
@@ -373,7 +423,7 @@ export async function launch() {
}
}
-function promptForPasswordAndLaunch(playerName, javaPath, gpuPreference) {
+function promptForPasswordAndLaunch(playerName, javaPath, gpuPreference, uuid) {
return new Promise((resolve) => {
// Remove any existing password prompt
const existing = document.querySelector('.custom-confirm-modal');
@@ -427,6 +477,10 @@ function promptForPasswordAndLaunch(playerName, javaPath, gpuPreference) {
font-size: 0.95rem;
outline: none;
" placeholder="Password" autofocus />
+