fix: comprehensive UUID/username persistence bug fixes (#252)

* fix: comprehensive UUID/username persistence bug fixes

Major fixes for UUID/skin reset issues that caused players to lose cosmetics:

Core fixes:
- Username rename now preserves UUID (atomic rename, not new identity)
- Atomic config writes with backup/recovery system
- Case-insensitive UUID lookup with case-preserving storage
- Pre-launch validation blocks play if no username configured
- Removed saveUsername calls from launch/install flows

UUID Modal fixes:
- Fixed isCurrent badge showing on wrong user
- Added switch identity button to change between saved usernames
- Fixed custom UUID input using unsaved DOM username
- UUID list now refreshes when player name changes
- Enabled copy/paste in custom UUID input field

UI/UX improvements:
- Added translation keys for switch username functionality
- CSS user-select fix for UUID input fields
- Allowed Ctrl+V/C/X/A shortcuts in Electron

Files: config.js, gameLauncher.js, gameManager.js, playerManager.js,
launcher.js, settings.js, main.js, preload.js, style.css, en.json

See UUID_BUGS_FIX_PLAN.md for detailed bug list (18 bugs, 16 fixed)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(i18n): add switch username translations to all locales

Added translation keys for username switching functionality:
- notifications.noUsername
- notifications.switchUsernameSuccess
- notifications.switchUsernameFailed
- notifications.playerNameTooLong
- confirm.switchUsernameTitle
- confirm.switchUsernameMessage
- confirm.switchUsernameButton

Languages updated: de-DE, es-ES, fr-FR, id-ID, pl-PL, pt-BR, ru-RU, sv-SE, tr-TR

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: move UUID_BUGS_FIX_PLAN.md to docs folder

* docs: update UUID_BUGS_FIX_PLAN with complete fix details

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Alex
2026-02-01 04:01:58 +07:00
committed by GitHub
parent 6fbf37422f
commit 62430fe8f0
21 changed files with 1564 additions and 181 deletions

View File

@@ -194,27 +194,81 @@ window.switchProfile = async (id) => {
export async function launch() {
if (isDownloading || (playBtn && playBtn.disabled)) return;
let playerName = 'Player';
if (window.SettingsAPI && window.SettingsAPI.getCurrentPlayerName) {
playerName = window.SettingsAPI.getCurrentPlayerName();
} else if (playerNameInput && playerNameInput.value.trim()) {
playerName = playerNameInput.value.trim();
// ==========================================================================
// STEP 1: Check launch readiness from backend (single source of truth)
// ==========================================================================
let launchState = null;
let playerName = null;
try {
if (window.electronAPI && window.electronAPI.checkLaunchReady) {
launchState = await window.electronAPI.checkLaunchReady();
playerName = launchState?.username;
} else if (window.electronAPI && window.electronAPI.loadUsername) {
// Fallback to loadUsername if checkLaunchReady not available
playerName = await window.electronAPI.loadUsername();
launchState = { ready: !!playerName, hasUsername: !!playerName, username: playerName, issues: [] };
}
} catch (error) {
console.error('[Launcher] Error checking launch readiness:', error);
}
let javaPath = '';
if (window.SettingsAPI && window.SettingsAPI.getCurrentJavaPath) {
javaPath = window.SettingsAPI.getCurrentJavaPath();
// Validate launch readiness
if (!launchState?.ready || !playerName) {
const issues = launchState?.issues || ['No username configured'];
const errorMsg = window.i18n
? window.i18n.t('errors.noUsername')
: 'Please set your username in Settings before playing.';
console.error('[Launcher] Launch blocked:', issues.join(', '));
// Show error to user
if (window.LauncherUI && window.LauncherUI.showError) {
window.LauncherUI.showError(errorMsg);
} else {
alert(errorMsg);
}
// Navigate to settings if possible
if (window.LauncherUI && window.LauncherUI.showPage) {
window.LauncherUI.showPage('settings-page');
window.LauncherUI.setActiveNav('settings');
}
return;
}
// Warn if using default 'Player' name (shouldn't happen with new logic, but keep as safety)
if (playerName === 'Player') {
console.warn('[Launcher] Warning: Using default username "Player"');
}
console.log(`[Launcher] Launching game for: "${playerName}"`);
// ==========================================================================
// STEP 2: Load other settings from backend
// ==========================================================================
let javaPath = '';
try {
if (window.electronAPI && window.electronAPI.loadJavaPath) {
javaPath = await window.electronAPI.loadJavaPath() || '';
}
} catch (error) {
console.error('[Launcher] Error loading Java path:', error);
}
let gpuPreference = 'auto';
try {
if (window.electronAPI && window.electronAPI.loadGpuPreference) {
gpuPreference = await window.electronAPI.loadGpuPreference();
}
} catch (error) {
console.error('Error loading GPU preference:', error);
console.error('[Launcher] Error loading GPU preference:', error);
}
// ==========================================================================
// STEP 3: Start launch process
// ==========================================================================
if (window.LauncherUI) window.LauncherUI.showProgress();
isDownloading = true;
if (playBtn) {
@@ -227,8 +281,9 @@ export async function launch() {
if (window.LauncherUI) window.LauncherUI.updateProgress({ message: startingMsg });
if (window.electronAPI && window.electronAPI.launchGame) {
// Pass playerName from config - backend will validate again
const result = await window.electronAPI.launchGame(playerName, javaPath, '', gpuPreference);
isDownloading = false;
if (window.LauncherUI) {
@@ -243,7 +298,35 @@ export async function launch() {
}, 500);
}
} else {
console.error('Launch failed:', result.error);
console.error('[Launcher] Launch failed:', result.error);
// Handle specific error cases
if (result.needsUsername) {
const errorMsg = window.i18n
? window.i18n.t('errors.noUsername')
: 'Please set your username in Settings before playing.';
if (window.LauncherUI && window.LauncherUI.showError) {
window.LauncherUI.showError(errorMsg);
} else {
alert(errorMsg);
}
// Navigate to settings
if (window.LauncherUI && window.LauncherUI.showPage) {
window.LauncherUI.showPage('settings-page');
window.LauncherUI.setActiveNav('settings');
}
} else if (result.error) {
// Show generic error
const errorMsg = window.i18n
? window.i18n.t('errors.launchFailed').replace('{error}', result.error)
: `Launch failed: ${result.error}`;
if (window.LauncherUI && window.LauncherUI.showError) {
window.LauncherUI.showError(errorMsg);
}
}
}
} else {
isDownloading = false;
@@ -260,7 +343,13 @@ export async function launch() {
window.LauncherUI.hideProgress();
}
resetPlayButton();
console.error('Launch error:', error);
console.error('[Launcher] Launch error:', error);
// Show error to user
const errorMsg = error.message || 'Unknown launch error';
if (window.LauncherUI && window.LauncherUI.showError) {
window.LauncherUI.showError(errorMsg);
}
}
}