bc/bc.js
2025-05-14 19:02:46 +03:00

166 lines
9.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// bc.js (или server.js - ваш основной файл сервера)
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const path = require('path');
//hello4
// Серверные модули
const GameManager = require('./server_modules/gameManager');
const authController = require('./server_modules/auth'); // Ваш модуль аутентификации
// const GAME_CONFIG = require('./server_modules/config'); // Не используется напрямую здесь, но может быть полезен для отладки
const hostname = 'localhost'; // или '0.0.0.0' для доступа извне
const app = express();
const server = http.createServer(app);
const io = socketIo(server, {
cors: {
origin: "*", // Разрешить все источники для простоты разработки. В продакшене укажите конкретный домен клиента.
methods: ["GET", "POST"]
}
});
const PORT = process.env.PORT || 3200;
// Статическое обслуживание файлов из папки 'public'
app.use(express.static(path.join(__dirname, 'public')));
// Создание экземпляра GameManager
const gameManager = new GameManager(io);
io.on('connection', (socket) => {
console.log(`[Server BC.JS] New client connected: ${socket.id}`);
// При подключении нового клиента, отправляем ему текущий список доступных PvP игр
const availableGames = gameManager.getAvailablePvPGamesListForClient();
socket.emit('availablePvPGamesList', availableGames);
// Обработчик запроса на обновление списка PvP игр
socket.on('requestPvPGameList', () => {
const currentAvailableGames = gameManager.getAvailablePvPGamesListForClient();
socket.emit('availablePvPGamesList', currentAvailableGames);
});
// --- Аутентификация ---
socket.on('register', async (data) => {
console.log(`[Server BC.JS] Received 'register' event from ${socket.id} with username: ${data?.username}`);
if (!data || typeof data.username !== 'string' || typeof data.password !== 'string') {
socket.emit('registerResponse', { success: false, message: 'Некорректные данные запроса для регистрации.' });
return;
}
const result = await authController.registerUser(data.username, data.password);
socket.emit('registerResponse', result);
});
socket.on('login', async (data) => {
console.log(`[Server BC.JS] Received 'login' event from ${socket.id} with username: ${data?.username}`);
if (!data || typeof data.username !== 'string' || typeof data.password !== 'string') {
socket.emit('loginResponse', { success: false, message: 'Некорректные данные запроса для входа.' });
return;
}
const result = await authController.loginUser(data.username, data.password);
if (result.success) {
// Сохраняем данные пользователя в объекте сокета для последующего использования
socket.userData = { userId: result.userId, username: result.username };
console.log(`[Server BC.JS] User ${result.username} (ID: ${result.userId}) associated with socket ${socket.id}. Welcome!`);
}
socket.emit('loginResponse', result);
});
socket.on('logout', () => {
const username = socket.userData?.username || socket.id;
console.log(`[Server BC.JS] Received 'logout' event from ${username}.`);
if (socket.userData) {
// При выходе пользователя, обрабатываем его возможное участие в играх
gameManager.handleDisconnect(socket.id, socket.userData.userId); // Используем userId для более точной обработки
delete socket.userData; // Удаляем данные пользователя из сокета
console.log(`[Server BC.JS] User data cleared for ${username}.`);
}
// Можно отправить подтверждение выхода, если нужно
// socket.emit('logoutResponse', { success: true, message: 'Вы успешно вышли.' });
});
// --- Управление Играми ---
socket.on('createGame', (data) => {
if (!socket.userData) {
socket.emit('gameError', { message: "Ошибка: Вы не авторизованы для создания игры." });
return;
}
const mode = data?.mode || 'ai'; // 'ai' или 'pvp'
const characterKey = (data?.characterKey === 'almagest') ? 'almagest' : 'elena'; // По умолчанию Елена
console.log(`[Server BC.JS] User ${socket.userData.username} (socket: ${socket.id}) requests createGame. Mode: ${mode}, Character: ${characterKey}`);
gameManager.createGame(socket, mode, characterKey, socket.userData.userId);
});
socket.on('joinGame', (data) => {
if (!socket.userData) {
socket.emit('gameError', { message: "Ошибка: Вы не авторизованы для присоединения к игре." });
return;
}
console.log(`[Server BC.JS] User ${socket.userData.username} (socket: ${socket.id}) requests joinGame for ID: ${data?.gameId}`);
if (data && typeof data.gameId === 'string') {
gameManager.joinGame(socket, data.gameId, socket.userData.userId);
} else {
socket.emit('gameError', { message: 'Ошибка присоединения: неверный формат ID игры.' });
}
});
socket.on('findRandomGame', (data) => {
if (!socket.userData) {
socket.emit('gameError', { message: "Ошибка: Вы не авторизованы для поиска игры." });
return;
}
const characterKey = (data?.characterKey === 'almagest') ? 'almagest' : 'elena';
console.log(`[Server BC.JS] User ${socket.userData.username} (socket: ${socket.id}) requests findRandomGame. Preferred Character: ${characterKey}`);
gameManager.findAndJoinRandomPvPGame(socket, characterKey, socket.userData.userId);
});
// --- Игровые Действия ---
socket.on('playerAction', (data) => {
if (!socket.userData) {
// Если пользователь не авторизован, но пытается совершить действие (маловероятно при правильной логике клиента)
socket.emit('gameError', { message: "Ошибка: Вы не авторизованы для совершения этого действия." });
return;
}
// GameManager сам проверит, принадлежит ли этот сокет к активной игре
gameManager.handlePlayerAction(socket.id, data);
});
// Обработчик 'requestRestart' удален, так как эта функциональность заменена на "возврат в меню"
// --- Отключение Клиента ---
socket.on('disconnect', (reason) => {
const username = socket.userData?.username || socket.id;
console.log(`[Server BC.JS] Client ${username} disconnected. Reason: ${reason}. Socket ID: ${socket.id}`);
// Передаем userId, если он есть, для более точной обработки в GameManager
// (например, для удаления его ожидающих игр или корректного завершения активной игры)
const userId = socket.userData?.userId;
gameManager.handleDisconnect(socket.id, userId);
// socket.userData автоматически очистится для этого объекта socket при его удалении из io.sockets
});
// Для отладки: вывод списка активных игр каждые N секунд
// setInterval(() => {
// console.log("--- Active Games ---");
// const activeGames = gameManager.getActiveGamesList();
// if (activeGames.length > 0) {
// activeGames.forEach(game => {
// console.log(`ID: ${game.id}, Mode: ${game.mode}, Players: ${game.playerCount}, GameOver: ${game.isGameOver}, P1: ${game.playerSlot}, P2: ${game.opponentSlot}, Owner: ${game.ownerUserId}, Pending: ${game.pending}`);
// });
// } else {
// console.log("No active games.");
// }
// console.log("--- Pending PvP Games IDs ---");
// console.log(gameManager.pendingPvPGames.map(id => id.substring(0,8)));
// console.log("--- User to Pending Game Map ---");
// console.log(gameManager.userToPendingGame);
// console.log("---------------------");
// }, 30000); // Каждые 30 секунд
});
server.listen(PORT, hostname, () => {
console.log(`==== Medieval Clash Server ====`);
console.log(` Listening on http://${hostname}:${PORT}`);
console.log(` Public files served from: ${path.join(__dirname, 'public')}`);
console.log(` Waiting for connections...`);
console.log(`===============================`);
});