/** * Live Main Menu System * Handles server authentication, server browser, and multiplayer game initialization */ console.log('[LIVE MAIN MENU] LiveMainMenu.js script loaded'); class LiveMainMenu { constructor() { console.log('[LIVE MAIN MENU] Constructor called'); // Check if DOM is ready if (document.readyState === 'loading') { console.warn('[LIVE MAIN MENU] DOM not ready yet, elements may not be found'); } else { console.log('[LIVE MAIN MENU] DOM is ready'); } this.mainMenu = document.getElementById('mainMenu'); console.log('[LIVE MAIN MENU] Main menu element found:', !!this.mainMenu); this.selectedServer = null; this.authToken = null; this.currentUser = null; this.servers = []; // Renamed from serverList to avoid conflict with DOM element this.apiBaseUrl = 'https://api.korvarix.com/api'; // API Server URL this.gameServerUrl = 'https://dev.gameserver.galaxystrike.online'; // Game Server URL for Socket.IO this.localGameServerUrl = 'http://localhost:3002'; // Local Game Server URL this.isLocalMode = false; // Track if we're in local mode console.log('[LIVE MAIN MENU] Initializing elements'); this.initializeElements(); console.log('[LIVE MAIN MENU] Initializing event listeners'); this.bindEvents(); // Check for existing auth token this.checkExistingAuth(); // DISABLE local server check - always use remote multiplayer server // this.checkForLocalServer(); console.log('[LIVE MAIN MENU] Local server check disabled - using remote multiplayer server only'); console.log('[LIVE MAIN MENU] Using remote API:', this.apiBaseUrl); console.log('[LIVE MAIN MENU] Using remote game server:', this.gameServerUrl); // Initialize SmartSaveManager to singleplayer mode by default if (window.smartSaveManager) { window.smartSaveManager.setMultiplayerMode(false); } console.log('[LIVE MAIN MENU] Constructor completed'); } initializeElements() { // Menu sections this.loginSection = document.getElementById('loginSection'); this.serverSection = document.getElementById('serverSection'); this.serverConfirmSection = document.getElementById('serverConfirmSection'); this.optionsSection = document.getElementById('optionsSection'); // Login form elements this.emailInput = document.getElementById('emailInput'); this.passwordInput = document.getElementById('passwordInput'); this.loginBtn = document.getElementById('loginBtn'); this.registerBtn = document.getElementById('registerBtn'); this.loginNotice = document.getElementById('loginNotice'); // Server browser elements this.createServerBtn = document.getElementById('createServerBtn'); this.refreshServersBtn = document.getElementById('refreshServersBtn'); this.regionFilter = document.getElementById('regionFilter'); this.typeFilter = document.getElementById('typeFilter'); this.serverList = document.getElementById('serverList'); this.serverLoading = document.getElementById('serverLoading'); this.serverEmpty = document.getElementById('serverEmpty'); // Server confirmation elements this.joinServerBtn = document.getElementById('joinServerBtn'); this.serverInfoBtn = document.getElementById('serverInfoBtn'); this.leaveServerBtn = document.getElementById('leaveServerBtn'); // Server detail elements this.selectedServerName = document.getElementById('selectedServerName'); this.selectedServerType = document.getElementById('selectedServerType'); this.selectedServerRegion = document.getElementById('selectedServerRegion'); this.selectedServerPlayers = document.getElementById('selectedServerPlayers'); this.selectedServerOwner = document.getElementById('selectedServerOwner'); // Navigation buttons this.backToLoginBtn = document.getElementById('backToLoginBtn'); this.backToServersBtn = document.getElementById('backToServersBtn'); console.log('[LIVE MAIN MENU] All elements initialized'); } bindEvents() { console.log('[LIVE MAIN MENU] Binding events...'); // Login events if (this.loginBtn) { this.loginBtn.addEventListener('click', () => this.handleLogin()); console.log('[LIVE MAIN MENU] Login button event bound'); } else { console.warn('[LIVE MAIN MENU] Login button not found'); } if (this.registerBtn) { this.registerBtn.addEventListener('click', () => this.handleRegister()); console.log('[LIVE MAIN MENU] Register button event bound'); } else { console.warn('[LIVE MAIN MENU] Register button not found'); } // Enter key login if (this.passwordInput) { this.passwordInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') this.handleLogin(); }); console.log('[LIVE MAIN MENU] Password input event bound'); } else { console.warn('[LIVE MAIN MENU] Password input not found'); } // Server browser events if (this.createServerBtn) { this.createServerBtn.addEventListener('click', () => this.startLocalServer()); console.log('[LIVE MAIN MENU] Create server button event bound (now starts local server)'); } else { console.warn('[LIVE MAIN MENU] Create server button not found'); } if (this.refreshServersBtn) { this.refreshServersBtn.addEventListener('click', () => this.refreshServerListWithoutAnimation()); console.log('[LIVE MAIN MENU] Refresh servers button event bound'); } else { console.warn('[LIVE MAIN MENU] Refresh servers button not found'); } if (this.regionFilter) { this.regionFilter.addEventListener('change', () => this.filterServers()); console.log('[LIVE MAIN MENU] Region filter event bound'); } else { console.warn('[LIVE MAIN MENU] Region filter not found'); } if (this.typeFilter) { this.typeFilter.addEventListener('change', () => this.filterServers()); console.log('[LIVE MAIN MENU] Type filter event bound'); } else { console.warn('[LIVE MAIN MENU] Type filter not found'); } // Server confirmation events if (this.joinServerBtn) { this.joinServerBtn.addEventListener('click', () => this.joinServer()); console.log('[LIVE MAIN MENU] Join server button event bound'); } else { console.warn('[LIVE MAIN MENU] Join server not found'); } // Navigation events if (this.backToLoginBtn) { this.backToLoginBtn.addEventListener('click', () => this.showLoginSection()); console.log('[LIVE MAIN MENU] Back to login button event bound'); } else { console.warn('[LIVE MAIN MENU] Back to login button not found'); } if (this.backToServersBtn) { this.backToServersBtn.addEventListener('click', () => this.showServerSection()); console.log('[LIVE MAIN MENU] Back to servers button event bound'); } else { console.warn('[LIVE MAIN MENU] Back to servers button not found'); } console.log('[LIVE MAIN MENU] All events bound (with warnings for missing elements)'); } checkExistingAuth() { const token = localStorage.getItem('authToken'); const user = localStorage.getItem('currentUser'); if (token && user) { this.authToken = token; this.currentUser = JSON.parse(user); console.log('[LIVE MAIN MENU] Found existing auth token, validating...'); this.validateToken(); } else { console.log('[LIVE MAIN MENU] No existing auth found'); this.showLoginSection(); } } async validateToken() { try { const response = await fetch(`${this.apiBaseUrl}/auth/verify`, { method: 'GET', headers: { 'Authorization': `Bearer ${this.authToken}`, 'Content-Type': 'application/json' } }); if (response.ok) { const data = await response.json(); this.currentUser = data.user; localStorage.setItem('currentUser', JSON.stringify(this.currentUser)); console.log('[LIVE MAIN MENU] Token validated successfully'); this.showServerSection(); } else { console.log('[LIVE MAIN MENU] Token invalid, clearing auth'); this.clearAuth(); this.showLoginSection(); } } catch (error) { console.error('[LIVE MAIN MENU] Token validation failed:', error); this.clearAuth(); this.showLoginSection(); } } clearAuth() { this.authToken = null; this.currentUser = null; localStorage.removeItem('authToken'); localStorage.removeItem('currentUser'); } showSection(sectionName, animate = true) { // Don't re-animate if we're showing the same section if (this.currentSection === sectionName) { animate = false; } // Hide all sections this.loginSection?.classList.add('hidden'); this.serverSection?.classList.add('hidden'); this.serverConfirmSection?.classList.add('hidden'); this.optionsSection?.classList.add('hidden'); // Show selected section const section = document.getElementById(`${sectionName}Section`); if (section) { section.classList.remove('hidden'); // Control animation if (animate) { section.style.animation = 'fadeInUp 0.5s ease-out'; } else { section.style.animation = 'none'; } this.currentSection = sectionName; } } showLoginSection() { this.showSection('login'); this.clearLoginForm(); } showServerSection(refreshServers = true, animate = true) { this.showSection('server', animate); if (refreshServers) { this.refreshServerList(); } } showServerConfirmSection() { this.showSection('serverConfirm'); this.updateServerConfirmSection(); } clearLoginForm() { if (this.emailInput) this.emailInput.value = ''; if (this.passwordInput) this.passwordInput.value = ''; this.clearLoginNotice(); } clearLoginNotice() { if (this.loginNotice) { this.loginNotice.innerHTML = `
Connect to the live server to play
Note: You need an internet connection to play Galaxy Strike Online.
`; } } showLoginNotice(message, type = 'info') { if (this.loginNotice) { const iconClass = type === 'error' ? 'fa-exclamation-triangle' : type === 'success' ? 'fa-check-circle' : 'fa-info-circle'; this.loginNotice.innerHTML = `${message}
`; this.loginNotice.className = `login-notice ${type}`; this.loginNotice.style.display = 'block'; } } hideLoginNotice() { if (this.loginNotice) { this.loginNotice.style.display = 'none'; } } async handleLogin() { const email = this.emailInput?.value?.trim(); const password = this.passwordInput?.value?.trim(); if (!email || !password) { this.showLoginNotice('Please enter email and password', 'error'); return; } // Disable login button if (this.loginBtn) { this.loginBtn.disabled = true; this.loginBtn.innerHTML = ' Logging in...'; } try { const response = await fetch(`${this.apiBaseUrl}/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) }); // Check if response is HTML (error page) instead of JSON const contentType = response.headers.get('content-type'); if (!contentType || !contentType.includes('application/json')) { throw new Error('API server is not available. Please check your connection.'); } const data = await response.json(); if (response.ok) { this.authToken = data.token; this.currentUser = data.user; // Save to localStorage localStorage.setItem('authToken', this.authToken); localStorage.setItem('currentUser', JSON.stringify(this.currentUser)); this.showLoginNotice('Login successful!', 'success'); console.log('[LIVE MAIN MENU] Login successful'); // Show server browser after a short delay setTimeout(() => this.showServerSection(), 1000); } else { this.showLoginNotice(data.error || 'Login failed', 'error'); } } catch (error) { console.error('[LIVE MAIN MENU] Login error:', error); this.showLoginNotice('Connection error. Please try again.', 'error'); } finally { // Re-enable login button if (this.loginBtn) { this.loginBtn.disabled = false; this.loginBtn.innerHTML = ' Login'; } } } async handleRegister() { const email = this.emailInput?.value?.trim(); const password = this.passwordInput?.value?.trim(); if (!email || !password) { this.showLoginNotice('Please enter email and password', 'error'); return; } if (password.length < 6) { this.showLoginNotice('Password must be at least 6 characters', 'error'); return; } // Disable register button if (this.registerBtn) { this.registerBtn.disabled = true; this.registerBtn.innerHTML = ' Registering...'; } try { // Generate a username from email const username = email.split('@')[0]; const response = await fetch(`${this.apiBaseUrl}/auth/register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, email, password }) }); // Check if response is HTML (error page) instead of JSON const contentType = response.headers.get('content-type'); if (!contentType || !contentType.includes('application/json')) { throw new Error('API server is not available. Please check your connection.'); } const data = await response.json(); if (response.ok) { this.authToken = data.token; this.currentUser = data.user; // Save to localStorage localStorage.setItem('authToken', this.authToken); localStorage.setItem('currentUser', JSON.stringify(this.currentUser)); this.showLoginNotice('Registration successful!', 'success'); console.log('[LIVE MAIN MENU] Registration successful'); // Show server browser after a short delay setTimeout(() => this.showServerSection(), 1000); } else { this.showLoginNotice(data.error || 'Registration failed', 'error'); } } catch (error) { console.error('[LIVE MAIN MENU] Registration error:', error); this.showLoginNotice('Connection error. Please try again.', 'error'); } finally { // Re-enable register button if (this.registerBtn) { this.registerBtn.disabled = false; this.registerBtn.innerHTML = ' Register'; } } } async refreshServerListWithoutAnimation() { // Ensure we're in server section without animation if (this.currentSection !== 'server') { this.showServerSection(true, false); // Refresh but don't animate } else { // Already in server section, just refresh await this.refreshServerList(); } } async refreshServerList() { // Build server list with local server, dev server, and API servers const servers = []; if (!this.authToken) { console.error('[LIVE MAIN MENU] No auth token for server list'); return; } // Show loading state if (this.serverLoading) this.serverLoading.classList.remove('hidden'); if (this.serverEmpty) this.serverEmpty.classList.add('hidden'); try { let response; // Add local server if available if (this.isLocalMode && window.localServerManager && window.localServerManager.localServer && window.localServerManager.localServer.mockRequest) { console.log('[LIVE MAIN MENU] Using SimpleLocalServer mock API for local server'); const localResponse = await window.localServerManager.localServer.mockRequest('GET', '/api/servers'); if (localResponse.success && localResponse.servers) { servers.push(...localResponse.servers); } } // Skip local dev server check to avoid blocking console.log('[LIVE MAIN MENU] Skipping local dev server check to avoid blocking'); // Add API servers console.log('[LIVE MAIN MENU] Fetching server list from:', `${this.apiBaseUrl}/servers`); const apiResponse = await fetch(`${this.apiBaseUrl}/servers`, { method: 'GET', headers: { 'Authorization': `Bearer ${this.authToken}`, 'Content-Type': 'application/json' } }); if (apiResponse.ok) { const apiData = await apiResponse.json(); if (apiData.success && apiData.servers) { servers.push(...apiData.servers); console.log(`[LIVE MAIN MENU] Server list loaded: ${servers.length} servers found`); // Debug: Log server list data console.log('[LIVE MAIN MENU] Server list loaded:', servers); if (servers.length > 0) { console.log('[LIVE MAIN MENU] First server details:', servers[0]); } } } } catch (error) { console.error('[LIVE MAIN MENU] Error fetching server list:', error); this.showLoginNotice('Connection error. Please try again.', 'error'); } finally { // Hide loading state if (this.serverLoading) this.serverLoading.classList.add('hidden'); } // Store servers this.servers = servers; // Render server list this.renderServerList(); } renderServerList() { const filteredServers = this.getFilteredServers(); // Handle empty state if (filteredServers.length === 0) { if (this.serverEmpty) this.serverEmpty.classList.remove('hidden'); // Remove existing server items smoothly this.removeServerItemsSmoothly(); return; } else { if (this.serverEmpty) this.serverEmpty.classList.add('hidden'); } // Get current server items const currentItems = this.serverList?.querySelectorAll('.server-item') || []; // Create new server items HTML const serverListHtml = filteredServers.map(server => this.createServerItem(server)).join(''); // Create a temporary container to hold new items const tempDiv = document.createElement('div'); tempDiv.innerHTML = serverListHtml; const newItems = Array.from(tempDiv.querySelectorAll('.server-item')); // Smooth update: fade out current items, then replace with new ones this.updateServerItemsSmoothly(currentItems, newItems); } removeServerItemsSmoothly() { const existingItems = this.serverList?.querySelectorAll('.server-item') || []; if (existingItems.length === 0) return; // Add fade-out transition existingItems.forEach(item => { item.style.transition = 'opacity 0.2s ease-out'; item.style.opacity = '0'; }); // Remove items after fade out setTimeout(() => { existingItems.forEach(item => item.remove()); }, 200); } removeServerItemsSmoothly() { const existingItems = this.serverList?.querySelectorAll('.server-item') || []; if (existingItems.length === 0) return; // Add fade-out transition existingItems.forEach(item => { item.style.transition = 'opacity 0.2s ease-out'; item.style.opacity = '0'; }); // Remove items after fade out setTimeout(() => { existingItems.forEach(item => item.remove()); }, 200); } updateServerItemsSmoothly(currentItems, newItems) { // Fade out current items if (currentItems.length > 0) { currentItems.forEach(item => { item.style.transition = 'opacity 0.2s ease-out'; item.style.opacity = '0'; }); // Replace with new items after fade out setTimeout(() => { currentItems.forEach(item => item.remove()); this.addNewServerItems(newItems); }, 200); } else { // No current items, add new ones immediately this.addNewServerItems(newItems); } } addNewServerItems(newItems) { if (!this.serverList) return; // Add fade-in transition to new items newItems.forEach(item => { item.style.transition = 'opacity 0.3s ease-in'; item.style.opacity = '0'; }); // Add new items to DOM newItems.forEach(item => { this.serverList.appendChild(item); }); // Add click handlers newItems.forEach(item => { item.addEventListener('click', () => { const serverId = item.dataset.serverId; this.selectServer(serverId); }); }); // Fade in new items setTimeout(() => { newItems.forEach(item => { item.style.opacity = '1'; }); }, 50); } createServerItem(server) { const playerCount = `${server.currentPlayers}/${server.maxPlayers}`; const createdDate = new Date(server.createdAt).toLocaleDateString(); return `