mirror of
https://git.sanhost.net/sanasol/hytale-f2p.git
synced 2026-02-26 06:41:47 -03:00
Release Stable Build v2.2.1 (#258)
* fix: resolve cross-platform EPERM permissions errors modManager.js: - Switch from hardcoded 'junction' to dynamic symlink type based on OS (fixing Linux EPERM). - Add retry logic for directory removal to handle file locking race conditions. - Improve broken symlink detection during profile sync. gameManager.js: - Implement retry loop (3 attempts) for game directory removal in updateGameFiles to prevent EBUSY/EPERM errors on Windows. paths.js: - Prevent fs.mkdirSync failure in getModsPath by pre-checking for broken symbolic links. * fix: missing pacman builds * prepare release for 2.1.1 minor fix for EPERM error permission * prepare release 2.1.1 minor fix EPERM permission error * prepare release 2.1.1 * Update README.md Windows Prequisites for ARM64 builds * fix: remove broken symlink after detected * fix: add pathexists for paths.js to check symlink * fix: isbrokenlink should be true to remove the symlink * add arch package .pkg.tar.zst for release * fix: release workflow for build-arch and build-linux * build-arch job now only build arch .pkg.tar.zst package instead of the whole generic linux. * build-linux job now exclude .pacman package since its deprecated and should not be used. * fix: removes pacman build as it replaced by tar.zst and adds build:arch shortcut for pkgbuild * aur: add proper VCS (-git) PKGBUILD created clean VCS-based PKGBUILD following arch packaging conventions. this explicitly marked as a rolling (-git) build and derives its version dynamically from git tags and commit history via pkgver(). previous hybrid approach has been changed. key changes: - use -git suffix to clearly indicate rolling source builds - set pkgver=0 and compute the actual version via pkgver() - build only a directory layout using electron-builder (--dir) - avoid generating AppImage, deb, rpm, or pacman installers - align build and package steps with Arch packaging guidelines note: this PKGBUILD is intended for development and AUR use only and is not suitable for binary redistribution or release artifacts. * ci: add fixed-version PKGBUILD for Arch Linux releases this PKGBUILD intended for CI and GitHub release artifacts. targets tagged releases only and uses a fixed pkgver that matches the corresponding git tag. all of the VCS logic has been removed to PKGBUILD-git to ensure reproducible builds and stable versioning suitable for binary distribution. the build process relies on electron-builder directory output (--dir) and packages only the unpacked application into a standard Arch Linux package (.pkg.tar.zst). other distro format are excluded from this path and handled separately. this change establishes a clear separation between: - rolling AUR development builds (-git) - CI-generated, versioned Arch Linux release packages the result is predictable artifact naming, correct version alignment, and Arch-compliant packaging for downstream users. * Update README.md adds information for Arch build * Update README.md BUILD.md location was changed and now this link is poiting to nothing * Update PKGBUILD * Update PKGBUILD-git * chore: fix ubuntu/debian part in README.md * Polish language support (#195) * Update support_request.yml Added hardware specification * Update bug_report.yml Add logs textfield to bug report * chore: add changelog in README.md * fix screenshot input in feature_request.yml * add hardware spec input in bug_report.yml * fix: PKGBUILD pkgname variable fix * userdata migration [need review from other OS] * french translate * Add German and Swedish translations Added de.json and sv.json locale files for German and Swedish language support. Updated i18n.js to register 'de' and 'sv' as available languages in the launcher. * Update README.md * chore: add offline-mode warning to the README.md * chore: add downloads counter in README.md * fix: Steam Deck/Ubuntu crash - use system libzstd.so The bundled libzstd.so is incompatible with glibc 2.41's stricter heap validation, causing "free(): invalid pointer" crashes. Solution: Automatically replace bundled libzstd.so with system version on Linux. The launcher detects and symlinks to /usr/lib/libzstd.so.1. - Auto-detect system libzstd at common paths (Arch, Debian, Fedora) - Backup bundled version as libzstd.so.bundled - Create symlink to system version - Add HYTALE_NO_LIBZSTD_FIX=1 to disable if needed Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: remove Windows and Linux ARM64 information on the README.md * Update support_request.yml * fix: improve update system UX and macOS compatibility Update System Improvements: - Fix duplicate update popups by disabling legacy updater.js - Add skip button to update popup (shows after 30s, on error, or after download) - Add macOS-specific handling with manual download as primary option - Add missing open-download-page IPC handler - Add missing unblockInterface() method to properly clean up after popup close - Add quitAndInstallUpdate alias in preload for compatibility - Remove pulse animation when download completes - Fix manual download button to show correct status and close popup - Sync player name to settings input after first install Client Patcher Cleanup: - Remove server patching code (server uses pre-patched JAR from CDN) - Simplify to client-only patching - Remove unused imports (crypto, AdmZip, execSync, spawn, javaManager) - Remove unused methods (stringToUtf8, findAndReplaceDomainUtf8) - Move localhost dev code to backup file for reference Code Quality Fixes: - Fix duplicate DOMContentLoaded handlers in install.js - Fix duplicate checkForUpdates definition in preload.js - Fix redundant if/else in onProgressUpdate callback - Fix typo "Harwadre" -> "Hardware" in preload.js Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Add Russian language support Added Russian (ru) to the list of available languages. * chore: drafting documentation on SERVER.md * Some updates in Russian language localization file * fix * Update ru.json * Fixed Java runtime name and fixed typo * fixed untranslated place * Update ru.json * Update ru.json * Update ru.json * Update ru.json * Update ru.json * fix: timeout getLatestClient fixes #138 * fix: change default version to 7.pwr in main.js * fix: change default release version to 7.pwr * fix: change version release to 7.pwr * docs: Add comprehensive troubleshooting guide (#209) Add TROUBLESHOOTING.md with solutions for common issues including: - Windows: Firewall configuration, duplicate mods, SmartScreen - Linux: GPU detection (NVIDIA/AMD), SDL3_image/libpng dependencies, Wayland/X11 issues, Steam Deck support - macOS: Rosetta 2 for Apple Silicon, code signing, quarantine - Connection: Server boot failures, regional restrictions - Authentication: Token errors, config reset procedures - Avatar/Cosmetics: F2P limitations documentation - Backup locations for all platforms - Log locations for bug reports Solutions compiled from closed GitHub issues (#205, #155, #90, #60, #144, #192) and community feedback. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> * Standardize language codes, improve formatting, and update all locale files. (#224) * Update German (Germany) localization * Update Español (España) localization * Update French (France) localization * Update Polish (Poland) localization * Update Portuguese (Brazil) localization * Update Russian (Russia) localization * Update Swedish (Sweden) localization * Update Turkish (Turkey) localization * Update language codes, names and alphabetical in i18n system * Changed Spanish language name to the Formal name "Spanish (Spain)" * Fix PKGBUILD-git * Fix PKGBUILD * delete cache after installation * Enforce 16-char player name limit and update mod sync Added a maxlength attribute to the player name input and enforced a 16-character limit in both install and settings scripts, providing user feedback if exceeded. Refactored modManager.js to replace symlink-based mod management with a copy-based system, copying enabled mods to HytaleSaves\Mods and removing legacy symlink logic to improve compatibility and avoid permission issues. * Update installation subtitle * chore: update quickstart link in README.md * chore: delete warning of Ubuntu-Debian at Linux Prequisites section * added featured server list from api * Add Featured Servers page to GUI * Update Discord invite URL in client patcher * Add differential update system * Remove launcher chat and add Discord popup * fix: removed 'check disk space' alert on permission file error * fix: upgrade tar to ^7.5.6 version * fix: re-add universal arch for mac * fix: upgrade electron/rebuild to 4.0.3 * fix: removed override tar version * fix: pkgbuild version to 2.1.2 * fix: src.tar.zst and srcinfo missing files * feat: add Indonesian language translation * fix: GPU preference hint to Laptop-only * feat: create two columns for settings page * Add Discord invite link to rpc * docs: add recordings form, fix OS list * Release v2.2.0 * Release v2.2.0 * Release v2.2.0 * chore: delete icon.ico, moved to build folder * chore: delete icon.png, moved to build folder * fix: build and release for tag push-only in release.yml * fix: gamescope steam deck issue fixes #186 hopefully * Support branch selection for server patching * chose: add auto-patch system for pre-release JAR * fix: preserves arch x64 on linux target for #242 * fix: removed arm64 flags * fix: redo package.json arch * update package-lock.json * Update release.yml * chore: sync package-lock with package.json * fix: reorder fedora libzstd paths to first iteration * feat: enhance gpu detection, drafting * 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> * chore: rearrange, fix, and improve README.md * chore: link downloads, platform, and version to release page in README.md * chore: update discord link * chore: insert contact link in CODE_OF_CONDUCT.md * fix: missing version text on launcher * chore: update quickstart button link to header * chore: update discord link and give warning quickstart * chore revise online play hosting instructions in README Updated instructions for hosting an online game and clarified troubleshooting steps. * Fix Turkish translations in tr-TR.json * fix: EPERM error in Repair Game Button [windows testing needed] * fix: invalid generated token that caused hangs on exit [windows testing needed] * fix: major bug - hytale won't launch with laptop machine and ghost processes * fix: discord RPC destroy error if not connected * fix: major bug - detach game process to avoid launcher-held handles causing zombie process * docs: add analysis on ghost process and launcher cleanup * revert generateLocalTokens, wrong analysis on game launching issue * revert add deps for generateLocalTokens * Add proxy client and route downloads through it * fix: Prevent JAR file corruption during proxy downloads Fixed binary file corruption when downloading through proxy by using PassThrough stream to preserve data integrity while tracking download progress. * Improve featured servers layout with Discord integration - Add Discord button to server cards when discord link is present in API data - Remove HF2P Servers section to use full width for featured servers - Increase server card size (300x180px banner, larger fonts and spacing) - Simplify layout from 2-column grid to single full-width container - Discord button opens external browser with server invite link * package version to 2.2.1 Update package.json version from 2.2.0 to 2.2.1 to publish a patch release. * fix: add game_running_marker to prevent duplicate launches * Add smart proxy with direct-fallback and logging * fix: remove duplicate check * fix: cache invalidation from .env prevents multiple launch attempts for all env related, it is necessary to clear cache first, otherwise on few launch attempts the game wouldn't run * fix: redact proxy_url and remove timed out emoji * Prepare Release v2.2.1 * docs: enhance bug report template with placeholders and options Updated the bug report template to include placeholders and additional Linux distributions. * chore revise windows prerequisites and changelog Updated prerequisites and changelog for version 2.2.1. * chore: improvise badges, relocate star history, fix discord links * chore: fix release notes for v2.2.1 --------- Co-authored-by: TalesAmaral <57869141+TalesAmaral@users.noreply.github.com> Co-authored-by: walti0 <95646872+walti0@users.noreply.github.com> Co-authored-by: AMIAY <letudiantenrap.collab@gmail.com> Co-authored-by: sanasol <mail@sanasol.ws> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Terromur <79866197+Terromur@users.noreply.github.com> Co-authored-by: Zakhar Smokotov <zaharb840@gmail.com> Co-authored-by: xSamiVS <samtaiebc@gmail.com> Co-authored-by: MetricsLite <66024355+MetricsLite@users.noreply.github.com>
This commit is contained in:
@@ -217,32 +217,16 @@
|
||||
</div>
|
||||
|
||||
<div id="featured-page" class="page">
|
||||
<div class="featured-layout">
|
||||
<div class="featured-left">
|
||||
<div class="featured-header">
|
||||
<h2 class="featured-title">
|
||||
<i class="fas fa-star mr-2"></i>
|
||||
<span>FEATURED SERVERS</span>
|
||||
</h2>
|
||||
</div>
|
||||
<div id="featuredServersList" class="featured-list">
|
||||
<div class="loading-spinner">
|
||||
<i class="fas fa-spinner fa-spin fa-2x"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="featured-container">
|
||||
<div class="featured-header">
|
||||
<h2 class="featured-title">
|
||||
<i class="fas fa-star mr-2"></i>
|
||||
<span>FEATURED SERVERS</span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="featured-right">
|
||||
<div class="featured-header">
|
||||
<h2 class="featured-title">
|
||||
<i class="fas fa-server mr-2"></i>
|
||||
<span>HF2P SERVERS</span>
|
||||
</h2>
|
||||
</div>
|
||||
<div id="myServersList" class="featured-list">
|
||||
<div class="loading-spinner">
|
||||
<i class="fas fa-spinner fa-spin fa-2x"></i>
|
||||
</div>
|
||||
<div id="featuredServersList" class="featured-list">
|
||||
<div class="loading-spinner">
|
||||
<i class="fas fa-spinner fa-spin fa-2x"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -746,6 +730,7 @@
|
||||
|
||||
<div class="version-display-bottom">
|
||||
<i class="fas fa-code-branch"></i>
|
||||
<span id="launcherVersion"></span>
|
||||
</div>
|
||||
|
||||
<footer class="fixed bottom-0 left-0 right-0 z-50 bg-black/80 backdrop-blur-sm px-4 py-2">
|
||||
|
||||
@@ -15,7 +15,6 @@ function escapeHtml(text) {
|
||||
*/
|
||||
async function loadFeaturedServers() {
|
||||
const featuredContainer = document.getElementById('featuredServersList');
|
||||
const myServersContainer = document.getElementById('myServersList');
|
||||
|
||||
try {
|
||||
console.log('[FeaturedServers] Fetching from', FEATURED_SERVERS_API);
|
||||
@@ -54,6 +53,15 @@ async function loadFeaturedServers() {
|
||||
const escapedName = escapeHtml(server.Name || 'Unknown Server');
|
||||
const escapedAddress = escapeHtml(server.Address || '');
|
||||
const bannerUrl = server.img_Banner || 'https://via.placeholder.com/400x240/1e293b/ffffff?text=Server+Banner';
|
||||
const discordUrl = server.discord || '';
|
||||
|
||||
// Build Discord button HTML if discord link exists
|
||||
const discordButton = discordUrl ? `
|
||||
<button class="server-discord-btn" onclick="openServerDiscord('${discordUrl}')">
|
||||
<i class="fab fa-discord"></i>
|
||||
<span>Discord</span>
|
||||
</button>
|
||||
` : '';
|
||||
|
||||
return `
|
||||
<div class="featured-server-card">
|
||||
@@ -67,10 +75,13 @@ async function loadFeaturedServers() {
|
||||
<h3 class="featured-server-name">${escapedName}</h3>
|
||||
<div class="featured-server-address">
|
||||
<span class="server-address-text">${escapedAddress}</span>
|
||||
<button class="copy-address-btn" onclick="copyServerAddress('${escapedAddress}', this)">
|
||||
<i class="fas fa-copy"></i>
|
||||
<span>Copy</span>
|
||||
</button>
|
||||
<div class="server-action-buttons">
|
||||
<button class="copy-address-btn" onclick="copyServerAddress('${escapedAddress}', this)">
|
||||
<i class="fas fa-copy"></i>
|
||||
<span>Copy</span>
|
||||
</button>
|
||||
${discordButton}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -80,13 +91,6 @@ async function loadFeaturedServers() {
|
||||
featuredContainer.innerHTML = featuredHTML;
|
||||
}
|
||||
|
||||
// Show "Coming Soon" for my servers
|
||||
myServersContainer.innerHTML = `
|
||||
<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #94a3b8; font-size: 1.2rem;">
|
||||
<p>Coming Soon</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
} catch (error) {
|
||||
console.error('[FeaturedServers] Error loading servers:', error);
|
||||
featuredContainer.innerHTML = `
|
||||
@@ -96,11 +100,6 @@ async function loadFeaturedServers() {
|
||||
<p style="font-size: 0.9rem; color: #64748b;">${error.message}</p>
|
||||
</div>
|
||||
`;
|
||||
myServersContainer.innerHTML = `
|
||||
<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #94a3b8; font-size: 1.2rem;">
|
||||
<p>Coming Soon</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +150,22 @@ async function copyServerAddress(address, button) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open server Discord in external browser
|
||||
*/
|
||||
function openServerDiscord(discordUrl) {
|
||||
try {
|
||||
console.log('[FeaturedServers] Opening Discord:', discordUrl);
|
||||
if (window.electronAPI && window.electronAPI.openExternal) {
|
||||
window.electronAPI.openExternal(discordUrl);
|
||||
} else {
|
||||
window.open(discordUrl, '_blank');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[FeaturedServers] Failed to open Discord link:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Load featured servers when the featured page becomes visible
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -446,10 +446,27 @@ async function savePlayerName() {
|
||||
return;
|
||||
}
|
||||
|
||||
await window.electronAPI.saveUsername(playerName);
|
||||
const result = await window.electronAPI.saveUsername(playerName);
|
||||
|
||||
// Check if save was successful
|
||||
if (result && result.success === false) {
|
||||
console.error('[Settings] Failed to save username:', result.error);
|
||||
const errorMsg = window.i18n
|
||||
? window.i18n.t('notifications.playerNameSaveFailed')
|
||||
: `Failed to save player name: ${result.error || 'Unknown error'}`;
|
||||
showNotification(errorMsg, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const successMsg = window.i18n ? window.i18n.t('notifications.playerNameSaved') : 'Player name saved successfully';
|
||||
showNotification(successMsg, 'success');
|
||||
|
||||
// Refresh UUID display since it may have changed for the new username
|
||||
await loadCurrentUuid();
|
||||
|
||||
// Also refresh the UUID list to update which entry is marked as current
|
||||
await loadAllUuids();
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error saving player name:', error);
|
||||
const errorMsg = window.i18n ? window.i18n.t('notifications.playerNameSaveFailed') : 'Failed to save player name';
|
||||
@@ -573,11 +590,26 @@ export function getCurrentJavaPath() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get current player name from UI input
|
||||
* Returns null if no name is set (caller must handle this)
|
||||
* NOTE: launcher.js now loads username directly from backend config
|
||||
* This function is used for display purposes only
|
||||
*/
|
||||
export function getCurrentPlayerName() {
|
||||
if (settingsPlayerName && settingsPlayerName.value.trim()) {
|
||||
return settingsPlayerName.value.trim();
|
||||
}
|
||||
return 'Player';
|
||||
// Return null instead of 'Player' - caller must handle missing username
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current player name with fallback for display purposes only
|
||||
* DO NOT use this for launching game - use backend loadUsername() instead
|
||||
*/
|
||||
export function getCurrentPlayerNameForDisplay() {
|
||||
return getCurrentPlayerName() || 'Player';
|
||||
}
|
||||
|
||||
window.openGameLocation = openGameLocation;
|
||||
@@ -587,6 +619,7 @@ document.addEventListener('DOMContentLoaded', initSettings);
|
||||
window.SettingsAPI = {
|
||||
getCurrentJavaPath,
|
||||
getCurrentPlayerName,
|
||||
getCurrentPlayerNameForDisplay,
|
||||
reloadBranch: loadVersionBranch
|
||||
};
|
||||
|
||||
@@ -729,6 +762,9 @@ async function loadAllUuids() {
|
||||
</div>
|
||||
<div class="uuid-item-actions">
|
||||
${mapping.isCurrent ? '<div class="uuid-item-current-badge">Current</div>' : ''}
|
||||
${!mapping.isCurrent ? `<button class="uuid-item-btn switch" onclick="switchToUsername('${escapeHtml(mapping.username)}')" title="Switch to this identity">
|
||||
<i class="fas fa-user-check"></i>
|
||||
</button>` : ''}
|
||||
<button class="uuid-item-btn copy" onclick="copyUuid('${mapping.uuid}')" title="Copy UUID">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
@@ -813,7 +849,17 @@ async function setCustomUuid() {
|
||||
async function performSetCustomUuid(uuid) {
|
||||
try {
|
||||
if (window.electronAPI && window.electronAPI.setUuidForUser) {
|
||||
const username = getCurrentPlayerName();
|
||||
// IMPORTANT: Use saved username from config, not unsaved DOM input
|
||||
// This prevents setting UUID for wrong user if username field was edited but not saved
|
||||
let username = null;
|
||||
if (window.electronAPI.loadUsername) {
|
||||
username = await window.electronAPI.loadUsername();
|
||||
}
|
||||
if (!username) {
|
||||
const msg = window.i18n ? window.i18n.t('notifications.noUsername') : 'No username configured. Please save your username first.';
|
||||
showNotification(msg, 'error');
|
||||
return;
|
||||
}
|
||||
const result = await window.electronAPI.setUuidForUser(username, uuid);
|
||||
|
||||
if (result.success) {
|
||||
@@ -850,6 +896,73 @@ window.copyUuid = async function (uuid) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Switch to a different username/UUID identity
|
||||
* This changes the active username to use that username's UUID
|
||||
*/
|
||||
window.switchToUsername = async function (username) {
|
||||
try {
|
||||
const message = window.i18n
|
||||
? window.i18n.t('confirm.switchUsernameMessage').replace('{username}', username)
|
||||
: `Switch to username "${username}"? This will change your active player identity.`;
|
||||
const title = window.i18n ? window.i18n.t('confirm.switchUsernameTitle') : 'Switch Identity';
|
||||
const confirmBtn = window.i18n ? window.i18n.t('confirm.switchUsernameButton') : 'Switch';
|
||||
const cancelBtn = window.i18n ? window.i18n.t('common.cancel') : 'Cancel';
|
||||
|
||||
showCustomConfirm(
|
||||
message,
|
||||
title,
|
||||
async () => {
|
||||
await performSwitchToUsername(username);
|
||||
},
|
||||
null,
|
||||
confirmBtn,
|
||||
cancelBtn
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error in switchToUsername:', error);
|
||||
const msg = window.i18n ? window.i18n.t('notifications.switchUsernameFailed') : 'Failed to switch username';
|
||||
showNotification(msg, 'error');
|
||||
}
|
||||
};
|
||||
|
||||
async function performSwitchToUsername(username) {
|
||||
try {
|
||||
if (!window.electronAPI || !window.electronAPI.saveUsername) {
|
||||
throw new Error('API not available');
|
||||
}
|
||||
|
||||
const result = await window.electronAPI.saveUsername(username);
|
||||
|
||||
if (result && result.success === false) {
|
||||
throw new Error(result.error || 'Failed to save username');
|
||||
}
|
||||
|
||||
// Update the username input field
|
||||
if (settingsPlayerName) {
|
||||
settingsPlayerName.value = username;
|
||||
}
|
||||
|
||||
// Refresh the current UUID display
|
||||
await loadCurrentUuid();
|
||||
|
||||
// Refresh the UUID list to show new "Current" badge
|
||||
await loadAllUuids();
|
||||
|
||||
const msg = window.i18n
|
||||
? window.i18n.t('notifications.switchUsernameSuccess').replace('{username}', username)
|
||||
: `Switched to "${username}" successfully!`;
|
||||
showNotification(msg, 'success');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error switching username:', error);
|
||||
const msg = window.i18n
|
||||
? window.i18n.t('notifications.switchUsernameFailed')
|
||||
: `Failed to switch username: ${error.message}`;
|
||||
showNotification(msg, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
window.deleteUuid = async function (username) {
|
||||
try {
|
||||
const message = window.i18n ? window.i18n.t('confirm.deleteUuidMessage').replace('{username}', username) : `Are you sure you want to delete the UUID for "${username}"? This action cannot be undone.`;
|
||||
|
||||
@@ -211,7 +211,11 @@
|
||||
"modsDeleteFailed": "Mod konnte nicht gelöscht werden: {error}",
|
||||
"modsModNotFound": "Mod-Informationen nicht gefunden",
|
||||
"hwAccelSaved": "Hardware-Beschleunigungseinstellung gespeichert",
|
||||
"hwAccelSaveFailed": "Hardware-Beschleunigungseinstellung konnte nicht gespeichert werden"
|
||||
"hwAccelSaveFailed": "Hardware-Beschleunigungseinstellung konnte nicht gespeichert werden",
|
||||
"noUsername": "Kein Benutzername konfiguriert. Bitte speichere zuerst deinen Benutzernamen.",
|
||||
"switchUsernameSuccess": "Erfolgreich zu \"{username}\" gewechselt!",
|
||||
"switchUsernameFailed": "Benutzername konnte nicht gewechselt werden",
|
||||
"playerNameTooLong": "Spielername darf maximal 16 Zeichen haben"
|
||||
},
|
||||
"confirm": {
|
||||
"defaultTitle": "Aktion bestätigen",
|
||||
@@ -226,7 +230,10 @@
|
||||
"deleteUuidButton": "Löschen",
|
||||
"uninstallGameTitle": "Spiel deinstallieren",
|
||||
"uninstallGameMessage": "Möchtest du Hytale wirklich deinstallieren? Alle Spieldateien werden gelöscht.",
|
||||
"uninstallGameButton": "Deinstallieren"
|
||||
"uninstallGameButton": "Deinstallieren",
|
||||
"switchUsernameTitle": "Identität wechseln",
|
||||
"switchUsernameMessage": "Zu Benutzername \"{username}\" wechseln? Dies ändert deine aktuelle Spieleridentität.",
|
||||
"switchUsernameButton": "Wechseln"
|
||||
},
|
||||
"progress": {
|
||||
"initializing": "Initialisiere...",
|
||||
|
||||
@@ -211,7 +211,11 @@
|
||||
"modsDeleteFailed": "Failed to delete mod: {error}",
|
||||
"modsModNotFound": "Mod information not found",
|
||||
"hwAccelSaved": "Hardware acceleration setting saved",
|
||||
"hwAccelSaveFailed": "Failed to save hardware acceleration setting"
|
||||
"hwAccelSaveFailed": "Failed to save hardware acceleration setting",
|
||||
"noUsername": "No username configured. Please save your username first.",
|
||||
"switchUsernameSuccess": "Switched to \"{username}\" successfully!",
|
||||
"switchUsernameFailed": "Failed to switch username",
|
||||
"playerNameTooLong": "Player name must be 16 characters or less"
|
||||
},
|
||||
"confirm": {
|
||||
"defaultTitle": "Confirm action",
|
||||
@@ -226,7 +230,10 @@
|
||||
"deleteUuidButton": "Delete",
|
||||
"uninstallGameTitle": "Uninstall game",
|
||||
"uninstallGameMessage": "Are you sure you want to uninstall Hytale? All game files will be deleted.",
|
||||
"uninstallGameButton": "Uninstall"
|
||||
"uninstallGameButton": "Uninstall",
|
||||
"switchUsernameTitle": "Switch Identity",
|
||||
"switchUsernameMessage": "Switch to username \"{username}\"? This will change your current player identity.",
|
||||
"switchUsernameButton": "Switch"
|
||||
},
|
||||
"progress": {
|
||||
"initializing": "Initializing...",
|
||||
|
||||
@@ -211,7 +211,11 @@
|
||||
"modsDeleteFailed": "Error al eliminar mod: {error}",
|
||||
"modsModNotFound": "Información del mod no encontrada",
|
||||
"hwAccelSaved": "Configuración de aceleración por hardware guardada",
|
||||
"hwAccelSaveFailed": "Error al guardar la configuración de aceleración por hardware"
|
||||
"hwAccelSaveFailed": "Error al guardar la configuración de aceleración por hardware",
|
||||
"noUsername": "No hay nombre de usuario configurado. Por favor, guarda tu nombre de usuario primero.",
|
||||
"switchUsernameSuccess": "¡Cambiado a \"{username}\" con éxito!",
|
||||
"switchUsernameFailed": "Error al cambiar nombre de usuario",
|
||||
"playerNameTooLong": "El nombre del jugador debe tener 16 caracteres o menos"
|
||||
},
|
||||
"confirm": {
|
||||
"defaultTitle": "Confirmar acción",
|
||||
@@ -226,7 +230,10 @@
|
||||
"deleteUuidButton": "Eliminar",
|
||||
"uninstallGameTitle": "Desinstalar juego",
|
||||
"uninstallGameMessage": "¿Estás seguro de que quieres desinstalar Hytale? Se eliminarán todos los archivos del juego.",
|
||||
"uninstallGameButton": "Desinstalar"
|
||||
"uninstallGameButton": "Desinstalar",
|
||||
"switchUsernameTitle": "Cambiar identidad",
|
||||
"switchUsernameMessage": "¿Cambiar al nombre de usuario \"{username}\"? Esto cambiará tu identidad de jugador actual.",
|
||||
"switchUsernameButton": "Cambiar"
|
||||
},
|
||||
"progress": {
|
||||
"initializing": "Inicializando...",
|
||||
|
||||
@@ -211,7 +211,11 @@
|
||||
"modsDeleteFailed": "Échec de la suppression du mod: {error}",
|
||||
"modsModNotFound": "Informations du mod introuvables",
|
||||
"hwAccelSaved": "Paramètre d'accélération matérielle sauvegardé",
|
||||
"hwAccelSaveFailed": "Échec de la sauvegarde du paramètre d'accélération matérielle"
|
||||
"hwAccelSaveFailed": "Échec de la sauvegarde du paramètre d'accélération matérielle",
|
||||
"noUsername": "Aucun nom d'utilisateur configuré. Veuillez d'abord enregistrer votre nom d'utilisateur.",
|
||||
"switchUsernameSuccess": "Basculé vers \"{username}\" avec succès!",
|
||||
"switchUsernameFailed": "Échec du changement de nom d'utilisateur",
|
||||
"playerNameTooLong": "Le nom du joueur doit comporter 16 caractères ou moins"
|
||||
},
|
||||
"confirm": {
|
||||
"defaultTitle": "Confirmer l'action",
|
||||
@@ -226,7 +230,10 @@
|
||||
"deleteUuidButton": "Supprimer",
|
||||
"uninstallGameTitle": "Désinstaller le jeu",
|
||||
"uninstallGameMessage": "Êtes-vous sûr de vouloir désinstaller Hytale? Tous les fichiers du jeu seront supprimés.",
|
||||
"uninstallGameButton": "Désinstaller"
|
||||
"uninstallGameButton": "Désinstaller",
|
||||
"switchUsernameTitle": "Changer d'identité",
|
||||
"switchUsernameMessage": "Basculer vers le nom d'utilisateur \"{username}\"? Cela changera votre identité de joueur actuelle.",
|
||||
"switchUsernameButton": "Changer"
|
||||
},
|
||||
"progress": {
|
||||
"initializing": "Initialisation...",
|
||||
|
||||
@@ -211,7 +211,11 @@
|
||||
"modsDeleteFailed": "Gagal menghapus mod: {error}",
|
||||
"modsModNotFound": "Informasi mod tidak ditemukan",
|
||||
"hwAccelSaved": "Pengaturan akselerasi perangkat keras disimpan",
|
||||
"hwAccelSaveFailed": "Gagal menyimpan pengaturan akselerasi perangkat keras"
|
||||
"hwAccelSaveFailed": "Gagal menyimpan pengaturan akselerasi perangkat keras",
|
||||
"noUsername": "Nama pengguna belum dikonfigurasi. Silakan simpan nama pengguna terlebih dahulu.",
|
||||
"switchUsernameSuccess": "Berhasil beralih ke \"{username}\"!",
|
||||
"switchUsernameFailed": "Gagal beralih nama pengguna",
|
||||
"playerNameTooLong": "Nama pemain harus 16 karakter atau kurang"
|
||||
},
|
||||
"confirm": {
|
||||
"defaultTitle": "Konfirmasi tindakan",
|
||||
@@ -226,7 +230,10 @@
|
||||
"deleteUuidButton": "Hapus",
|
||||
"uninstallGameTitle": "Hapus instalasi game",
|
||||
"uninstallGameMessage": "Apakah kamu yakin ingin menghapus instalasi Hytale? Semua file game akan dihapus.",
|
||||
"uninstallGameButton": "Hapus Instalasi"
|
||||
"uninstallGameButton": "Hapus Instalasi",
|
||||
"switchUsernameTitle": "Ganti Identitas",
|
||||
"switchUsernameMessage": "Beralih ke nama pengguna \"{username}\"? Ini akan mengubah identitas pemain saat ini.",
|
||||
"switchUsernameButton": "Ganti"
|
||||
},
|
||||
"progress": {
|
||||
"initializing": "Menginisialisasi...",
|
||||
|
||||
@@ -211,7 +211,11 @@
|
||||
"modsDeleteFailed": "Nie udało się usunąć moda: {error}",
|
||||
"modsModNotFound": "Nie znaleziono informacji o modzie",
|
||||
"hwAccelSaved": "Zapisano ustawienie przyspieszenia sprzętowego",
|
||||
"hwAccelSaveFailed": "Nie udało się zapisać ustawienia przyspieszenia sprzętowego"
|
||||
"hwAccelSaveFailed": "Nie udało się zapisać ustawienia przyspieszenia sprzętowego",
|
||||
"noUsername": "Nie skonfigurowano nazwy użytkownika. Najpierw zapisz swoją nazwę użytkownika.",
|
||||
"switchUsernameSuccess": "Pomyślnie przełączono na \"{username}\"!",
|
||||
"switchUsernameFailed": "Nie udało się przełączyć nazwy użytkownika",
|
||||
"playerNameTooLong": "Nazwa gracza musi mieć 16 znaków lub mniej"
|
||||
},
|
||||
"confirm": {
|
||||
"defaultTitle": "Potwierdź działanie",
|
||||
@@ -226,7 +230,10 @@
|
||||
"deleteUuidButton": "Usuń",
|
||||
"uninstallGameTitle": "Odinstaluj grę",
|
||||
"uninstallGameMessage": "Czy na pewno chcesz odinstalować Hytale? Wszystkie pliki gry zostaną usunięte.",
|
||||
"uninstallGameButton": "Odinstaluj"
|
||||
"uninstallGameButton": "Odinstaluj",
|
||||
"switchUsernameTitle": "Zmień tożsamość",
|
||||
"switchUsernameMessage": "Przełączyć na nazwę użytkownika \"{username}\"? To zmieni Twoją aktualną tożsamość gracza.",
|
||||
"switchUsernameButton": "Przełącz"
|
||||
},
|
||||
"progress": {
|
||||
"initializing": "Inicjalizacja...",
|
||||
|
||||
@@ -211,7 +211,11 @@
|
||||
"modsDeleteFailed": "Falha ao excluir mod: {error}",
|
||||
"modsModNotFound": "Informações do mod não encontradas",
|
||||
"hwAccelSaved": "Configuração de aceleração de hardware salva",
|
||||
"hwAccelSaveFailed": "Falha ao salvar configuração de aceleração de hardware"
|
||||
"hwAccelSaveFailed": "Falha ao salvar configuração de aceleração de hardware",
|
||||
"noUsername": "Nenhum nome de usuário configurado. Por favor, salve seu nome de usuário primeiro.",
|
||||
"switchUsernameSuccess": "Alterado para \"{username}\" com sucesso!",
|
||||
"switchUsernameFailed": "Falha ao trocar nome de usuário",
|
||||
"playerNameTooLong": "O nome do jogador deve ter 16 caracteres ou menos"
|
||||
},
|
||||
"confirm": {
|
||||
"defaultTitle": "Confirmar ação",
|
||||
@@ -226,7 +230,10 @@
|
||||
"deleteUuidButton": "Excluir",
|
||||
"uninstallGameTitle": "Desinstalar jogo",
|
||||
"uninstallGameMessage": "Tem certeza de que deseja desinstalar Hytale? Todos os arquivos do jogo serão excluídos.",
|
||||
"uninstallGameButton": "Desinstalar"
|
||||
"uninstallGameButton": "Desinstalar",
|
||||
"switchUsernameTitle": "Trocar Identidade",
|
||||
"switchUsernameMessage": "Trocar para o nome de usuário \"{username}\"? Isso mudará sua identidade de jogador atual.",
|
||||
"switchUsernameButton": "Trocar"
|
||||
},
|
||||
"progress": {
|
||||
"initializing": "Inicializando...",
|
||||
|
||||
@@ -211,7 +211,11 @@
|
||||
"modsDeleteFailed": "Не получилось удалить мод: {error}",
|
||||
"modsModNotFound": "Информация по моду не найдена",
|
||||
"hwAccelSaved": "Настройка аппаратного ускорения сохранена!",
|
||||
"hwAccelSaveFailed": "Не удалось сохранить настройку аппаратного ускорения"
|
||||
"hwAccelSaveFailed": "Не удалось сохранить настройку аппаратного ускорения",
|
||||
"noUsername": "Имя пользователя не настроено. Пожалуйста, сначала сохраните имя пользователя.",
|
||||
"switchUsernameSuccess": "Успешно переключено на \"{username}\"!",
|
||||
"switchUsernameFailed": "Не удалось переключить имя пользователя",
|
||||
"playerNameTooLong": "Имя игрока должно быть не более 16 символов"
|
||||
},
|
||||
"confirm": {
|
||||
"defaultTitle": "Подтвердить действие",
|
||||
@@ -226,7 +230,10 @@
|
||||
"deleteUuidButton": "Удалить",
|
||||
"uninstallGameTitle": "Удалить игру",
|
||||
"uninstallGameMessage": "Вы уверены, что хотите удалить Hytale? Все данные игры будут безвозвратно удалены!",
|
||||
"uninstallGameButton": "Удалить"
|
||||
"uninstallGameButton": "Удалить",
|
||||
"switchUsernameTitle": "Сменить личность",
|
||||
"switchUsernameMessage": "Переключиться на имя пользователя \"{username}\"? Это изменит вашу текущую личность игрока.",
|
||||
"switchUsernameButton": "Переключить"
|
||||
},
|
||||
"progress": {
|
||||
"initializing": "Инициализация...",
|
||||
|
||||
@@ -211,7 +211,11 @@
|
||||
"modsDeleteFailed": "Misslyckades med att ta bort modd: {error}",
|
||||
"modsModNotFound": "Moddinformation hittades inte",
|
||||
"hwAccelSaved": "Hårdvaruaccelerationsinställning sparad",
|
||||
"hwAccelSaveFailed": "Misslyckades med att spara hårdvaruaccelerationsinställning"
|
||||
"hwAccelSaveFailed": "Misslyckades med att spara hårdvaruaccelerationsinställning",
|
||||
"noUsername": "Inget användarnamn konfigurerat. Vänligen spara ditt användarnamn först.",
|
||||
"switchUsernameSuccess": "Bytte till \"{username}\" framgångsrikt!",
|
||||
"switchUsernameFailed": "Misslyckades med att byta användarnamn",
|
||||
"playerNameTooLong": "Spelarnamnet måste vara 16 tecken eller mindre"
|
||||
},
|
||||
"confirm": {
|
||||
"defaultTitle": "Bekräfta åtgärd",
|
||||
@@ -226,7 +230,10 @@
|
||||
"deleteUuidButton": "Ta bort",
|
||||
"uninstallGameTitle": "Avinstallera spel",
|
||||
"uninstallGameMessage": "Är du säker på att du vill avinstallera Hytale? Alla spelfiler kommer att tas bort.",
|
||||
"uninstallGameButton": "Avinstallera"
|
||||
"uninstallGameButton": "Avinstallera",
|
||||
"switchUsernameTitle": "Byt identitet",
|
||||
"switchUsernameMessage": "Byta till användarnamn \"{username}\"? Detta kommer att ändra din nuvarande spelaridentitet.",
|
||||
"switchUsernameButton": "Byt"
|
||||
},
|
||||
"progress": {
|
||||
"initializing": "Initierar...",
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
"installationFolder": "Kurulum Klasörü",
|
||||
"pathPlaceholder": "Varsayılan konum",
|
||||
"browse": "Gözat",
|
||||
"installButton": "HYTALE KURU",
|
||||
"installButton": "HYTALE KUR",
|
||||
"installing": "KURULUYOR..."
|
||||
},
|
||||
"play": {
|
||||
"ready": "OYNAMAYA HAZIR",
|
||||
"subtitle": "Hytale'i başlat ve maceraya başla",
|
||||
"playButton": "HYTALE'YI OYNA",
|
||||
"subtitle": "Hytale'ı başlat ve maceraya başla",
|
||||
"playButton": "HYTALE'I OYNA",
|
||||
"latestNews": "SON HABERLER",
|
||||
"viewAll": "HEPSINI GÖR",
|
||||
"checking": "KONTROL EDİLİYOR...",
|
||||
@@ -47,13 +47,13 @@
|
||||
"noModsInstalled": "Hiçbir Mod Kurulu Değil",
|
||||
"noModsInstalledDesc": "CurseForge'dan modlar ekleyin veya yerel dosyalar içe aktarın",
|
||||
"view": "GÖR",
|
||||
"install": "KURU",
|
||||
"install": "KUR",
|
||||
"installed": "KURULU",
|
||||
"enable": "ETKİNLEŞTİR",
|
||||
"disable": "DEĞİ",
|
||||
"enable": "AÇ",
|
||||
"disable": "KAPAT",
|
||||
"active": "AKTİF",
|
||||
"disabled": "DEĞİ",
|
||||
"delete": "Modı sil",
|
||||
"disabled": "DEVREDIŞI",
|
||||
"delete": "Modu sil",
|
||||
"noDescription": "Açıklama yok",
|
||||
"confirmDelete": "\"{name}\" öğesini silmek istediğinizden emin misiniz?",
|
||||
"confirmDeleteDesc": "Bu işlem geri alınamaz.",
|
||||
@@ -67,7 +67,7 @@
|
||||
},
|
||||
"chat": {
|
||||
"title": "OYUNCU SOHBETI",
|
||||
"pickColor": "Renk",
|
||||
"pickColor": "Renk Seç",
|
||||
"inputPlaceholder": "Mesajınızı yazın...",
|
||||
"send": "Gönder",
|
||||
"online": "çevrimiçi",
|
||||
@@ -116,7 +116,7 @@
|
||||
"manageUUIDsDesc": "Tüm oyuncu UUID'lerini görüntüleyin ve yönetin",
|
||||
"language": "Dil",
|
||||
"selectLanguage": "Dil Seçin",
|
||||
"repairGame": "Oyunu Onarı",
|
||||
"repairGame": "Oyunu Düzelt",
|
||||
"reinstallGame": "Oyun dosyalarını yeniden kur (veri korur)",
|
||||
"gpuPreference": "GPU Tercihi",
|
||||
"gpuHint": "Sadece dizüstü bilgisayarlarda bulunan bir özellik; PC'de kullanılıyorsa Entegre olarak ayarlayın.",
|
||||
@@ -211,7 +211,11 @@
|
||||
"modsDeleteFailed": "Mod silinemedi: {error}",
|
||||
"modsModNotFound": "Mod bilgileri bulunamadı",
|
||||
"hwAccelSaved": "Donanım hızlandırma ayarı kaydedildi",
|
||||
"hwAccelSaveFailed": "Donanım hızlandırma ayarı kaydedilemedi"
|
||||
"hwAccelSaveFailed": "Donanım hızlandırma ayarı kaydedilemedi",
|
||||
"noUsername": "Kullanıcı adı yapılandırılmadı. Lütfen önce kullanıcı adınızı kaydedin.",
|
||||
"switchUsernameSuccess": "\"{username}\" adına başarıyla geçildi!",
|
||||
"switchUsernameFailed": "Kullanıcı adı değiştirilemedi",
|
||||
"playerNameTooLong": "Oyuncu adı 16 karakter veya daha az olmalıdır"
|
||||
},
|
||||
"confirm": {
|
||||
"defaultTitle": "Eylemi onayla",
|
||||
@@ -226,7 +230,10 @@
|
||||
"deleteUuidButton": "Sil",
|
||||
"uninstallGameTitle": "Oyunu kaldır",
|
||||
"uninstallGameMessage": "Hytale'yi kaldırmak istediğinizden emin misiniz? Tüm oyun dosyaları silinecektir.",
|
||||
"uninstallGameButton": "Kaldır"
|
||||
"uninstallGameButton": "Kaldır",
|
||||
"switchUsernameTitle": "Kimlik Değiştir",
|
||||
"switchUsernameMessage": "\"{username}\" kullanıcı adına geçilsin mi? Bu mevcut oyuncu kimliğinizi değiştirecektir.",
|
||||
"switchUsernameButton": "Değiştir"
|
||||
},
|
||||
"progress": {
|
||||
"initializing": "Başlatılıyor...",
|
||||
@@ -247,4 +254,5 @@
|
||||
"installingGameFiles": "Oyun dosyaları kuruluyor...",
|
||||
"installComplete": "Kurulum tamamlandı!"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1005,20 +1005,12 @@ body {
|
||||
}
|
||||
|
||||
/* Featured Servers Styles */
|
||||
.featured-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 2rem;
|
||||
height: calc(100vh - 180px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.featured-left,
|
||||
.featured-right {
|
||||
.featured-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100vh - 180px);
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
.featured-header {
|
||||
@@ -1074,8 +1066,8 @@ body {
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||
display: grid;
|
||||
grid-template-columns: 200px 1fr;
|
||||
min-height: 120px;
|
||||
grid-template-columns: 300px 1fr;
|
||||
min-height: 180px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -1086,24 +1078,24 @@ body {
|
||||
}
|
||||
|
||||
.featured-server-banner {
|
||||
width: 200px;
|
||||
width: 300px;
|
||||
height: 100%;
|
||||
min-height: 120px;
|
||||
min-height: 180px;
|
||||
object-fit: cover;
|
||||
background: linear-gradient(135deg, #1e293b, #334155);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.featured-server-content {
|
||||
padding: 1.25rem;
|
||||
padding: 1.5rem 2rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 0.75rem;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.featured-server-name {
|
||||
font-size: 1.15rem;
|
||||
font-size: 1.35rem;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
line-height: 1.4;
|
||||
@@ -1118,27 +1110,40 @@ body {
|
||||
padding: 0.625rem 1rem;
|
||||
border-radius: 6px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.server-address-text {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
color: #94a3b8;
|
||||
font-size: 0.9rem;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.server-action-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.copy-address-btn {
|
||||
background: linear-gradient(135deg, #9333ea, #7c3aed);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0.5rem 1rem;
|
||||
padding: 0.5rem 0.875rem;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 0.875rem;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
gap: 0.375rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -1155,6 +1160,31 @@ body {
|
||||
background: linear-gradient(135deg, #10b981, #059669);
|
||||
}
|
||||
|
||||
.server-discord-btn {
|
||||
background: linear-gradient(135deg, #5865F2, #4752C4);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0.5rem 0.875rem;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.server-discord-btn:hover {
|
||||
background: linear-gradient(135deg, #4752C4, #3c45a5);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.server-discord-btn:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -5236,6 +5266,21 @@ select.settings-input option {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 0.875rem;
|
||||
letter-spacing: 0.5px;
|
||||
-webkit-user-select: text !important;
|
||||
-moz-user-select: text !important;
|
||||
-ms-user-select: text !important;
|
||||
user-select: text !important;
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
/* Ensure all input fields allow text selection and paste */
|
||||
input[type="text"].uuid-input,
|
||||
#customUuidInput {
|
||||
-webkit-user-select: text !important;
|
||||
-moz-user-select: text !important;
|
||||
-ms-user-select: text !important;
|
||||
user-select: text !important;
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
.uuid-btn {
|
||||
@@ -5623,6 +5668,12 @@ select.settings-input option {
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
.uuid-item-btn.switch:hover {
|
||||
background: rgba(59, 130, 246, 0.2);
|
||||
border-color: rgba(59, 130, 246, 0.4);
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.uuid-modal-content {
|
||||
width: 95vw;
|
||||
|
||||
Reference in New Issue
Block a user