397 lines
26 KiB
JavaScript
397 lines
26 KiB
JavaScript
// /server/game/instance/PlayerConnectionHandler.js
|
||
const GAME_CONFIG = require('../../core/config');
|
||
const dataUtils = require('../../data/dataUtils'); // Потребуется для получения данных персонажа при реконнекте
|
||
|
||
class PlayerConnectionHandler {
|
||
constructor(gameInstance) {
|
||
this.gameInstance = gameInstance; // Ссылка на основной GameInstance
|
||
this.io = gameInstance.io;
|
||
this.gameId = gameInstance.id;
|
||
this.mode = gameInstance.mode;
|
||
|
||
this.players = {}; // { socket.id: { id, socket, chosenCharacterKey, identifier, isTemporarilyDisconnected } }
|
||
this.playerSockets = {}; // { playerIdRole: socket }
|
||
this.playerCount = 0;
|
||
|
||
this.reconnectTimers = {}; // { playerIdRole: { timerId, updateIntervalId, startTimeMs, durationMs } }
|
||
this.pausedTurnState = null; // { remainingTime, forPlayerRoleIsPlayer, isAiCurrentlyMoving }
|
||
console.log(`[PCH for Game ${this.gameId}] Initialized.`);
|
||
}
|
||
|
||
addPlayer(socket, chosenCharacterKey = 'elena', identifier) {
|
||
console.log(`[PCH ${this.gameId}] addPlayer attempt. Socket: ${socket.id}, CharKey: ${chosenCharacterKey}, Identifier: ${identifier}`);
|
||
const existingPlayerByIdentifier = Object.values(this.players).find(p => p.identifier === identifier);
|
||
|
||
if (existingPlayerByIdentifier) {
|
||
console.warn(`[PCH ${this.gameId}] Identifier ${identifier} already associated with player role ${existingPlayerByIdentifier.id} (socket ${existingPlayerByIdentifier.socket?.id}). Handling as potential reconnect.`);
|
||
if (this.gameInstance.gameState && this.gameInstance.gameState.isGameOver) {
|
||
console.warn(`[PCH ${this.gameId}] Player ${identifier} trying to (re)join an already finished game. Emitting gameError.`);
|
||
socket.emit('gameError', { message: 'Эта игра уже завершена.' });
|
||
this.gameInstance.gameManager._cleanupGame(this.gameId, `rejoin_attempt_to_finished_game_pch_${identifier}`);
|
||
return false;
|
||
}
|
||
if (existingPlayerByIdentifier.isTemporarilyDisconnected) {
|
||
return this.handlePlayerReconnected(existingPlayerByIdentifier.id, socket);
|
||
}
|
||
socket.emit('gameError', { message: 'Вы уже находитесь в этой игре. Попробуйте обновить страницу.' });
|
||
return false;
|
||
}
|
||
|
||
if (Object.keys(this.players).length >= 2 && this.playerCount >=2) {
|
||
socket.emit('gameError', { message: 'Эта игра уже заполнена.' });
|
||
return false;
|
||
}
|
||
|
||
let assignedPlayerId;
|
||
let actualCharacterKey = chosenCharacterKey || 'elena';
|
||
|
||
if (this.mode === 'ai') {
|
||
if (this.playerSockets[GAME_CONFIG.PLAYER_ID]) {
|
||
socket.emit('gameError', { message: 'Нельзя присоединиться к AI игре как второй игрок.' });
|
||
return false;
|
||
}
|
||
assignedPlayerId = GAME_CONFIG.PLAYER_ID;
|
||
} else { // pvp
|
||
if (!this.playerSockets[GAME_CONFIG.PLAYER_ID]) {
|
||
assignedPlayerId = GAME_CONFIG.PLAYER_ID;
|
||
} else if (!this.playerSockets[GAME_CONFIG.OPPONENT_ID]) {
|
||
assignedPlayerId = GAME_CONFIG.OPPONENT_ID;
|
||
const firstPlayerInfo = Object.values(this.players).find(p => p.id === GAME_CONFIG.PLAYER_ID);
|
||
if (firstPlayerInfo && firstPlayerInfo.chosenCharacterKey === actualCharacterKey) {
|
||
if (actualCharacterKey === 'elena') actualCharacterKey = 'almagest';
|
||
else if (actualCharacterKey === 'almagest') actualCharacterKey = 'elena';
|
||
// Добавьте другие пары, если нужно, или более общую логику выбора другого персонажа
|
||
}
|
||
} else {
|
||
socket.emit('gameError', { message: 'Не удалось найти свободный слот в PvP игре.' });
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// Если для этой роли уже был игрок (например, старый сокет), удаляем его
|
||
const oldPlayerSocketIdForRole = Object.keys(this.players).find(sid => this.players[sid].id === assignedPlayerId && this.players[sid].socket?.id !== socket.id);
|
||
if (oldPlayerSocketIdForRole) {
|
||
const oldPlayerInfo = this.players[oldPlayerSocketIdForRole];
|
||
if(oldPlayerInfo.socket) { try { oldPlayerInfo.socket.leave(this.gameId); } catch(e){} } // Убедимся, что старый сокет покинул комнату
|
||
delete this.players[oldPlayerSocketIdForRole];
|
||
}
|
||
|
||
|
||
this.players[socket.id] = {
|
||
id: assignedPlayerId,
|
||
socket: socket,
|
||
chosenCharacterKey: actualCharacterKey,
|
||
identifier: identifier,
|
||
isTemporarilyDisconnected: false
|
||
};
|
||
this.playerSockets[assignedPlayerId] = socket;
|
||
this.playerCount++;
|
||
socket.join(this.gameId);
|
||
|
||
// Сообщаем GameInstance об установленных ключах и владельце
|
||
if (assignedPlayerId === GAME_CONFIG.PLAYER_ID) this.gameInstance.setPlayerCharacterKey(actualCharacterKey);
|
||
else if (assignedPlayerId === GAME_CONFIG.OPPONENT_ID) this.gameInstance.setOpponentCharacterKey(actualCharacterKey);
|
||
|
||
if (!this.gameInstance.ownerIdentifier && (this.mode === 'ai' || (this.mode === 'pvp' && assignedPlayerId === GAME_CONFIG.PLAYER_ID))) {
|
||
this.gameInstance.setOwnerIdentifier(identifier);
|
||
}
|
||
|
||
const charData = dataUtils.getCharacterData(actualCharacterKey); // Используем dataUtils напрямую
|
||
console.log(`[PCH ${this.gameId}] Player ${identifier} (Socket: ${socket.id}) added as ${assignedPlayerId} with char ${charData?.baseStats?.name || actualCharacterKey}. Active players: ${this.playerCount}. Owner: ${this.gameInstance.ownerIdentifier}`);
|
||
return true;
|
||
}
|
||
|
||
removePlayer(socketId, reason = "unknown_reason_for_removal") {
|
||
const playerInfo = this.players[socketId];
|
||
if (playerInfo) {
|
||
const playerRole = playerInfo.id;
|
||
const playerIdentifier = playerInfo.identifier;
|
||
console.log(`[PCH ${this.gameId}] Final removal of player ${playerIdentifier} (Socket: ${socketId}, Role: ${playerRole}). Reason: ${reason}.`);
|
||
|
||
if (playerInfo.socket) {
|
||
try { playerInfo.socket.leave(this.gameId); } catch (e) { /* ignore */ }
|
||
}
|
||
|
||
if (!playerInfo.isTemporarilyDisconnected) { // Уменьшаем счетчик только если это был активный игрок, а не временное отключение
|
||
this.playerCount--;
|
||
}
|
||
|
||
delete this.players[socketId];
|
||
if (this.playerSockets[playerRole]?.id === socketId) { // Если это был текущий сокет для роли
|
||
delete this.playerSockets[playerRole];
|
||
}
|
||
this.clearReconnectTimer(playerRole); // Очищаем таймер переподключения для этой роли
|
||
|
||
console.log(`[PCH ${this.gameId}] Player ${playerIdentifier} removed. Active players now: ${this.playerCount}.`);
|
||
|
||
// Сигнализируем GameInstance, чтобы он решил, нужно ли завершать игру
|
||
this.gameInstance.handlePlayerPermanentlyLeft(playerRole, playerInfo.chosenCharacterKey, reason);
|
||
|
||
} else {
|
||
console.warn(`[PCH ${this.gameId}] removePlayer called for unknown socketId: ${socketId}`);
|
||
}
|
||
}
|
||
|
||
handlePlayerPotentiallyLeft(playerIdRole, identifier, characterKey) {
|
||
console.log(`[PCH ${this.gameId}] handlePlayerPotentiallyLeft for role ${playerIdRole}, id ${identifier}, char ${characterKey}`);
|
||
// Находим запись игрока по роли и идентификатору, так как сокет мог уже измениться или быть удален
|
||
const playerEntry = Object.values(this.players).find(p => p.id === playerIdRole && p.identifier === identifier);
|
||
|
||
if (!playerEntry || !playerEntry.socket) {
|
||
console.warn(`[PCH ${this.gameId}] No player entry or socket found for ${identifier} (role ${playerIdRole}) during potential left.`);
|
||
return;
|
||
}
|
||
if (this.gameInstance.gameState && this.gameInstance.gameState.isGameOver) {
|
||
console.log(`[PCH ${this.gameId}] Game already over, not handling potential left for ${identifier}.`);
|
||
return;
|
||
}
|
||
if (playerEntry.isTemporarilyDisconnected) {
|
||
console.log(`[PCH ${this.gameId}] Player ${identifier} already marked as temp disconnected.`);
|
||
return;
|
||
}
|
||
|
||
playerEntry.isTemporarilyDisconnected = true;
|
||
this.playerCount--; // Уменьшаем счетчик активных игроков
|
||
console.log(`[PCH ${this.gameId}] Player ${identifier} (role ${playerIdRole}) temp disconnected. Active: ${this.playerCount}. Starting reconnect timer.`);
|
||
|
||
const disconnectedName = this.gameInstance.gameState?.[playerIdRole]?.name || characterKey || `Игрок (Роль ${playerIdRole})`;
|
||
this.gameInstance.addToLog(`🔌 Игрок ${disconnectedName} отключился. Ожидание переподключения...`, GAME_CONFIG.LOG_TYPE_SYSTEM);
|
||
this.gameInstance.broadcastLogUpdate();
|
||
|
||
// Уведомляем другого игрока, если он есть и подключен
|
||
const otherPlayerRole = playerIdRole === GAME_CONFIG.PLAYER_ID ? GAME_CONFIG.OPPONENT_ID : GAME_CONFIG.PLAYER_ID;
|
||
const otherSocket = this.playerSockets[otherPlayerRole]; // Берем сокет из нашего this.playerSockets
|
||
const otherPlayerEntry = Object.values(this.players).find(p=> p.id === otherPlayerRole);
|
||
|
||
if (otherSocket?.connected && otherPlayerEntry && !otherPlayerEntry.isTemporarilyDisconnected) {
|
||
otherSocket.emit('opponentDisconnected', {
|
||
disconnectedPlayerId: playerIdRole,
|
||
disconnectedCharacterName: disconnectedName,
|
||
});
|
||
}
|
||
|
||
// Приостанавливаем таймер хода, если он активен
|
||
if (this.gameInstance.turnTimer.isActive() || (this.mode === 'ai' && this.gameInstance.turnTimer.isAiCurrentlyMakingMove) ) {
|
||
this.pausedTurnState = this.gameInstance.turnTimer.pause();
|
||
console.log(`[PCH ${this.gameId}] Turn timer paused due to disconnect. State:`, JSON.stringify(this.pausedTurnState));
|
||
} else {
|
||
this.pausedTurnState = null; // Явно сбрасываем, если таймер не был активен
|
||
}
|
||
|
||
this.clearReconnectTimer(playerIdRole); // Очищаем старый таймер, если был
|
||
const reconnectDuration = GAME_CONFIG.RECONNECT_TIMEOUT_MS || 30000;
|
||
const reconnectStartTime = Date.now();
|
||
|
||
// Таймер для обновления UI клиента
|
||
const updateInterval = setInterval(() => {
|
||
const remaining = reconnectDuration - (Date.now() - reconnectStartTime);
|
||
if (remaining <= 0) { // Если основной таймаут уже сработал или время вышло
|
||
if (this.reconnectTimers[playerIdRole]?.updateIntervalId) clearInterval(this.reconnectTimers[playerIdRole].updateIntervalId);
|
||
this.io.to(this.gameId).emit('reconnectTimerUpdate', { disconnectingPlayerId: playerIdRole, remainingTime: 0 });
|
||
return;
|
||
}
|
||
this.io.to(this.gameId).emit('reconnectTimerUpdate', { disconnectingPlayerId: playerIdRole, remainingTime: Math.ceil(remaining) });
|
||
}, 1000);
|
||
|
||
// Основной таймер на окончательное удаление
|
||
const timeoutId = setTimeout(() => {
|
||
this.clearReconnectTimer(playerIdRole); // Очищаем таймеры (включая updateInterval)
|
||
const stillDiscPlayer = Object.values(this.players).find(p => p.id === playerIdRole && p.identifier === identifier);
|
||
if (stillDiscPlayer && stillDiscPlayer.isTemporarilyDisconnected) {
|
||
// Передаем socket.id из записи, а не старый socketId, который мог быть от предыдущего сокета
|
||
this.removePlayer(stillDiscPlayer.socket.id, "reconnect_timeout");
|
||
}
|
||
}, reconnectDuration);
|
||
this.reconnectTimers[playerIdRole] = { timerId: timeoutId, updateIntervalId: updateInterval, startTimeMs: reconnectStartTime, durationMs: reconnectDuration };
|
||
}
|
||
|
||
handlePlayerReconnected(playerIdRole, newSocket) {
|
||
const identifier = newSocket.userData?.userId; // Получаем идентификатор из нового сокета
|
||
console.log(`[PCH ${this.gameId}] handlePlayerReconnected for role ${playerIdRole}, id ${identifier}, newSocket ${newSocket.id}`);
|
||
|
||
if (this.gameInstance.gameState && this.gameInstance.gameState.isGameOver) {
|
||
newSocket.emit('gameError', { message: 'Игра уже завершена.' });
|
||
this.gameInstance.gameManager._cleanupGame(this.gameId, `reconnect_to_finished_game_pch_${identifier}`);
|
||
return false;
|
||
}
|
||
|
||
// Находим запись игрока по роли и идентификатору
|
||
const playerEntry = Object.values(this.players).find(p => p.id === playerIdRole && p.identifier === identifier);
|
||
|
||
if (playerEntry && playerEntry.isTemporarilyDisconnected) {
|
||
this.clearReconnectTimer(playerIdRole);
|
||
this.io.to(this.gameId).emit('reconnectTimerUpdate', { disconnectingPlayerId: playerIdRole, remainingTime: null }); // Сигнал, что таймер остановлен
|
||
|
||
// Удаляем старую запись по socket.id, если сокет действительно новый
|
||
const oldSocketId = playerEntry.socket.id;
|
||
if (this.players[oldSocketId] && oldSocketId !== newSocket.id) {
|
||
delete this.players[oldSocketId];
|
||
}
|
||
|
||
// Обновляем запись игрока
|
||
playerEntry.socket = newSocket;
|
||
playerEntry.isTemporarilyDisconnected = false;
|
||
this.players[newSocket.id] = playerEntry; // Добавляем/обновляем запись с новым socket.id
|
||
this.playerSockets[playerIdRole] = newSocket; // Обновляем активный сокет для роли
|
||
this.playerCount++; // Восстанавливаем счетчик активных игроков
|
||
|
||
newSocket.join(this.gameId);
|
||
const reconnectedName = this.gameInstance.gameState?.[playerIdRole]?.name || playerEntry.chosenCharacterKey;
|
||
console.log(`[PCH ${this.gameId}] Player ${identifier} (${reconnectedName}) reconnected. Active: ${this.playerCount}.`);
|
||
this.gameInstance.addToLog(`🔌 Игрок ${reconnectedName} снова в игре!`, GAME_CONFIG.LOG_TYPE_SYSTEM);
|
||
|
||
const pData = dataUtils.getCharacterData(playerEntry.chosenCharacterKey);
|
||
const oppRoleKey = playerIdRole === GAME_CONFIG.PLAYER_ID ? GAME_CONFIG.OPPONENT_ID : GAME_CONFIG.PLAYER_ID;
|
||
// Получаем ключ персонажа оппонента из gameState ИЛИ из предварительно сохраненных ключей в GameInstance
|
||
let oCharKey = this.gameInstance.gameState?.[oppRoleKey]?.characterKey ||
|
||
(playerIdRole === GAME_CONFIG.PLAYER_ID ? this.gameInstance.opponentCharacterKey : this.gameInstance.playerCharacterKey);
|
||
const oData = oCharKey ? dataUtils.getCharacterData(oCharKey) : null;
|
||
|
||
// Если gameState нет (маловероятно при реконнекте в активную игру, но возможно если это был первый игрок PvP)
|
||
// GameInstance должен сам решить, нужно ли ему initializeGame()
|
||
if (!this.gameInstance.gameState) {
|
||
// Пытаемся инициализировать игру, если она не была инициализирована
|
||
// Это важно, если первый игрок в PvP отключался до подключения второго
|
||
if (!this.gameInstance.initializeGame()) {
|
||
this.gameInstance._handleCriticalError('reconnect_no_gs_after_init_pch', 'PCH: GS null after re-init on reconnect.');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
newSocket.emit('gameStarted', {
|
||
gameId: this.gameId,
|
||
yourPlayerId: playerIdRole,
|
||
initialGameState: this.gameInstance.gameState, // Отправляем текущее состояние
|
||
playerBaseStats: pData?.baseStats, // Данные для этого игрока
|
||
opponentBaseStats: oData?.baseStats || dataUtils.getCharacterBaseStats(null) || {name: 'Ожидание...', maxHp:1, maxResource:0, resourceName:'N/A', attackPower:0, characterKey: null},
|
||
playerAbilities: pData?.abilities,
|
||
opponentAbilities: oData?.abilities || [],
|
||
log: this.gameInstance.consumeLogBuffer(),
|
||
clientConfig: { ...GAME_CONFIG } // Отправляем копию конфига
|
||
});
|
||
|
||
// Уведомляем другого игрока
|
||
const otherSocket = this.playerSockets[oppRoleKey];
|
||
const otherPlayerEntry = Object.values(this.players).find(p=> p.id === oppRoleKey);
|
||
if (otherSocket?.connected && otherPlayerEntry && !otherPlayerEntry.isTemporarilyDisconnected) {
|
||
otherSocket.emit('playerReconnected', {
|
||
reconnectedPlayerId: playerIdRole,
|
||
reconnectedPlayerName: reconnectedName
|
||
});
|
||
if (this.gameInstance.logBuffer.length > 0) { // Отправляем накопившиеся логи, если есть
|
||
otherSocket.emit('logUpdate', { log: this.gameInstance.consumeLogBuffer() });
|
||
}
|
||
}
|
||
|
||
// Если игра не на "эффективной" паузе и не закончена, возобновляем игру
|
||
if (!this.isGameEffectivelyPaused() && this.gameInstance.gameState && !this.gameInstance.gameState.isGameOver) {
|
||
this.gameInstance.broadcastGameStateUpdate(); // Обновляем состояние для всех
|
||
if (this.pausedTurnState && typeof this.pausedTurnState.remainingTime === 'number') {
|
||
this.gameInstance.turnTimer.resume(
|
||
this.pausedTurnState.remainingTime,
|
||
this.pausedTurnState.forPlayerRoleIsPlayer,
|
||
this.pausedTurnState.isAiCurrentlyMoving
|
||
);
|
||
this.pausedTurnState = null; // Сбрасываем сохраненное состояние таймера
|
||
} else {
|
||
// Если pausedTurnState нет, значит, таймер не был активен или это первый ход
|
||
// GameInstance.startGame или switchTurn должны запустить таймер корректно
|
||
// Но если это реконнект в середину игры, где ход уже чей-то, нужно запустить таймер
|
||
const currentTurnIsForPlayer = this.gameInstance.gameState.isPlayerTurn;
|
||
const isCurrentTurnAi = this.mode === 'ai' && !currentTurnIsForPlayer;
|
||
this.gameInstance.turnTimer.start(currentTurnIsForPlayer, isCurrentTurnAi);
|
||
}
|
||
}
|
||
return true;
|
||
|
||
} else if (playerEntry && !playerEntry.isTemporarilyDisconnected) {
|
||
// Игрок уже был подключен и не был отмечен как isTemporarilyDisconnected
|
||
// Это может быть попытка открыть игру в новой вкладке или "обновить сессию"
|
||
if (playerEntry.socket.id !== newSocket.id) {
|
||
newSocket.emit('gameError', {message: "Вы уже активно подключены с другой сессии."});
|
||
return false; // Не позволяем подключиться с нового сокета, если старый активен
|
||
}
|
||
// Если это тот же сокет (например, клиент запросил состояние), просто отправляем ему данные
|
||
if (!this.gameInstance.gameState) { // На всякий случай, если gameState вдруг нет
|
||
if (!this.gameInstance.initializeGame()) {
|
||
this.gameInstance._handleCriticalError('reconnect_same_socket_no_gs_pch','PCH: GS null on same socket reconnect.');
|
||
return false;
|
||
}
|
||
}
|
||
const pData = dataUtils.getCharacterData(playerEntry.chosenCharacterKey);
|
||
const oppRoleKey = playerIdRole === GAME_CONFIG.PLAYER_ID ? GAME_CONFIG.OPPONENT_ID : GAME_CONFIG.PLAYER_ID;
|
||
let oCharKey = this.gameInstance.gameState?.[oppRoleKey]?.characterKey ||
|
||
(playerIdRole === GAME_CONFIG.PLAYER_ID ? this.gameInstance.opponentCharacterKey : this.gameInstance.playerCharacterKey);
|
||
const oData = oCharKey ? dataUtils.getCharacterData(oCharKey) : null;
|
||
|
||
newSocket.emit('gameStarted', {
|
||
gameId: this.gameId,
|
||
yourPlayerId: playerIdRole,
|
||
initialGameState: this.gameInstance.gameState,
|
||
playerBaseStats: pData?.baseStats,
|
||
opponentBaseStats: oData?.baseStats, // Могут быть неполными, если оппонент еще не подключился
|
||
playerAbilities: pData?.abilities,
|
||
opponentAbilities: oData?.abilities,
|
||
log: this.gameInstance.consumeLogBuffer(),
|
||
clientConfig: { ...GAME_CONFIG }
|
||
});
|
||
return true;
|
||
} else {
|
||
// Запись игрока не найдена или он не был помечен как isTemporarilyDisconnected, но сокет новый.
|
||
// Это может быть попытка реконнекта к игре, из которой игрок был уже удален (например, по таймауту).
|
||
newSocket.emit('gameError', { message: 'Не удалось восстановить сессию (запись игрока не найдена или сессия устарела).' });
|
||
return false;
|
||
}
|
||
}
|
||
|
||
clearReconnectTimer(playerIdRole) {
|
||
if (this.reconnectTimers[playerIdRole]) {
|
||
clearTimeout(this.reconnectTimers[playerIdRole].timerId);
|
||
if (this.reconnectTimers[playerIdRole].updateIntervalId) {
|
||
clearInterval(this.reconnectTimers[playerIdRole].updateIntervalId);
|
||
}
|
||
delete this.reconnectTimers[playerIdRole];
|
||
console.log(`[PCH ${this.gameId}] Cleared reconnect timer for role ${playerIdRole}.`);
|
||
}
|
||
}
|
||
|
||
clearAllReconnectTimers() {
|
||
console.log(`[PCH ${this.gameId}] Clearing ALL reconnect timers.`);
|
||
for (const roleId in this.reconnectTimers) {
|
||
this.clearReconnectTimer(roleId);
|
||
}
|
||
}
|
||
|
||
isGameEffectivelyPaused() {
|
||
if (this.mode === 'pvp') {
|
||
// Если игроков меньше 2, И есть хотя бы один игрок в this.players (ожидающий или в процессе дисконнекта)
|
||
if (this.playerCount < 2 && Object.keys(this.players).length > 0) {
|
||
// Проверяем, есть ли кто-то из них в состоянии временного дисконнекта
|
||
const p1Entry = Object.values(this.players).find(p => p.id === GAME_CONFIG.PLAYER_ID);
|
||
const p2Entry = Object.values(this.players).find(p => p.id === GAME_CONFIG.OPPONENT_ID);
|
||
|
||
if ((p1Entry && p1Entry.isTemporarilyDisconnected) || (p2Entry && p2Entry.isTemporarilyDisconnected)) {
|
||
return true; // Игра на паузе, если один из игроков временно отключен
|
||
}
|
||
}
|
||
} else if (this.mode === 'ai') {
|
||
// В AI режиме игра на паузе, если единственный человек-игрок временно отключен
|
||
const humanPlayer = Object.values(this.players).find(p => p.id === GAME_CONFIG.PLAYER_ID);
|
||
return humanPlayer?.isTemporarilyDisconnected ?? false; // Если игрока нет, не на паузе. Если есть - зависит от его состояния.
|
||
}
|
||
return false; // В остальных случаях игра не считается на паузе из-за дисконнектов
|
||
}
|
||
|
||
// Вспомогательный метод для получения информации о всех игроках (может пригодиться GameInstance)
|
||
getAllPlayersInfo() {
|
||
return { ...this.players };
|
||
}
|
||
|
||
// Вспомогательный метод для получения сокетов (может пригодиться GameInstance)
|
||
getPlayerSockets() {
|
||
return { ...this.playerSockets };
|
||
}
|
||
}
|
||
|
||
module.exports = PlayerConnectionHandler; |