Вернулся к старой концепции main.js без явного указания адреса.

This commit is contained in:
PsiMagistr 2025-05-25 11:16:48 +03:00
parent 4461987bc4
commit 6499e8d9ea

View File

@ -3,7 +3,7 @@
import { initAuth } from './auth.js';
import { initGameSetup } from './gameSetup.js';
import { initGameplay } from './gameplay.js';
// ui.js загружен глобально
// ui.js загружен глобально и ожидает window.* переменных
function parseJwtPayload(token) {
try {
@ -23,8 +23,8 @@ function parseJwtPayload(token) {
}
document.addEventListener('DOMContentLoaded', () => {
const SERVER_URL = 'https://81.177.140.16:3200' //'http://127.0.0.1:3200';
const API_BASE_URL = SERVER_URL;
// SERVER_URL и API_BASE_URL убраны. Socket.IO подключится к источнику загрузки страницы.
// auth.js будет использовать относительные пути для API запросов.
const initialToken = localStorage.getItem('jwtToken');
let clientState = {
@ -33,7 +33,7 @@ document.addEventListener('DOMContentLoaded', () => {
myUserId: null,
isInGame: false,
currentGameId: null,
currentGameState: null, // Будет объектом или null
currentGameState: null,
myPlayerId: null,
myCharacterKey: null,
opponentCharacterKey: null,
@ -62,11 +62,12 @@ document.addEventListener('DOMContentLoaded', () => {
}
}
const socket = io(SERVER_URL, {
const socket = io({ // SERVER_URL удален отсюда
autoConnect: false,
auth: { token: localStorage.getItem('jwtToken') }
});
// --- DOM Элементы ---
const authSection = document.getElementById('auth-section');
const loginForm = document.getElementById('login-form');
const registerForm = document.getElementById('register-form');
@ -85,13 +86,13 @@ document.addEventListener('DOMContentLoaded', () => {
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'); // Он же в ui.elements.gameOver.returnToMenuButton
const returnToMenuButton = document.getElementById('return-to-menu-button');
const turnTimerContainer = document.getElementById('turn-timer-container');
const turnTimerSpan = document.getElementById('turn-timer');
// --- Функции обновления UI и состояния ---
function updateGlobalWindowVariablesForUI() {
// console.log("[Main] Updating global window variables. currentGameState:", clientState.currentGameState ? JSON.parse(JSON.stringify(clientState.currentGameState)) : null);
window.gameState = clientState.currentGameState; // Может быть null
window.gameState = clientState.currentGameState;
window.gameData = {
playerBaseStats: clientState.playerBaseStatsServer,
opponentBaseStats: clientState.opponentBaseStatsServer,
@ -99,18 +100,12 @@ document.addEventListener('DOMContentLoaded', () => {
opponentAbilities: clientState.opponentAbilitiesServer
};
window.myPlayerId = clientState.myPlayerId;
// window.GAME_CONFIG устанавливается при gameStarted/gameState из gameplay.js
}
function resetGameVariables() {
console.log("[Main:resetGameVariables] Resetting game variables. State BEFORE:", JSON.parse(JSON.stringify(clientState)));
clientState.currentGameId = null;
// ВАЖНО: currentGameState должен быть сброшен в состояние "нет игры"
// Либо null, либо объект, который ui.js интерпретирует как "нет игры"
clientState.currentGameState = null;
// Можно также так, если ui.js лучше работает с объектом:
// clientState.currentGameState = { isGameOver: false, player: null, opponent: null, turnNumber: 0 };
clientState.myPlayerId = null;
clientState.myCharacterKey = null;
clientState.opponentCharacterKey = null;
@ -118,9 +113,7 @@ document.addEventListener('DOMContentLoaded', () => {
clientState.opponentBaseStatsServer = null;
clientState.playerAbilitiesServer = null;
clientState.opponentAbilitiesServer = null;
// clientState.isInGame будет установлено в вызывающей функции (showAuthScreen/showGameSelectionScreen)
updateGlobalWindowVariablesForUI(); // Обновляем глобальные переменные СРАЗУ после сброса
updateGlobalWindowVariablesForUI();
console.log("[Main:resetGameVariables] Game variables reset. State AFTER:", JSON.parse(JSON.stringify(clientState)));
}
@ -134,7 +127,6 @@ document.addEventListener('DOMContentLoaded', () => {
if (gameOverScreenElement && !gameOverScreenElement.classList.contains(hiddenClass)) {
gameOverScreenElement.classList.add(hiddenClass);
// Принудительно сбрасываем стили для анимации скрытия, если она есть
gameOverScreenElement.style.opacity = '0';
if (modalContentElement) {
modalContentElement.style.transform = 'scale(0.8) translateY(30px)';
@ -144,31 +136,27 @@ document.addEventListener('DOMContentLoaded', () => {
} else if (gameOverScreenElement) {
console.log("[Main:explicitlyHideGameOverModal] Game Over screen was already hidden or not found.");
}
if (messageElement) messageElement.textContent = ''; // Очищаем сообщение
if (messageElement) messageElement.textContent = '';
} else {
console.warn("[Main:explicitlyHideGameOverModal] Cannot hide Game Over modal: gameUI or GAME_CONFIG not available.");
}
}
function showAuthScreen() {
console.log("[Main:showAuthScreen] Showing Auth Screen. Resetting game state.");
authSection.style.display = 'block';
userInfoDiv.style.display = 'none';
gameSetupDiv.style.display = 'none';
gameWrapper.style.display = 'none';
explicitlyHideGameOverModal(); // <-- ЯВНО СКРЫВАЕМ МОДАЛКУ
explicitlyHideGameOverModal();
statusContainer.style.display = 'block';
clientState.isInGame = false; // Важно
resetGameVariables(); // Сбрасываем все переменные предыдущей игры
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; // Кнопка Logout должна быть недоступна на экране логина
if(logoutButton) logoutButton.disabled = true;
}
function showGameSelectionScreen(username) {
@ -176,12 +164,10 @@ document.addEventListener('DOMContentLoaded', () => {
authSection.style.display = 'none';
userInfoDiv.style.display = 'block';
if(loggedInUsernameSpan) loggedInUsernameSpan.textContent = username;
if(logoutButton) logoutButton.disabled = false; // Logout доступен
if(logoutButton) logoutButton.disabled = false;
gameSetupDiv.style.display = 'block';
gameWrapper.style.display = 'none';
explicitlyHideGameOverModal(); // <-- ЯВНО СКРЫВАЕМ МОДАЛКУ
explicitlyHideGameOverModal();
setGameStatusMessage("Выберите режим игры или присоединитесь к существующей.");
statusContainer.style.display = 'block';
@ -195,15 +181,11 @@ document.addEventListener('DOMContentLoaded', () => {
if (gameIdInput) gameIdInput.value = '';
const elenaRadio = document.getElementById('char-elena');
if (elenaRadio) elenaRadio.checked = true;
clientState.isInGame = false; // Важно
resetGameVariables(); // Сбрасываем все переменные предыдущей игры
clientState.isInGame = false;
resetGameVariables();
if (turnTimerContainer) turnTimerContainer.style.display = 'none';
if (turnTimerSpan) turnTimerSpan.textContent = '--';
enableSetupButtons();
// Убедимся, что кнопка "Вернуться в меню" на gameOver модалке (если она вдруг видима) активна,
// хотя сама модалка должна быть скрыта.
if (window.gameUI?.uiElements?.gameOver?.returnToMenuButton) {
window.gameUI.uiElements.gameOver.returnToMenuButton.disabled = false;
}
@ -211,9 +193,6 @@ document.addEventListener('DOMContentLoaded', () => {
function showGameScreen() {
console.log("[Main:showGameScreen] Showing Game Screen.");
// Не нужно здесь вызывать explicitlyHideGameOverModal, так как если игра начинается,
// а модалка была видима, это ошибка логики где-то еще.
// GameStarted/GameState должно само приводить UI в порядок.
authSection.style.display = 'none';
userInfoDiv.style.display = 'block';
if(logoutButton) logoutButton.disabled = false;
@ -221,13 +200,12 @@ document.addEventListener('DOMContentLoaded', () => {
gameWrapper.style.display = 'flex';
setGameStatusMessage("");
statusContainer.style.display = 'none';
clientState.isInGame = true; // Важно
updateGlobalWindowVariablesForUI(); // Обновляем перед тем, как UI начнет рендерить игровой экран
clientState.isInGame = true;
updateGlobalWindowVariablesForUI();
if (turnTimerContainer) turnTimerContainer.style.display = 'block';
if (turnTimerSpan) turnTimerSpan.textContent = '--';
}
function setAuthMessage(message, isError = false) {
if (authMessage) {
authMessage.textContent = message;
@ -259,9 +237,9 @@ document.addEventListener('DOMContentLoaded', () => {
if(createPvPGameButton) createPvPGameButton.disabled = false;
if(joinPvPGameButton) joinPvPGameButton.disabled = false;
if(findRandomPvPGameButton) findRandomPvPGameButton.disabled = false;
// Кнопки в списке доступных игр управляются в gameSetup.js -> updateAvailableGamesList
}
// --- Сборка зависимостей для модулей ---
const dependencies = {
socket,
clientState,
@ -271,7 +249,7 @@ document.addEventListener('DOMContentLoaded', () => {
showGameScreen,
setAuthMessage,
setGameStatusMessage,
resetGameVariables, // Передаем, чтобы другие модули могли вызвать при необходимости (хотя лучше избегать)
resetGameVariables,
updateGlobalWindowVariablesForUI,
disableSetupButtons,
enableSetupButtons,
@ -279,16 +257,20 @@ document.addEventListener('DOMContentLoaded', () => {
loginForm, registerForm, logoutButton,
createAIGameButton, createPvPGameButton, joinPvPGameButton,
findRandomPvPGameButton, gameIdInput, availableGamesDiv,
pvpCharacterRadios, returnToMenuButton, // returnToMenuButton из gameplay.js, но здесь тоже может быть полезен
pvpCharacterRadios, returnToMenuButton,
}
},
API_BASE_URL: API_BASE_URL
// API_BASE_URL больше не передается, т.к. auth.js будет использовать относительные пути.
// Если auth.js все еще требует явного API_BASE_URL для случая, когда он не может
// сам определить window.location.origin, можно было бы передать:
// API_BASE_URL: window.location.origin
};
initAuth(dependencies);
initGameSetup(dependencies);
initGameplay(dependencies);
// --- Обработчики событий 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);
@ -296,17 +278,12 @@ document.addEventListener('DOMContentLoaded', () => {
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') {
// Если мы на экране логина или выбора игры, но считаем себя залогиненными,
// покажем сообщение о восстановлении.
setGameStatusMessage("Восстановление игровой сессии...");
}
// Не очищаем здесь resetGameVariables, так как gameplay.js ожидает, что clientState может содержать
// предыдущие данные, которые он перезапишет при получении gameState или gameStarted.
// Если придет gameNotFound, то там уже будет reset.
socket.emit('requestGameState');
} else {
console.log('[Main:SocketConnect] Client state indicates NOT logged in. Showing auth screen.');
showAuthScreen(); // Убеждаемся, что все сброшено и показан экран логина
showAuthScreen();
setAuthMessage("Пожалуйста, войдите или зарегистрируйтесь.");
}
});
@ -325,19 +302,20 @@ document.addEventListener('DOMContentLoaded', () => {
clientState.loggedInUsername = '';
clientState.myUserId = null;
if (socket.auth) socket.auth.token = null;
showAuthScreen(); // Это вызовет resetGameVariables и скроет модалку
showAuthScreen();
setAuthMessage("Ошибка аутентификации. Пожалуйста, войдите снова.", true);
} else {
// Общая ошибка подключения
let currentScreenMessageFunc = setAuthMessage;
if (clientState.isLoggedIn && clientState.isInGame) {
setGameStatusMessage(`Ошибка подключения: ${err.message}. Попытка переподключения...`, true);
currentScreenMessageFunc = setGameStatusMessage;
} else if (clientState.isLoggedIn) {
setGameStatusMessage(`Ошибка подключения к серверу: ${err.message}. Попытка переподключения...`, true);
} else {
setAuthMessage(`Ошибка подключения к серверу: ${err.message}. Попытка переподключения...`, true);
if (authSection.style.display !== 'block') {
showAuthScreen(); // Если не на экране логина, но ошибка не auth, все равно показываем его
}
currentScreenMessageFunc = setGameStatusMessage; // Или setAuthMessage, если statusContainer не виден
}
currentScreenMessageFunc(`Ошибка подключения: ${err.message}. Попытка переподключения...`, true);
if (authSection.style.display !== 'block' && !clientState.isLoggedIn) {
showAuthScreen(); // Если не на экране логина и не залогинен, показываем его
}
}
if (turnTimerSpan) turnTimerSpan.textContent = 'Ошибка';
@ -345,33 +323,24 @@ document.addEventListener('DOMContentLoaded', () => {
socket.on('disconnect', (reason) => {
console.warn('[Main:SocketDisconnect] Disconnected from server:', reason);
// Сообщения в зависимости от текущего состояния
let messageFunc = setAuthMessage;
if (clientState.isInGame) {
setGameStatusMessage(`Потеряно соединение: ${reason}. Попытка переподключения...`, true);
} else if (clientState.isLoggedIn) {
// Уже должен быть на экране выбора игры или восстановления, setGameStatusMessage там уместно
if (gameSetupDiv.style.display === 'block') {
setGameStatusMessage(`Потеряно соединение с сервером: ${reason}. Попытка переподключения...`, true);
} else {
// Если где-то между экранами, но залогинен
setAuthMessage(`Потеряно соединение: ${reason}. Попытка переподключения...`, true); // Используем authMessage для общего случая
}
} else {
setAuthMessage(`Потеряно соединение с сервером: ${reason}. Попытка переподключения...`, true);
messageFunc = setGameStatusMessage;
} else if (clientState.isLoggedIn && gameSetupDiv.style.display === 'block') {
messageFunc = setGameStatusMessage;
}
messageFunc(`Потеряно соединение: ${reason}. Попытка переподключения...`, true);
if (turnTimerSpan) turnTimerSpan.textContent = 'Откл.';
// Не сбрасываем clientState.isLoggedIn здесь, чтобы socket.connect мог попытаться восстановить сессию
});
socket.on('gameError', (data) => {
console.error('[Main:SocketGameError] Received gameError from server:', data.message);
if (clientState.isInGame && window.gameUI?.addToLog) {
window.gameUI.addToLog(`❌ Ошибка сервера: ${data.message}`, 'system');
// Можно добавить setGameStatusMessage и здесь, если ошибка критическая для игры
} else if (clientState.isLoggedIn) { // На экране выбора игры
} else if (clientState.isLoggedIn) {
setGameStatusMessage(`❌ Ошибка: ${data.message}`, true);
enableSetupButtons(); // Разблокировать кнопки, если ошибка при создании/присоединении
} else { // На экране логина
enableSetupButtons();
} else {
setAuthMessage(`❌ Ошибка: ${data.message}`, true);
if(registerForm) registerForm.querySelector('button').disabled = false;
if(loginForm) loginForm.querySelector('button').disabled = false;
@ -380,27 +349,22 @@ document.addEventListener('DOMContentLoaded', () => {
socket.on('gameNotFound', (data) => {
console.log('[Main:SocketGameNotFound] Game not found/ended after request:', data?.message);
// Важно: gameNotFound означает, что активной игры нет.
// Сбрасываем состояние и показываем экран выбора игры, если залогинены.
clientState.isInGame = false; // Явно выходим из игры
resetGameVariables(); // Полный сброс игровых переменных
explicitlyHideGameOverModal(); // Убеждаемся, что модалка скрыта
clientState.isInGame = false;
resetGameVariables();
explicitlyHideGameOverModal();
if (turnTimerContainer) turnTimerContainer.style.display = 'none';
if (turnTimerSpan) turnTimerSpan.textContent = '--';
if (clientState.isLoggedIn && clientState.myUserId) {
showGameSelectionScreen(clientState.loggedInUsername); // Переходим на выбор игры (он вызовет resetGameVariables еще раз, но это не страшно)
showGameSelectionScreen(clientState.loggedInUsername);
setGameStatusMessage(data?.message || "Активная игровая сессия не найдена. Выберите новую игру.");
} else {
// Если по какой-то причине мы не залогинены (например, токен истек и connect_error сбросил isLoggedIn)
showAuthScreen();
setAuthMessage(data?.message || "Пожалуйста, войдите.");
}
});
// Инициализация UI
// --- Инициализация UI ---
authSection.style.display = 'none';
gameSetupDiv.style.display = 'none';
gameWrapper.style.display = 'none';
@ -408,10 +372,10 @@ document.addEventListener('DOMContentLoaded', () => {
statusContainer.style.display = 'block';
if (clientState.isLoggedIn) {
setGameStatusMessage("Подключение и восстановление сессии..."); // Или setAuthMessage, если statusContainer не виден сразу
setGameStatusMessage("Подключение и восстановление сессии...");
} else {
setAuthMessage("Подключение к серверу...");
}
socket.connect();
socket.connect(); // Начинаем подключение к серверу
});