482 lines
28 KiB
JavaScript
482 lines
28 KiB
JavaScript
// /public/js/main.js
|
||
|
||
import { initAuth } from './auth.js';
|
||
import { initGameSetup } from './gameSetup.js';
|
||
import { initGameplay } from './gameplay.js';
|
||
// ui.js загружен глобально и ожидает window.* переменных
|
||
|
||
// --- ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ДЛЯ РАБОТЫ С JWT (для isTokenValid) ---
|
||
function parseJwtPayloadForValidation(token) {
|
||
try {
|
||
if (typeof token !== 'string') {
|
||
return null;
|
||
}
|
||
const parts = token.split('.');
|
||
if (parts.length !== 3) {
|
||
return null;
|
||
}
|
||
const base64Url = parts[1];
|
||
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
||
const jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
|
||
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
||
}).join(''));
|
||
return JSON.parse(jsonPayload);
|
||
} catch (e) {
|
||
console.error("[Main.js parseJwtPayloadForValidation] Error parsing JWT payload:", e, "Token:", token);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
function isTokenValid(token) {
|
||
if (!token) {
|
||
return false;
|
||
}
|
||
const decodedToken = parseJwtPayloadForValidation(token);
|
||
if (!decodedToken || typeof decodedToken.exp !== 'number') {
|
||
localStorage.removeItem('jwtToken');
|
||
return false;
|
||
}
|
||
const currentTimeInSeconds = Math.floor(Date.now() / 1000);
|
||
if (decodedToken.exp < currentTimeInSeconds) {
|
||
localStorage.removeItem('jwtToken');
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
// --- КОНЕЦ ВСПОМОГАТЕЛЬНЫХ ФУНКЦИЙ ДЛЯ JWT ---
|
||
|
||
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
console.log('[Main.js] DOMContentLoaded event fired.');
|
||
|
||
const initialToken = localStorage.getItem('jwtToken');
|
||
console.log('[Main.js] Initial token from localStorage:', initialToken ? 'Exists' : 'Not found');
|
||
|
||
let clientState = {
|
||
isLoggedIn: false,
|
||
loggedInUsername: '',
|
||
myUserId: null,
|
||
isInGame: false,
|
||
currentGameId: null,
|
||
currentGameState: null,
|
||
myPlayerId: null, // Роль в текущей игре (player/opponent)
|
||
myCharacterKey: null,
|
||
opponentCharacterKey: null,
|
||
playerBaseStatsServer: null,
|
||
opponentBaseStatsServer: null,
|
||
playerAbilitiesServer: null,
|
||
opponentAbilitiesServer: null,
|
||
isActionInProgress: false, // <--- ВАЖНО: Флаг для предотвращения двойных действий
|
||
};
|
||
|
||
if (initialToken && isTokenValid(initialToken)) {
|
||
const decodedToken = parseJwtPayloadForValidation(initialToken);
|
||
if (decodedToken && decodedToken.userId && decodedToken.username) {
|
||
console.log("[Main.js] Token found and confirmed valid, pre-populating clientState:", decodedToken);
|
||
clientState.isLoggedIn = true;
|
||
clientState.myUserId = decodedToken.userId; // Это ID пользователя из БД
|
||
clientState.loggedInUsername = decodedToken.username;
|
||
} else {
|
||
console.warn("[Main.js] Token deemed valid by isTokenValid, but payload incomplete. Clearing.");
|
||
localStorage.removeItem('jwtToken');
|
||
}
|
||
} else if (initialToken) {
|
||
console.warn("[Main.js] Initial token was present but invalid/expired. It has been cleared.");
|
||
} else {
|
||
console.log("[Main.js] No initial token found in localStorage.");
|
||
}
|
||
|
||
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({
|
||
path:base_path + "/socket.io", // base_path определяется в HTML
|
||
autoConnect: false, // Подключаемся вручную после инициализации всего
|
||
auth: { token: localStorage.getItem('jwtToken') }
|
||
});
|
||
console.log('[Main.js] Socket.IO client initialized.');
|
||
|
||
// --- 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');
|
||
const authMessage = document.getElementById('auth-message');
|
||
const statusContainer = document.getElementById('status-container'); // Общий контейнер для сообщений
|
||
const userInfoDiv = document.getElementById('user-info');
|
||
const loggedInUsernameSpan = document.getElementById('logged-in-username');
|
||
const logoutButton = document.getElementById('logout-button');
|
||
const gameSetupDiv = document.getElementById('game-setup');
|
||
const createAIGameButton = document.getElementById('create-ai-game');
|
||
const createPvPGameButton = document.getElementById('create-pvp-game');
|
||
const joinPvPGameButton = document.getElementById('join-pvp-game');
|
||
const findRandomPvPGameButton = document.getElementById('find-random-pvp-game');
|
||
const gameIdInput = document.getElementById('game-id-input');
|
||
const availableGamesDiv = document.getElementById('available-games-list');
|
||
const gameStatusMessage = document.getElementById('game-status-message'); // Сообщение на экране выбора игры
|
||
const pvpCharacterRadios = document.querySelectorAll('input[name="pvp-character"]');
|
||
const gameWrapper = document.querySelector('.game-wrapper');
|
||
const returnToMenuButton = document.getElementById('return-to-menu-button'); // Кнопка в gameOver модальном окне
|
||
const turnTimerContainer = document.getElementById('turn-timer-container');
|
||
const turnTimerSpan = document.getElementById('turn-timer');
|
||
|
||
// --- Функции обновления UI и состояния ---
|
||
function updateGlobalWindowVariablesForUI() {
|
||
window.gameState = clientState.currentGameState;
|
||
window.gameData = {
|
||
playerBaseStats: clientState.playerBaseStatsServer,
|
||
opponentBaseStats: clientState.opponentBaseStatsServer,
|
||
playerAbilities: clientState.playerAbilitiesServer,
|
||
opponentAbilities: clientState.opponentAbilitiesServer
|
||
};
|
||
window.myPlayerId = clientState.myPlayerId; // Роль игрока (player/opponent)
|
||
}
|
||
|
||
function resetGameVariables() {
|
||
console.log("[Main.js resetGameVariables] Resetting game variables. State BEFORE:", JSON.parse(JSON.stringify(clientState)));
|
||
clientState.currentGameId = null;
|
||
clientState.currentGameState = null;
|
||
clientState.myPlayerId = null;
|
||
clientState.myCharacterKey = null;
|
||
clientState.opponentCharacterKey = null;
|
||
clientState.playerBaseStatsServer = null;
|
||
clientState.opponentBaseStatsServer = null;
|
||
clientState.playerAbilitiesServer = null;
|
||
clientState.opponentAbilitiesServer = null;
|
||
clientState.isActionInProgress = false; // <--- Сброс флага
|
||
updateGlobalWindowVariablesForUI();
|
||
console.log("[Main.js resetGameVariables] Game variables reset. State AFTER:", JSON.parse(JSON.stringify(clientState)));
|
||
}
|
||
|
||
function explicitlyHideGameOverModal() {
|
||
if (window.gameUI?.uiElements?.gameOver?.screen && window.GAME_CONFIG) {
|
||
const gameOverScreenElement = window.gameUI.uiElements.gameOver.screen;
|
||
const modalContentElement = window.gameUI.uiElements.gameOver.modalContent;
|
||
const messageElement = window.gameUI.uiElements.gameOver.message;
|
||
const hiddenClass = window.GAME_CONFIG.CSS_CLASS_HIDDEN || 'hidden';
|
||
|
||
if (gameOverScreenElement && !gameOverScreenElement.classList.contains(hiddenClass)) {
|
||
gameOverScreenElement.classList.add(hiddenClass);
|
||
gameOverScreenElement.style.opacity = '0';
|
||
if (modalContentElement) {
|
||
modalContentElement.style.transform = 'scale(0.8) translateY(30px)';
|
||
modalContentElement.style.opacity = '0';
|
||
}
|
||
}
|
||
if (messageElement) messageElement.textContent = '';
|
||
}
|
||
}
|
||
|
||
function showAuthScreen() {
|
||
console.log("[Main.js showAuthScreen] Showing Auth Screen. Resetting game state.");
|
||
if(authSection) authSection.style.display = 'block';
|
||
if(userInfoDiv) userInfoDiv.style.display = 'none';
|
||
if(gameSetupDiv) gameSetupDiv.style.display = 'none';
|
||
if(gameWrapper) gameWrapper.style.display = 'none';
|
||
explicitlyHideGameOverModal();
|
||
if(statusContainer) statusContainer.style.display = 'block'; // Показываем общий контейнер для сообщений
|
||
clientState.isInGame = false;
|
||
resetGameVariables(); // Включает сброс isActionInProgress
|
||
if (turnTimerContainer) turnTimerContainer.style.display = 'none';
|
||
if (turnTimerSpan) turnTimerSpan.textContent = '--';
|
||
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.js showGameSelectionScreen] Showing Game Selection Screen for ${username}.`);
|
||
if(authSection) authSection.style.display = 'none';
|
||
if(userInfoDiv) userInfoDiv.style.display = 'block';
|
||
if(loggedInUsernameSpan) loggedInUsernameSpan.textContent = username;
|
||
if(logoutButton) logoutButton.disabled = false;
|
||
if(gameSetupDiv) gameSetupDiv.style.display = 'block';
|
||
if(gameWrapper) gameWrapper.style.display = 'none';
|
||
explicitlyHideGameOverModal();
|
||
setGameStatusMessage("Выберите режим игры или присоединитесь к существующей.");
|
||
if(statusContainer) 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.js showGameSelectionScreen] Socket not connected, cannot request PvP game list yet.");
|
||
// Можно попробовать подключить сокет, если он не подключен
|
||
// socket.connect(); // Или дождаться авто-реконнекта
|
||
}
|
||
|
||
if (availableGamesDiv) availableGamesDiv.innerHTML = '<h3>Доступные PvP игры:</h3><p>Загрузка...</p>';
|
||
if (gameIdInput) gameIdInput.value = '';
|
||
const elenaRadio = document.getElementById('char-elena');
|
||
if (elenaRadio) elenaRadio.checked = true; // Персонаж по умолчанию
|
||
clientState.isInGame = false;
|
||
clientState.isActionInProgress = false; // <--- Сброс флага при переходе в меню
|
||
if (turnTimerContainer) turnTimerContainer.style.display = 'none';
|
||
if (turnTimerSpan) turnTimerSpan.textContent = '--';
|
||
enableSetupButtons(); // Включаем кнопки настройки игры
|
||
if (window.gameUI?.uiElements?.gameOver?.returnToMenuButton) {
|
||
window.gameUI.uiElements.gameOver.returnToMenuButton.disabled = false; // Убедимся, что кнопка в модалке gameOver активна
|
||
}
|
||
}
|
||
|
||
function showGameScreen() {
|
||
console.log("[Main.js showGameScreen] Showing Game Screen.");
|
||
if(authSection) authSection.style.display = 'none';
|
||
if(userInfoDiv) userInfoDiv.style.display = 'block'; // userInfo (имя, выход) остается видимым
|
||
if(logoutButton) logoutButton.disabled = false;
|
||
if(gameSetupDiv) gameSetupDiv.style.display = 'none';
|
||
if(gameWrapper) gameWrapper.style.display = 'flex'; // Используем flex для game-wrapper
|
||
setGameStatusMessage(""); // Очищаем сообщение статуса игры при входе на экран игры
|
||
if(statusContainer) statusContainer.style.display = 'none'; // Скрываем общий статус-контейнер на игровом экране
|
||
clientState.isInGame = true;
|
||
// clientState.isActionInProgress остается false до первого действия игрока
|
||
updateGlobalWindowVariablesForUI();
|
||
if (turnTimerContainer) turnTimerContainer.style.display = 'block';
|
||
if (turnTimerSpan) turnTimerSpan.textContent = '--'; // Таймер обновится по событию
|
||
}
|
||
|
||
function setAuthMessage(message, isError = false) {
|
||
console.log(`[Main.js setAuthMessage] Message: "${message}", isError: ${isError}`);
|
||
if (authMessage) {
|
||
authMessage.textContent = message;
|
||
authMessage.className = isError ? 'error' : 'success';
|
||
authMessage.style.display = message ? 'block' : 'none';
|
||
}
|
||
// Если показываем authMessage, скрываем gameStatusMessage
|
||
if (message && gameStatusMessage && gameStatusMessage.style.display !== 'none') {
|
||
gameStatusMessage.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
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';
|
||
gameStatusMessage.style.color = isError ? 'var(--damage-color, red)' : 'var(--turn-color, yellow)'; // или другой цвет для обычных сообщений
|
||
// Управляем видимостью общего контейнера статуса
|
||
if (statusContainer) statusContainer.style.display = message ? 'block' : 'none';
|
||
}
|
||
// Если показываем gameStatusMessage, скрываем authMessage
|
||
if (message && authMessage && authMessage.style.display !== 'none') {
|
||
authMessage.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
function disableSetupButtons() {
|
||
if(createAIGameButton) createAIGameButton.disabled = true;
|
||
if(createPvPGameButton) createPvPGameButton.disabled = true;
|
||
if(joinPvPGameButton) joinPvPGameButton.disabled = true;
|
||
if(findRandomPvPGameButton) findRandomPvPGameButton.disabled = true;
|
||
if(availableGamesDiv) availableGamesDiv.querySelectorAll('button').forEach(btn => btn.disabled = true);
|
||
}
|
||
function enableSetupButtons() {
|
||
if(createAIGameButton) createAIGameButton.disabled = false;
|
||
if(createPvPGameButton) createPvPGameButton.disabled = false;
|
||
if(joinPvPGameButton) joinPvPGameButton.disabled = false;
|
||
if(findRandomPvPGameButton) findRandomPvPGameButton.disabled = false;
|
||
// Кнопки в списке доступных игр управляются в updateAvailableGamesList в gameSetup.js
|
||
}
|
||
|
||
function redirectToLogin(message) {
|
||
console.log(`[Main.js redirectToLogin] Redirecting to login. Message: "${message}"`);
|
||
clientState.isLoggedIn = false;
|
||
clientState.loggedInUsername = '';
|
||
clientState.myUserId = null;
|
||
clientState.isInGame = false;
|
||
localStorage.removeItem('jwtToken');
|
||
resetGameVariables(); // Сбрасываем все игровые переменные, включая isActionInProgress
|
||
|
||
if (socket.auth) socket.auth.token = null; // Обновляем auth объект сокета
|
||
if (socket.connected) {
|
||
console.log("[Main.js redirectToLogin] Socket connected, disconnecting before showing auth screen.");
|
||
socket.disconnect();
|
||
}
|
||
|
||
showAuthScreen();
|
||
setAuthMessage(message || "Для продолжения необходимо войти или обновить сессию.", true);
|
||
}
|
||
|
||
// --- Сборка зависимостей для модулей ---
|
||
console.log('[Main.js] Preparing dependencies for modules...');
|
||
const dependencies = {
|
||
socket,
|
||
clientState,
|
||
ui: {
|
||
showAuthScreen,
|
||
showGameSelectionScreen,
|
||
showGameScreen,
|
||
setAuthMessage,
|
||
setGameStatusMessage,
|
||
resetGameVariables,
|
||
updateGlobalWindowVariablesForUI,
|
||
disableSetupButtons,
|
||
enableSetupButtons,
|
||
redirectToLogin,
|
||
elements: {
|
||
loginForm, registerForm, logoutButton,
|
||
createAIGameButton, createPvPGameButton, joinPvPGameButton,
|
||
findRandomPvPGameButton, gameIdInput, availableGamesDiv,
|
||
pvpCharacterRadios, returnToMenuButton,
|
||
// Не передаем сюда все элементы из ui.js, так как ui.js сам их менеджит.
|
||
// Если какой-то модуль должен напрямую менять что-то из ui.js.uiElements,
|
||
// то можно передать ui.js.uiElements целиком или конкретные элементы.
|
||
}
|
||
},
|
||
utils: {
|
||
isTokenValid,
|
||
parseJwtPayloadForValidation // На всякий случай, если понадобится где-то еще
|
||
}
|
||
};
|
||
|
||
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 = localStorage.getItem('jwtToken');
|
||
if (socket.auth) socket.auth.token = currentToken; // Убедимся, что auth объект сокета обновлен
|
||
else socket.auth = { token: currentToken }; // Если auth объекта не было
|
||
|
||
console.log('[Main.js Socket.IO] Event: connect. Socket ID:', socket.id, 'Auth token associated with this connection attempt:', !!currentToken);
|
||
|
||
if (clientState.isLoggedIn && clientState.myUserId && isTokenValid(currentToken)) {
|
||
console.log(`[Main.js Socket.IO] Client state indicates logged in as ${clientState.loggedInUsername} (ID: ${clientState.myUserId}) and token is valid. Requesting game state.`);
|
||
// Если мы на экране выбора игры, показываем сообщение о восстановлении
|
||
if (!clientState.isInGame && (gameSetupDiv.style.display === 'block' || authSection.style.display === 'block')) {
|
||
setGameStatusMessage("Восстановление игровой сессии...");
|
||
}
|
||
socket.emit('requestGameState');
|
||
} else {
|
||
if (clientState.isLoggedIn && !isTokenValid(currentToken)) {
|
||
console.warn('[Main.js Socket.IO connect] Client state says logged in, but token is invalid/expired. Redirecting to login.');
|
||
redirectToLogin("Ваша сессия истекла. Пожалуйста, войдите снова.");
|
||
} else {
|
||
console.log('[Main.js Socket.IO connect] Client state indicates NOT logged in or no valid token. Showing auth screen if not already visible.');
|
||
if (authSection.style.display !== 'block') {
|
||
showAuthScreen(); // Показываем экран логина, если еще не на нем
|
||
}
|
||
setAuthMessage("Пожалуйста, войдите или зарегистрируйтесь."); // Сообщение по умолчанию для экрана логина
|
||
}
|
||
}
|
||
});
|
||
|
||
socket.on('connect_error', (err) => {
|
||
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.js Socket.IO connect_error] Authentication error during connection. Redirecting to login.');
|
||
redirectToLogin("Ошибка аутентификации. Пожалуйста, войдите снова.");
|
||
} else {
|
||
let currentScreenMessageFunc = setAuthMessage;
|
||
if (clientState.isLoggedIn && clientState.isInGame) {
|
||
currentScreenMessageFunc = setGameStatusMessage;
|
||
} else if (clientState.isLoggedIn) { // Если залогинен, но не в игре (на экране выбора)
|
||
currentScreenMessageFunc = setGameStatusMessage;
|
||
}
|
||
currentScreenMessageFunc(`Ошибка подключения: ${err.message}. Попытка переподключения...`, true);
|
||
// Если не залогинены и не на экране авторизации, показываем его
|
||
if (!clientState.isLoggedIn && authSection.style.display !== 'block') {
|
||
showAuthScreen();
|
||
}
|
||
}
|
||
if (turnTimerSpan) turnTimerSpan.textContent = 'Ошибка';
|
||
});
|
||
|
||
socket.on('disconnect', (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;
|
||
}
|
||
|
||
if (reason === 'io server disconnect') {
|
||
messageFunc("Соединение разорвано сервером. Пожалуйста, попробуйте войти снова.", true);
|
||
redirectToLogin("Соединение разорвано сервером. Пожалуйста, войдите снова.");
|
||
} else if (reason === 'io client disconnect') {
|
||
// Это преднамеренный дисконнект (например, при logout или смене токена).
|
||
// Сообщение уже должно быть установлено функцией, вызвавшей дисконнект.
|
||
// Ничего не делаем здесь, чтобы не перезаписать его.
|
||
console.log('[Main.js Socket.IO] Disconnect was intentional (io client disconnect). No additional message needed.');
|
||
} else { // Другие причины (например, проблемы с сетью)
|
||
messageFunc(`Потеряно соединение: ${reason}. Попытка переподключения...`, true);
|
||
}
|
||
if (turnTimerSpan) turnTimerSpan.textContent = 'Откл.';
|
||
clientState.isActionInProgress = false; // На всякий случай сбрасываем флаг при дисконнекте
|
||
});
|
||
|
||
socket.on('gameError', (data) => {
|
||
console.error('[Main.js Socket.IO] Event: gameError. Message:', data.message, 'Data:', JSON.stringify(data));
|
||
clientState.isActionInProgress = false; // Сбрасываем флаг при ошибке сервера
|
||
|
||
if (data.message && (data.message.toLowerCase().includes("сессия истекла") || data.message.toLowerCase().includes("необходимо войти"))) {
|
||
redirectToLogin(data.message);
|
||
return;
|
||
}
|
||
|
||
if (clientState.isInGame && window.gameUI?.addToLog) {
|
||
window.gameUI.addToLog(`❌ Ошибка сервера: ${data.message}`, 'system');
|
||
// Если ошибка произошла в игре, но игра не закончилась, кнопки могут остаться заблокированными.
|
||
// Возможно, стоит проверить, чей ход, и разблокировать, если ход игрока и игра не окончена.
|
||
// Но это зависит от типа ошибки. Сейчас просто логируем.
|
||
} else if (clientState.isLoggedIn) {
|
||
setGameStatusMessage(`❌ Ошибка: ${data.message}`, true);
|
||
enableSetupButtons(); // Разблокируем кнопки, если ошибка на экране выбора игры
|
||
} else {
|
||
setAuthMessage(`❌ Ошибка: ${data.message}`, true);
|
||
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.js Socket.IO] Event: gameNotFound. Message:', data?.message, 'Data:', JSON.stringify(data));
|
||
clientState.isInGame = false;
|
||
resetGameVariables(); // Включает сброс isActionInProgress
|
||
explicitlyHideGameOverModal();
|
||
if (turnTimerContainer) turnTimerContainer.style.display = 'none';
|
||
if (turnTimerSpan) turnTimerSpan.textContent = '--';
|
||
|
||
if (clientState.isLoggedIn && isTokenValid(localStorage.getItem('jwtToken'))) {
|
||
if (gameSetupDiv.style.display !== 'block') { // Если мы не на экране выбора игры, показываем его
|
||
showGameSelectionScreen(clientState.loggedInUsername);
|
||
}
|
||
setGameStatusMessage(data?.message || "Активная игровая сессия не найдена. Выберите новую игру.");
|
||
} else {
|
||
redirectToLogin(data?.message || "Пожалуйста, войдите для продолжения.");
|
||
}
|
||
});
|
||
|
||
// --- Инициализация UI ---
|
||
console.log('[Main.js] Initializing UI visibility...');
|
||
if(authSection) authSection.style.display = 'none';
|
||
if(gameSetupDiv) gameSetupDiv.style.display = 'none';
|
||
if(gameWrapper) gameWrapper.style.display = 'none';
|
||
if(userInfoDiv) userInfoDiv.style.display = 'none';
|
||
if(statusContainer) statusContainer.style.display = 'block'; // Показываем общий контейнер для сообщений
|
||
|
||
if (clientState.isLoggedIn) {
|
||
console.log('[Main.js] Client is considered logged in. Will attempt session recovery on socket connect.');
|
||
// Не показываем экран выбора игры сразу, дожидаемся 'connect' и 'requestGameState'
|
||
setAuthMessage("Подключение и восстановление сессии..."); // Используем authMessage для начального сообщения
|
||
} else {
|
||
console.log('[Main.js] Client is NOT considered logged in. Showing auth screen.');
|
||
showAuthScreen();
|
||
setAuthMessage("Подключение к серверу...");
|
||
}
|
||
|
||
console.log('[Main.js] Attempting to connect socket...');
|
||
socket.connect(); // Подключаемся здесь, после всей инициализации
|
||
console.log('[Main.js] socket.connect() called.');
|
||
}); |