diff --git a/public/js/auth.js b/public/js/auth.js index 61f9cca..303bde8 100644 --- a/public/js/auth.js +++ b/public/js/auth.js @@ -2,122 +2,140 @@ // Эта функция будет вызвана из main.js и получит необходимые зависимости export function initAuth(dependencies) { + console.log('[Auth.js] initAuth called. Dependencies received:', !!dependencies); // <--- ДОБАВЛЕНО + const { socket, clientState, ui } = dependencies; - const { loginForm, registerForm, logoutButton } = ui.elements; // Получаем нужные DOM элементы + const { loginForm, registerForm, logoutButton } = ui.elements; + + console.log('[Auth.js DOM Check] loginForm in initAuth:', loginForm); // <--- ДОБАВЛЕНО + console.log('[Auth.js DOM Check] registerForm in initAuth:', registerForm); // <--- ДОБАВЛЕНО + console.log('[Auth.js DOM Check] logoutButton in initAuth:', logoutButton); // <--- ДОБАВЛЕНО - // URL вашего API сервера. В данной версии main.js не передает API_BASE_URL, - // предполагая, что fetch будет использовать относительные пути к текущему домену. - // Если ваш main.js снова будет передавать API_BASE_URL, раскомментируйте и используйте его. - // const API_BASE_URL = dependencies.API_BASE_URL || ''; // Пустая строка заставит fetch использовать относительные пути - // Если API на другом домене, API_BASE_URL обязателен. Для относительных путей: const getApiUrl = (path) => `${window.location.origin}${path}`; + console.log('[Auth.js] API URLs will be relative to:', window.location.origin); // <--- ДОБАВЛЕНО - - // Название ключа для хранения JWT в localStorage const JWT_TOKEN_KEY = 'jwtToken'; async function handleAuthResponse(response, formType) { + console.log(`[Auth.js handleAuthResponse] Handling response for form: ${formType}. Response status: ${response.status}`); // <--- ДОБАВЛЕНО const regButton = registerForm ? registerForm.querySelector('button') : null; const loginButton = loginForm ? loginForm.querySelector('button') : null; try { const data = await response.json(); + console.log(`[Auth.js handleAuthResponse] Parsed data for ${formType}:`, data); // <--- ДОБАВЛЕНО if (response.ok && data.success && data.token) { - // Успешная аутентификация/регистрация - localStorage.setItem(JWT_TOKEN_KEY, data.token); // Сохраняем токен + console.log(`[Auth.js handleAuthResponse] ${formType} successful. Token received.`); // <--- ДОБАВЛЕНО + localStorage.setItem(JWT_TOKEN_KEY, data.token); clientState.isLoggedIn = true; clientState.loggedInUsername = data.username; clientState.myUserId = data.userId; + console.log('[Auth.js handleAuthResponse] Client state updated:', JSON.parse(JSON.stringify(clientState))); // <--- ДОБАВЛЕНО - ui.setAuthMessage(''); // Очищаем сообщение об аутентификации - ui.showGameSelectionScreen(data.username); // Показываем экран выбора игры - // Важно: переподключить сокет с новым токеном + ui.setAuthMessage(''); + ui.showGameSelectionScreen(data.username); + + console.log('[Auth.js handleAuthResponse] Disconnecting and reconnecting socket with new token.'); // <--- ДОБАВЛЕНО if (socket.connected) { - socket.disconnect(); // Отключаемся, чтобы при следующем connect отправился новый токен + socket.disconnect(); } - // Обновляем auth объект сокета перед подключением - // socket.io клиент автоматически подхватит новый токен из localStorage при следующем .connect(), - // если он был инициализирован с auth: () => { token: localStorage.getItem(...) } - // или мы можем явно установить его здесь: socket.auth = { token: data.token }; - socket.connect(); // Это вызовет 'connect' и 'requestGameState' в main.js + socket.connect(); } else { - // Ошибка аутентификации/регистрации + console.warn(`[Auth.js handleAuthResponse] ${formType} failed or token missing. Message: ${data.message}`); // <--- ДОБАВЛЕНО clientState.isLoggedIn = false; clientState.loggedInUsername = ''; clientState.myUserId = null; - localStorage.removeItem(JWT_TOKEN_KEY); // Удаляем старый токен, если был + localStorage.removeItem(JWT_TOKEN_KEY); ui.setAuthMessage(data.message || 'Ошибка сервера.', true); } } catch (error) { - // Ошибка парсинга JSON или другая сетевая ошибка - console.error(`[Auth] Error processing ${formType} response:`, error); + console.error(`[Auth.js handleAuthResponse] Error processing ${formType} response JSON or other:`, error); // <--- ДОБАВЛЕНО clientState.isLoggedIn = false; clientState.loggedInUsername = ''; clientState.myUserId = null; localStorage.removeItem(JWT_TOKEN_KEY); - ui.setAuthMessage('Произошла ошибка сети. Попробуйте снова.', true); + ui.setAuthMessage('Произошла ошибка сети или ответа сервера. Попробуйте снова.', true); } finally { - // Разблокируем кнопки в любом случае + console.log(`[Auth.js handleAuthResponse] Re-enabling buttons for ${formType}.`); // <--- ДОБАВЛЕНО if (regButton) regButton.disabled = false; if (loginButton) loginButton.disabled = false; - // Кнопка logout управляется состоянием isLoggedIn и видимостью экрана } } // --- Обработчики событий DOM --- if (registerForm) { + console.log('[Auth.js] Attaching submit listener to registerForm.'); // <--- ДОБАВЛЕНО registerForm.addEventListener('submit', async (e) => { e.preventDefault(); + console.log('[Auth.js] Register form submitted.'); // <--- ДОБАВЛЕНО + const usernameInput = document.getElementById('register-username'); const passwordInput = document.getElementById('register-password'); - if (!usernameInput || !passwordInput) return; + + if (!usernameInput || !passwordInput) { + console.error('[Auth.js] Register form username or password input not found!'); // <--- ДОБАВЛЕНО + return; + } const username = usernameInput.value; const password = passwordInput.value; + console.log(`[Auth.js] Attempting to register with username: "${username}", password length: ${password.length}`); // <--- ДОБАВЛЕНО const regButton = registerForm.querySelector('button'); - const loginButton = loginForm ? loginForm.querySelector('button') : null; // Может быть null, если форма логина на другой странице + const loginButton = loginForm ? loginForm.querySelector('button') : null; if (regButton) regButton.disabled = true; - if (loginButton) loginButton.disabled = true; + if (loginButton) loginButton.disabled = true; // Блокируем обе кнопки на время запроса ui.setAuthMessage('Регистрация...'); + const apiUrl = getApiUrl('/auth/register'); + console.log('[Auth.js] Sending register request to:', apiUrl); // <--- ДОБАВЛЕНО try { - // Используем относительный путь, если API_BASE_URL не задан или пуст - const response = await fetch(getApiUrl('/auth/register'), { + const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }), }); + console.log('[Auth.js] Received response from register request.'); // <--- ДОБАВЛЕНО await handleAuthResponse(response, 'register'); - if (response.ok && clientState.isLoggedIn && registerForm) { // Проверяем clientState.isLoggedIn для очистки - registerForm.reset(); // Очищаем форму при успехе + if (response.ok && clientState.isLoggedIn && registerForm) { + console.log('[Auth.js] Registration successful, resetting register form.'); // <--- ДОБАВЛЕНО + registerForm.reset(); } } catch (error) { - console.error('[Auth] Network error during registration:', error); + console.error('[Auth.js] Network error during registration fetch:', error); // <--- ДОБАВЛЕНО ui.setAuthMessage('Ошибка сети при регистрации. Пожалуйста, проверьте ваше подключение.', true); - // Разблокируем кнопки при ошибке сети, т.к. finally в handleAuthResponse может не сработать if (regButton) regButton.disabled = false; if (loginButton) loginButton.disabled = false; } }); + } else { + console.warn('[Auth.js] registerForm element not found, listener not attached.'); // <--- ДОБАВЛЕНО } if (loginForm) { + console.log('[Auth.js] Attaching submit listener to loginForm.'); // <--- ДОБАВЛЕНО loginForm.addEventListener('submit', async (e) => { e.preventDefault(); + console.log('[Auth.js] Login form submitted.'); // <--- ДОБАВЛЕНО + const usernameInput = document.getElementById('login-username'); const passwordInput = document.getElementById('login-password'); - if (!usernameInput || !passwordInput) return; + + if (!usernameInput || !passwordInput) { + console.error('[Auth.js] Login form username or password input not found!'); // <--- ДОБАВЛЕНО + return; + } const username = usernameInput.value; const password = passwordInput.value; + console.log(`[Auth.js] Attempting to login with username: "${username}", password length: ${password.length}`); // <--- ДОБАВЛЕНО const loginButton = loginForm.querySelector('button'); const regButton = registerForm ? registerForm.querySelector('button') : null; @@ -125,88 +143,71 @@ export function initAuth(dependencies) { if (regButton) regButton.disabled = true; ui.setAuthMessage('Вход...'); + const apiUrl = getApiUrl('/auth/login'); + console.log('[Auth.js] Sending login request to:', apiUrl); // <--- ДОБАВЛЕНО try { - // Используем относительный путь - const response = await fetch(getApiUrl('/auth/login'), { + const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }), }); + console.log('[Auth.js] Received response from login request.'); // <--- ДОБАВЛЕНО await handleAuthResponse(response, 'login'); - // Форма логина обычно не сбрасывается или перенаправляется + // Форма логина обычно не сбрасывается или перенаправляется немедленно, + // это делает showGameSelectionScreen } catch (error) { - console.error('[Auth] Network error during login:', error); + console.error('[Auth.js] Network error during login fetch:', error); // <--- ДОБАВЛЕНО ui.setAuthMessage('Ошибка сети при входе. Пожалуйста, проверьте ваше подключение.', true); if (loginButton) loginButton.disabled = false; if (regButton) regButton.disabled = false; } }); + } else { + console.warn('[Auth.js] loginForm element not found, listener not attached.'); // <--- ДОБАВЛЕНО } if (logoutButton) { + console.log('[Auth.js] Attaching click listener to logoutButton.'); // <--- ДОБАВЛЕНО logoutButton.addEventListener('click', () => { - logoutButton.disabled = true; // Блокируем кнопку сразу + console.log('[Auth.js] Logout button clicked.'); // <--- ДОБАВЛЕНО + logoutButton.disabled = true; - // Проверяем, находится ли игрок в активной игре if (clientState.isLoggedIn && clientState.isInGame && clientState.currentGameId) { - // Если это PvP игра и она не закончена if (clientState.currentGameState && clientState.currentGameState.gameMode === 'pvp' && !clientState.currentGameState.isGameOver) { - console.log('[Auth] Player is in an active PvP game. Emitting playerSurrender.'); + console.log('[Auth.js] Player is in an active PvP game. Emitting playerSurrender.'); socket.emit('playerSurrender'); - // Не ждем ответа от сервера здесь, так как logout - это безусловное действие на клиенте. } - // --- НАЧАЛО ИЗМЕНЕНИЯ ДЛЯ ВАРИАНТА А --- else if (clientState.currentGameState && clientState.currentGameState.gameMode === 'ai' && !clientState.currentGameState.isGameOver) { - console.log('[Auth] Player is in an active AI game. Emitting leaveAiGame.'); + console.log('[Auth.js] Player is in an active AI game. Emitting leaveAiGame.'); socket.emit('leaveAiGame'); - // Сервер должен обработать это и завершить AI игру. } - // --- КОНЕЦ ИЗМЕНЕНИЯ ДЛЯ ВАРИАНТА А --- } - // Серверный эндпоинт для логаута не обязателен для JWT, - // если нет необходимости аннулировать токен на сервере (что сложно с JWT). - // Основное действие - удаление токена на клиенте. - // socket.emit('logout'); // Клиент сам инициирует разрыв и новое подключение без токена. - // Это событие из bc.js скорее для очистки серверной сессии сокета. + console.log('[Auth.js] Removing JWT token from localStorage.'); // <--- ДОБАВЛЕНО + localStorage.removeItem(JWT_TOKEN_KEY); - localStorage.removeItem(JWT_TOKEN_KEY); // Удаляем токен - - // Сбрасываем состояние клиента clientState.isLoggedIn = false; clientState.loggedInUsername = ''; clientState.myUserId = null; - // clientState.isInGame и другие игровые переменные будут сброшены в ui.showAuthScreen() - // или ui.resetGameVariables() если вызывается напрямую. + console.log('[Auth.js] Client state reset for logout.'); // <--- ДОБАВЛЕНО - ui.showAuthScreen(); // Показываем экран логина (это вызовет resetGameVariables) - ui.setAuthMessage("Вы успешно вышли из системы."); // Сообщение на экране логина + ui.showAuthScreen(); + ui.setAuthMessage("Вы успешно вышли из системы."); - // Переподключаем сокет без токена (или он сам переподключится при следующем действии) + console.log('[Auth.js] Disconnecting and reconnecting socket after logout.'); // <--- ДОБАВЛЕНО if (socket.connected) { - socket.disconnect(); // Принудительно отключаемся + socket.disconnect(); } - socket.auth = { token: null }; // Очищаем токен в auth объекте сокета - socket.connect(); // Сокет подключится как неаутентифицированный (или main.js инициирует) - // Фактически, connect() будет вызван из main.js при переходе на authScreen - // и проверке состояния. Здесь главное - очистить токен. - // Но явный connect() после disconnect() более предсказуем. - - // Кнопка logoutButton.disabled = true; уже была установлена в showAuthScreen() + socket.auth = { token: null }; + socket.connect(); // Это вызовет 'connect' в main.js, который затем вызовет showAuthScreen }); + } else { + console.warn('[Auth.js] logoutButton element not found, listener not attached.'); // <--- ДОБАВЛЕНО } - - // --- Обработчики событий Socket.IO --- - // Старые 'registerResponse' и 'loginResponse' (если были через сокет) больше не нужны, - // так как эти ответы приходят через HTTP. - - // Логика проверки токена при загрузке страницы (если токен есть в localStorage) - // обычно выполняется в main.js до инициализации сокета. - // Здесь мы предполагаем, что main.js уже подготовил clientState - // на основе существующего токена или оставил его пустым. + console.log('[Auth.js] initAuth finished.'); // <--- ДОБАВЛЕНО } \ No newline at end of file diff --git a/public/js/main.js b/public/js/main.js index d1c0d83..cba300d 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,6 +1,6 @@ // /public/js/main.js -import { initAuth } from './auth.js';/// +import { initAuth } from './auth.js'; import { initGameSetup } from './gameSetup.js'; import { initGameplay } from './gameplay.js'; // ui.js загружен глобально и ожидает window.* переменных @@ -17,15 +17,16 @@ function parseJwtPayload(token) { }).join('')); return JSON.parse(jsonPayload); } catch (e) { - console.error("[parseJwtPayload] Error parsing JWT payload:", e); + console.error("[Main.js parseJwtPayload] Error parsing JWT payload:", e); return null; } } document.addEventListener('DOMContentLoaded', () => { - // SERVER_URL и API_BASE_URL убраны. Socket.IO подключится к источнику загрузки страницы. - // auth.js будет использовать относительные пути для API запросов. + console.log('[Main.js] DOMContentLoaded event fired.'); // <--- ДОБАВЛЕНО + const initialToken = localStorage.getItem('jwtToken'); + console.log('[Main.js] Initial token from localStorage:', initialToken); // <--- ДОБАВЛЕНО let clientState = { isLoggedIn: false, @@ -48,26 +49,33 @@ document.addEventListener('DOMContentLoaded', () => { if (decodedToken && decodedToken.userId && decodedToken.username) { const nowInSeconds = Math.floor(Date.now() / 1000); if (decodedToken.exp && decodedToken.exp > nowInSeconds) { - console.log("[Client Init] Token found, pre-populating clientState."); + console.log("[Main.js] Token found and valid, pre-populating clientState:", decodedToken); // <--- ДОБАВЛЕНО clientState.isLoggedIn = true; clientState.myUserId = decodedToken.userId; clientState.loggedInUsername = decodedToken.username; } else { - console.warn("[Client Init] Token expired or invalid 'exp'. Clearing."); + console.warn("[Main.js] Token expired or invalid 'exp'. Clearing."); localStorage.removeItem('jwtToken'); } } else { - console.warn("[Client Init] Token invalid or missing data. Clearing."); + console.warn("[Main.js] Token invalid or missing data. Clearing."); localStorage.removeItem('jwtToken'); } + } else { + console.log("[Main.js] No initial token found in localStorage."); // <--- ДОБАВЛЕНО } - const socket = io({ // SERVER_URL удален отсюда + console.log('[Main.js] Initial clientState after token check:', JSON.parse(JSON.stringify(clientState))); // <--- ДОБАВЛЕНО + + console.log('[Main.js] Initializing Socket.IO client...'); // <--- ДОБАВЛЕНО + const socket = io({ autoConnect: false, - auth: { token: localStorage.getItem('jwtToken') } + auth: { token: localStorage.getItem('jwtToken') } // Передаем токен (может быть null) }); + console.log('[Main.js] Socket.IO client initialized. Socket ID (if connected):', socket.id); // <--- ДОБАВЛЕНО (ID будет при autoConnect:true или после .connect()) // --- DOM Элементы --- + console.log('[Main.js] Getting DOM elements...'); // <--- ДОБАВЛЕНО const authSection = document.getElementById('auth-section'); const loginForm = document.getElementById('login-form'); const registerForm = document.getElementById('register-form'); @@ -90,8 +98,17 @@ document.addEventListener('DOMContentLoaded', () => { const turnTimerContainer = document.getElementById('turn-timer-container'); const turnTimerSpan = document.getElementById('turn-timer'); + // --- ДОБАВЛЕНО: Логирование найденных DOM элементов --- + console.log('[Main.js DOM Check] authSection:', authSection); + console.log('[Main.js DOM Check] loginForm:', loginForm); + console.log('[Main.js DOM Check] registerForm:', registerForm); + console.log('[Main.js DOM Check] logoutButton:', logoutButton); + // --- КОНЕЦ: Логирование найденных DOM элементов --- + + // --- Функции обновления UI и состояния --- function updateGlobalWindowVariablesForUI() { + // console.log("[Main.js updateGlobalWindowVariablesForUI] Updating window variables."); // Можно раскомментировать для очень детальной отладки window.gameState = clientState.currentGameState; window.gameData = { playerBaseStats: clientState.playerBaseStatsServer, @@ -103,7 +120,7 @@ document.addEventListener('DOMContentLoaded', () => { } function resetGameVariables() { - console.log("[Main:resetGameVariables] Resetting game variables. State BEFORE:", JSON.parse(JSON.stringify(clientState))); + console.log("[Main.js resetGameVariables] Resetting game variables. State BEFORE:", JSON.parse(JSON.stringify(clientState))); clientState.currentGameId = null; clientState.currentGameState = null; clientState.myPlayerId = null; @@ -114,11 +131,11 @@ document.addEventListener('DOMContentLoaded', () => { clientState.playerAbilitiesServer = null; clientState.opponentAbilitiesServer = null; updateGlobalWindowVariablesForUI(); - console.log("[Main:resetGameVariables] Game variables reset. State AFTER:", JSON.parse(JSON.stringify(clientState))); + console.log("[Main.js resetGameVariables] Game variables reset. State AFTER:", JSON.parse(JSON.stringify(clientState))); } function explicitlyHideGameOverModal() { - console.log("[Main:explicitlyHideGameOverModal] Attempting to hide Game Over modal."); + // console.log("[Main.js explicitlyHideGameOverModal] Attempting to hide Game Over modal."); // Можно раскомментировать if (window.gameUI?.uiElements?.gameOver?.screen && window.GAME_CONFIG) { const gameOverScreenElement = window.gameUI.uiElements.gameOver.screen; const modalContentElement = window.gameUI.uiElements.gameOver.modalContent; @@ -132,35 +149,35 @@ document.addEventListener('DOMContentLoaded', () => { modalContentElement.style.transform = 'scale(0.8) translateY(30px)'; modalContentElement.style.opacity = '0'; } - console.log("[Main:explicitlyHideGameOverModal] Game Over screen explicitly hidden."); + // console.log("[Main.js explicitlyHideGameOverModal] Game Over screen explicitly hidden."); } else if (gameOverScreenElement) { - console.log("[Main:explicitlyHideGameOverModal] Game Over screen was already hidden or not found."); + // console.log("[Main.js explicitlyHideGameOverModal] Game Over screen was already hidden or not found."); } if (messageElement) messageElement.textContent = ''; } else { - console.warn("[Main:explicitlyHideGameOverModal] Cannot hide Game Over modal: gameUI or GAME_CONFIG not available."); + // console.warn("[Main.js explicitlyHideGameOverModal] Cannot hide Game Over modal: gameUI or GAME_CONFIG not available."); } } function showAuthScreen() { - console.log("[Main:showAuthScreen] Showing Auth Screen. Resetting game state."); + console.log("[Main.js showAuthScreen] Showing Auth Screen. Resetting game state if not already done."); authSection.style.display = 'block'; userInfoDiv.style.display = 'none'; gameSetupDiv.style.display = 'none'; gameWrapper.style.display = 'none'; explicitlyHideGameOverModal(); - statusContainer.style.display = 'block'; - clientState.isInGame = false; - resetGameVariables(); + statusContainer.style.display = 'block'; // Убедимся, что контейнер статуса виден + clientState.isInGame = false; // Сбрасываем флаг игры + resetGameVariables(); // Сбрасываем игровые переменные if (turnTimerContainer) turnTimerContainer.style.display = 'none'; if (turnTimerSpan) turnTimerSpan.textContent = '--'; - if(registerForm) registerForm.querySelector('button').disabled = false; - if(loginForm) loginForm.querySelector('button').disabled = false; - if(logoutButton) logoutButton.disabled = true; + if(registerForm && registerForm.querySelector('button')) registerForm.querySelector('button').disabled = false; + if(loginForm && loginForm.querySelector('button')) loginForm.querySelector('button').disabled = false; + if(logoutButton) logoutButton.disabled = true; // Кнопка выхода должна быть неактивна на экране логина } function showGameSelectionScreen(username) { - console.log(`[Main:showGameSelectionScreen] Showing Game Selection Screen for ${username}. Resetting game state.`); + console.log(`[Main.js showGameSelectionScreen] Showing Game Selection Screen for ${username}.`); authSection.style.display = 'none'; userInfoDiv.style.display = 'block'; if(loggedInUsernameSpan) loggedInUsernameSpan.textContent = username; @@ -172,9 +189,10 @@ document.addEventListener('DOMContentLoaded', () => { statusContainer.style.display = 'block'; if (socket.connected) { + console.log("[Main.js showGameSelectionScreen] Socket connected, requesting PvP game list."); // <--- ДОБАВЛЕНО socket.emit('requestPvPGameList'); } else { - console.warn("[Main:showGameSelectionScreen] Socket not connected, cannot request PvP game list yet."); + console.warn("[Main.js showGameSelectionScreen] Socket not connected, cannot request PvP game list yet."); } if (availableGamesDiv) availableGamesDiv.innerHTML = '
Загрузка...
'; @@ -182,7 +200,7 @@ document.addEventListener('DOMContentLoaded', () => { const elenaRadio = document.getElementById('char-elena'); if (elenaRadio) elenaRadio.checked = true; clientState.isInGame = false; - resetGameVariables(); + // resetGameVariables(); // Обычно не нужно здесь, т.к. мы только вошли, игры еще не было if (turnTimerContainer) turnTimerContainer.style.display = 'none'; if (turnTimerSpan) turnTimerSpan.textContent = '--'; enableSetupButtons(); @@ -192,14 +210,14 @@ document.addEventListener('DOMContentLoaded', () => { } function showGameScreen() { - console.log("[Main:showGameScreen] Showing Game Screen."); + console.log("[Main.js showGameScreen] Showing Game Screen."); authSection.style.display = 'none'; userInfoDiv.style.display = 'block'; if(logoutButton) logoutButton.disabled = false; gameSetupDiv.style.display = 'none'; - gameWrapper.style.display = 'flex'; - setGameStatusMessage(""); - statusContainer.style.display = 'none'; + gameWrapper.style.display = 'flex'; // Используем flex для .game-wrapper + setGameStatusMessage(""); // Очищаем статусное сообщение + statusContainer.style.display = 'none'; // Скрываем контейнер статуса, т.к. игра началась clientState.isInGame = true; updateGlobalWindowVariablesForUI(); if (turnTimerContainer) turnTimerContainer.style.display = 'block'; @@ -207,6 +225,7 @@ document.addEventListener('DOMContentLoaded', () => { } function setAuthMessage(message, isError = false) { + console.log(`[Main.js setAuthMessage] Message: "${message}", isError: ${isError}`); // <--- ДОБАВЛЕНО if (authMessage) { authMessage.textContent = message; authMessage.className = isError ? 'error' : 'success'; @@ -216,6 +235,7 @@ document.addEventListener('DOMContentLoaded', () => { } function setGameStatusMessage(message, isError = false) { + console.log(`[Main.js setGameStatusMessage] Message: "${message}", isError: ${isError}`); // <--- ДОБАВЛЕНО if (gameStatusMessage) { gameStatusMessage.textContent = message; gameStatusMessage.style.display = message ? 'block' : 'none'; @@ -225,7 +245,9 @@ document.addEventListener('DOMContentLoaded', () => { if (message && authMessage && authMessage.style.display !== 'none') authMessage.style.display = 'none'; } + function disableSetupButtons() { + // console.log("[Main.js] Disabling setup buttons."); // Можно раскомментировать if(createAIGameButton) createAIGameButton.disabled = true; if(createPvPGameButton) createPvPGameButton.disabled = true; if(joinPvPGameButton) joinPvPGameButton.disabled = true; @@ -233,6 +255,7 @@ document.addEventListener('DOMContentLoaded', () => { if(availableGamesDiv) availableGamesDiv.querySelectorAll('button').forEach(btn => btn.disabled = true); } function enableSetupButtons() { + // console.log("[Main.js] Enabling setup buttons."); // Можно раскомментировать if(createAIGameButton) createAIGameButton.disabled = false; if(createPvPGameButton) createPvPGameButton.disabled = false; if(joinPvPGameButton) joinPvPGameButton.disabled = false; @@ -240,6 +263,7 @@ document.addEventListener('DOMContentLoaded', () => { } // --- Сборка зависимостей для модулей --- + console.log('[Main.js] Preparing dependencies for modules...'); // <--- ДОБАВЛЕНО const dependencies = { socket, clientState, @@ -259,82 +283,90 @@ document.addEventListener('DOMContentLoaded', () => { findRandomPvPGameButton, gameIdInput, availableGamesDiv, pvpCharacterRadios, returnToMenuButton, } - }, - // API_BASE_URL больше не передается, т.к. auth.js будет использовать относительные пути. - // Если auth.js все еще требует явного API_BASE_URL для случая, когда он не может - // сам определить window.location.origin, можно было бы передать: - // API_BASE_URL: window.location.origin + } }; + console.log('[Main.js] Initializing auth module...'); // <--- ДОБАВЛЕНО initAuth(dependencies); + console.log('[Main.js] Initializing gameSetup module...'); // <--- ДОБАВЛЕНО initGameSetup(dependencies); + console.log('[Main.js] Initializing gameplay module...'); // <--- ДОБАВЛЕНО initGameplay(dependencies); + console.log('[Main.js] All modules initialized.'); // <--- ДОБАВЛЕНО // --- Обработчики событий Socket.IO --- socket.on('connect', () => { - const currentToken = socket.auth.token || localStorage.getItem('jwtToken'); - console.log('[Main:SocketConnect] Socket connected:', socket.id, 'Auth token sent:', !!currentToken); + const currentToken = socket.auth.token || localStorage.getItem('jwtToken'); // Проверяем токен для лога + console.log('[Main.js Socket.IO] Event: connect. Socket ID:', socket.id, 'Auth token sent to server:', !!currentToken); // <--- ИЗМЕНЕНО if (clientState.isLoggedIn && clientState.myUserId) { - console.log(`[Main:SocketConnect] Client state indicates logged in as ${clientState.loggedInUsername}. Requesting game state.`); - if (authSection.style.display === 'block' || gameSetupDiv.style.display === 'block') { + console.log(`[Main.js Socket.IO] Client state indicates logged in as ${clientState.loggedInUsername} (ID: ${clientState.myUserId}). Requesting game state.`); + // Сообщение о восстановлении сессии лучше показывать, только если мы НЕ в игре + if (!clientState.isInGame && (authSection.style.display === 'block' || gameSetupDiv.style.display === 'block')) { setGameStatusMessage("Восстановление игровой сессии..."); } socket.emit('requestGameState'); } else { - console.log('[Main:SocketConnect] Client state indicates NOT logged in. Showing auth screen.'); - showAuthScreen(); + console.log('[Main.js Socket.IO] Client state indicates NOT logged in. Showing auth screen if not already visible.'); + if (authSection.style.display !== 'block') { // Показываем, только если еще не там + showAuthScreen(); + } setAuthMessage("Пожалуйста, войдите или зарегистрируйтесь."); } }); socket.on('connect_error', (err) => { - console.error('[Main:SocketConnectError] Socket connection error:', err.message, err.data ? err.data : ''); + console.error('[Main.js Socket.IO] Event: connect_error. Message:', err.message, err.data ? JSON.stringify(err.data) : ''); // <--- ИЗМЕНЕНО const errorMessageLower = err.message ? err.message.toLowerCase() : ""; const isAuthError = errorMessageLower.includes('auth') || errorMessageLower.includes('token') || errorMessageLower.includes('unauthorized') || err.message === 'invalid token' || err.message === 'no token' || (err.data && typeof err.data === 'string' && err.data.toLowerCase().includes('auth')); if (isAuthError) { - console.warn('[Main:SocketConnectError] Authentication error. Clearing token, resetting state, showing auth screen.'); - localStorage.removeItem('jwtToken'); + console.warn('[Main.js Socket.IO] Authentication error during connection. Clearing token, resetting state, showing auth screen.'); + localStorage.removeItem('jwtToken'); // Убедимся, что токен удален clientState.isLoggedIn = false; clientState.loggedInUsername = ''; clientState.myUserId = null; - if (socket.auth) socket.auth.token = null; - showAuthScreen(); + if (socket.auth) socket.auth.token = null; // Очищаем токен и в объекте сокета + + if (authSection.style.display !== 'block') { + showAuthScreen(); + } setAuthMessage("Ошибка аутентификации. Пожалуйста, войдите снова.", true); } else { - // Общая ошибка подключения let currentScreenMessageFunc = setAuthMessage; if (clientState.isLoggedIn && clientState.isInGame) { currentScreenMessageFunc = setGameStatusMessage; } else if (clientState.isLoggedIn) { - currentScreenMessageFunc = setGameStatusMessage; // Или setAuthMessage, если statusContainer не виден + // Если залогинен, но не в игре (на экране выбора игры), сообщение на gameStatusMessage + currentScreenMessageFunc = setGameStatusMessage; } - currentScreenMessageFunc(`Ошибка подключения: ${err.message}. Попытка переподключения...`, true); if (authSection.style.display !== 'block' && !clientState.isLoggedIn) { - showAuthScreen(); // Если не на экране логина и не залогинен, показываем его + showAuthScreen(); } } if (turnTimerSpan) turnTimerSpan.textContent = 'Ошибка'; }); socket.on('disconnect', (reason) => { - console.warn('[Main:SocketDisconnect] Disconnected from server:', reason); + console.warn('[Main.js Socket.IO] Event: disconnect. Reason:', reason); // <--- ИЗМЕНЕНО let messageFunc = setAuthMessage; if (clientState.isInGame) { messageFunc = setGameStatusMessage; } else if (clientState.isLoggedIn && gameSetupDiv.style.display === 'block') { messageFunc = setGameStatusMessage; } - messageFunc(`Потеряно соединение: ${reason}. Попытка переподключения...`, true); + // Не показываем сообщение об ошибке, если это преднамеренный дисконнект при логауте + if (reason !== 'io client disconnect') { + messageFunc(`Потеряно соединение: ${reason}. Попытка переподключения...`, true); + } if (turnTimerSpan) turnTimerSpan.textContent = 'Откл.'; }); socket.on('gameError', (data) => { - console.error('[Main:SocketGameError] Received gameError from server:', data.message); + console.error('[Main.js Socket.IO] Event: gameError. Message:', data.message, 'Data:', JSON.stringify(data)); // <--- ИЗМЕНЕНО if (clientState.isInGame && window.gameUI?.addToLog) { window.gameUI.addToLog(`❌ Ошибка сервера: ${data.message}`, 'system'); } else if (clientState.isLoggedIn) { @@ -342,13 +374,13 @@ document.addEventListener('DOMContentLoaded', () => { enableSetupButtons(); } else { setAuthMessage(`❌ Ошибка: ${data.message}`, true); - if(registerForm) registerForm.querySelector('button').disabled = false; - if(loginForm) loginForm.querySelector('button').disabled = false; + if(registerForm && registerForm.querySelector('button')) registerForm.querySelector('button').disabled = false; + if(loginForm && loginForm.querySelector('button')) loginForm.querySelector('button').disabled = false; } }); socket.on('gameNotFound', (data) => { - console.log('[Main:SocketGameNotFound] Game not found/ended after request:', data?.message); + console.log('[Main.js Socket.IO] Event: gameNotFound. Message:', data?.message, 'Data:', JSON.stringify(data)); // <--- ИЗМЕНЕНО clientState.isInGame = false; resetGameVariables(); explicitlyHideGameOverModal(); @@ -356,26 +388,42 @@ document.addEventListener('DOMContentLoaded', () => { if (turnTimerSpan) turnTimerSpan.textContent = '--'; if (clientState.isLoggedIn && clientState.myUserId) { - showGameSelectionScreen(clientState.loggedInUsername); + if (gameSetupDiv.style.display !== 'block') { // Показываем, только если еще не там + showGameSelectionScreen(clientState.loggedInUsername); + } setGameStatusMessage(data?.message || "Активная игровая сессия не найдена. Выберите новую игру."); } else { - showAuthScreen(); + if (authSection.style.display !== 'block') { + showAuthScreen(); + } setAuthMessage(data?.message || "Пожалуйста, войдите."); } }); // --- Инициализация UI --- + console.log('[Main.js] Initializing UI visibility...'); // <--- ДОБАВЛЕНО authSection.style.display = 'none'; gameSetupDiv.style.display = 'none'; gameWrapper.style.display = 'none'; userInfoDiv.style.display = 'none'; - statusContainer.style.display = 'block'; + statusContainer.style.display = 'block'; // Показываем контейнер статуса по умолчанию if (clientState.isLoggedIn) { - setGameStatusMessage("Подключение и восстановление сессии..."); + // Если токен есть и валиден, НЕ показываем экран логина, а пытаемся восстановить сессию + // Это будет обработано в socket.on('connect') -> requestGameState + // Если requestGameState вернет gameNotFound, тогда покажется gameSelectionScreen + // Если requestGameState вернет игру, покажется gameScreen + // Сообщение "Подключение и восстановление сессии..." может быть показано здесь + console.log('[Main.js] Client is considered logged in. Will attempt session recovery on socket connect.'); + setGameStatusMessage("Подключение и восстановление сессии..."); // Показываем на общем статусном элементе } else { - setAuthMessage("Подключение к серверу..."); + // Если нет валидного токена, показываем экран аутентификации + console.log('[Main.js] Client is NOT considered logged in. Showing auth screen.'); + showAuthScreen(); // Это установит правильные display для authSection и скроет другие + setAuthMessage("Подключение к серверу..."); // Начальное сообщение на экране логина } + console.log('[Main.js] Attempting to connect socket...'); // <--- ДОБАВЛЕНО socket.connect(); // Начинаем подключение к серверу + console.log('[Main.js] socket.connect() called.'); // <--- ДОБАВЛЕНО }); \ No newline at end of file