fix
This commit is contained in:
parent
06e95fb432
commit
5390d5d675
4 changed files with 41 additions and 22 deletions
|
|
@ -105,6 +105,11 @@ export class GameGateway implements OnGatewayConnection, OnGatewayDisconnect, On
|
||||||
console.log(`🔌 Client ${client.id} joining WebSocket room ${payload.roomCode}, userId: ${payload.userId}`);
|
console.log(`🔌 Client ${client.id} joining WebSocket room ${payload.roomCode}, userId: ${payload.userId}`);
|
||||||
client.join(payload.roomCode);
|
client.join(payload.roomCode);
|
||||||
|
|
||||||
|
// Логируем всех клиентов в комнате
|
||||||
|
const roomClients = this.server.sockets.adapter.rooms.get(payload.roomCode);
|
||||||
|
console.log(`👥 Clients in room ${payload.roomCode}: ${roomClients?.size || 0}`,
|
||||||
|
Array.from(roomClients || []));
|
||||||
|
|
||||||
// Получаем полное состояние для отправки присоединившемуся клиенту
|
// Получаем полное состояние для отправки присоединившемуся клиенту
|
||||||
const room = (await this.prisma.room.findUnique({
|
const room = (await this.prisma.room.findUnique({
|
||||||
where: { code: payload.roomCode },
|
where: { code: payload.roomCode },
|
||||||
|
|
@ -574,7 +579,9 @@ export class GameGateway implements OnGatewayConnection, OnGatewayDisconnect, On
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const roomClients = this.server.sockets.adapter.rooms.get(roomCode);
|
||||||
console.log(`📡 Broadcasting gameStateUpdated to room ${roomCode} with ${room.participants.length} participants`);
|
console.log(`📡 Broadcasting gameStateUpdated to room ${roomCode} with ${room.participants.length} participants`);
|
||||||
|
console.log(`📡 Target clients: ${roomClients?.size || 0}`, Array.from(roomClients || []));
|
||||||
this.server.to(roomCode).emit('gameStateUpdated', fullState);
|
this.server.to(roomCode).emit('gameStateUpdated', fullState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -153,10 +153,6 @@ export class RoomsService {
|
||||||
|
|
||||||
// Отправляем событие roomUpdate всем клиентам в комнате
|
// Отправляем событие roomUpdate всем клиентам в комнате
|
||||||
if (updatedRoom) {
|
if (updatedRoom) {
|
||||||
// Небольшая задержка, чтобы дать время новому игроку присоединиться к WebSocket комнате
|
|
||||||
// WebSocket joinRoom может выполняться параллельно с REST API joinRoom
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 50));
|
|
||||||
|
|
||||||
console.log(`📤 Broadcasting room update for ${updatedRoom.code} with ${updatedRoom.participants.length} participants`);
|
console.log(`📤 Broadcasting room update for ${updatedRoom.code} with ${updatedRoom.participants.length} participants`);
|
||||||
this.roomEventsService.emitRoomUpdate(updatedRoom.code, updatedRoom);
|
this.roomEventsService.emitRoomUpdate(updatedRoom.code, updatedRoom);
|
||||||
// Также отправляем gameStateUpdated через broadcastFullState
|
// Также отправляем gameStateUpdated через broadcastFullState
|
||||||
|
|
@ -248,9 +244,6 @@ export class RoomsService {
|
||||||
|
|
||||||
// Отправляем событие roomUpdate всем клиентам в комнате
|
// Отправляем событие roomUpdate всем клиентам в комнате
|
||||||
if (updatedRoom) {
|
if (updatedRoom) {
|
||||||
// Небольшая задержка, чтобы дать время новому игроку присоединиться к WebSocket комнате
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 50));
|
|
||||||
|
|
||||||
this.roomEventsService.emitRoomUpdate(updatedRoom.code, updatedRoom);
|
this.roomEventsService.emitRoomUpdate(updatedRoom.code, updatedRoom);
|
||||||
// Также отправляем gameStateUpdated через broadcastFullState
|
// Также отправляем gameStateUpdated через broadcastFullState
|
||||||
await this.gameGateway.broadcastFullState(updatedRoom.code);
|
await this.gameGateway.broadcastFullState(updatedRoom.code);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,12 @@ export const useRoom = (roomCode, onGameStarted = null, password = null) => {
|
||||||
const [participants, setParticipants] = useState([]);
|
const [participants, setParticipants] = useState([]);
|
||||||
const [requiresPassword, setRequiresPassword] = useState(false);
|
const [requiresPassword, setRequiresPassword] = useState(false);
|
||||||
|
|
||||||
|
// Используем ref для onGameStarted, чтобы не пересоздавать обработчики при его изменении
|
||||||
|
const onGameStartedRef = useRef(onGameStarted);
|
||||||
|
useEffect(() => {
|
||||||
|
onGameStartedRef.current = onGameStarted;
|
||||||
|
}, [onGameStarted]);
|
||||||
|
|
||||||
// Обработчики событий вынесены наружу useEffect, чтобы они регистрировались только один раз
|
// Обработчики событий вынесены наружу useEffect, чтобы они регистрировались только один раз
|
||||||
// и не зависели от изменений зависимостей
|
// и не зависели от изменений зависимостей
|
||||||
const handleRoomUpdate = useCallback((updatedRoom) => {
|
const handleRoomUpdate = useCallback((updatedRoom) => {
|
||||||
|
|
@ -22,11 +28,11 @@ export const useRoom = (roomCode, onGameStarted = null, password = null) => {
|
||||||
const handleGameStarted = useCallback((updatedRoom) => {
|
const handleGameStarted = useCallback((updatedRoom) => {
|
||||||
console.log('🎮 gameStarted received');
|
console.log('🎮 gameStarted received');
|
||||||
setRoom(updatedRoom);
|
setRoom(updatedRoom);
|
||||||
// Вызываем callback для навигации на страницу игры
|
// Вызываем callback через ref
|
||||||
if (onGameStarted) {
|
if (onGameStartedRef.current) {
|
||||||
onGameStarted(updatedRoom);
|
onGameStartedRef.current(updatedRoom);
|
||||||
}
|
}
|
||||||
}, [onGameStarted]);
|
}, []); // Теперь НЕТ зависимости от onGameStarted!
|
||||||
|
|
||||||
const handleGameStateUpdated = useCallback((state) => {
|
const handleGameStateUpdated = useCallback((state) => {
|
||||||
console.log('🔄 gameStateUpdated received:', state.participants?.length, 'participants');
|
console.log('🔄 gameStateUpdated received:', state.participants?.length, 'participants');
|
||||||
|
|
@ -57,11 +63,11 @@ export const useRoom = (roomCode, onGameStarted = null, password = null) => {
|
||||||
return updatedRoom;
|
return updatedRoom;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Если игра началась, вызываем callback
|
// Если игра началась, вызываем callback через ref
|
||||||
if (state.status === 'PLAYING' && onGameStarted) {
|
if (state.status === 'PLAYING' && onGameStartedRef.current) {
|
||||||
onGameStarted(state);
|
onGameStartedRef.current(state);
|
||||||
}
|
}
|
||||||
}, [onGameStarted]);
|
}, []); // Теперь НЕТ зависимости от onGameStarted!
|
||||||
|
|
||||||
const handleRoomPackUpdated = useCallback((updatedRoom) => {
|
const handleRoomPackUpdated = useCallback((updatedRoom) => {
|
||||||
setRoom(updatedRoom);
|
setRoom(updatedRoom);
|
||||||
|
|
@ -140,7 +146,7 @@ export const useRoom = (roomCode, onGameStarted = null, password = null) => {
|
||||||
socketService.off('gameStateUpdated', handleGameStateUpdated);
|
socketService.off('gameStateUpdated', handleGameStateUpdated);
|
||||||
socketService.off('roomPackUpdated', handleRoomPackUpdated);
|
socketService.off('roomPackUpdated', handleRoomPackUpdated);
|
||||||
};
|
};
|
||||||
}, [roomCode, password, user?.id, authLoading, handleRoomUpdate, handleGameStarted, handleGameStateUpdated, handleRoomPackUpdated]);
|
}, [roomCode, password, user?.id, authLoading]); // Убрали обработчики из зависимостей!
|
||||||
|
|
||||||
const createRoom = useCallback(async (hostId, questionPackId, settings = {}, hostName) => {
|
const createRoom = useCallback(async (hostId, questionPackId, settings = {}, hostName) => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -155,16 +161,24 @@ export const useRoom = (roomCode, onGameStarted = null, password = null) => {
|
||||||
|
|
||||||
const joinRoom = useCallback(async (roomId, userId, name, role = 'PLAYER') => {
|
const joinRoom = useCallback(async (roomId, userId, name, role = 'PLAYER') => {
|
||||||
try {
|
try {
|
||||||
|
// ВАЖНО: Сначала подключаемся к WebSocket комнате
|
||||||
|
// Это гарантирует, что мы получим broadcast от backend после создания участника
|
||||||
|
if (roomCode) {
|
||||||
|
socketService.connect();
|
||||||
|
socketService.joinRoom(roomCode, userId);
|
||||||
|
// Даем время на установку WebSocket соединения
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Теперь вызываем REST API для создания участника
|
||||||
const response = await roomsApi.join(roomId, userId, name, role);
|
const response = await roomsApi.join(roomId, userId, name, role);
|
||||||
|
|
||||||
// После успешного присоединения запрашиваем полное состояние через WebSocket
|
// После успешного присоединения запрашиваем полное состояние через WebSocket
|
||||||
// Это гарантирует получение актуального состояния от сервера (список игроков, тема, voiceMode)
|
// (дополнительная гарантия получения актуального состояния)
|
||||||
// НЕ обновляем состояние локально - полагаемся только на серверные обновления для консистентности
|
|
||||||
if (roomCode) {
|
if (roomCode) {
|
||||||
// Небольшая задержка, чтобы убедиться, что WebSocket подключен
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
socketService.emit('requestFullState', { roomCode });
|
socketService.emit('requestFullState', { roomCode });
|
||||||
}, 100);
|
}, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.data;
|
return response.data;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import GameManagementModal from '../components/GameManagementModal';
|
||||||
const RoomPage = () => {
|
const RoomPage = () => {
|
||||||
const { roomCode } = useParams();
|
const { roomCode } = useParams();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { user } = useAuth();
|
const { user, loading: authLoading } = useAuth();
|
||||||
const { changeTheme } = useTheme();
|
const { changeTheme } = useTheme();
|
||||||
|
|
||||||
// Храним предыдущий themeId комнаты для отслеживания изменений
|
// Храним предыдущий themeId комнаты для отслеживания изменений
|
||||||
|
|
@ -107,6 +107,11 @@ const RoomPage = () => {
|
||||||
// Единая логика присоединения к комнате
|
// Единая логика присоединения к комнате
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleJoin = async () => {
|
const handleJoin = async () => {
|
||||||
|
// Ждем загрузки пользователя из куки
|
||||||
|
if (authLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Перенаправляем на главный экран, если нет пользователя
|
// Перенаправляем на главный экран, если нет пользователя
|
||||||
if (!user) {
|
if (!user) {
|
||||||
alert('Пожалуйста, задайте имя на главном экране');
|
alert('Пожалуйста, задайте имя на главном экране');
|
||||||
|
|
@ -156,7 +161,7 @@ const RoomPage = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
handleJoin();
|
handleJoin();
|
||||||
}, [room, user, joined, participants, joinRoom, navigate, isRoleSelectionModalOpen]);
|
}, [room, user, joined, participants, joinRoom, navigate, isRoleSelectionModalOpen, authLoading]);
|
||||||
|
|
||||||
// Обработка выбора роли
|
// Обработка выбора роли
|
||||||
// Присоединение разрешено независимо от статуса игры (WAITING, PLAYING, FINISHED)
|
// Присоединение разрешено независимо от статуса игры (WAITING, PLAYING, FINISHED)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue